[Pkg-voip-commits] [kamailio] 01/04: Imported Upstream version 4.1.0

Victor Seva Lopez maniac-guest at moszumanska.debian.org
Wed Dec 11 15:32:30 UTC 2013


This is an automated email from the git hooks/post-receive script.

maniac-guest pushed a commit to branch vseva/4.1.0
in repository kamailio.

commit b74e773caad4907332486a44b87ad5124468103e
Author: Victor Seva <linuxmaniac at torreviejawireless.org>
Date:   Fri Dec 6 12:22:27 2013 +0100

    Imported Upstream version 4.1.0
---
 ChangeLog                                          | 16075 +++++++------------
 Makefile                                           |    45 +
 Makefile.defs                                      |   103 +-
 Makefile.groups                                    |    39 +-
 README                                             |    23 +-
 action.c                                           |    31 +-
 action.h                                           |     3 +
 autover.h                                          |     4 +-
 cfg.lex                                            |    89 +-
 cfg.y                                              |   237 +-
 cfg/cfg.h                                          |    31 +-
 cfg_core.c                                         |    15 +-
 cfg_core.h                                         |     1 +
 config.h                                           |     4 +
 core_cmd.c                                         |   139 +-
 counters.c                                         |    10 +-
 counters.h                                         |     1 +
 data_lump.h                                        |     2 +-
 dns_cache.c                                        |   209 +-
 dns_func.c                                         |    55 +
 dns_func.h                                         |    55 +
 doc/cfg_list/Makefile                              |    16 +-
 doc/cfg_list/cfg_core.txt                          |    35 +-
 doc/cfg_list/cfg_registrar.txt                     |    27 +-
 doc/cfg_list/cfg_tcp.txt                           |    53 +-
 doc/cfg_list/cfg_tm.txt                            |    71 +-
 doc/counter_list/Makefile                          |     2 +-
 doc/rpc_list/Makefile                              |    49 +-
 doc/rpc_list/docbook/rpc_app_lua.xml               |    27 +
 doc/rpc_list/docbook/rpc_carrierroute.xml          |    19 +
 doc/rpc_list/docbook/rpc_cnxcc.xml                 |    35 +
 doc/rpc_list/docbook/rpc_core.xml                  |    26 +-
 doc/rpc_list/docbook/rpc_corex.xml                 |    27 +
 doc/rpc_list/docbook/rpc_cpl-c.xml                 |    35 -
 doc/rpc_list/docbook/rpc_db_flatstore.xml          |     4 +-
 doc/rpc_list/docbook/rpc_db_text.xml               |    19 +
 doc/rpc_list/docbook/rpc_debugger.xml              |    18 +-
 doc/rpc_list/docbook/rpc_dialog_ng.xml             |    19 +
 doc/rpc_list/docbook/rpc_dialplan.xml              |     2 +-
 doc/rpc_list/docbook/rpc_dispatcher_s.xml          |    27 -
 doc/rpc_list/docbook/rpc_domain.xml                |     4 +-
 doc/rpc_list/docbook/rpc_domain_s.xml              |    27 -
 doc/rpc_list/docbook/rpc_drouting.xml              |    19 +
 doc/rpc_list/docbook/rpc_gflags.xml                |    59 -
 doc/rpc_list/docbook/rpc_htable.xml                |    56 +
 doc/rpc_list/docbook/rpc_ims_usrloc_pcscf.xml      |    19 +
 doc/rpc_list/docbook/rpc_ims_usrloc_scscf.xml      |    27 +
 doc/rpc_list/docbook/rpc_lcr.xml                   |     8 +
 doc/rpc_list/docbook/rpc_list.xml                  |    47 +-
 doc/rpc_list/docbook/rpc_msrp.xml                  |    19 +
 doc/rpc_list/docbook/rpc_mtree.xml                 |    27 +
 doc/rpc_list/docbook/rpc_pdt.xml                   |    15 +-
 doc/rpc_list/docbook/rpc_permissions.xml           |    68 +
 doc/rpc_list/docbook/rpc_pike.xml                  |     2 +-
 doc/rpc_list/docbook/rpc_pipelimit.xml             |    65 +
 doc/rpc_list/docbook/rpc_prefix_route.xml          |     4 +-
 doc/rpc_list/docbook/rpc_presence.xml              |    20 +
 doc/rpc_list/docbook/rpc_presence_b2b.xml          |    27 -
 doc/rpc_list/docbook/rpc_pv.xml                    |    27 +
 doc/rpc_list/docbook/rpc_sca.xml                   |   100 +
 doc/rpc_list/docbook/rpc_sctp.xml                  |    33 +
 doc/rpc_list/docbook/rpc_sipcapture.xml            |    19 +
 doc/rpc_list/docbook/rpc_siptrace.xml              |    20 +
 doc/rpc_list/docbook/rpc_sl.xml                    |     2 +-
 doc/rpc_list/docbook/rpc_tls.xml                   |     8 +-
 doc/rpc_list/docbook/rpc_tm.xml                    |    17 +-
 doc/rpc_list/docbook/rpc_uid_domain.xml            |    27 +
 doc/rpc_list/docbook/rpc_uid_gflags.xml            |    59 +
 doc/rpc_list/docbook/rpc_usrloc.xml                |    67 +
 doc/rpc_list/docbook/rpc_usrloc_k.xml              |    19 -
 doc/rpc_list/docbook/rpc_usrloc_s.xml              |    77 -
 doc/rpc_list/docbook/rpc_xhttp_pi.xml              |    19 +
 doc/rpc_list/rpc_app_lua.txt                       |    12 +
 doc/rpc_list/rpc_carrierroute.txt                  |     9 +
 doc/rpc_list/rpc_cnxcc.txt                         |    15 +
 doc/rpc_list/rpc_core.txt                          |    68 +-
 doc/rpc_list/rpc_corex.txt                         |    12 +
 doc/rpc_list/rpc_cpl-c.txt                         |    15 -
 doc/rpc_list/rpc_db_flatstore.txt                  |     4 +-
 doc/rpc_list/rpc_db_text.txt                       |     9 +
 doc/rpc_list/rpc_debugger.txt                      |     8 +-
 doc/rpc_list/rpc_dialog_ng.txt                     |     9 +
 doc/rpc_list/rpc_dialplan.txt                      |     2 +-
 doc/rpc_list/rpc_dispatcher_s.txt                  |    12 -
 doc/rpc_list/rpc_domain.txt                        |     4 +-
 doc/rpc_list/rpc_domain_s.txt                      |    12 -
 doc/rpc_list/rpc_drouting.txt                      |     9 +
 doc/rpc_list/rpc_gflags.txt                        |    24 -
 doc/rpc_list/rpc_htable.txt                        |    21 +
 doc/rpc_list/rpc_ims_usrloc_pcscf.txt              |     9 +
 doc/rpc_list/rpc_ims_usrloc_scscf.txt              |    12 +
 doc/rpc_list/rpc_lcr.txt                           |     3 +
 doc/rpc_list/rpc_msrp.txt                          |     9 +
 doc/rpc_list/rpc_mtree.txt                         |    12 +
 doc/rpc_list/rpc_pdt.txt                           |    12 +-
 doc/rpc_list/rpc_permissions.txt                   |    28 +
 doc/rpc_list/rpc_pike.txt                          |     2 +-
 doc/rpc_list/rpc_pipelimit.txt                     |    27 +
 doc/rpc_list/rpc_prefix_route.txt                  |     4 +-
 doc/rpc_list/rpc_presence.txt                      |    10 +
 doc/rpc_list/rpc_presence_b2b.txt                  |    12 -
 doc/rpc_list/rpc_pv.txt                            |    12 +
 doc/rpc_list/rpc_sca.txt                           |    40 +
 doc/rpc_list/rpc_sctp.txt                          |    17 +
 doc/rpc_list/rpc_sipcapture.txt                    |     9 +
 doc/rpc_list/rpc_siptrace.txt                      |    10 +
 doc/rpc_list/rpc_sl.txt                            |     2 +-
 doc/rpc_list/rpc_tls.txt                           |     8 +-
 doc/rpc_list/rpc_tm.txt                            |    17 +-
 doc/rpc_list/rpc_uid_domain.txt                    |    12 +
 doc/rpc_list/rpc_uid_gflags.txt                    |    24 +
 doc/rpc_list/rpc_usrloc.txt                        |    27 +
 doc/rpc_list/rpc_usrloc_k.txt                      |     9 -
 doc/rpc_list/rpc_usrloc_s.txt                      |    32 -
 doc/rpc_list/rpc_xhttp_pi.txt                      |     9 +
 doc/select_list/Makefile                           |     2 +-
 doc/stylesheets/dbschema_k/xsl/mysql.xsl           |     6 +-
 dprint.c                                           |    19 +-
 dprint.h                                           |    15 +-
 dset.c                                             |   343 +-
 dset.h                                             |    28 +-
 dst_blacklist.c                                    |    22 -
 etc/kamailio-basic.cfg                             |   612 +
 etc/kamailio.cfg                                   |    42 +-
 events.c                                           |    59 +
 events.h                                           |    12 +-
 examples/icscf/icscf.cfg                           |    12 +-
 examples/icscf/kamailio.cfg                        |    85 +-
 examples/ims_dnszone/kamailio-ims.org.dnszone      |    34 +
 examples/outbound/edge.cfg                         |   172 +
 examples/outbound/edge_websocket.cfg               |   293 +
 examples/outbound/registrar.cfg                    |   202 +
 examples/pcscf/kamailio.cfg                        |    43 +-
 examples/pcscf/pcscf.cfg                           |    23 +-
 examples/scscf/kamailio.cfg                        |   166 +-
 examples/scscf/scscf.cfg                           |    13 +-
 examples/websocket.cfg                             |     7 +-
 forward.c                                          |    46 +-
 forward.h                                          |     4 +-
 globals.h                                          |    11 +-
 ip_addr.c                                          |    13 +-
 ip_addr.h                                          |    36 -
 lib/ims/ims_getters.c                              |   103 +
 lib/ims/ims_getters.h                              |     8 +
 lib/kcore/parse_pai.c                              |    77 -
 lib/kcore/parse_pai.h                              |    45 -
 lib/kcore/parse_ppi.c                              |   119 -
 lib/kcore/parse_ppi.h                              |    53 -
 lib/kcore/parse_supported.c                        |   190 -
 lib/kcore/parse_supported.h                        |    94 -
 lib/kcore/statistics.c                             |    82 +-
 lib/kcore/statistics.h                             |    10 +-
 lib/srdb1/schema/acc_cdrs.xml                      |    57 +
 lib/srdb1/schema/dbaliases.xml                     |    11 +-
 lib/srdb1/schema/entities.xml                      |     2 +-
 lib/srdb1/schema/kamailio-acc.xml                  |     1 +
 lib/srdb1/schema/kamailio-mohqueue.xml             |    14 +
 lib/srdb1/schema/kamailio-rtpproxy.xml             |    12 +
 lib/srdb1/schema/mohqcalls.xml                     |    75 +
 lib/srdb1/schema/mohqueues.xml                     |    75 +
 lib/srdb1/schema/rtpproxy.xml                      |    69 +
 lvalue.c                                           |    16 +-
 lvalue.h                                           |     5 +-
 main.c                                             |    55 +-
 mem/f_malloc.c                                     |     2 +
 mem/q_malloc.c                                     |     2 +
 modules/acc/README                                 |   235 +-
 modules/acc/acc.c                                  |   107 +-
 modules/acc/acc.h                                  |     1 +
 modules/acc/acc_api.h                              |     4 +-
 modules/acc/acc_cdr.c                              |   113 +-
 modules/acc/acc_logic.c                            |     3 +-
 modules/acc/acc_mod.c                              |    28 +-
 modules/acc/acc_mod.h                              |     7 +
 modules/acc/doc/acc_admin.xml                      |   354 +-
 modules/acc_radius/acc_radius_mod.c                |     6 +-
 modules/alias_db/README                            |     2 +-
 modules/alias_db/alookup.c                         |     2 +-
 modules/app_java/BUILDING_JAR.TXT                  |    54 +
 modules/app_java/Makefile                          |    35 +
 modules/app_java/QUICKSTART.TXT                    |    25 +
 modules/app_java/README                            |   573 +
 modules/app_java/README-draft                      |   837 +
 modules/app_java/doc/Makefile                      |     4 +
 modules/app_java/doc/app_java.xml                  |    35 +
 modules/app_java/doc/app_java_admin.xml            |   648 +
 modules/app_java/global.h                          |    48 +
 modules/app_java/java_iface.c                      |   284 +
 modules/app_java/java_iface.h                      |    44 +
 modules/app_java/java_mod.c                        |   260 +
 modules/app_java/java_mod.h                        |    30 +
 modules/app_java/java_msgobj.c                     |   324 +
 modules/app_java/java_msgobj.h                     |    34 +
 modules/app_java/java_native_methods.c             |  1223 ++
 modules/app_java/java_native_methods.h             |    86 +
 modules/app_java/java_sig_parser.c                 |   439 +
 modules/app_java/java_sig_parser.h                 |    50 +
 modules/app_java/java_support.c                    |   220 +
 modules/app_java/java_support.h                    |    38 +
 .../java-untested/Kamailio.java                    |   388 +
 .../java-untested/WrappedMethods.java              |    87 +
 .../kamailio_java_folder/java-untested/build.xml   |    46 +
 .../java-untested/siprouter_src/CoreMethods.java   |    34 +
 .../java-untested/siprouter_src/IPPair.java        |    15 +
 .../siprouter_src/NativeInterface.java             |    46 +
 .../java-untested/siprouter_src/NativeMethods.java |    22 +
 .../java-untested/siprouter_src/SipMsg.java        |    43 +
 .../kamailio_java_folder/java/Kamailio.java        |   130 +
 .../app_java/kamailio_java_folder/java/build.xml   |    46 +
 .../java/siprouter_src/IPPair.java                 |    15 +
 .../java/siprouter_src/NativeInterface.java        |    46 +
 .../java/siprouter_src/NativeMethods.java          |    23 +
 .../java/siprouter_src/SipMsg.java                 |    43 +
 modules/app_java/utils.c                           |    89 +
 modules/app_java/utils.h                           |    34 +
 modules/app_lua/README                             |    78 +-
 modules/app_lua/app_lua_api.c                      |   248 +-
 modules/app_lua/app_lua_api.h                      |    22 +
 modules/app_lua/app_lua_mod.c                      |    94 +-
 modules/app_lua/app_lua_sr.c                       |   281 +-
 modules/app_lua/doc/app_lua_admin.xml              |    89 +-
 modules/app_perl/README                            |   176 +-
 modules/app_perl/app_perl_mod.c                    |   205 +-
 modules/app_perl/doc/app_perl_admin.xml            |    79 +-
 modules/app_perl/perlfunc.c                        |     3 +
 modules/app_perl/perlfunc.h                        |     2 +
 modules/auth/README                                |   686 +-
 modules/auth/doc/auth_functions.xml                |    18 +-
 modules/auth/doc/auth_params.xml                   |    54 +-
 modules/auth_db/README                             |    12 +-
 modules/auth_db/doc/auth_db_admin.xml              |    20 +-
 modules/auth_ephemeral/Makefile                    |    41 +
 modules/auth_ephemeral/README                      |   497 +
 modules/auth_ephemeral/autheph_mod.c               |   449 +
 modules/auth_ephemeral/autheph_mod.h               |    50 +
 modules/auth_ephemeral/authorize.c                 |   479 +
 modules/auth_ephemeral/authorize.h                 |    37 +
 modules/auth_ephemeral/checks.c                    |   282 +
 modules/auth_ephemeral/checks.h                    |    40 +
 modules/auth_ephemeral/doc/Makefile                |     4 +
 modules/auth_ephemeral/doc/auth_ephemeral.xml      |    30 +
 .../auth_ephemeral/doc/auth_ephemeral_admin.xml    |   574 +
 modules/avp/doc/avp_functions.xml                  |    48 +-
 modules/avp/doc/avp_params.xml                     |     2 +-
 modules/avpops/README                              |    68 +-
 modules/avpops/avpops.c                            |    63 +-
 modules/avpops/avpops_impl.c                       |   229 +-
 modules/avpops/avpops_impl.h                       |     2 +-
 modules/avpops/avpops_parse.c                      |    28 +-
 modules/avpops/doc/avpops_admin.xml                |    70 +-
 modules/carrierroute/README                        |     7 +-
 modules/carrierroute/carrierroute.c                |    44 +-
 modules/carrierroute/carrierroute.h                |     3 +
 modules/carrierroute/cr_func.c                     |   121 +-
 modules/carrierroute/doc/carrierroute_admin.xml    |     8 +-
 modules/cdp/acctstatemachine.c                     |   254 +
 modules/cdp/acctstatemachine.h                     |    19 +
 modules/cdp/authstatemachine.c                     |    66 +-
 modules/cdp/authstatemachine.h                     |     2 -
 modules/cdp/cdp_load.c                             |    11 +-
 modules/cdp/cdp_load.h                             |     6 +
 modules/cdp/common.c                               |    52 +
 modules/cdp/common.h                               |    19 +
 modules/cdp/configexample/ConfigExample.xml        |     2 +-
 modules/cdp/diameter_peer.c                        |    11 +-
 modules/cdp/mod.c                                  |     9 +
 modules/cdp/peerstatemachine.c                     |    20 +
 modules/cdp/receiver.c                             |     3 +
 modules/cdp/session.c                              |   189 +-
 modules/cdp/session.h                              |   112 +-
 modules/cdp/tcp_accept.c                           |     4 +
 modules/cdp/timer.c                                |     3 +
 modules/cdp/worker.c                               |     3 +
 modules/cfgutils/README                            |   103 +-
 modules/cfgutils/cfgutils.c                        |    36 +-
 modules/cfgutils/doc/cfgutils.xml                  |     7 +
 modules/cfgutils/doc/cfgutils_admin.xml            |   107 +-
 modules/cnxcc/Makefile                             |    17 +
 modules/cnxcc/README                               |   362 +
 modules/cnxcc/cnxcc.c                              |    63 +
 modules/cnxcc/cnxcc.h                              |    39 +
 modules/cnxcc/cnxcc_check.c                        |   193 +
 modules/cnxcc/cnxcc_check.h                        |    33 +
 modules/cnxcc/cnxcc_mod.c                          |  1960 +++
 modules/cnxcc/cnxcc_mod.h                          |   156 +
 modules/cnxcc/cnxcc_rpc.c                          |   286 +
 modules/cnxcc/cnxcc_rpc.h                          |    33 +
 modules/cnxcc/cnxcc_select.c                       |    67 +
 modules/cnxcc/cnxcc_select.h                       |    32 +
 modules/cnxcc/cnxcc_sip_msg_faker.c                |    71 +
 modules/cnxcc/cnxcc_sip_msg_faker.h                |    29 +
 modules/cnxcc/doc/Makefile                         |     4 +
 modules/cnxcc/doc/cnxcc.xml                        |    36 +
 modules/cnxcc/doc/cnxcc_admin.xml                  |   456 +
 modules/cnxcc/example/kamailio-cnxcc.cfg           |  1092 ++
 modules/corex/README                               |    10 +-
 modules/corex/corex_lib.c                          |     2 +-
 modules/corex/corex_mod.c                          |    10 +-
 modules/corex/corex_var.c                          |    83 +
 modules/corex/corex_var.h                          |    28 +
 modules/cpl-c/cpl_sig.c                            |     2 +-
 modules/db_cluster/README                          |    21 +-
 modules/db_cluster/doc/db_cluster_admin.xml        |    25 +-
 modules/db_mysql/README                            |    28 +-
 modules/db_mysql/doc/db_mysql_admin.xml            |    20 +
 modules/db_mysql/km_db_mysql.c                     |     4 +
 modules/db_mysql/km_db_mysql.h                     |     1 +
 modules/db_mysql/km_dbase.c                        |   203 +-
 modules/db_mysql/km_dbase.h                        |    16 +
 modules/db_mysql/km_my_con.h                       |     8 +-
 modules/db_mysql/mysql_mod.c                       |     8 +-
 modules/db_sqlite/Makefile                         |     7 +-
 modules/db_text/README                             |     2 +-
 modules/db_unixodbc/con.c                          |   225 -
 modules/db_unixodbc/connection.c                   |   225 +
 modules/db_unixodbc/{con.h => connection.h}        |     0
 modules/db_unixodbc/dbase.c                        |     2 +-
 modules/db_unixodbc/list.h                         |     2 +-
 modules/db_unixodbc/res.c                          |     2 +-
 modules/db_unixodbc/row.c                          |     2 +-
 modules/db_unixodbc/val.c                          |     2 +-
 modules/debugger/Makefile                          |     2 +
 modules/debugger/README                            |   183 +-
 modules/debugger/debugger_api.c                    |   913 +-
 modules/debugger/debugger_api.h                    |    24 +
 modules/debugger/debugger_config.c                 |    48 +
 modules/debugger/debugger_config.h                 |    46 +
 modules/debugger/debugger_mod.c                    |   154 +-
 modules/debugger/doc/debugger_admin.xml            |   282 +-
 modules/dialog/dialog.c                            |    62 +-
 modules/dialog/dlg_hash.c                          |    49 +-
 modules/dialog/dlg_hash.h                          |     3 +
 modules/dialog/dlg_req_within.c                    |    57 +-
 modules/dialog/dlg_transfer.c                      |    13 +-
 modules/dialog/dlg_transfer.h                      |     2 +-
 modules/dialog_ng/dialog.c                         |    78 +
 modules/dialog_ng/dlg_handlers.c                   |    36 +-
 modules/dialog_ng/dlg_handlers.h                   |     8 +-
 modules/dialog_ng/dlg_hash.c                       |    12 +-
 modules/dialog_ng/dlg_load.h                       |    19 +-
 modules/dialog_ng/dlg_req_within.c                 |    18 +
 modules/dialog_ng/dlg_req_within.h                 |     1 +
 modules/dialog_ng/doc/dialog_ng.xml                |     4 +-
 modules/dialog_ng/doc/dialog_ng_admin.xml          |    46 +-
 modules/dialog_ng/doc/dialog_ng_devel.xml          |    29 +
 modules/dialplan/dialplan.c                        |    72 +-
 modules/dialplan/dialplan.h                        |     2 +-
 modules/dispatcher/README                          |   176 +-
 modules/dispatcher/dispatch.c                      |    46 +-
 modules/dispatcher/dispatch.h                      |     3 +
 modules/dispatcher/dispatcher.c                    |    30 +-
 modules/dispatcher/doc/dispatcher.xml              |     2 +-
 modules/dispatcher/doc/dispatcher_admin.xml        |   107 +-
 modules/dmq/README                                 |   217 +-
 modules/dmq/bind_dmq.h                             |    19 +-
 modules/dmq/dmq.c                                  |    17 +-
 modules/dmq/dmq.h                                  |    18 -
 modules/dmq/dmq_funcs.c                            |    48 +-
 modules/dmq/dmq_funcs.h                            |     6 +-
 modules/dmq/dmqnode.c                              |    22 +-
 modules/dmq/doc/dmq.xml                            |    27 +-
 modules/dmq/doc/dmq_admin.xml                      |   156 +-
 modules/dmq/doc/dmq_devel.xml                      |    91 +-
 modules/dmq/message.c                              |    14 +-
 modules/dmq/message.h                              |     2 +-
 modules/dmq/notification_peer.c                    |    11 +-
 modules/dmq/notification_peer.h                    |     2 +
 modules/dmq/worker.c                               |    34 +-
 modules/dmq/worker.h                               |     1 +
 modules/dnssec/Makefile                            |    17 +
 modules/dnssec/README                              |   124 +
 modules/dnssec/dnssec_func.c                       |   150 +
 modules/dnssec/dnssec_func.h                       |    54 +
 modules/dnssec/dnssec_mod.c                        |   135 +
 modules/dnssec/doc/Makefile                        |     3 +
 modules/dnssec/doc/dnssec.xml                      |    33 +
 modules/dnssec/doc/dnssec_admin.xml                |   129 +
 modules/domain/README                              |     2 +-
 modules/domain/domain.c                            |     2 +-
 modules/domainpolicy/README                        |     2 +-
 modules/drouting/README                            |   169 +-
 modules/drouting/doc/drouting_admin.xml            |    15 +
 modules/drouting/drouting.c                        |    40 +-
 modules/enum/enum.c                                |    12 +-
 modules/enum/enum.h                                |     5 +-
 modules/exec/exec.c                                |     2 +-
 modules/group/README                               |    11 +-
 modules/group/doc/group_admin.xml                  |    30 +-
 modules/gzcompress/Makefile                        |    25 +
 modules/gzcompress/README                          |   220 +
 modules/gzcompress/doc/Makefile                    |     4 +
 modules/gzcompress/doc/gzcompress.xml              |    37 +
 modules/gzcompress/doc/gzcompress_admin.xml        |   229 +
 modules/gzcompress/gzcompress_mod.c                |   396 +
 modules/htable/Makefile                            |     1 +
 modules/htable/README                              |   203 +-
 modules/htable/api.c                               |    20 +
 modules/htable/doc/htable_admin.xml                |   198 +-
 modules/htable/ht_api.c                            |    18 +-
 modules/htable/ht_api.h                            |     6 +-
 modules/htable/ht_dmq.c                            |   277 +
 modules/htable/ht_dmq.h                            |    48 +
 modules/htable/ht_var.c                            |    18 +
 modules/htable/htable.c                            |   355 +-
 modules/imc/README                                 |     8 +-
 modules/ims_auth/authims_mod.c                     |    55 +-
 modules/ims_auth/authorize.c                       |    78 +-
 modules/ims_auth/authorize.h                       |     4 +-
 modules/ims_auth/cxdx_avp.c                        |     2 +-
 modules/ims_auth/cxdx_mar.c                        |     3 +-
 modules/ims_auth/cxdx_mar.h                        |     6 -
 modules/ims_auth/doc/ims_auth.xml                  |    11 +
 modules/ims_auth/doc/ims_auth_admin.xml            |   149 +-
 modules/ims_charging/Makefile                      |    22 +
 modules/ims_charging/README                        |   714 +
 modules/ims_charging/Ro_data.c                     |   289 +
 modules/ims_charging/Ro_data.h                     |   408 +
 modules/ims_charging/ccr.c                         |   328 +
 modules/ims_charging/ccr.h                         |    10 +
 modules/ims_charging/config.h                      |    12 +
 modules/ims_charging/dialog.c                      |   161 +
 modules/ims_charging/dialog.h                      |    14 +
 modules/ims_charging/diameter_ro.c                 |    40 +
 modules/ims_charging/diameter_ro.h                 |    11 +
 modules/ims_charging/doc/Makefile                  |     4 +
 modules/ims_charging/doc/images/charging1.png      |   Bin 0 -> 8503 bytes
 modules/ims_charging/doc/images/charging2.png      |   Bin 0 -> 80472 bytes
 modules/ims_charging/doc/ims_charging.xml          |    50 +
 modules/ims_charging/doc/ims_charging_admin.xml    |   651 +
 modules/ims_charging/ims_ro.c                      |  1209 ++
 modules/ims_charging/ims_ro.h                      |    23 +
 modules/ims_charging/mod.c                         |   358 +
 modules/ims_charging/mod.h                         |    50 +
 modules/ims_charging/ro_fixup.c                    |    19 +
 modules/ims_charging/ro_fixup.h                    |    14 +
 modules/ims_charging/ro_session_hash.c             |   284 +
 modules/ims_charging/ro_session_hash.h             |   195 +
 modules/ims_charging/ro_timer.c                    |   466 +
 modules/ims_charging/ro_timer.h                    |    93 +
 modules/ims_charging/stats.c                       |    45 +
 modules/ims_charging/stats.h                       |    29 +
 modules/ims_icscf/cxdx_lir.h                       |     5 -
 modules/ims_icscf/cxdx_uar.h                       |     6 -
 modules/ims_icscf/db.c                             |     2 +-
 modules/ims_icscf/doc/ims_icscf_admin.xml          |   107 +-
 modules/ims_icscf/location.c                       |    23 +-
 modules/ims_icscf/location.h                       |     2 +-
 modules/ims_icscf/mod.c                            |    59 +-
 modules/ims_icscf/registration.c                   |    28 +-
 modules/ims_icscf/registration.h                   |     2 +-
 modules/ims_icscf/scscf_list.c                     |     2 +-
 modules/ims_isc/doc/ims_isc_admin.xml              |    20 +
 modules/ims_isc/isc.c                              |     2 +-
 modules/ims_isc/mark.c                             |    72 +-
 modules/ims_isc/mark.h                             |     1 +
 modules/ims_isc/mod.c                              |     2 +
 modules/ims_qos/cdpeventprocessor.c                |    65 +-
 modules/ims_qos/doc/ims_qos_admin.xml              |    48 +-
 modules/ims_qos/mod.c                              |   518 +-
 modules/ims_qos/mod.h                              |    11 -
 modules/ims_qos/rx_aar.c                           |   176 +-
 modules/ims_qos/rx_aar.h                           |    26 +-
 modules/ims_qos/rx_authdata.c                      |     2 +
 modules/ims_qos/rx_authdata.h                      |     1 +
 modules/ims_qos/rx_avp.c                           |   122 +-
 modules/ims_qos/rx_str.c                           |    12 +-
 modules/ims_registrar_pcscf/save.c                 |    50 +-
 modules/ims_registrar_pcscf/service_routes.c       |    46 +-
 modules/ims_registrar_scscf/cxdx_sar.c             |     7 +-
 modules/ims_registrar_scscf/cxdx_sar.h             |     8 -
 modules/ims_registrar_scscf/doc/Makefile           |     4 +
 .../doc/ims_registrar_scscf.xml                    |    58 +
 .../doc/ims_registrar_scscf_admin.xml              |   727 +
 .../doc/ims_registrar_scscf_faq.xml                |    68 +
 modules/ims_registrar_scscf/reg_mod.c              |    46 +-
 modules/ims_registrar_scscf/reg_mod.h              |     1 -
 modules/ims_registrar_scscf/reply.c                |    10 +-
 modules/ims_registrar_scscf/save.c                 |    59 +-
 modules/ims_registrar_scscf/save.h                 |     4 +-
 modules/ims_usrloc_pcscf/udomain.c                 |    61 +-
 modules/ims_usrloc_pcscf/udomain.h                 |     1 +
 modules/ims_usrloc_pcscf/usrloc.c                  |     1 +
 modules/ims_usrloc_pcscf/usrloc.h                  |     3 +
 modules/ipops/README                               |    91 +-
 modules/ipops/doc/ipops_admin.xml                  |   173 +-
 modules/ipops/ipops_mod.c                          |   177 +-
 modules/ipops/ipops_pv.c                           |   430 +
 modules/ipops/ipops_pv.h                           |    39 +
 modules/iptrtpproxy/doc/iptrtpproxy_admin.xml      |     2 +-
 modules/kex/README                                 |     8 +-
 modules/kex/doc/kex_admin.xml                      |    58 +-
 modules/lcr/lcr_mod.c                              |    58 +-
 modules/mangler/contact_ops.c                      |     2 +-
 modules/matrix/README                              |     6 +-
 modules/mediaproxy/README                          |    16 +-
 modules/memcached/Makefile                         |    16 +-
 modules/memcached/README                           |    99 +-
 modules/memcached/doc/memcached_admin.xml          |    74 +-
 modules/memcached/mcd_var.c                        |   259 +-
 modules/memcached/mcd_var.h                        |     7 +-
 modules/memcached/memcached.c                      |   273 +-
 modules/memcached/memcached.h                      |    22 +-
 modules/mi_datagram/datagram_fnc.c                 |     2 -
 modules/mi_xmlrpc/Makefile                         |     4 +-
 modules/mi_xmlrpc/abyss_data.h                     |     2 +
 modules/mi_xmlrpc/abyss_response.c                 |     2 +
 modules/mi_xmlrpc/abyss_socket_unix.h              |     3 +
 modules/mi_xmlrpc/abyss_xmlrpc_server.c            |     9 +-
 modules/misc_radius/README                         |    84 +-
 modules/misc_radius/doc/misc_radius_admin.xml      |    45 +
 modules/misc_radius/functions.c                    |   966 +-
 modules/misc_radius/misc_radius.c                  |    24 +-
 modules/misc_radius/misc_radius.h                  |     1 +
 modules/mohqueue/Makefile                          |    18 +
 modules/mohqueue/NOTES                             |     6 +
 modules/mohqueue/README                            |   406 +
 modules/mohqueue/doc/Makefile                      |     4 +
 modules/mohqueue/doc/mohqueue.xml                  |    31 +
 modules/mohqueue/doc/mohqueue_admin.xml            |   510 +
 modules/mohqueue/mohq.c                            |   442 +
 modules/mohqueue/mohq.h                            |   132 +
 modules/mohqueue/mohq_common.h                     |   104 +
 modules/mohqueue/mohq_db.c                         |   626 +
 modules/mohqueue/mohq_db.h                         |    66 +
 modules/mohqueue/mohq_funcs.c                      |  2665 +++
 modules/mohqueue/mohq_funcs.h                      |    40 +
 modules/mohqueue/mohq_locks.c                      |   199 +
 modules/mohqueue/mohq_locks.h                      |    49 +
 modules/mqueue/README                              |     8 +-
 modules/msilo/README                               |     2 +-
 modules/msrp/README                                |    25 +-
 modules/msrp/doc/msrp_admin.xml                    |    11 +
 modules/msrp/msrp_cmap.c                           |     8 +-
 modules/msrp/msrp_mod.c                            |    11 +
 modules/msrp/msrp_vars.c                           |     5 +-
 modules/mtree/README                               |    33 +-
 modules/mtree/doc/mtree_admin.xml                  |    21 +-
 modules/mtree/mtree.c                              |    25 +-
 modules/mtree/mtree.h                              |     5 +-
 modules/mtree/mtree_mod.c                          |    91 +-
 modules/nathelper/README                           |   123 +-
 modules/nathelper/doc/nathelper_admin.xml          |    72 +
 modules/nathelper/nathelper.c                      |   162 +-
 modules/ndb_redis/doc/ndb_redis_admin.xml          |     6 +-
 modules/ndb_redis/redis_client.c                   |    10 +-
 modules/outbound/README                            |   267 +-
 modules/outbound/api.h                             |     4 +-
 modules/outbound/config.c                          |    43 +
 modules/outbound/config.h                          |    42 +
 modules/outbound/doc/outbound.xml                  |     2 +-
 modules/outbound/doc/outbound_admin.xml            |   264 +-
 modules/outbound/ob_mod.c                          |   103 +-
 modules/p_usrloc/README                            |    10 +-
 modules/path/Makefile                              |     3 +
 modules/path/README                                |   127 +-
 modules/path/doc/path.xml                          |     7 +
 modules/path/doc/path_admin.xml                    |    74 +-
 modules/path/path.c                                |   194 +-
 modules/path/path_mod.c                            |    10 +-
 modules/pdb/pdb.c                                  |     5 +-
 modules/pdt/README                                 |     2 +-
 modules/permissions/README                         |   161 +-
 modules/permissions/address.c                      |   198 +-
 modules/permissions/address.h                      |     8 +
 modules/permissions/doc/permissions_admin.xml      |    38 +-
 modules/permissions/hash.c                         |   217 +
 modules/permissions/hash.h                         |    54 +
 modules/permissions/mi.c                           |    36 +-
 modules/permissions/mi.h                           |     4 +
 modules/permissions/permissions.c                  |    10 +-
 modules/permissions/trusted.c                      |     2 +-
 modules/pike/doc/pike_admin.xml                    |    12 +-
 modules/pike/pike.c                                |     3 +
 modules/pike/pike_funcs.c                          |     9 +
 modules/pike/pike_funcs.h                          |     1 +
 modules/pipelimit/README                           |     2 +-
 modules/pipelimit/doc/pipelimit_admin.xml          |    50 +-
 modules/presence/README                            |    70 +-
 modules/presence/doc/presence_admin.xml            |    19 +
 modules/presence/event_list.c                      |     2 +-
 modules/presence/hash.c                            |     2 +-
 modules/presence/presence.c                        |    41 +
 modules/presence_conference/presence_conference.c  |     2 +-
 modules/presence_dialoginfo/notify_body.c          |   194 +-
 modules/presence_xml/add_events.c                  |    20 +
 modules/presence_xml/presence_xml.c                |     2 +
 modules/pua/add_events.c                           |     8 +
 modules/pua/hash.h                                 |     3 +
 modules/pua_dialoginfo/dialog_publish.c            |    48 +-
 modules/pua_dialoginfo/pua_dialoginfo.c            |   118 +-
 modules/pua_mi/mi_func.c                           |     4 +-
 modules/pua_reginfo/Makefile                       |     3 +
 modules/pua_reginfo/README                         |    80 +-
 modules/pua_reginfo/doc/pua_reginfo_admin.xml      |    12 +-
 modules/pua_reginfo/notify.c                       |    36 +-
 modules/pua_reginfo/pua_reginfo.c                  |    13 +
 modules/pua_reginfo/pua_reginfo.h                  |     2 +
 modules/pua_usrloc/ul_publish.c                    |     4 +-
 modules/pv/README                                  |    37 +
 modules/pv/doc/pv.xml                              |     4 +
 modules/pv/doc/pv_admin.xml                        |    34 +
 modules/pv/pv.c                                    |    58 +-
 modules/pv/pv_branch.c                             |    22 +-
 modules/pv/pv_core.c                               |   303 +-
 modules/pv/pv_core.h                               |    14 +
 modules/pv/pv_shv.c                                |   147 +
 modules/pv/pv_shv.h                                |     3 +
 modules/pv/pv_trans.c                              |   243 +-
 modules/pv/pv_trans.h                              |     4 +-
 modules/pv/pv_xavp.c                               |    40 +
 modules/pv/pv_xavp.h                               |     6 -
 modules/ratelimit/README                           |    22 +-
 modules/registrar/README                           |   138 +-
 modules/registrar/api.c                            |    15 +
 modules/registrar/api.h                            |     4 +
 modules/registrar/doc/registrar_admin.xml          |   127 +-
 modules/registrar/lookup.c                         |    25 +-
 modules/registrar/path.c                           |    19 +-
 modules/registrar/reg_mod.c                        |    41 +-
 modules/registrar/reg_mod.h                        |     5 +-
 modules/registrar/reply.c                          |    57 +-
 modules/registrar/rerrno.h                         |     4 +-
 modules/registrar/save.c                           |   300 +-
 modules/registrar/save.h                           |     4 +-
 modules/rls/notify.c                               |    10 +-
 modules/rls/subscribe.c                            |     4 +-
 modules/rr/README                                  |    25 +-
 modules/rr/doc/rr_admin.xml                        |     9 +-
 modules/rr/loose.c                                 |   167 +-
 modules/rr/record.c                                |    25 +-
 modules/rr/rr_mod.c                                |     2 +-
 modules/rtpproxy-ng/Makefile                       |    19 +
 modules/rtpproxy-ng/README                         |   652 +
 modules/rtpproxy-ng/bencode.c                      |   703 +
 modules/rtpproxy-ng/bencode.h                      |   530 +
 modules/rtpproxy-ng/doc/Makefile                   |     4 +
 modules/rtpproxy-ng/doc/rtpproxy-ng.xml            |   103 +
 modules/rtpproxy-ng/doc/rtpproxy_admin.xml         |   823 +
 modules/rtpproxy-ng/doc/rtpproxy_faq.xml           |    79 +
 modules/rtpproxy-ng/rtpproxy.c                     |  1941 +++
 modules/rtpproxy-ng/rtpproxy.h                     |    64 +
 modules/rtpproxy-ng/rtpproxy_funcs.c               |   434 +
 modules/rtpproxy-ng/rtpproxy_funcs.h               |    40 +
 modules/rtpproxy/Makefile                          |     1 +
 modules/rtpproxy/README                            |   546 +-
 modules/rtpproxy/doc/rtpproxy_admin.xml            |    54 +-
 modules/rtpproxy/rtpproxy.c                        |   318 +-
 modules/rtpproxy/rtpproxy.h                        |     9 +
 modules/rtpproxy/rtpproxy_db.c                     |   169 +
 modules/sca/README                                 |     4 +-
 modules/sca/sca_call_info.h                        |     5 +-
 modules/sca/sca_hash.c                             |     2 +-
 modules/sctp/Makefile                              |    16 +
 modules/sctp/README                                |   502 +
 modules/sctp/doc/Makefile                          |     4 +
 modules/sctp/doc/sctp.xml                          |    34 +
 modules/sctp/doc/sctp_admin.xml                    |   622 +
 modules/sctp/sctp_ev.h                             |    97 +
 modules/sctp/sctp_mod.c                            |   145 +
 modules/sctp/sctp_options.c                        |   748 +
 sctp_options.h => modules/sctp/sctp_options.h      |     0
 modules/sctp/sctp_rpc.c                            |   175 +
 modules/sctp/sctp_rpc.h                            |    24 +
 modules/sctp/sctp_server.c                         |  2922 ++++
 modules/sctp/sctp_server.h                         |    55 +
 sctp_sockopts.h => modules/sctp/sctp_sockopts.h    |     0
 modules/sctp/sctp_stats.c                          |   124 +
 modules/sctp/sctp_stats.h                          |   139 +
 modules/sdpops/README                              |   134 +-
 modules/sdpops/doc/sdpops_admin.xml                |    68 +
 modules/sdpops/sdpops_mod.c                        |   296 +
 modules/seas/README                                |    28 +-
 modules/seas/seas_action.c                         |     5 +-
 modules/sipcapture/README                          |     4 +-
 modules/sipcapture/doc/sipcapture_admin.xml        |    56 +-
 modules/sipcapture/hep.c                           |    14 +-
 modules/sipcapture/hep.h                           |     6 -
 modules/sipcapture/sipcapture.c                    |   687 +-
 modules/sipt/Makefile                              |    18 +
 modules/sipt/README                                |   246 +
 modules/sipt/doc/Makefile                          |     4 +
 modules/sipt/doc/sipt.xml                          |    31 +
 modules/sipt/doc/sipt_admin.xml                    |   257 +
 modules/sipt/sdp_mangle.c                          |    73 +
 modules/sipt/sdp_mangle.h                          |    41 +
 modules/sipt/sipt.c                                |   384 +
 modules/sipt/ss7.h                                 |   188 +
 modules/sipt/ss7_parser.c                          |   441 +
 modules/siptrace/README                            |     6 +-
 modules/siptrace/siptrace.c                        |    14 +-
 modules/siputils/README                            |   157 +-
 modules/siputils/doc/siputils_admin.xml            |   125 +-
 modules/siputils/sipops.c                          |    88 +
 modules/siputils/sipops.h                          |     2 +
 modules/siputils/siputils.c                        |    72 +
 modules/sl/README                                  |   102 +-
 modules/sl/doc/sl_functions.xml                    |     5 +-
 modules/sl/sl.c                                    |    11 +-
 modules/sl/sl_funcs.c                              |    26 +-
 modules/sl/sl_funcs.h                              |     2 +
 modules/snmpstats/README                           |    33 +-
 modules/snmpstats/doc/snmpstats.xml                |    11 +
 modules/snmpstats/doc/snmpstats_admin.xml          |    31 +-
 modules/snmpstats/kamailioNet.c                    |  1354 ++
 modules/snmpstats/kamailioNet.h                    |    78 +
 modules/snmpstats/kamailioNetConfig.c              |   446 +
 modules/snmpstats/kamailioNetConfig.h              |    23 +
 modules/snmpstats/kamailioServer.c                 |   481 +
 modules/snmpstats/kamailioServer.h                 |    55 +
 modules/snmpstats/mibs/KAMAILIO-MIB                |   706 +-
 modules/snmpstats/mibs/KAMAILIO-SIP-COMMON-MIB     |    11 +-
 modules/snmpstats/mibs/KAMAILIO-TC                 |    24 +-
 modules/snmpstats/snmpSIPCommonObjects.c           |     6 +
 modules/snmpstats/snmpSIPMethodSupportedTable.c    |    20 +-
 modules/snmpstats/snmpSIPPortTable.c               |   102 +-
 modules/snmpstats/snmpSIPPortTable.h               |    10 +-
 modules/snmpstats/snmpSIPServerObjects.c           |     2 +-
 modules/snmpstats/snmpstats.c                      |     9 +-
 modules/snmpstats/snmpstats_globals.h              |    10 +-
 modules/snmpstats/sub_agent.c                      |    12 +
 modules/snmpstats/utilities.c                      |    47 +
 modules/snmpstats/utilities.h                      |    10 +
 modules/sqlops/README                              |     8 +-
 modules/sst/README                                 |     2 +-
 modules/sst/doc/sst_admin.xml                      |    15 +-
 modules/sst/sst_handlers.c                         |     6 +-
 modules/statistics/README                          |     3 +-
 modules/stun/Makefile                              |    13 +
 modules/stun/README                                |    72 +
 modules/stun/config.c                              |    45 +
 modules/stun/config.h                              |    44 +
 modules/stun/doc/Makefile                          |     4 +
 modules/stun/doc/stun.xml                          |    37 +
 modules/stun/doc/stun_admin.xml                    |    68 +
 modules/stun/kam_stun.c                            |   967 ++
 modules/stun/kam_stun.h                            |   147 +
 modules/stun/stun_mod.c                            |    74 +
 modules/textops/README                             |   552 +-
 modules/textops/doc/textops_admin.xml              |     2 +-
 modules/textops/textops.c                          |     3 +-
 modules/textops/txt_var.c                          |     2 +
 modules/textopsx/README                            |   240 +-
 modules/textopsx/doc/functions.xml                 |    40 +-
 modules/textopsx/textopsx.c                        |    19 +-
 modules/timer/doc/timer.xml                        |     4 +-
 modules/tls/README                                 |   552 +-
 modules/tls/doc/functions.xml                      |     2 +-
 modules/tls/doc/history.xml                        |    27 +-
 modules/tls/doc/params.xml                         |    91 +-
 modules/tls/doc/rpc.xml                            |     8 +-
 modules/tls/fixed_c_zlib.h                         |     3 +-
 modules/tls/sbufq.h                                |     4 +-
 modules/tls/tls_bio.c                              |     2 +
 modules/tls/tls_bio.h                              |     2 +
 modules/tls/tls_cfg.c                              |     3 +
 modules/tls/tls_cfg.h                              |     2 +-
 modules/tls/tls_config.c                           |   182 +-
 modules/tls/tls_config.h                           |    40 +-
 modules/tls/tls_ct_q.h                             |     2 +
 modules/tls/tls_ct_wrq.c                           |     2 +
 modules/tls/tls_ct_wrq.h                           |     2 +
 modules/tls/tls_domain.c                           |     4 +-
 modules/tls/tls_domain.h                           |     9 +-
 modules/tls/tls_dump_vf.c                          |     7 +-
 modules/tls/tls_dump_vf.h                          |     7 +-
 modules/tls/tls_init.c                             |    58 +-
 modules/tls/tls_init.h                             |    37 +-
 modules/tls/tls_locking.c                          |    10 +-
 modules/tls/tls_locking.h                          |     2 +-
 modules/tls/tls_mod.c                              |    49 +-
 modules/tls/tls_mod.h                              |    35 +-
 modules/tls/tls_rpc.c                              |     4 +-
 modules/tls/tls_rpc.h                              |     5 +-
 modules/tls/tls_select.c                           |    10 +-
 modules/tls/tls_select.h                           |     9 +-
 modules/tls/tls_server.c                           |     5 +-
 modules/tls/tls_server.h                           |     3 -
 modules/tls/tls_util.c                             |    33 +-
 modules/tls/tls_util.h                             |    39 +-
 modules/tls/tls_verify.c                           |    34 +-
 modules/tls/tls_verify.h                           |    37 +-
 modules/tm/README                                  |   666 +-
 modules/tm/doc/api.xml                             |     2 +-
 modules/tm/doc/event_routes.xml                    |    40 +
 modules/tm/doc/functions.xml                       |   214 +-
 modules/tm/doc/params.xml                          |    51 +
 modules/tm/doc/tm.xml                              |     1 +
 modules/tm/h_table.c                               |    46 +-
 modules/tm/h_table.h                               |    37 +-
 modules/tm/lock.c                                  |    36 +-
 modules/tm/lock.h                                  |     1 +
 modules/tm/t_cancel.c                              |     2 +-
 modules/tm/t_funcs.c                               |     1 +
 modules/tm/t_fwd.c                                 |   267 +-
 modules/tm/t_hooks.h                               |     6 +-
 modules/tm/t_lookup.c                              |    54 +-
 modules/tm/t_lookup.h                              |     3 +
 modules/tm/t_msgbuilder.c                          |    20 +-
 modules/tm/t_reply.c                               |   314 +-
 modules/tm/t_reply.h                               |    12 +-
 modules/tm/t_serial.c                              |  1200 +-
 modules/tm/t_serial.h                              |     2 +-
 modules/tm/t_suspend.c                             |   473 +-
 modules/tm/t_suspend.h                             |     3 +
 modules/tm/tm.c                                    |   105 +-
 modules/tm/tm_load.c                               |     3 +
 modules/tm/tm_load.h                               |     3 +
 modules/tm/uac.c                                   |    27 +-
 modules/tm/uac.h                                   |     3 +
 modules/tmrec/README                               |     2 +-
 modules/tmx/README                                 |   153 +-
 modules/tmx/doc/tmx_admin.xml                      |     3 +
 modules/tmx/t_var.c                                |    37 +
 modules/tmx/t_var.h                                |     2 +
 modules/tmx/tmx_mod.c                              |     8 +
 modules/uac/README                                 |     1 +
 modules/uac/doc/uac_admin.xml                      |    65 +-
 modules/uac/uac_reg.c                              |     2 +-
 modules/uac/uac_send.c                             |   303 +-
 modules/uac_redirect/rd_funcs.c                    |     3 +-
 modules/uid_avp_db/uid_avp_db.c                    |     4 +-
 modules/uri_db/README                              |     2 +-
 modules/userblacklist/README                       |     2 +-
 modules/usrloc/README                              |   217 +-
 modules/usrloc/doc/usrloc_admin.xml                |   260 +-
 modules/usrloc/doc/usrloc_devel.xml                |    25 +
 modules/usrloc/ucontact.c                          |   327 +-
 modules/usrloc/udomain.c                           |     9 +-
 modules/usrloc/ul_mi.c                             |     8 +-
 modules/usrloc/ul_mod.c                            |    20 +-
 modules/usrloc/ul_mod.h                            |     1 +
 modules/usrloc/ul_rpc.c                            |   414 +-
 modules/usrloc/urecord.c                           |    79 +-
 modules/usrloc/urecord.h                           |    10 +
 modules/usrloc/usrloc.c                            |     1 +
 modules/usrloc/usrloc.h                            |     6 +
 modules/utils/README                               |     4 +-
 modules/utils/doc/utils.xml                        |    12 +
 modules/utils/doc/utils_admin.xml                  |    48 +-
 modules/utils/functions.c                          |    32 +-
 modules/utils/functions.h                          |     3 +-
 modules/utils/utils.c                              |    81 +-
 modules/websocket/README                           |    65 +-
 modules/websocket/config.c                         |    56 +
 modules/websocket/config.h                         |    44 +
 modules/websocket/doc/websocket.xml                |     2 +-
 modules/websocket/doc/websocket_admin.xml          |   117 +-
 modules/websocket/ws_conn.c                        |    71 +-
 modules/websocket/ws_conn.h                        |     6 +-
 modules/websocket/ws_frame.c                       |   175 +-
 modules/websocket/ws_frame.h                       |    20 +-
 modules/websocket/ws_handshake.c                   |    63 +-
 modules/websocket/ws_handshake.h                   |    15 +-
 modules/websocket/ws_mod.c                         |   112 +-
 modules/websocket/ws_mod.h                         |     9 +-
 modules/xcap_client/xcap_callbacks.c               |     2 +-
 modules/xcap_client/xcap_functions.c               |     4 +-
 modules/xcap_server/xcap_misc.c                    |     6 +-
 modules/xcap_server/xcap_server.c                  |    81 +-
 modules/xhttp/xhttp_mod.c                          |    13 +
 modules/xhttp/xhttp_trans.c                        |   145 +
 modules/xhttp/xhttp_trans.h                        |    30 +
 modules/xhttp_pi/xhttp_pi_fnc.c                    |    61 +-
 modules/xhttp_rpc/README                           |     4 +-
 modules/xmlrpc/xmlrpc.c                            |     4 +-
 modules/xprint/xp_lib.c                            |     6 +-
 msg_translator.c                                   |    54 +-
 msg_translator.h                                   |     2 +
 name_alias.h                                       |     2 -
 obsolete/permissions/ip_set.c                      |    14 -
 obsolete/permissions/ip_set.h                      |     2 -
 obsolete/permissions/ip_set_rpc.c                  |     2 -
 obsolete/permissions/permissions.c                 |     2 -
 obsolete/registrar/save.c                          |     4 -
 parser/hf.c                                        |     5 +-
 parser/keys.h                                      |     2 +
 parser/msg_parser.c                                |   110 +-
 parser/msg_parser.h                                |    65 +-
 parser/parse_addr_spec.c                           |   927 ++
 parser/parse_addr_spec.h                           |    70 +
 parser/parse_body.h                                |     2 +-
 parser/parse_content.c                             |     6 +-
 parser/parse_content.h                             |     1 +
 parser/parse_fline.c                               |    12 +-
 parser/parse_option_tags.c                         |    40 +
 parser/parse_option_tags.h                         |   166 +
 parser/parse_param.c                               |    62 +-
 parser/parse_param.h                               |    13 +
 parser/parse_ppi_pai.c                             |   213 +
 parser/parse_ppi_pai.h                             |    51 +
 parser/parse_require.c                             |    73 +
 parser/parse_require.h                             |    50 +
 parser/parse_supported.c                           |    73 +
 parser/parse_supported.h                           |    54 +
 parser/parse_to.c                                  |   797 +-
 parser/parse_to.h                                  |    29 +-
 pkg/kamailio/centos/6/README                       |    28 +-
 pkg/kamailio/centos/6/kamailio-build.appl          |    41 -
 pkg/kamailio/centos/6/kamailio.appl                |    35 -
 pkg/kamailio/centos/6/kamailio.init                |    87 +-
 pkg/kamailio/centos/6/kamailio.spec                |  1180 +-
 pkg/kamailio/centos/6/kamailio.sysconfig           |    19 +-
 pkg/kamailio/deb/debian/changelog                  |    24 +-
 pkg/kamailio/deb/debian/control                    |    58 +-
 pkg/kamailio/deb/debian/rules                      |     3 +-
 pkg/kamailio/deb/jessie/changelog                  |    88 +
 pkg/kamailio/deb/{lenny => jessie}/compat          |     0
 pkg/kamailio/deb/jessie/control                    |   516 +
 pkg/kamailio/deb/{lenny => jessie}/copyright       |     0
 .../deb/{lenny => jessie}/kamailio.README.Debian   |     0
 .../deb/{lenny => jessie}/kamailio.default         |     0
 pkg/kamailio/deb/{lenny => jessie}/kamailio.dirs   |     0
 .../deb/{lenny => jessie}/kamailio.examples        |     0
 pkg/kamailio/deb/jessie/kamailio.init              |   240 +
 .../deb/{lenny => jessie}/kamailio.postinst        |     0
 pkg/kamailio/deb/jessie/rules                      |   228 +
 pkg/kamailio/deb/lenny/changelog                   |   106 -
 pkg/kamailio/deb/lenny/control                     |   387 -
 pkg/kamailio/deb/lenny/kamailio.init               |   240 -
 pkg/kamailio/deb/lenny/rules                       |   227 -
 pkg/kamailio/deb/lucid/changelog                   |    24 +-
 pkg/kamailio/deb/lucid/control                     |    61 +-
 pkg/kamailio/deb/lucid/rules                       |     5 +-
 pkg/kamailio/deb/precise/changelog                 |    24 +-
 pkg/kamailio/deb/precise/control                   |    24 +-
 pkg/kamailio/deb/precise/rules                     |     3 +-
 pkg/kamailio/deb/squeeze/changelog                 |    24 +-
 pkg/kamailio/deb/squeeze/control                   |    24 +-
 pkg/kamailio/deb/squeeze/rules                     |     3 +-
 pkg/kamailio/deb/wheezy/changelog                  |    24 +-
 pkg/kamailio/deb/wheezy/control                    |    43 +-
 pkg/kamailio/deb/wheezy/rules                      |     3 +-
 pkg/kamailio/fedora/17/kamailio.spec               |   960 +-
 pkg/kamailio/rpm/kamailio.spec-4.1                 |     2 +-
 pkg/kamailio/rpm/kamailio.spec.CenOS               |     2 +-
 pkg/kamailio/rpm/kamailio.spec.SuSE                |     2 +-
 pt.c                                               |     4 -
 pvapi.c                                            |    47 +-
 pvar.h                                             |    29 +-
 receive.c                                          |     1 +
 resolve.c                                          |   300 +-
 resolve.h                                          |    47 +-
 route.h                                            |     1 +
 rvalue.c                                           |    14 +
 rvalue.h                                           |     1 +
 script_cb.c                                        |     2 +-
 script_cb.h                                        |     4 +-
 sctp_core.c                                        |   109 +
 sctp_core.h                                        |    62 +
 sctp_ev.h                                          |    97 -
 sctp_options.c                                     |   746 -
 sctp_server.c                                      |  2926 ----
 sctp_server.h                                      |    55 -
 sctp_stats.c                                       |   123 -
 sctp_stats.h                                       |   139 -
 select_core.c                                      |     6 +-
 ser_stun.c                                         |  1025 --
 ser_stun.h                                         |   186 -
 sip_msg_clone.c                                    |     8 +
 socket_info.c                                      |   112 +-
 socket_info.h                                      |    10 +
 sr_module.c                                        |    33 +-
 sr_module.h                                        |     2 +
 stun.c                                             |    46 +
 stun.h                                             |    64 +
 tcp_main.c                                         |    10 -
 tcp_options.c                                      |     2 +-
 tcp_options.h                                      |     2 +-
 tcp_read.c                                         |    46 +-
 timer_funcs.h                                      |     5 +-
 udp_server.c                                       |    54 +-
 utils/kamctl/db_berkeley/kamailio/acc_cdrs         |    10 +
 utils/kamctl/db_berkeley/kamailio/mohqcalls        |    10 +
 utils/kamctl/db_berkeley/kamailio/mohqueues        |    10 +
 utils/kamctl/db_berkeley/kamailio/rtpproxy         |    10 +
 utils/kamctl/db_berkeley/kamailio/version          |     8 +
 utils/kamctl/db_sqlite/acc-create.sql              |    10 +
 utils/kamctl/db_sqlite/alias_db-create.sql         |     5 +-
 utils/kamctl/db_sqlite/mohqueue-create.sql         |    24 +
 utils/kamctl/db_sqlite/rtpproxy-create.sql         |    10 +
 utils/kamctl/dbtext/kamailio/acc_cdrs              |     1 +
 utils/kamctl/dbtext/kamailio/mohqcalls             |     1 +
 utils/kamctl/dbtext/kamailio/mohqueues             |     1 +
 utils/kamctl/dbtext/kamailio/rtpproxy              |     1 +
 utils/kamctl/dbtext/kamailio/version               |     4 +
 utils/kamctl/kamctl                                |   206 +-
 utils/kamctl/kamctl.8                              |    17 +-
 utils/kamctl/kamctl.base                           |    33 +-
 utils/kamctl/kamctl.ctlbase                        |    11 +-
 utils/kamctl/kamctl.fifo                           |    34 +-
 utils/kamctl/kamctl.sqlbase                        |     6 +
 utils/kamctl/kamctl.sqlite                         |     3 +
 utils/kamctl/kamctlrc                              |     2 +-
 utils/kamctl/kamdbctl                              |    17 +
 utils/kamctl/kamdbctl.base                         |     8 +-
 utils/kamctl/kamdbctl.mysql                        |    22 +
 utils/kamctl/mysql/acc-create.sql                  |    14 +-
 utils/kamctl/mysql/alias_db-create.sql             |     7 +-
 utils/kamctl/mysql/auth_db-create.sql              |     2 +-
 utils/kamctl/mysql/avpops-create.sql               |     2 +-
 utils/kamctl/mysql/carrierroute-create.sql         |     8 +-
 utils/kamctl/mysql/cpl-create.sql                  |     2 +-
 utils/kamctl/mysql/dialog-create.sql               |     4 +-
 utils/kamctl/mysql/dialplan-create.sql             |     2 +-
 utils/kamctl/mysql/dispatcher-create.sql           |     2 +-
 utils/kamctl/mysql/domain-create.sql               |     4 +-
 utils/kamctl/mysql/domainpolicy-create.sql         |     2 +-
 utils/kamctl/mysql/drouting-create.sql             |     8 +-
 utils/kamctl/mysql/group-create.sql                |     4 +-
 utils/kamctl/mysql/htable-create.sql               |     2 +-
 utils/kamctl/mysql/imc-create.sql                  |     4 +-
 utils/kamctl/mysql/lcr-create.sql                  |     6 +-
 utils/kamctl/mysql/matrix-create.sql               |     2 +-
 utils/kamctl/mysql/mohqueue-create.sql             |    24 +
 utils/kamctl/mysql/msilo-create.sql                |     2 +-
 utils/kamctl/mysql/mtree-create.sql                |     4 +-
 utils/kamctl/mysql/pdt-create.sql                  |     2 +-
 utils/kamctl/mysql/permissions-create.sql          |     4 +-
 utils/kamctl/mysql/pipelimit-create.sql            |     2 +-
 utils/kamctl/mysql/presence-create.sql             |    10 +-
 utils/kamctl/mysql/purple-create.sql               |     2 +-
 utils/kamctl/mysql/registrar-create.sql            |     2 +-
 utils/kamctl/mysql/rls-create.sql                  |     4 +-
 utils/kamctl/mysql/rtpproxy-create.sql             |    10 +
 utils/kamctl/mysql/sca-create.sql                  |     2 +-
 utils/kamctl/mysql/siptrace-create.sql             |     2 +-
 utils/kamctl/mysql/speeddial-create.sql            |     2 +-
 utils/kamctl/mysql/standard-create.sql             |     2 +-
 utils/kamctl/mysql/uac-create.sql                  |     2 +-
 utils/kamctl/mysql/uid_auth_db-create.sql          |     2 +-
 utils/kamctl/mysql/uid_avp_db-create.sql           |     2 +-
 utils/kamctl/mysql/uid_domain-create.sql           |     4 +-
 utils/kamctl/mysql/uid_gflags-create.sql           |     2 +-
 utils/kamctl/mysql/uid_uri_db-create.sql           |     4 +-
 utils/kamctl/mysql/uri_db-create.sql               |     2 +-
 utils/kamctl/mysql/userblacklist-create.sql        |     4 +-
 utils/kamctl/mysql/usrloc-create.sql               |     4 +-
 utils/kamctl/oracle/acc-create.sql                 |    18 +
 utils/kamctl/oracle/alias_db-create.sql            |     5 +-
 utils/kamctl/oracle/mohqueue-create.sql            |    40 +
 utils/kamctl/oracle/rtpproxy-create.sql            |    18 +
 utils/kamctl/postgres/acc-create.sql               |    10 +
 utils/kamctl/postgres/alias_db-create.sql          |     5 +-
 utils/kamctl/postgres/mohqueue-create.sql          |    24 +
 utils/kamctl/postgres/rtpproxy-create.sql          |    10 +
 utils/kamctl/xhttp_pi/acc-mod                      |    41 +
 utils/kamctl/xhttp_pi/acc-table                    |     9 +
 utils/kamctl/xhttp_pi/mohqueue-mod                 |    97 +
 utils/kamctl/xhttp_pi/mohqueue-table               |    23 +
 utils/kamctl/xhttp_pi/pi_framework.xml             |   250 +-
 utils/kamctl/xhttp_pi/rtpproxy-mod                 |    47 +
 utils/kamctl/xhttp_pi/rtpproxy-table               |    11 +
 utils/sercmd/Makefile                              |     2 +-
 utils/sercmd/parse_listen_id.c                     |    18 +-
 ver_defs.h                                         |    16 +-
 xavp.c                                             |   129 +
 xavp.h                                             |     6 +
 1057 files changed, 86418 insertions(+), 28793 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 88fc526..da203d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,12765 +1,8538 @@
-===================== 2013-10-02 Version 4.0.4 Released =====================
+===================== 2013-XY-XY Version 4.1.0 Released =====================
 
-===================== Changes Since Version 4.0.3 ===========================
-
-commit 69d5e22b21ad4cb163e39f68a123cae3cf99e1c9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 2 16:54:14 2013 +0200
-
-    Makefile.defs: version set to 4.0.4
-
-commit 00cfb136d9532aa5e7cf2a40848e62b7df1692fa
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 2 16:50:37 2013 +0200
-
-    pkg/rpm: updated version to 4.0.4 in spec files
-
-commit 6b26032ee8b581983d547657c9d229645cf2bd0e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 2 16:50:05 2013 +0200
-
-    pkg/deb: updated version to 4.0.4 in specs
-
-commit f8ae762545b85ead432f67bcb6969bc92f01b93d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 20 11:18:09 2013 +0200
-
-    registrar: note about empty value for received_param
-    
-    (cherry picked from commit e35fe9c6095361414565b1099dea1ad5950fb38d)
-
-commit fc410ae69c6b371538f457947fd3a2946dc492cd
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 20 11:15:16 2013 +0200
-
-    registrar: if rcv_parm value is empty, don't add received to contacts in 200ok reply
-    
-    - otherwise results in malformed value
-    
-    (cherry picked from commit 2f213e313a86e16665f6d0acfec959bf23f72b7d)
-
-commit cbe6d2dc199e552576501a74b3cafbceeb048385
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed Oct 2 10:04:35 2013 +0100
-
-    xcap_server: Fix memory allocation check bug in xcap_misc
-    
-    - Would cause crash if out of package memory
-    (cherry picked from commit 165a351d18fd0f1639087c8eb5d9294e46a6e2b7)
-
-commit 82a23f22c1bba400304a7f44523e8db8b09ae295
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Sep 26 13:23:46 2013 +0200
-
-    presence_xml: updated docs about integrated_xcap_server
-    
-    (cherry picked from commit 8e35cef8716bbd0caa406a5080e93acb3c881c41)
-
-commit 3a927389f2667fa3e453f30604b5448ca99f4d77
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Sep 26 12:59:59 2013 +0200
-
-    mi_rpc: compatibility with libxmlrpc-c3 library on wheezy
-    
-    - patch by Muhammad Shahzad
-    
-    (cherry picked from commit baa4fccc2870df102a66089d6e9b6ca1ff47fc25)
-
-commit 9f3f494289ab25d2a4a35672e21d1b1c76cfbd6b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Sep 30 16:49:26 2013 +0200
-
-    app_perl: use local buffer to print dynamic string in pv_sprintf()
-    
-    - avoid pkg malloc for temporary need
-    - fix leak in case of fmt parse error, discovered on a report by Dragos
-      Oancea
-    
-    (cherry picked from commit 1c3e761fbd087ee578ce305d89f6b8ee4e9ab79d)
-
-commit 3253fcb7e7ef628727799a92ca68739dba3d10ca
-Author: Øyvind Kolbu <oyvind.kolbu at usit.uio.no>
-Date:   Mon Sep 30 11:15:13 2013 +0200
-
-    core: resolve down to A/AAAA records when no naptr records
-    
-    - try all protocols, not only UDP
-    
-    (cherry picked from commit b50888cf447ea3a3315e665c97f71a07bb687337)
-
-commit b49899f75052ea4e23125c7af3e60dd3ab141aae
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 19 13:49:24 2013 -0400
-
-    modules/sca: fix return value of sca_call_info_uri_update()
-    
-    - return value of 0 can bubble up as return value of sca_call_info_update(),
-      causing early script termination (exported function returning 0 in script
-      is equivalent to "exit")
-    - report and patch from Timo Teräs
-    (cherry picked from commit 844c398bba30452f0b136895b9f928cc17e5c80b)
-
-commit c9551e55a8a0d46de69bb49fc3eb8376fd737ccb
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 20 15:54:17 2013 -0400
-
-    modules/sca: AoR should not be treated as SCA if there are no subscribers.
-    (cherry picked from commit a8fb905e8bf27093dcf86866ae946431ed441a41)
-
-commit 22268940a63747e1ef3faf47b40c493c8f34a7b3
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 20 15:14:26 2013 -0400
-
-    modules/sca: improved handling of host-only Contact URIs
-    (cherry picked from commit bf747c2d65aeaa74d1cea4e0a531607415e8d17d)
-
-commit 1672b92eb5d7eb7d07741c24bfec912e1e6b7acf
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Jul 22 00:48:46 2013 -0400
-
-    modules/sca: restore missing prototype.
-    
-    sca_subscription_aor_has_subscribers
-    (cherry picked from commit 7bf7e9f858faab2329e5edf3d988bef76ac2c804)
-
-commit 92c6c3b680047962721bb48134345012e7f631db
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Jul 22 00:42:18 2013 -0400
-
-    modules/sca: detect when an AoR is no longer SCA.
-    
-    Don't, for example, create an appearance for callees that do not send
-    a Call-Info header, and whose AoR also has no subscribers.
-    (cherry picked from commit 3464f62565dd153cb87af71a71df5db2306d74a1)
-
-commit 2f767f2b3454dc0bad206c0b7aa04b8a2550be25
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Jul 22 00:37:32 2013 -0400
-
-    modules/sca: Clear stale line-seize appearances via timer.
-    
-    Some badly behaved/buggy UAs don't know when to say when.
-    (cherry picked from commit 8416a1c65d26ac81b71e08274f9292a7f7713fff)
-
-commit b15a586fd6eb226318d7111a0e14c312ec56ad8f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Jun 13 16:06:10 2013 -0400
-
-    modules/sca: fix regression: restore purge expired timer
-    (cherry picked from commit d5f259f7ce04b012f7704ba433f167d034548e09)
-
-commit b1faa930bd69333eda47291a6354fb2bda59b822
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Jun 13 15:34:00 2013 -0400
-
-    modules/sca: clear appearance on receipt of out-of-dialog SUBSCRIBE
-    
-    - If a call-info SUBSCRIBE with no To-tag arrives from a subscriber
-      with an active subscription, release any appearances owned by the
-      subscriber, on the assumption that the subscriber has lost track
-      of SCA (reboot, power/network loss).
-    (cherry picked from commit c6280e2eb9c2e1243d5d4ab78b8b683c8239a4b9)
-
-commit 0d0a6c2d0de9b56c31ce3de59ec0c9e9bd86241b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Jun 13 15:30:40 2013 -0400
-
-    modules/sca: detect and clear orphaned appearances caused by answer glare
-    
-    - set appearance state created by SCA callee answer to ACTIVE_PENDING,
-      and promote to ACTIVE on ACK from caller. If no ACK from caller is
-      received within 30 seconds (enough time for retransmission to fail),
-      the ACTIVE_PENDING appearance will be cleared by the
-      sca_appearance_purge_stale timer.
-    (cherry picked from commit a9014c2b9edd200cf0032fdb30405710afc97c0b)
-
-commit 67bd5d6d315c89089d54dbf01531e79fe832339f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed May 15 16:13:23 2013 -0400
-
-    modules/sca: reconcile Contact and From URIs in ACK callback.
-    
-    - fix Music-on-Hold in Polycoms when SCA caller has MoH enabled and SCA callee
-      does SCA hold/pickup with identical To & From URIs. Previously, module would
-      end up looking up an appearance for callee in ACK callback instead of caller.
-    (cherry picked from commit ba2f749d4a894f6890601ce3d2ff3697b78c5b73)
-
-commit 68898fdd936c5aa34377b894240dfd460315f23e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue May 14 16:25:06 2013 -0400
-
-    modules/sca: improved BYE handling.
-    
-    - Clear appearances for both legs on BYE request if possible.
-    (cherry picked from commit 71f012de15bd4fecce006c35b9452854818f03af)
-
-commit b765ed287e61c43e299fad8396b22759a04cb7d9
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue May 14 16:23:46 2013 -0400
-
-    modules/sca: free previous appearance owner, callee, dialog if non-NULL.
-    (cherry picked from commit 6a126232767256a2495c846184acaec788576591)
-
-commit 87daab43172e780de06378773e50bf1f48cb1793
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu May 2 15:12:16 2013 -0400
-
-    modules/sca: change logging level for failed lookup by appearance-index.
-    
-    - appearance-index won't be found yet if SCA callee is answering, logging
-      at WARN is misleading.
-    (cherry picked from commit 95b38c4d239f0098e94eafb1c3ddc8834fc767e0)
-
-commit f547e09bfe791e485d7b15d3238e4f84242654be
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Apr 30 23:31:12 2013 -0400
-
-    modules/sca: space-separate dialog tags in sca.all_appearances output
-    (cherry picked from commit 16243261d7cc6dc3e03db9c589209b534d6dab74)
-
-commit d16ee1a19c681726b35da78f120a05317b294ce1
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Apr 30 23:10:10 2013 -0400
-
-    modules/sca: track appearance times.
-    
-    Include time of last state chance in sca.all_appearances output.
-    (cherry picked from commit da3f7cbd955311309665ab0e6958e009f183f795)
-
-commit 86930557070857aecf8110ead7b6e5e3761fb796
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Apr 24 11:30:35 2013 -0400
-
-    modules/sca: add sca.subscription_count to rpc exports list.
-    (cherry picked from commit 1d361c70b5ed87e0808bc446be327f21d8725a3f)
-
-commit b1bd9727e91991649bc37cd8c79cd3876876da92
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Apr 24 01:18:27 2013 -0400
-
-    modules/sca: RPC: fix sca.show_subscription, add sca.subscription_count
-    
-    - sca.subscription_count will eventually be subsumed by sca.stats.
-    (cherry picked from commit f156eb0f82bb729e773027e44f1e7f930418dc93)
-
-commit 5ca4e8e743e1e7e61c7218858a68c9c83b4618f1
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Apr 18 13:52:10 2013 -0400
-
-    modules/sca: fall back to tag lookup if lookup by index fails.
-    
-    - Fix appearance tracking for SCA implementations with inconsistent
-      Call-Info header inclusion.
-    (cherry picked from commit c41806685483546d00324d351ca72143a2a6c787)
-
-commit f4169c46d885b0d6568961bc302d0be0173a697d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Apr 15 20:16:36 2013 -0400
-
-    modules/sca: add SCA_DB_DEFAULT_FETCH_ROW_COUNT
-    (cherry picked from commit 2292666bf234a168120b1c1504bea86300a440ea)
-
-commit e57b740d35590e7a8049cf82c38deb49a414f816
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Apr 15 20:11:08 2013 -0400
-
-    modules/sca: use DB fetch queries when restoring subscribers from database.
-    
-    - Previously used standard query, exhausting pkg memory when subscriber
-      count is high.
-    (cherry picked from commit c9f47e608f655b3558e7c0c319f32b189732cf34)
-
-commit 4f7b9ac3c64c4baf20b8da76e947c777a073ef61
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Apr 15 20:09:01 2013 -0400
-
-    modules/sca: only check if callee is SCA if callee_aor has a value.
-    (cherry picked from commit d1ef3000b9db99c51d5c37134af2c679ce017a82)
-
-commit 8c790ae25cb5927166bbf154233ca74e36b1d225
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Apr 15 17:17:05 2013 -0400
-
-    modules/sca: add check for empty AoR in lock_shared_appearance calls.
-    
-    - Sanity checking
-    (cherry picked from commit 8ce54ef9b33ef533b3f4474b2c68c9ae454db458)
-
-commit 940d60dc398383aede76b01cfa7618fb11081da6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Apr 11 22:34:10 2013 -0400
-
-    modules/sca: clear appearance on t_reply with error after receiving 18x.
-    
-    - Receiving a 18x provisional reply triggers line-seize subscription
-      termination. Releasing the seized appearance while processing a t_reply
-      with an error status *after* getting a 18x would fail because
-      sca_subscription_terminate could not find a matching line-seize
-      subscription. In that case, look up appearance by tags and release it.
-    (cherry picked from commit aa0c84475140dc44186c68e9c544367553c891c2)
-
-commit d220cdbf8eb9d6c0d7108c81cd1ba762a2fa8938
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Apr 8 15:01:41 2013 -0400
-
-    modules/sca: reduce verbosity of RPC sca.all_subscriptions output
-    
-    - accommodate more subscriptions without hitting kamcmd buffer limits.
-    (cherry picked from commit a9e555e6e41271e015c47d29ba85276673d3b7b6)
-
-commit 2a072eeea166c93a9419f6249b52c30da9367c3d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Apr 3 14:54:36 2013 -0400
-
-    modules/sca: ensure line-seize sub update uses index from request
-    
-    - lazy removal of line-seize subscriptions that were not used for a
-      call could lead to failure to release expired seized appearance.
-      Client must have a lingering, expired line-seize subscription that
-      hasn't yet been purged by the timer, and indices must not match.
-      Fix ensures that the appearance-index from the new line-seize
-      subscription overwrites the index left over from the expired one.
-    (cherry picked from commit 43cc6015e8604e309672da4d754b5022d1e256c9)
-
-commit 47aeade304e6731354ff190eb07b2e01a8059a25
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Apr 3 14:46:27 2013 -0400
-
-    modules/sca: fix SCA_CALL_INFO_EMPTY macro
-    
-    - test should be a logical OR, not AND.
-    (cherry picked from commit 3339e7a5bd205599fed63f82536626732b3f23d9)
-
-commit bbd4f9e7f4e27ecc73a5703c1a4acd0331a47f5c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Mar 15 17:01:23 2013 -0400
-
-    modules/sca: process BYE without Call-Info from shared line.
-    
-    - Ciscos & Aastras don't seem include Call-Info header in BYE. Look up
-      dialog by tags and release associated appearance-index.
-    (cherry picked from commit 287cccf2af17e5f2f8fe09c41025b4d27bb4fda9)
-
-commit eb130422b65cb4ed418c9ed0b9398a069fff397f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Mar 15 10:22:26 2013 -0400
-
-    sca: reduce log level to DBG when replacing RURI when retrieving held call.
-    (cherry picked from commit a51bc822f70f4185b55455456dc147205cbbbdc7)
-
-commit 489fd1ba70db6aefc68f037eadf92877b1f2e6cf
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Mar 1 16:33:59 2013 -0500
-
-    sca: fix private hold handling
-    
-    - private hold call-info was being ignored in hold reINVITEs, causing
-      inaccurate "active" notifications to go to subscribers.
-    (cherry picked from commit 81b5473f5a191a5aa81295acf0d96a22160f7f31)
-
-commit 888ea024de803c4d01be15cb30929339790a09ef
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Mar 4 23:13:53 2013 -0500
-
-    sca: fix regression dropping Expires header from SUBSCRIBE replies.
-    
-    - extra_headers.len lacked Expires header length after snprintf.
-    (cherry picked from commit 3b557293a33f6f3003fdd62a45e02cf8736b534e)
-
-commit 18593c16f5a4a7504a0de890b2bbc9025cff049f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sun Mar 3 17:01:53 2013 -0500
-
-    sca: move SUBSCRIBE response handling to sca_subscription_reply
-    
-    - create necessary headers, pass to newly generic sca_reply function.
-    (cherry picked from commit d528c27b6fa69530bfde4a6ce83c5d4dcc6499a5)
-
-commit 08b6b184dcab912edf8d58d8867f74f13c50c2da
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sun Mar 3 17:00:44 2013 -0500
-
-    sca: reject out-of-dialog attempts to seize privately held call.
-    
-    - per spec, reject with 403 Forbidden.
-    (cherry picked from commit e565748048d7a6b6fda0a28959e092380c5bc26a)
-
-commit 5f017710a95d21ef89a936ca28ef73f5d80081e2
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sun Mar 3 16:59:23 2013 -0500
-
-    sca: make sca_reply a generic reply function.
-    
-    - take a pre-filled extra_headers parameter instead, add with add_lump_rpl.
-    (cherry picked from commit d6d71b0e217226fe43491a0e9ba75ec0a6649cd5)
-
-commit 8972be270b422a5a1eef39249162e2abcde0feda
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Feb 14 16:55:36 2013 -0500
-
-    sca: fix race condition when two endpoints seize same index simultaneously
-    
-    - return 480 Temporarily Unavailable to loser of race.
-    (cherry picked from commit 522d06e75bf3c549af007701332f7db53a1b5ab6)
-
-commit e2642ea25cc19344d6e3e7f71e9df1cd7ef2532d
-Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
-Date:   Tue Oct 1 10:52:01 2013 +0100
-
-    core: fix TCP connection leak
-    
-    - patch provided by Vitally Aleksandrov
-    (cherry picked from commit 6cfd13cbddd1869ffbc947fdecd77d18a3fcb886)
-
-commit a7e7d9277f503ab42055b4b3be130e3f4a6fcae1
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Mon Sep 30 10:44:27 2013 +0100
-
-    modules/websocket: Fix connection leaks
-    
-    - Decrease the TCP connection reference count after each use
-    (cherry picked from commit 27474179bdeef0ddaba05389f510446a387d85e1)
-    
-    Resolved conflicts due to new feeatures in master:
-    
-    	modules/websocket/ws_conn.c
-    	modules/websocket/ws_handshake.c
-
-commit d5eadc90ebdb6460b43d304de86a37893263ce2d
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Thu Jul 4 10:30:51 2013 +0100
-
-    core: Fix connection leak with websockets
-    
-    - Decrease connection ref count after using connection
-    (cherry picked from commit ffdae5987b99b9bfd39992d407a3a0a33aa772ab)
-
-commit 1e774166724e0bdd2c43091b3b19c1b82d197242
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed Jul 3 10:39:32 2013 +0100
-
-    modules/tls: Free TLS data for secure websocket connections
-    (cherry picked from commit 074f12c5a444188aa023797ac70e2d38d225cb18)
-
-commit 76319cf9600b71364e3cd6509f61da2f60b2f10f
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed Jul 3 10:46:44 2013 +0100
-
-    modules/websocket: Fix pkg memory leaks
-    
-    - Fix pkg memory leaks in error cases
-    - Fix incorrect memory allocation size for ws connections
-    - Fix typo in websocket stats
-    (cherry picked from commit d0f88e19577d9b914922f83049075b7786f3d8df)
-
-commit 77a53b8df680808a20c73953f1e5348df5d309d2
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Thu Jul 4 09:33:56 2013 +0100
-
-    core: Improve tcp stats output
-    
-    - Add connection ref count
-    - Add websocket protocols
-    (cherry picked from commit fb4dc4b7b866239a90a4d6441ed319664697edab)
-
-commit 052dfbe29933bf773ba5d109a530c2b2f7ecb59c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Sep 19 15:59:18 2013 +0200
-
-    pkg: kamailio - provide -f $CFGFILE to init.d config check function
-    
-    - reported by Grant Bagdasarian
-    
-    (cherry picked from commit f7fe8b68ffb100fbaa27344e4bee7ba69c760584)
-
-commit 38157fdbdadd1ff2a0ac902088082ad96b0c2f04
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Sep 19 14:06:46 2013 +0200
-
-    core: reset fields from sip_msg_t in shm cloned structure
-    
-    - instance was pointing to pkg
-
-commit 1550ce9a0ffa012daf413a0abee5d80bd7cc60de
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Sep 19 14:05:21 2013 +0200
-
-    tm: reset faked request fields that can be set in failure handlers
-
-commit 3ca71bbf4f61c83d8e82c988d0789d147f81f30b
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed Sep 18 21:34:16 2013 +0100
-
-    modules/sdpops: Check for valid sdp body in sdp_remove_line_by_prefix
-    
-    - Fixes crash when used on requests with no body
-
-commit 84b21f2e9f602032d5950069cbd1dbf3ac416fcb
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed Sep 18 21:58:12 2013 +0100
-
-    modules/app_lua: Fix off-by-one error in modf
-    
-    - Fixes calling sr.modf with additional parameters
-
-commit 8ffa88060ebfd0634c0cebfea43189a8e1545b4b
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Sep 18 08:29:41 2013 +0300
-
-    modules/lcr: fixed checking of IPv4 address in to_any_gw_2 function
-
-commit a331af11519765e863ddad68878f7c5d571d0823
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Sep 15 16:38:34 2013 -0400
-
-    xhttp_pi: fix crash when checking bad configs
-    (cherry picked from commit d1219dc0d0c5e2eab0672a439aa7ce6486c31ba3)
-
-commit c79fb705391b90813a501165049ac79aff80928f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Sep 14 11:08:23 2013 +0200
-
-    tm: docs - no event_routes.xml in this version
-    
-    - readme regenerated
-
-commit 07a8f0da3d8f3d1ec4b3e4e88db485e5015a31f2
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Sep 14 09:46:23 2013 +0200
-
-    tm: added missing documentation for t_check_status()
-    
-    (cherry picked from commit f328b864418020b1e166b13804fe173110500d75)
-    
-    Conflicts:
-    	modules/tm/doc/functions.xml
-
-commit 120b736c14b3dae780cfc9ef7fc8fd1c79d32d92
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 10 14:14:52 2013 +0200
-
-    kamdbctl: added missing dbuid tables group creation
-    
-    - patch by elactrum [at] jamailca.com
-    (cherry picked from commit 6f17209a70e84d91976ea42b476ae248b9b37501)
-
-commit 51f40460096d9c249ce34d9b4fbecf366b5f974e
-Author: Victor Seva <linuxmaniac at torreviejawireless.org>
-Date:   Mon Sep 9 16:52:47 2013 +0200
-
-    uac_redirect: get_redirect() check reason value before using it.
-    
-    This fix a core dump when get_redirects() config fuction is called with just
-    the one parameter.
-    (cherry picked from commit abf0026782c0ba4643feb25ded022e8c12725584)
-
-commit 9c8fd38683d9f6531b0d6ee966d81d878095bf6a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 4 22:59:13 2013 +0200
-
-    registrar: reset r-uri pointer after backup in lookup_branches()
-    
-    - otherwise can be invalidated by next branch lookup
-    
-    (cherry picked from commit 9b44e4b48862947f2ea634c6dd611ce7c07546a2)
-
-commit d8739609c85cb00da9486b3f91d0c4834048485f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 4 13:04:23 2013 +0200
-
-    topoh: safety check for missing To header
-    
-    - based on a patch by Michel de Weerd, FS#303
-    
-    (cherry picked from commit 362d374a61953aee3cf9f96eadaef63c5f22763e)
-
-commit 756e30f5c33ef4ab122b333b4d1b6ce80cec0f2f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 4 12:33:45 2013 +0200
-
-    db_postgres: use variable for make tool in module Makefile
-    
-    - fixes builds in BSD systems
-    - patch by Victor (coyote), FS#335
-    
-    (cherry picked from commit 7abd496560c6274680d451f49355ad1f6a14a6a7)
-
-commit 796d53ddec3fe12dcb93d4a4c293de0f610581d5
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 4 11:54:07 2013 +0200
-
-    tm: readme regenerated from xml files
-
-commit e7a00bb913fc24be894a668317dd2f2ac143cbed
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 4 11:53:28 2013 +0200
-
-    tm: updated xml docs with t_set_disable_internal_reply()
-    
-    - backported from 6073949aa224ea7a973058891a88a58cc0841860
-
-commit 55587b6bd035f2ab10f73c6c9bde95628688e799
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Aug 23 21:03:13 2013 +0200
-
-    tm: removed note about no-implentation for no-reply flag for t_relay_to()
-    
-    (cherry picked from commit ef9b69bbb54302e9985dd37d79831b6f80463fc1)
-
-commit 98ba4cec3ca2caef40725c3884e7dd5693d6c3c1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 4 11:44:23 2013 +0200
-
-    rtpproxy: updated rtpproxy_manage() to handle PRACKs with sdp
-    
-    (cherry picked from commit 2aa5095252f9434c7c2a63ecb130bdaf1346fde9)
-
-commit 3d836040bdb6d191e6f6a54e37fe680e1e3973d0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 4 11:47:36 2013 +0200
-
-    tm: re-added the option for no-internal reply on error
-    
-    - new function t_set_disable_internal_reply(0|1) to disable|enable this
-      option per transaction
-    - t_relay_to() flags re-enabled for this option
-    - backport of 0f2f9c85eff0b6ad35b4c58dfcde74c8a65559d6
-
-commit 2a224a569cea270d8db84438f163b9f309569df9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 22 00:14:53 2013 +0200
-
-    core: print src address details if initial message parsing fails
-    
-    - reported by Juha Heinanen
-    
-    (cherry picked from commit 3ccf4b43e81bd2654cb306a3c2cc21b97cb51f62)
-
-commit fd4a2dde96a692c165f382839c3bef8636dfd9e2
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Thu Aug 22 08:20:52 2013 +0300
-
-    modules/lcr: added some linefeed chars missing from syslog messages
-    
-    - Patch provided by Kevin Scott Adams.
-    (cherry picked from commit d03651fb4c3a6b50923029e121eed201fb1ff550)
-
-
-===================== 2013-08-15 Version 4.0.3 Released =====================
-
-===================== Changes Since Version 4.0.2 ===========================
-
-commit a75a8a140e53ef8cee58d670b3954e7ac4cdb1b8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 15 15:33:55 2013 +0200
-
-    Makefile.defs: version set to 4.0.3
-
-commit c67ac0b5ef5183947acf02d496eb5899dad0ba9b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jun 16 17:17:36 2013 +0200
-
-    topoh: safety check for To header
-    
-    - protection for the case when sanity module checks are not enabled
-    - reported in FS#303 by Michel de Weerd
-    
-    (cherry picked from commit 4f3d04d547c66a1b59398cf80e93974175141514)
-
-commit 2ffedf0e6bd3d9231988fbb70153bd6d72ae63ab
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jul 4 11:48:26 2013 +0200
-
-    tm: avoid double execution of response-in callbacks
-    
-    - double execution of response-in callbacks could happen when using tm
-      pvs inside core reply route, being done in transaction matching
-      function, which is executed again by tm reply received function
-    
-    (cherry picked from commit d4cef7f5e49105c65df9651a1ad086b035f8ffdb)
-
-commit 9e231ae7f6a80abf686448e1593195b9012c2e8c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jul 4 11:47:18 2013 +0200
-
-    core: new internam sip msg flag FL_TM_RPL_MATCHED
-    
-    - mark sip reply when matched first time by tm
-    - used to avoid double execution of response-in callbacks
-    
-    (cherry picked from commit 230a138991b25f7f9b07b4f9cbeffbdd6acef2e8)
-
-commit 58322807c275ce07be6a339dd5db2416f1905470
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Jul 20 10:01:25 2013 +0200
-
-    Makefile: sercmd renamed to kamcmd in uninstall option
-    
-    (cherry picked from commit ab601ea9a1b2561c2eaa860583cdeed478b9ea8d)
-
-commit 17f2611e668af139399c21677d3503c0c5a6a860
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Aug 4 14:22:41 2013 +0200
-
-    imc: wrap bit shift defines in parenthesis
-    
-    - avoid priority conflicts when using the defines
-    - reported by Shankar
-    
-    (cherry picked from commit e6e0419a46c3e5127d07c95390931d10b2a01c3b)
-
-commit 75e20d79763094fccaacddf127699ce9f22e973a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 15 10:38:26 2013 +0200
-
-    pkg/rpm: version set to 4.0.3 in spec files
-
-commit 701b5faef517a65208907e771d2c3b7b015afb19
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 15 10:37:15 2013 +0200
-
-    pkg/deb: version set to 4.0.3 in spec files
-
-commit 3898507f56eefe5c9d8e72b37280e0d133f6e357
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Aug 13 09:37:21 2013 +0200
-
-    usrloc: safety checks to catch empty ruid
-    
-    (cherry picked from commit b0e9132ccd1e8385b8b4faf72db806320d48e2f5)
-
-commit e59bb3303252c0b47f6027ae2b99a11096521154
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Aug 13 09:19:02 2013 +0200
-
-    usrloc: more verbose log messages in case of failure to update db records
-    
-    (cherry picked from commit 66c8e730d59f9816f09573f5300e4463e5997876)
-
-commit d3be7fa1c47d12a1eb6e725729c6a0a2e481bc63
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Mon Aug 12 11:05:55 2013 +0100
-
-    rls: Fix memory leak in rls notify.c
-    
-    - xml is leaked in an error case
-
-commit a72a01a1cac4bd17e0aa91912ab158e73908d561
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Mon Aug 12 11:15:55 2013 +0100
-
-    presence: Iterate correctly around presence updates
-    
-    - timer_send_notify should increment the subset by one on each loop
-
-commit 6abd4b4d1eeea2c57a8bcfb071fadaca21efc20f
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Tue Jul 16 10:51:29 2013 +0100
-
-    outbound: Fix freeing null pointer in destroy function
-    
-    - Only appears in error cases, e.g. syntax check
-    (cherry picked from commit e88af0a02de79fac583c126f08d762f7ef3f1b01)
-
-commit d2f62dd1855faef35bea8eff932d250557868ae5
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 1 15:58:59 2013 +0200
-
-    db_flatstore: free id pointer if no more space for table name
-    
-    - related to previus commit on this module
-    - keep table name null terminated
-    
-    (cherry picked from commit 6a981d3d922c914054d4c8dc7e672bb6a4ddb5f5)
-
-commit c50d559b4da94238a430c059dd02d74e63dd96fe
-Author: Federico Cabiddu <fcabiddu at orange-vallee.net>
-Date:   Mon Jul 29 07:59:34 2013 +0200
-
-    db_flatstore: fixup for new_flat_id function
-    
-    - locally copy table's name
-    
-    (cherry picked from commit 8fb0f711aaa611eac8b2776c7e5ae3c5e19243ac)
-
-commit 76b82480f74006d830afc9c9ae81ada25dbc7730
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jul 26 14:52:21 2013 +0200
-
-    uac_redirect: fixup for using acc table parameter
-    
-    - set reason parameter for acc function
-    - based on a patch by  Federico Cabiddu, FS#327
-    
-    (cherry picked from commit 3d33733f299dda595704108aef73a2912dc3069f)
-
-commit ece14d42fda4baefc4f0e8465faad17b678a6a4b
-Author: Federico Cabiddu <fcabiddu at orange-vallee.net>
-Date:   Mon Jul 29 07:59:13 2013 +0200
-
-    acc: acc_db_set_table_name fixup
-    
-    - add termination char to db_table_name_buf
-    
-    (cherry picked from commit 7ba6cbfcaf70cb546ea3a9f148a0f0b0bc38c16d)
-
-commit ea266beb3d678b36efeb82feeba6087df90d9f19
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jul 26 14:55:38 2013 +0200
-
-    acc: safety check for accounted values not to be NULL
-    
-    - based on a patch by  Federico Cabiddu, FS#327
-    
-    (cherry picked from commit fb3a5f7022ebd20fc516b5b8303a0274bda18258)
-
-commit 9f0a42dd31d765541c02d2b818dd52643589f59d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jul 2 23:32:37 2013 +0200
-
-    dialog: detect if no trasaction is created after config execution for new dialogs
-    
-    - release the dialog to avoid endless storage in state 1
-    
-    (cherry picked from commit fa0339b1906690f009786fc9ed92c73a8c9e6520)
-
-commit 369164c689950595b7e35c36a810ecd41aaa7a0a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jul 1 15:22:33 2013 +0200
-
-    dialog: increment cseq in early stage for PRACK and UPDATE
-    
-    - rework from a patch by Halina Nowak
-    
-    (cherry picked from commit 6cf3ab0ca6f38d1d2e60dbc644bb4d2fb563919a)
-
-commit 91f64af86eebde4a179a4d9cb6837994a587a967
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jul 1 14:51:03 2013 +0200
-
-    dialog: avoid realloc of memory for cseq when setting leg info
-    
-    - free already allocated structs when needed
-    - has part of a patch by Halina Nowak
-    
-    (cherry picked from commit 71d7dc6bc750406d510e0571e05da3966911cfea)
-
-commit 573096ad14c34364dad160bffd7e7ed5d007f5f6
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jul 1 14:44:45 2013 +0200
-
-    dialog: fixed callee cseq reference
-    
-    - part of patch by Halina Nowak
-    
-    (cherry picked from commit ed6dbb0ca11206049bee9ab515ce071eb70e7b63)
-
-commit 3935fedf23f3bf2b6675182193cef6af3bbd903a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 31 12:22:12 2013 +0200
-
-    app_perl: push the sip msg structure to perl after initializing it
-    
-    - reported by David Cunningham
-    
-    (cherry picked from commit 341f810dca0cc0596e22f2ac1bca86de0b8d142d)
-
-commit 3438215263f20f63f0e69121113999f952334886
-Author: Camille Oudot <camille.oudot at orange.com>
-Date:   Tue Jul 23 11:11:01 2013 +0200
-
-    modules/ims_registrar_scscf: safety check in async_cdp_callback
-    
-    (cherry-picked from commit 1aea13af9b3eea3788e90411bd94cb9e0b0c4ea3)
-
-commit 4471593e5f6e292d205bd84fb5912088bde32870
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jul 25 10:14:55 2013 +0200
-
-    app_perl: move initialization of SIP message var after initialization of temporary environment
-    
-    - upon a report by David Cunningham of a leak in operating system
-      memory
-    
-    (cherry picked from commit 6ff74701652a11497bd82ee3ba2ac7547d1ce666)
-
-commit 86864275e240be94d901fe21dde2472701e1669e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 17 20:19:28 2013 +0200
-
-    uac: restrict check of multiple from/to header changes to request route blocks
-    
-    - it can occur many times in due to branch route usage
-    - reported by Andrew Pogrebennyk, FS#323
-    
-    (cherry picked from commit d3a0a8b15af59846fdaee5d9ceae61484f1d7301)
-
-commit b7e890b309331a13eb92c5080d276036be5833ae
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 17 00:04:06 2013 +0200
-
-    presence_dialoginfo: add schema to entity
-    
-    - patch by Pawel Sternal, FS#324
-    
-    (cherry picked from commit 716ffd2787a68734a21a1374c3dc6dd4783844bd)
-
-commit b87040d6839985ceb107e4a097df71afd8c69fa5
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jul 16 21:43:42 2013 +0200
-
-    usrloc: fixed type for db_ops_parameter
-    
-    - reported by Alex Hermann
-
-commit fb9a6ff96355093baa59c4f0c5c8505cb7d29311
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Apr 27 18:07:21 2013 +0300
-
-    modules/usrloc: fixed typo in db_ops_ruid param name
-    
-    (cherry picked from commit edebc03f65445f968accb58b5a761817aaee55e8)
-
-commit f8826df994a6baac9cfee219abafa3e1b82ee4f8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jul 12 00:44:51 2013 +0200
-
-    core: avoid doing dns srv again after naptr function that includes srv lookup
-    
-    (cherry picked from commit 80935f9e8bbe20e5c320828183999b5d395ec34c)
-
-commit d821224ff33e7f7c43c6598482ab0870f728e763
-Author: Victor Seva <linuxmaniac at torreviejawireless.org>
-Date:   Sat Jul 6 20:22:41 2013 +0200
-
-    modules/nathelper: remove natping_proceses limit
-    (cherry picked from commit edb00b0566595b509a7cdf9a1c7455ce6ee6c4c8)
-
-commit 3612981970e8002b3ab7f7d0324354e282205e2b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jul 11 14:36:02 2013 +0200
-
-    pipelimit: avoid double locking when changing pipe via rpc
-    
-    (cherry picked from commit 0c6fef5fdc2a586ebfa607d3b5344266c08ca996)
-
-commit 5e11ebf34bd525f02c7ff08b9520382c3aaf00f2
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jul 11 14:32:48 2013 +0200
-
-    pipelimit: avoid double locking when changing pipe via mi
-    
-    - reported by Krischan Udelhoven, FS#315
-    
-    (cherry picked from commit 04fd56dc1b84b70a04438ccbf719eb85177524ad)
-
-commit d8c3a23ad2a5c925b16d75f33fcb865f09d7f308
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 3 23:29:29 2013 +0200
-
-    uac_redirect: adapted previous backport to append_branch() prototype for v4.0
-
-commit 0227f5b61e1ea03e92a7fec9b177f602481fac84
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 3 23:23:40 2013 +0200
-
-    uac_redirect: fetch all contact headers in redirect replies
-    
-    - only first header was considered for redirect handling
-    - based on a report by Geoffrey Mina
-    - generate fake ruid (used as instance and user-agent) to satisfy the
-      requirements of t_load_contacts()/t_next_contacts()
-    
-    (cherry picked from commit c5081ad634742d88e56e4fcc097b756098119e4e)
-
-commit c4b51e9f51b4b2c4e908b4c4dc33b824021f1ca1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jun 17 11:00:29 2013 +0200
-
-    pipelimit: fixed typo in module parameter name
-    
-    - patch by Krischan Udelhoven
-    
-    (cherry picked from commit c5573dddc4c11898fb68365e9a311aff0f1690c8)
-
-===================== 2013-06-12 Version 4.0.2 Released =====================
-
-===================== Changes Since Version 4.0.1 ===========================
-
-commit f6fc38aab505aab1301024b58581ebec9a7181c4
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 12 15:50:45 2013 +0200
-
-    Makefile.defs: version set to 4.0.2
-
-commit d4df824c3f16cf934d9056e94f8f44ae0bf3016f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 12 12:29:39 2013 +0200
-
-    pkg/rpm: version set to 4.0.2 in spec files
-
-commit 963fcd0ccfac6cccdc27b3a2d7a14d207ed7c516
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 12 12:29:16 2013 +0200
-
-    pkg/deb: version set to 4.0.2 in spec files
-
-commit d54024f873c641c21da197ee7eb3a49746f58229
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 12 09:14:14 2013 +0200
-
-    registrar: regenerated the readme file
-
-commit 81b61679cabd2470becf86700b777cc496f1d330
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 12 09:11:56 2013 +0200
-
-    mtree: use debug level for log message when invalid character in value to be matched
-    
-    - more verbose message when an invalid database record is found
-
-commit 6b0d759f0dabf36c529c6c7d22c8333e7a8731e1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jun 11 18:39:31 2013 +0200
-
-    registrar: fixed typo in example of xavp_rcd parameter
-    (cherry picked from commit c228851e068a080050c79107c760f8ab5ffae967)
-
-commit 3f1f50068b96ea4bde1a7255842bf07683cbed8a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jun 11 18:37:32 2013 +0200
-
-    registrar: more debug messages when adding ruid xavp
-    
-    - free local ruid xavp if cannot be added to root list
-    (cherry picked from commit 9589466916305146fb4f982542c3f3a51126dcef)
-
-commit 56ba8ea8b1f1f26ccc36dfb073e1559eca4d77b1
-Author: Camille Oudot <camille.oudot at orange.com>
-Date:   Tue Jun 11 16:34:49 2013 +0200
-
-    modules/ims_isc: several safety checks
-    
-    - fixed potential buffer overflow
-    - fixed potential crash if regcomp fails
-
-commit 9ee53f2abe580026c83d62b0edf1f6288dc0111a
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Mon Jun 10 12:14:54 2013 +0200
-
-    app_lua: solve crash when setting a variable not convertible to string.
-    (cherry picked from commit 4af0bc13901525a5638c2c64b863f377e033903f)
-
-commit c3f4bda21273a5172dbfe048c5a1a14216f6d047
-Author: Camille Oudot <camille.oudot at orange.com>
-Date:   Tue May 28 17:53:07 2013 +0200
-
-    modules/ims_registrar_scscf: safety check for log line when recieving an SAR_UNREGISTERED_USER response
-
-commit 1fefe2feae9fec5621d949fe3857fcf8fb62068e
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jun 7 12:09:38 2013 -0400
-
-    Makefile: update de-stable target: squeeze -> wheezy
-    (cherry picked from commit fd8dfb71d0eeae891ad0c83ff332929d54f3a3ec)
-
-commit a9089d05121e05287ce91fddb12769acfae866c8
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jun 7 11:17:10 2013 -0400
-
-    nathelper: fix IPV6 compiler warning
-
-commit 21747d786a4e0f8f606baeeb4f39166d351b824b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jun 6 11:47:10 2013 +0200
-
-    cfgutils: updated docs to specify correct time unit for usleep
-    
-    - it is microseconds, pointed by David K
-    (cherry picked from commit 8e937d260d0ff41f50be56e0a46ede44554f3f99)
-
-commit e52f1d6e5702bce8031d224f006627ab3fc3f859
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jun 6 09:09:14 2013 +0200
-
-    kamailio.cfg: reset $du for voicemail re-routing in failure route
-    (cherry picked from commit c4b29f6fac6155b9b087737df5956b687ff4e36a)
-
-commit 3dc0b79993863f7399b1cb579d81f3637370e35a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 5 22:44:13 2013 +0200
-
-    kamailio.cfg: few updates related to nat traversal
-    
-    - added "co" flags to rtpproxy_manage() to change all IPs in sdp, many
-      phone get confused if only media ip is changed
-    - add nat=yes parameter only for in branch route to avoid multiple
-      occurences
-    (cherry picked from commit 0193489cca56f58b512f5379c078c98a366c17e2)
-
-commit 72b483393b5e7c85096a79fd999caf17edde69b6
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Wed Jun 5 08:58:29 2013 +0200
-
-    module/ims_auth: protection against crash if there is no auth vector initialised.
-    	- patch submitted by Camille Oudot
-    (cherry picked from commit 4b65964dbe1f38bcf867301d43933f9bbf91ab7d)
-
-commit 51fc2140e1d0708ed213d4903552c2f98a39a5da
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jun 3 20:53:05 2013 +0200
-
-    dialog: shift next timer run for keepalives of dialog
-    
-    - reported by Daniel Tryba
-    (cherry picked from commit a17a32e5f7a3120c200d6e48fe91d7aa1dfd28b1)
-
-commit de9607079be932be6effe40573b3219724f4393e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon May 27 16:54:02 2013 +0200
-
-    core: enclose uri in angle brakets for redirect contact header
-    
-    - safer for uri with parameters and no q
-    - reported by Dan Bogos
-    (cherry picked from commit 74bf08ef30cf18fb609c2c067584f1515ede23da)
-
-commit f01889d6e717892d38df8c267e20c269dbc83b0e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun May 26 10:43:24 2013 +0200
-
-    dmq: many safety checks for mem mallocs and function return codes
-    
-    - added license header in the files
-    (cherry picked from commit 1977645ceb12ca2d0f2f767046606f6c5ae2c3bb)
-
-commit 2c04dd88c8911f3a67f3f94a5ad11b1ab865aca9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat May 25 16:30:33 2013 +0200
-
-    protoshoot: use Makefile pattern for utils
-    
-    - link to libsctp if SCTP support is enabled
-    (cherry picked from commit 1bdbdb64e4862ddb69c2bf13be0f9be93968bb1e)
-
-commit cd1120c6500bb396af9b5410ecd535160c2ba9d7
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Sat May 18 13:56:22 2013 +0300
-
-    parser/sdp: Fixed segfault in sdp_print() when no SDP body.
-    
-    - Failed scenario:
-    remove_body();
-    msg_apply_changes();
-    sdp_print("1");
-    
-    - Result: sdp=0x0
-    (cherry picked from commit e81b3aac19ab567813d6cb21fcba3d9bd6e1cc90)
-
-commit edde8d20806aca248e3a1c1e439084988d62d361
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri May 17 00:46:42 2013 +0200
-
-    core: fixed printing function name in log message
-    
-    - based on http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
-    (cherry picked from commit e081c2880b46174ad836ab1f56e3062bb17b4332)
-
-commit 959cab2009427fd850318980914dd0e91b3cbff8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed May 15 22:45:18 2013 +0200
-
-    pv: clone result of several string transformations
-    
-    - it is safer for assigning back to the same variable on which the
-      transformation was applied
-    - reported by Martin Mikkelsen
-    (cherry picked from commit fe7e4a5152674aa9c81c09dd2fc9938d9e9e762e)
-
-commit c3017b2e79e47edd88f2b4917afd4794d4e6ef11
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue May 14 19:52:45 2013 +0200
-
-    utils/misc: updated vim syntax file
-    (cherry picked from commit 6038bae188863f541994976d299c38f50b0a699b)
-
-commit 90a8f28c01d804dccc50112af3235fb886e57d89
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon May 13 10:59:20 2013 +0200
-
-    core: debug message to show mapping of routing block names to ids
-    (cherry picked from commit 80e8058d9acea7c994819d043456fd1b449b048b)
-
-commit 369143aeeab0761edd70ab42cbac5648194f8a55
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sun May 12 16:10:40 2013 +0300
-
-    modules/presence: downgraded unsupported event syslog message
-    
-    - Downgraded unsupported event syslog message from error to notice.
-    (cherry picked from commit afdae93c5eba15496498be292c0c99608d801757)
-
-commit 2c4bc8619c61993c02eccaada7dca5f5c84199af
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue May 7 19:15:36 2013 +0200
-
-    core: get rid of deferencing type-punned warning in deb wheezy
-    
-    - reported by Victor Seva
-    (cherry picked from commit 81d3eebd51089686949ab22da60166d4f3a460a7)
-
-commit 62071fddff1793254e3d615ccb956bbb7ce5ccca
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu May 2 21:17:57 2013 +0200
-
-    mangler: fix double definition of contact_flds_separator, reported from ld
-    (cherry picked from commit 003d87edc23f62de98a1a22db03b12ea58abcbc6)
-
-commit bb9a8ea4dcff649c06395efbe4f3aa2cc4f269f5
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Apr 29 20:54:52 2013 +0100
-
-    modules/websocket: fixed mandatory headers check
-    (cherry picked from commit 8f74c57605fdd1d31c7808a3b8afc79cc981b370)
-
-commit 61f68eae79b09898cec4a90f298c562f4c2f9a93
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Apr 29 20:38:06 2013 +0100
-
-    modules/websocket: doubled the size of the buffer for adding headers to WebSocket handshake responses
-    (cherry picked from commit a2e7f65ee8b86d37a6772619ae10087a05219192)
-
-commit 6eb6d92af2fe55d14b255bb5c5c939cc2f78ba79
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jun 7 11:00:51 2013 +0200
-
-    modules/rr: completely reverted after_strict() to its pre-outbound form
-    
-    - backported from c9448d9657f0e5792072c6803643c8d9075d711a by Peter
-      Dunkley
-
-commit 4b8f5eea61310a7d2545d06d513697b0c8631289
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jun 6 15:21:19 2013 -0400
-
-    registrar: print bogus AoR in error log
-    (cherry picked from commit e41230071e367015ecf794c147c60fda0bcd1907)
-
-commit 3a64a12e056670766da7e49a0275c1240d6d229a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri May 31 17:05:40 2013 +0200
-
-    pua: release lock on not finding temp dialog
-    
-    - patch by Halina Nowak
-    (cherry picked from commit 09cc2207b265d51dcbc28279623bf9c597fa3b46)
-
-commit be5c2e31c6498d916762b87b6d5e76403f9f1824
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 15:49:52 2013 +0100
-
-    documentation: Rebuild auth README
-
-commit 6978f42ae854385b437f637f7e6ce3fced33474c
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 15:46:18 2013 +0100
-
-    documentation: Rebuild all modified READMEs
-
-commit 96aff46759acd1df1a585866c1ce9295cb2810b1
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:10:31 2013 +0100
-
-    auth_identity: Fix TOC in documentation
-    (cherry picked from commit d4743ac526184ce3234518234ca77c715ca2f6b6)
-
-commit 203ba3e9c51852b245448ab44f4a7c181919cd33
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:11:23 2013 +0100
-
-    avp: Fix TOC in documentation
-    (cherry picked from commit 973973bef43acac5cdbae930427b6e347746a337)
-
-commit ce1da89afedc38e606446527bf218ea9eb032221
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:37:03 2013 +0100
-
-    blst: Fix TOC in documentation
-    (cherry picked from commit f53afaaf8c7fe65507ebe179a05049c64b380632)
-
-commit 479199a575a3cb4a8385cbf8ad8ece5d798e09f1
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:37:26 2013 +0100
-
-    cfg_db: Fix TOC in documentation
-    (cherry picked from commit c209510de26aadc7ff01506dca42ec0b39904f0a)
-
-commit 3d6e26cd8b2188b6236c98977c4c312c2320d3bd
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:37:45 2013 +0100
-
-    cfg_rpc: Fix TOC in documentation
-    (cherry picked from commit ca060e774dd95b0831b2efeea9b355ba3a4fc068)
-
-commit 67716c6c5cf5fbe89e69df5dc86db0f7dce7ed3c
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:38:07 2013 +0100
-
-    counters: Fix TOC in documentation
-    (cherry picked from commit 2980ba3881325102835297bc5cdf5b3199a8f9b7)
-
-commit 183562260acce4b5fcaeb1831b4c50757dfb9dbd
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:38:25 2013 +0100
-
-    ctl: Fix TOC in documentation
-    (cherry picked from commit cff735c7d4933d8fac54471897173a6b6c75bd4f)
-
-commit 43e15fa83ef1e5b043f1d2aca69864030f21dc81
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:38:43 2013 +0100
-
-    db2_ldap: Fix TOC in documentation
-    (cherry picked from commit 2e4e4d54015f850b377beb30a72cc4e0b2cb1cce)
-
-commit e6ee88798b26af044afe5d407cdb4c637171fb70
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:39:45 2013 +0100
-
-    db2_ops: Fix TOC in documentation
-    (cherry picked from commit f29709478f3492741803cf8ce100d6aa843de6be)
-
-commit d680a29621d81e4bd99a79c20474ff275eb364ee
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:40:06 2013 +0100
-
-    db_flatstore: Fix TOC in documentation
-    (cherry picked from commit 86b0c38c38822c93ccd3f2a80f629f35c83877bf)
-
-commit 2483b36569ca27db9e1952afdf9de6a838de3b4b
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:40:31 2013 +0100
-
-    iptrtpproxy: Fix TOC in documentation
-    (cherry picked from commit aaa7c1ca5b61ab156dc548647b5021cdfce79df8)
-
-commit f281fc57de32fe4ed23e5cfc44039ec4d83b43e3
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:40:54 2013 +0100
-
-    malloc_test: Fix TOC in documentation
-    (cherry picked from commit fa90c51bb3c1eace5ca3ef75bb0656ad00512081)
-
-commit f2d0437086f2208036affbf4a6a43fd5c47f27aa
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:41:28 2013 +0100
-
-    mangler: Fix TOC in documentation
-    (cherry picked from commit 0587120366a1e434c4b037aa9aea13ad47c00949)
-
-commit 88ba330fff5556d893a426acc1c1b96b1443ca72
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:41:51 2013 +0100
-
-    prefix_route: Fix TOC in documentation
-    (cherry picked from commit 0fec2b0e212a3578474ce4eb7165d218a5008741)
-
-commit 2b73d4a7a584891e3ce4087002418039bfcfa842
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:42:05 2013 +0100
-
-    print: Fix TOC in documentation
-    (cherry picked from commit 2a7b143ac5e16da2ef5a1b249a041a009fe2403c)
-
-commit 36fcb32c129a43bd8056a7b8bc3e0b44e0f266d0
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:42:20 2013 +0100
-
-    print_lib: Fix TOC in documentation
-    (cherry picked from commit c6a6057ad0a121b5fb756c05ebe7ae8819ad1eea)
-
-commit adaa412871b4e489ff41ba585365711cf2df5965
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:42:35 2013 +0100
-
-    sanity: Fix TOC in documentation
-    (cherry picked from commit 0428706c4c8ebb8ab55e29acea02e574a3f7301f)
-
-commit 461b1e248f0d3f749282f2145c4176bb979b5e66
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:42:54 2013 +0100
-
-    sl: Fix TOC in documentation
-    (cherry picked from commit 47c467fd2ea2351112acadd1f2b7317b97a15a86)
-
-commit de89f88a99ce546c73a4dcf52c37c42078dce972
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:43:09 2013 +0100
-
-    sms: Fix TOC in documentation
-    (cherry picked from commit 30a01b64344ae050a79cce83f56de56032580138)
-
-commit d115fa0291aa927f2ff8ceec67f29732c7faa69b
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:43:24 2013 +0100
-
-    textopsx: Fix TOC in documentation
-    (cherry picked from commit ec8c442d890d875cc412b24fdfafc4bac2d43d7e)
-
-commit 07f8341cc900dcb3b1c794f90d661619ce9d96bf
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:43:42 2013 +0100
-
-    timer: Fix TOC in documentation
-    (cherry picked from commit e7b02dfc716f39465600170059559af042642062)
-
-commit b66db21b7ece75e8ab241a2c3e910c606bca8519
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:43:57 2013 +0100
-
-    tls: Fix TOC in documentation
-    (cherry picked from commit 935607223847032559156c22e0a0988fd32e9d17)
-
-commit 04b1687078f26fceb7b50384c0b2f1f4a349e4a1
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 15:10:38 2013 +0100
-
-    tm: Fix TOC in documentation
-
-commit 7e3b141db106062141e18365601039ed382125e7
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:44:28 2013 +0100
-
-    xmlops: Fix TOC in documentation
-    (cherry picked from commit 285142447f23aa317a0a0d5b3e6e57d3afa78961)
-
-commit 5b0dc97812273d4f2cde2e4fd63df5c29c84165b
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:44:45 2013 +0100
-
-    xprint: Fix TOC in documentation
-    (cherry picked from commit 3a1c8104aca76ee1d0f3565c1179c67685d5e838)
-
-commit fc0b618fe2dfc8c54093e61c763bd3052fb27a86
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:45:28 2013 +0100
-
-    uid_auth_db: Fix TOC in documentation
-    (cherry picked from commit 740e37bd1f6e2370bae02b5e8d6d4fab8e89eaa9)
-
-commit 665573c8561aa69641b64062b2b5cd720914c925
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:45:49 2013 +0100
-
-    uid_avp_db: Fix TOC in documentation
-    (cherry picked from commit bdfb7274ffeffaf99ad8b4aeebf9b9493685f7b7)
-
-commit 6e996037deb698e8cb40a010c45004136ce74f7f
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:46:04 2013 +0100
-
-    uid_domain: Fix TOC in documentation
-    (cherry picked from commit a20b97560d35f367b0a8d8b203e9566e42acde52)
-
-commit 0f1f2f37546f6c4b0f7c7a27df684a81c8e5a8fa
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:46:24 2013 +0100
-
-    uid_gflags: Fix TOC in documentation
-    (cherry picked from commit 396363a78875af7fc6444705d5482d579d5ac0c5)
-
-commit 27e630e4fa8346b19f712ee5b7c5028bbfbf20ef
-Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
-Date:   Wed May 29 14:46:40 2013 +0100
-
-    uid_uri_db: Fix TOC in documentation
-    (cherry picked from commit 10d5ed156a59d8e8a000bd7cecec5bf968853c69)
-
-commit 817d5dfdd8fbae905c64c41672f197143b6f563c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed May 29 10:49:40 2013 +0200
-
-    topoh: safety check for Via header when removed from script
-    
-    - reported by Guillaume Bour, FS#300
-    (cherry picked from commit b480ac55508e5d9b92cc9560e0b1d338d04f3b11)
-
-commit 3a431ed6b79762162a907164d4fa3b76c6b6aaa6
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Mon May 27 10:48:00 2013 +0000
-
-    modules/dialog: regenerate README
-
-commit 59adebfe3ae6f18a337833d0df62ee67e161bff5
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Mon May 27 10:44:03 2013 +0000
-
-    modules/dialog: improve documentation of DID matching
-    (cherry picked from commit 68209cc2b15c2c0674d7cf4529607e148e3fc1b4)
-
-commit 533f2238d9d14ed8ef0a367ce574aef8052c0452
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun May 26 16:14:51 2013 +0200
-
-    topoh: safety check for SIP messages
-    
-    - received callback can be executed for non-sip messages
-    - reported by Julia
-    (cherry picked from commit 352a7dccf2570af857d7e2e50fed600c4762278d)
-
-commit b5f362f4ddbc932daad611996d3e9abf2d91cd12
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu May 23 12:06:45 2013 +0200
-
-    auth: add chapter tag around sections for Admin Guide
-    
-    - the ToC isn't properly generated otherwise
-    - reported by Andrew Pogrebennyk
-    (cherry picked from commit 76c883eb88359f6075712f648a1dfc675872487a)
-
-commit 721b0adc4addad2ed2da1579af21fc9b66915ddc
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Tue May 21 12:39:15 2013 +0000
-
-    modules/auth_db: detailed documentation of URI checking in auth_check function
-
-commit 9a75da1e9a302868729b171ad76dcf15404487e5
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Fri May 17 12:34:54 2013 +0200
-
-    modules/uac: update README after avoiding adding quotes in uac_replace_* functions
-
-commit 5eced6635b0a2165c9c107fb6031901459159b2d
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Thu May 16 12:06:55 2013 +0200
-
-    modules/uac: avoid adding double quotes in uac_replace_* functions
-    
-    - updated uac doc with a note and examples.
-    (cherry picked from commit 251c0218e7d5e09f43a2b834a5450c20bb4f6d60)
-
-commit 55f7def6b4ed889a27a19164faa0dd7f854fa983
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 25 14:50:41 2013 -0400
-
-    snmpstats: fix cross-compilation
-    (cherry picked from commit 5e96920289cbf448ac684d8cb1333d75f65a729a)
-
-commit 70ab195f753956a3f891d992787a76c2c4ff643b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Apr 6 22:04:51 2013 +0200
-
-    snmpstats fix typo in Makefile.
-    (cherry picked from commit bddf66407ef7521f3d1f1e941b4c1e104e59d1ef)
-
-commit f86be5e0aa282dc58680f28d01161437901fa2c8
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Apr 6 22:02:48 2013 +0200
-
-    snmpstats Add disabled section in Makefile for compilation on Centos systems
-    
-    Net-SNMP and snmpd can be built with embedded perl and libwrap support. If that's
-    the case on your system you need to enable the EMBEDDED_PERL section in the
-    Makefile. Maybe this could be enabled automatically.
-    (cherry picked from commit 7bbf8fece2cc93c5b1ddd2c3dcc12e8a920dd54d)
-
-commit f92eee8eecab6d0fa505011b20a57dea242fa982
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Mar 20 13:16:27 2013 -0400
-
-    kamailio/utils/sercmd: remove unused but set variable
-    (cherry picked from commit 67609608aa4306de9a34a28a3a31880ad0d17e8e)
-
-commit 320bf55cbfea89b145d41c938f75a7bf70f40613
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Mar 20 13:15:08 2013 -0400
-
-    kamailio/utils/sercmd: remove unused but set variable
-    (cherry picked from commit b7a41ef47ad5d7fa90e577673cc2f38ab5ef2237)
-
-commit 24e4d3dbd79ccb2e42aabcaaa17e391dc60d36d9
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Mar 20 13:13:27 2013 -0400
-
-    kamailio/utils/sercmd: remove unused but set variable
-    (cherry picked from commit ff94115921a08ba4da29baf2761db47bd0b7f8f5)
-
-commit 5f9d169e797425b0501de42ba2af196018166c71
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Mar 20 13:23:49 2013 -0400
-
-    p_usrloc: commenting out unused db_timer_udomain() to get rid of compiler warnings
-
-commit 56b8856f84aebd86c4e78232f8f2f37fead7b4f3
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Apr 13 15:37:18 2013 -0400
-
-    tls: fix compiler warning
-     - tls_config.c:61:19: warning: ât.val.sâ is used uninitialized in this function [-Wuninitialized]
-
-commit 3a18564eb905d93b85b9e0527fa40cd85eb2e3b7
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Mar 20 13:02:16 2013 -0400
-
-    auth_diameter: remove unused but set variable
-    (cherry picked from commit 387adace552c22eaf15a049b23694bcd79cea3a8)
-
-commit 68021c3247b096fabc287fc6d129bce463cbfa97
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Mar 20 13:00:27 2013 -0400
-
-    auth_diameter: remove unused but set variable
-    (cherry picked from commit 941c48ae6909994ae090c9d52766cd4dd5d4f938)
-
-commit b654a0d650af61bd4ec7212b48d71ccf7243e473
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 16:03:50 2013 -0400
-
-    seas: fix warning [-Wunused-result]
-     - ignoring return value of write, declared with attribute warn_unused_result [-Wunused-result]
-    (cherry picked from commit e3c0a3abb6045e841fbb4b1b61a518b2b87a217d)
-
-commit d3999770dec8628a214423bcdcc510d90a39dc40
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 16:01:16 2013 -0400
-
-    seas: fix compiler warning [-Wunused-but-set-variable]
-    (cherry picked from commit c0f4b6cf664ac552d0c994e99adb13991a37ef28)
-
-commit 3141c87bc4270ca2534250500dfdefa66c79a48f
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 15:54:14 2013 -0400
-
-    seas: fix compiler warning [-Wunused-but-set-variable]
-    (cherry picked from commit 12cd241d95b8d38cea6e60676b752f8ef8a2ed8c)
-
-commit 2fe9c5d1f7b0640b1e50976f4187d7362d6a3343
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 15:51:50 2013 -0400
-
-    seas: fix compiler warning [-Wunused-but-set-variable]
-    (cherry picked from commit 21e51107a5a08b182abc7bffbac1fec1be27950b)
-
-commit 250b90ed1ec6ee34e883a4cbf6ff55865752a2d9
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 15:50:25 2013 -0400
-
-    seas: fix compiler warning:
-     - warning: variable flags set but not used [-Wunused-but-set-variable]
-    (cherry picked from commit 2abf2d4a42c05004319e682d2ad07d69bf2fc89e)
-
-commit cb971e61a573d2a024ada52b6036a1cdc56ee68e
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 15:48:03 2013 -0400
-
-    seas: fix compiler warning:
-     - warning: variable flags set but not used [-Wunused-but-set-variable]
-    (cherry picked from commit 21386829d819c06c42871cf5b68d0d3a63ef0222)
-
-commit 15ec4ac4c0e815d648bbdf0e676227b93860f290
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 15:45:50 2013 -0400
-
-    seas: fix compiler warning
-     - warning: variable flags2 set but not used [-Wunused-but-set-variable]
-    (cherry picked from commit 200eddad28abd6bc51da3285dd52d5f8c88c4e56)
-
-commit d74129f1d80a38e29b152351d1c0cf4c1faffce4
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 15:42:40 2013 -0400
-
-    seas: fix compiler warning:
-     - warning: variable falgs set but not used [-Wunused-but-set-variable]
-    (cherry picked from commit 63736be1e4d2d6e82a0f7be6a85a96ee66c10146)
-
-commit 9374ee177e5c962eee8c47a1ff30683596114c7b
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Apr 18 14:09:09 2013 -0400
-
-    dns_cache.c: fix compiler warnings
-     - warningâsr_sums[*].r_sum may be used uninitialized in this function [-Wuninitialized]
-     - warningâsr_sums[*].rr may be used uninitialized in this function [-Wuninitialized]
-    (cherry picked from commit b3c8f92fe48ac90802c989c74c3a34cfea065861)
-
-commit e7a8752ad427f8f23df25edc6bd2e7ba531ac6c4
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Fri May 3 19:53:12 2013 +0300
-
-    modules/rls: added support for escaped chars in rls-services document
-    (cherry picked from commit fa9b8664a3b7c7a035c738a37b8ef0ef44190cb8)
-
-commit 19bcbfcacbc442488e93f8c684fd815323d3fcf7
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Mon Apr 29 11:26:18 2013 -0400
-
-    db_mysql: add cast to remove compile warning
-
-===================== 2013-04-25 Version 4.0.1 Released =====================
-
-===================== Changes Since Version 4.0.0 ===========================
-
-commit d293977786ae7831f89f7b8a09d22516775778b0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Apr 25 16:50:15 2013 +0200
-
-    Makefile.defs: version set to 4.0.1
-
-commit 62188fa05724c4eafb4a5f192b070d9ffe22f5ae
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Apr 25 12:10:47 2013 +0200
-
-    pkg/rpm: updated version to 4.0.1 in rpm specs
-
-commit aed7548d393f1562824a851d656d7b2789991cc9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Apr 25 12:08:49 2013 +0200
-
-    pkg/deb: updated version to 4.0.1 in deb specs
-
-commit 4fdc69e6eb8b03c4a28c2cfea1d0ee37b26207e2
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Thu Apr 25 08:12:07 2013 +0000
-
-    sipcapture/siptrace: set default db_url to read-write URL
-    (cherry picked from commit 81f622b9ef7d32434659f1e6d9a21c8013cefec7)
-
-commit 2c290ee29696f9c0c44fcaf04b8abd91d10c04a1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Apr 25 09:55:16 2013 +0200
-
-    modules/*: README regenerated for updates to db_url and wiki
-
-commit 88a0733ed03ecd2f16aa32ba00d146d8b395a8f6
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Apr 24 17:26:15 2013 +0200
-
-    usrloc: update call-id value in db when matching record by ruid
-    (cherry picked from commit 0125cdf0e75271a8478a3eadacc54ea1c1eb4da0)
-
-commit d87b33178e432726819e2b4c73a032d67d4a1d82
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Apr 24 15:41:34 2013 +0200
-
-    usrloc: documented db_ops_ruid parameter
-    (cherry picked from commit e66842c2fc34d8dc8980efa821f7039685edef87)
-
-commit 102a1108b9e3ed9415e4b25d45542faa2643329d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Apr 24 15:34:16 2013 +0200
-
-    usrloc: option to do db update/delete ops using ruid
-    
-    - new parameter db_obs_ruid - if set to 1, db update/delete operations
-      are done using ruid value
-    - if paramter set to 0 (default) the old style using aor, contact and
-      call-id is done
-    (cherry picked from commit 61e08282c905c2ee03a2be618b1e700fc0acbdeb)
-
-commit 744a6dc1c93c8b16750f4ab25deb57a02889f1d0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Apr 24 13:36:08 2013 +0200
-
-    registrar: added debug message to print generated ruid for contact
-    
-    - formatted condition to fit 80 char long line
-    (cherry picked from commit 735f83d6346c97d6f7b1da26a2fee1b6270872b1)
-
-commit 17b858ac9b88de8859f9f1cbc76da146d8f125db
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Apr 24 10:26:49 2013 +0200
-
-    sqlops: use one char buf for empty strings in db results
-    
-    - safe for the parts of code that want to access it even for write
-    (cherry picked from commit a74980270b655124c276279e54b8f82965f3f4b8)
-
-commit 224cc7ee5c9b6349cbd9755341898a94d97fd958
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Apr 23 13:02:49 2013 +0200
-
-    usrloc: re-init sruid struct for each child
-    
-    - avoid overapping values for xmlrpc handling
-    (cherry picked from commit 20646b530baa1a2807e52048a8d99d31d2171bb6)
-
-commit 484444f4f90c725567a759252e2b3c11d53c8756
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Apr 23 11:58:17 2013 +0200
-
-    docbook: uptdated wiki link in entities file
-    (cherry picked from commit 2b97e81b281802283ebc665da6f9190f0a9705ab)
-
-commit 137bb73470ba78fc7761f7c786abcb0de5c54cc8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Apr 21 16:06:56 2013 +0200
-
-    acc: updated link to pseudo-variables cookbook
-    (cherry picked from commit f0c467f64c044de0b0f37addccb97d3ccff78706)
-
-commit 20fedafc2d10b8911b03dce9d5100f00ee5e3b9a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Apr 21 16:07:34 2013 +0200
-
-    pv: updated link to wiki site
-    (cherry picked from commit ebeb18ffed8e81ae472b4c07097b58fbea115b5b)
-
-commit 66ebdf5bc5075874b2a791c042b7221e493d72be
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Apr 18 21:22:47 2013 +0200
-
-    xlog: link to wiki updated
-    (cherry picked from commit 343379957ab783a32c48822de479a9d8c2dafdf3)
-
-commit 11f031d4570c124fbb01a01b6c7ce0757e032a84
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Apr 14 10:11:29 2013 +0200
-
-    auth: skip processing of PRACK in consume_credentials()
-    
-    - report and patch suggestions by Jorj Bauer
-    (cherry picked from commit 2a77ed2bdc9341ecf7d7200e420a1f49e4e9b6ab)
-
-commit a06c5b31f3a30c405a87bdd7be269152edf14c7b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Apr 24 22:01:59 2013 +0100
-
-    modules/presence_xml: fixed issue with parsing some pres-rules documents
-    
-    - pres-rules that contain external links in a <conditions /> node don't
-      have to have <identity /> nodes in the <conditions /> node.
-    - Kamailio returns an error when it finds a <conditions /> node with
-      no <identity /> node inside it.
-    - Kamailio doesn't support external links, but it should skip over
-      the <conditions /> nodes that contain them rather than return
-      an error as later <conditions /> nodes may contain entries it can
-      work with.
-    (cherry picked from commit ac99219b0a850e0305eaf661b028536cfc28e2cb)
-
-commit a8991ef4b63c575a32807c3aacc7a076ae22d40d
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Wed Apr 24 09:09:25 2013 +0000
-
-    core: fix default read-only DB URL
-    (cherry picked from commit fdb6c8cbafec7849367f16f5dc56ffa20885bef4)
-
-commit 9d39d8b86576ca9784b96ebb43161c3174754876
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Tue Apr 16 14:28:59 2013 +0300
-
-    modules/usrloc: init _ul_sruid also in mi_child_init
-    (cherry picked from commit 2190c572cd1bc4b57a3c2dd5241e556b834c728c)
-
-commit a49467e98dc721a1e4dbd9ba547d72aa38018883
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Apr 12 00:50:24 2013 +0200
-
-    core: safety check for content-lenght size in tcp read
-    
-    - avoid getting negative
-    - upon a report by Kevin Wojtysiak
-    (cherry picked from commit 3c54420914c011bdd874a97c4c40ee9dacb59788)
-
-commit b2b26c811a7275dbdba90236f3cfc874fd117681
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Apr 9 00:15:47 2013 +0200
-
-    rr: use port.len to check for buffer overflow instead of max port len
-    
-    - reported by Kevin Wojtysiak
-    (cherry picked from commit 28a8b87885e373bee8cc81985277ae718973fdfd)
-
-commit 95903a0f12e10e4852316eb52c8097fb8b30a308
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Apr 9 00:21:44 2013 +0200
-
-    .gitignore: added protoshoot binary the ignore list of git
-    (cherry picked from commit a177a33b9938a36cfaedbce61734a1525e5b1665)
-
-commit 31f76fc50ec838b301dede678c97676d63355b4b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Apr 9 00:18:35 2013 +0200
-
-    parser: safety check for max port length in URI
-    
-    - can't be longer than 5, a port being 16b value
-    - reported by Kevin Wojtysiak
-    (cherry picked from commit 13fd48f89555f5421e8285669e303bcefe44f149)
-
-commit 118da22f979dfa8e97a7c029ff34251ba72b6833
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Apr 5 21:30:06 2013 +0200
-
-    rr: added missing s in sips for record route
-    
-    - reported by Sander van Grieken
-    (cherry picked from commit 0ecde91fe6e911997b1f5ee33eb50fa6778b7a89)
-
-commit 1e36ce594fa1c3ae180870025d79987fbfc90878
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Mar 30 20:59:24 2013 +0100
-
-    dialog_ng: set kamailio mod interface always
-    
-    - it breaks rpc list generation otherwise
-    (cherry picked from commit 11bc294a9d64e31014ccb836290467984c28ce65)
-
-commit 1d6e63967ba8eaa5e1cf0d63081ec38439f0bcaa
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Mar 30 09:24:19 2013 +0100
-
-    core: set TOS for tcp IPv6 sockets
-    (cherry picked from commit b9476db0c1e1ce869c1da2f87dfaf411edf69277)
-
-commit 77c275383c509d34ba0300182ace889a4f1d7963
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Mar 30 09:15:00 2013 +0100
-
-    core: set TOS for IPv6 sctp sockets
-    (cherry picked from commit b57f64533dbc538f3d5282d0196598062f0b4652)
-
-commit 060c8cd03ee745aa48b21d946ebfa9e3671d89c3
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Mar 29 11:02:31 2013 +0100
-
-    usrloc: use NULL domain for updating ul attributes for use_domain=0
-    
-    - use counter var for db matching keys
-    (cherry picked from commit 50b116cf4c9c33c4f23c1d5b66fd313a7f40c572)
-
-commit e83d6d4c34fb04223f5754fff1248286e1345e7d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Mar 27 20:53:00 2013 +0100
-
-    core: set TOS for IPv6 UDP sockets
-    
-    - reported by Klaus Feichtinger, FS#179
-    (cherry picked from commit 084be456bc0fab015cf9964ac85651fa60ea77c9)
-
-commit 22b614d06590f8c9adcadf9302882fba3e8f1d1b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Mar 24 12:38:45 2013 +0100
-
-    msrp: fix compile warning of argument type in dbg message
-    
-    - reported by Olle E. Johansson
-    (cherry picked from commit 7339d847adfd098c58426e96e5e3730ad580d543)
-
-commit 5ab5edc4bba76f7a46d243fb7b9ce329b31835b6
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Mar 23 10:44:31 2013 +0100
-
-    rr: use sips to build RR headers of R-URI has sips
-    
-    - reported by Hugh James, FS#277
-    (cherry picked from commit 1826a5f4e3a981e30956da61e11ea551aae0b714)
-
-commit c7ef60e6c960c029b49bca01a89498a5dcdeec19
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Apr 13 11:26:48 2013 +0200
-
-    xcap_server: init etag variable for PUT operations
-    
-    - the function xcaps_get_db_etag() may not found a record to db and will
-      not initialize it, resulting in bogus value passed to
-      check_preconditions()
-    - reported by Juha Heinanen, FS#283
-    (cherry picked from commit 2d27dd1080cd490e93646b38d3912dcbe3761ca5)
-
-commit 5e5ba673fa4d2351047eadeaec655017c962424d
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Wed Apr 10 09:34:49 2013 -0400
-
-    db_mysql: fix segfault when recursive queries are made
-    
-    The MySQL result object (MYSQL_RES) should not be stored within the
-    srdb1 connection object, but rather within the srdb1 result object.
-    Otherwise recursive queries overwrite each other's result sets, which
-    results in segfault.
-    
-    Conflicts:
-    	modules/db_mysql/km_my_con.h
-
-commit 5ba5a0a5bb6fc5080604e1abaef6cd41148911de
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Wed Apr 10 09:33:53 2013 -0400
-
-    srdb1: add new db-private generic pointer to struct db1_res
-
-commit 3b9347e41195587c323f5d6d643c1807a9905941
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Wed Apr 10 13:55:57 2013 +0200
-
-    modules/pipelimit: check correctly for all arguments in mi_set_pipe
-    (cherry picked from commit d17b02ed5014b4e32bd0060f32cabd750956779c)
-
-commit c907eff8140bd07022aaf028741392322892b2f4
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Tue Apr 9 01:03:49 2013 +0200
-
-    modules/ndb_redis: b/f redisc_exec returns false if redis server is down.
-
-commit 0e7d000a9c73b0fd06132e458f838cc78abddbed
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Mon Apr 8 11:47:51 2013 +0200
-
-    modules/ndb_redis: b/f restore correctly last char in argument strings.
-
-commit 1d009c3dad2352784b48ec821732e4cca1078497
-Author: Jon Bonilla <jbonilla at sipwise.com>
-Date:   Sat Mar 30 11:45:12 2013 +0100
-
-    Set lucid version to 4.0.0
-
-commit 71dbcc196db780d5d8ca2960130850ace956ceca
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 29 23:35:39 2013 +0000
-
-    modules/outbound: changed some INFO level output to DBG
-    (cherry picked from commit ce0c420ba30388256e958a0bdf6d8f37138c3f97)
-
-commit eedf78559a0f289f695cdff40c581ec37c712502
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Fri Mar 29 16:30:51 2013 +0200
-
-    modules/registrar: changed instance related INFO to DBG
-    (cherry picked from commit 33108f4843fdef6d45773849089446b0c408ecf3)
-
-commit c3f2d14337093843a81353aef34c078dc7e53787
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 29 01:08:02 2013 +0000
-
-    modules/outbound: updated edge proxy example in README
-    (cherry picked from commit 60953cd884af7d070ce44844a874f2bd75833998)
-
-commit 291900478f16272222b7c9138685ef871ece0875
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Mar 27 16:51:52 2013 +0000
-
-    modules/outbound: further improvement to the use_outbound() check
-    (cherry picked from commit a5f8f4cd4da60168fd73d7999c09181582ec5943)
-
-commit 1a8843319ac00020ed291d2904b202698c3bb1c8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Mar 27 16:33:17 2013 +0000
-
-    modules/rr: copy the flow-token for "incoming" messages when using outbound
-    (cherry picked from commit 0c1725c8ccb08280a9c161e34fa9e43347cae7b0)
-
-commit 9df1edfb18f1ec0846ca474f510532050b55fc80
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Mar 27 16:32:59 2013 +0000
-
-    modules/outbound: improved check for outbound
-    (cherry picked from commit b2fb355fe5c9c64727d873cbe8d6fd883ebd2537)
-
-commit 70217018e5a72c80cee37bc5a722b769890fc64c
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Mar 27 15:43:02 2013 +0000
-
-    modules/rr: only use flow-token for routing if it doesn't point to the source of the request
-    (cherry picked from commit 874669f483e1efba032bd695eb6cee4275673874)
-
-commit 00c4469624392cb252d65ecf0e53dd64cfb9bb87
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 15 15:04:07 2013 +0000
-
-    modules/outbound: Warn during mod_init() if STUN is not built or enabled
-    
-    - STUN is required for outbound with UDP.  Don't want to stop Kamailio starting
-      when the outbound module is loaded and STUN is not available - but a warning
-      seems appropriate.
-    (cherry picked from commit 85b26219f9e4c3c8c7c990a4897d40645b4ad6e7)
-
-commit 527db661fa3f3bc3899eaf9c264c9080cc757318
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 15 14:54:41 2013 +0000
-
-    modules/outbound: free shared memory for flow-token key during shutdown
-    (cherry picked from commit 9d9d51438acd1d534f14ecbc8eb0030b45333177)
-
-commit ac9f143b3cd2422a3fb2c3ca5e29724ed65ab43d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 15 14:07:04 2013 +0000
-
-    modules/outbound: Fixed bug in outbound mod_init
-    (cherry picked from commit c924645fcfb706fc20ed715a00531d785f99cbde)
-
-commit 6acbeef9ff574c079aaeeea72924905a0426c922
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 15 12:14:31 2013 +0000
-
-    modules/outbound: The flow-token key is now automatically generated
-    
-    - Uses OpenSSL RAND_bytes() to select 20 cryptographically strong pseudo-random
-      bytes for the key.
-    - Flow-token key can no longer be manually set.
-    (cherry picked from commit f474e85616f6f98a6ac193c7425f6c85af8efa20)
-
-commit 3c6f137ab904166cff791fab98008da2f5ebdc84
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 29 01:15:13 2013 +0000
-
-    Revert "index on 4.0: 9a57697 rtpproxy: fix spelling error in docs, reported from Victor V. Kustov, coyote at bks dot tv (cherry picked from commit a0b01f77de163cf7ea9d71d5293a1bfa20d31fa6)"
-    
-    This reverts commit 368b07fc76ee2bb0c292b7be4f06c7646036b605.
-
-commit b2a5e9dce705309ec1700ae10aa45663197c81de
-Merge: 9a57697 368b07f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 29 01:11:15 2013 +0000
-
-    WIP on 4.0: 9a57697 rtpproxy: fix spelling error in docs, reported from Victor V. Kustov, coyote at bks dot tv (cherry picked from commit a0b01f77de163cf7ea9d71d5293a1bfa20d31fa6)
-
-commit 368b07fc76ee2bb0c292b7be4f06c7646036b605
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Mar 29 01:11:14 2013 +0000
-
-    index on 4.0: 9a57697 rtpproxy: fix spelling error in docs, reported from Victor V. Kustov, coyote at bks dot tv (cherry picked from commit a0b01f77de163cf7ea9d71d5293a1bfa20d31fa6)
-
-commit 9a57697e07824071cdce1b9ae65338771c7e32a2
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Tue Mar 19 15:32:25 2013 +0100
-
-    rtpproxy: fix spelling error in docs, reported from Victor V. Kustov, coyote at bks dot tv
-    (cherry picked from commit a0b01f77de163cf7ea9d71d5293a1bfa20d31fa6)
-
-commit a189e7fd3e6e4915c762dd6c429e68f3d9d6b49a
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Mar 18 15:03:24 2013 -0400
-
-    modules/sca: seize appearance for SCA callee answering w/o Call-Info
-    
-    - Yealink firmware 7.70.0.130 doesn't include a Call-Info header with
-      200 OK response to INVITE.
-
-commit 65d3fc0ac958128d99448966951de64a01f72b58
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Mar 18 10:32:45 2013 -0400
-
-    modules/sca: cast logging of time_t to long int to quiet warnings.
-    
-    - Report from Olle Johansson. Latent Y2K38 problem, but that needs a
-      project-wide solution.
-
-commit 6d61484c6302bfd2ad74b3b92621e541405c3240
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sat Mar 16 16:35:29 2013 -0400
-
-    modules/sca: fix -Waddress warnings caused by static strs in SCA_STR_EMPTY
-    
-    - Tested on Ubunut 12.04 LTS. Report from Konstantin Mosesov.
-
-commit e446aa58a89c60ef9449fc8f79492232c7ed6f7f
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Mar 16 06:33:13 2013 +0200
-
-    modules/registrar: outbound_mode=1 fix
-    
-    outbound_mode=1 now accepts REGISTER requests that either contain
-    or do not contain a Supported: outbound header.
-    
-    a Supported: outbound header is always added to 200 OK reply and if
-    request contained a Supported: outbound header, also a Require: outbound
-    header is added.
-
-commit 86f3f2755bcf63a97a8eabb8a72a06614c2dbf5a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Mar 15 09:03:26 2013 +0100
-
-    ims_icscf: fix include list for BSD
-    
-    - patch by Victor V. Kustov
-    (cherry picked from commit e930f94b71d2e5c40fa44d78738ce5efb747c5b1)
-
-
-===================== 2013-03-11 Version 4.0.0 Released =====================
-
-===================== Changes Since Version 3.3.0 ===========================
-
-commit 33e0d0ec6a370bfe580dddbb473ff4e0c1b2e746
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 11 16:00:01 2013 +0100
-
-    Makefile.defs: version set to 4.0.0
-    
-    - new major release
-
-commit 146d08078b64f3a40e01bb8dba4f4de8a50a857b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 11 15:57:31 2013 +0100
-
-    Makefile.dirs: updated the list with module directories
-    (cherry picked from commit c72aabf37beb308f99b46f764ee9c01b0d875da3)
-
-commit bd0099263cf693a2a890450d8696c6d6fd17ae00
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Mar 11 11:43:49 2013 +0100
-
-    NEWS Update with reference to Wiki
-    (cherry picked from commit 697a272672e434b017cd7e3c6782c5cefa0f2de8)
-
-commit dbfa3769a3d50607126a5ad99b4e730c8be41514
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Mar 11 11:36:54 2013 +0100
-
-    INSTALL update for release
-    (cherry picked from commit 220b782018c3158a05f695eac5b1bff0f7ad239f)
-
-commit 4f084e251742f64ac423c5d266f0ea0dc1e33926
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Mar 11 11:13:36 2013 +0100
-
-    README - last minute release fixes
-
-commit b6040e7c14a9562d58649859a407f9f1f5b3a8cc
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 11 09:38:37 2013 +0100
-
-    tm: set proper buffer len when Max-Forward header is not added
-    
-    - reported by Juha Heinanen
-    (cherry picked from commit 2d38b046b6202a35c0adf4c8b61f0d665432dd4f)
-
-commit 5111813177bce534bbfbc158e3c90cfd381c0b63
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Mar 10 22:46:50 2013 +0100
-
-    pkg: deb specs updated for v4.0.0
-    (cherry picked from commit a349d9aab2d95b9b1cbc58870ead9a7294bcdcaa)
-
-commit 080db7fd62fcf3c941fce2e1e0552a6584572c3e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Mar 10 23:53:26 2013 +0100
-
-    core: try to detect ipv6 addresses only when USE_IPV6 is used
-    
-    - reported by Juha Heinanen
-    (cherry picked from commit b035aa9f2cc19d387b1b8f33a7888ffee27a4138)
-
-commit de672e729c52f27252c78759c9b68b5ca09dfbdc
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Mar 10 22:07:11 2013 +0100
-
-    INSTALL: updates for v4.0.0
-    (cherry picked from commit b4ebc4a8164cfee995fb3ed0570702ae0547c0ce)
-
-commit 73106e703c3e2ad031f9c875a52ecf9b99750c39
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Mar 8 23:22:06 2013 +0100
-
-    ChangeLog_k: removed obsolete file
-    (cherry picked from commit ff04edd6ee7ddc213b346afffeec04a995bf16fa)
-
-commit 69c3909a8701bf47fc31105e29382ae09d383943
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Mar 8 23:20:06 2013 +0100
-
-    ChangeLog: updated content to prepare for v4.0.0
-    (cherry picked from commit 28111e7943f209ed936a6e9f1d5278d6235cedbb)
-
-commit 71101a73000e2e00c9c7ce38d1bcc3efa94e58fc
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Mar 7 02:11:35 2013 +0000
-
-    pkg/kamailio/(centos|fedora): added docbook2X build requirement
-    (cherry picked from commit dd2ef87af7dac6fb1411d58a0dd2e6125b99da80)
-    
-    Conflicts:
-    	pkg/kamailio/fedora/17/kamailio.spec
-
-commit 57664f03123de808aa21f0ddc01548db4a069048
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Mar 7 00:10:54 2013 +0000
-
-    pkg/kamailio/(centos|fedora): updated .spec in preparation for release
-
-commit 6d44534858831b00a6036d66c23b11ea2d046f04
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Mar 6 11:08:32 2013 +0000
-
-    pkg/kamailio/(centos|fedora): re-added perl files
-    (cherry picked from commit df1af285d60e2d066c2753e8f3815a7dc4f97684)
-
-
-commit 58d937f34d90a812a44435b46e3185bea8eebb7e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Mar 5 18:35:08 2013 +0100
-
-    Makefile.groups: fixed typo in the name of perl mods list
-    
-    - reported by Peter Dunkley
-    (cherry picked from commit f4a4ad8effe41a30705a49da3097818c83d3be6e)
-
-commit 7ad1c63c53c0f85c5d06830dc52d8cb96105a003
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Mar 5 17:25:18 2013 +0000
-
-    pkg/kamailio/(centos|fedora): updated .spec to match latest changes
-
-commit 4f905e5998e2517d5382ee05411463af9df028d4
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Mar 5 15:51:56 2013 +0000
-
-    pkg/kamailio/(centos|fedora): updated release tag in .spec
-
-commit 13531b47c66f87ce1a3d21f11b1a32379d264821
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Mar 5 17:11:51 2013 +0100
-
-    Makefile.groups: mi_xmlrpc has a dedicated pkg grpup depending on xmlrpc-c library
-    (cherry picked from commit 49251e62da99bf05f257e12306cafec614feb408)
-
-commit 1933eef816241d157fa980709dc2b87dfb1f21d0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 23:41:31 2013 +0100
-
-    Makefile.groups: restored outbound as packaging group
-    (cherry picked from commit 6375044137494f1203f26580e16f63c92225c596)
-
-commit 9fd2a4cb210e08f576092a6a049570c1a9d0b27f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 20:06:53 2013 +0100
-
-    Makefile.defs: version set to 4.0.0-rc1
-
-commit 3fd1ec548504b574522cc2b3a2c623366612ffb7
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 19:56:54 2013 +0100
-
-    usrloc: added missing state from AoR contact dump
-    (cherry picked from commit 068e6e5903801ca7cb7d1ca304d35bca70a34b58)
-
-commit 5591cce6007b6d770fbf7e10309caa3593798684
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 16:30:34 2013 +0100
-
-    dispatcher: release lock instead of destroy when cleaning active calls hash table
-    
-    - this could happen when dispatcher list was reloaded
-    - reported and fix by Dmitry, closes FS#275
-    (cherry picked from commit d83b9aefd5afa25b2d18a8bf92357fbd33d627bf)
-
-commit c390d7ed3bf1072ddfa8c1b3ac240359ea0a466e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 16:19:20 2013 +0100
-
-    Makefile.groups: refer to pkg groups instead of K
-    (cherry picked from commit 3cf821d9983418d68ca33edc35ff5eb2e592d16f)
-
-commit d8606ec25cc4083a9c425639f14f0bbe26768f7a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 16:14:42 2013 +0100
-
-    db_postgres: handle prepare statements in DB APIv2
-    
-    - patch by  Markus Bucher, closes FS#272
-    (cherry picked from commit 09c7b67beee9529d6a7c06e600c7f294bf453eda)
-
-commit 31219de430f48fc15bbf58cde5d6073cd5625ef5
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 16:09:36 2013 +0100
-
-    Makefile: updated the groups of modules
-    
-    - they are kept in Makefile.groups to keep main Makefile cleaner
-    - most of modules are in lists groupped mostly by dependency
-    - compilation and packaging groups are build using the lists
-    - exclude_modules list is automatically built from all modules without
-      those part of lists with external dependencies
-    (cherry picked from commit b5024f320b578c831d3ee13b077bb87954bc61b0)
-
-commit dc15e648b398ef7d8052181b822c9756bed95013
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Mar 4 10:46:01 2013 +0100
-
-    Makefile.defs: -DWITH_AS_SUPPORT is on by default
-    
-    - it was for kamailio flavour only
-    - can be disabled with WITHAS=0 and exclude_modules+=seas
-    (cherry picked from commit 01cbe8bf98d6ad1ef8cf7e0b9f646fde81831fc6)
-
-commit c40939ad2aae3dfb7d33ed8016223da9038f1ca7
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Mar 3 23:53:14 2013 +0100
-
-    Makefile: split module groups definitions in Makefile.groups
-    
-    - the part was quite big and it is more config related than build rules
-    - it has to be updated with the current list of modules
-    (cherry picked from commit 23a22e2c8d73843798d66ec1bebe22cf7702213b)
-
-commit 0d6e0778ef4d86ebd06671333f86f45fc2ec375d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Mar 1 18:12:23 2013 +0100
-
-    rtpproxy: proper fixup function for rtpproxy_manage(...)
-    
-    - second parameter was resolved as spve type, although fixed as str
-    - reported by  Markus Bucher, FS#273
-    (cherry picked from commit b23510e0adb6060a257c8662700450ed7faef080)
-
-commit e239cb78c6a16e94c8ef42530a89f1a734e89afa
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Feb 27 09:24:52 2013 +0100
-
-    Makefile.defs: version set to 4.0.0-rc0
-    
-    - branch for release series 4.0.x has been created
-
-commit 9365c5c19cb0b9d4300fa5b0a220bf19738c808f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Feb 25 11:19:15 2013 +0100
-
-    core: parser - function to proper handling multipart bodies with same content type
-    
-    - closes FS#170, based on a patch by Luis Martin
-
-commit 45b2ea3018cc84f8bcf9e687dcc0a03e81597711
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Feb 24 20:04:51 2013 +0100
-
-    siputils: completed the function to return RURI parameter value
-    
-    - closes FS#238, based on a patch by Luis Martin
-
-commit 39bffdd7db9c3118045eae9640659997bac4bf4e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Feb 24 22:17:25 2013 +0100
-
-    snmpstats add support for ws, wss and sctp transports
-
-commit 4547a28b077b5bdaf9128e98fd4e1ee9a8c11847
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Feb 24 17:53:27 2013 +0100
-
-    snmpstats Add missing SIP response codes
-    
-    And switch from Wikipedia to the IANA list as a master list.
-
-commit 7952711e6079e02a07ad027c6d8840e755c6e528
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Feb 24 10:25:38 2013 +0100
-
-    snmpstats fix typo
-
-commit 402e44861c489d4246a0fe1f57bc2cc5fe7a70c9
-Author: Marius Zbihlei <mzbihlei at mzbihlei-macbookpro.local>
-Date:   Sat Feb 23 14:58:07 2013 +0000
-
-    Added own _strnstr method as strnstr is BSD only
-    
-    This cause the tm module to not be loaded on non-BSD (i.e. Linux) system
-    Problem reported by Joel Vandal.
-
-commit 09dcd2353773b011bcce9f24886ab35a47409ff1
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Feb 22 14:45:58 2013 -0500
-
-    sca: return true if no Contact header is found in an INVITE packet
-    
-    - stop spurious log messages when receiving a 100 Trying with no Contact.
-
-commit 8fbcb1d1003b3ff3c28cf18aa6791f191a831cea
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Feb 21 22:56:37 2013 -0500
-
-    sca: log at debug level when reporting lack of Contact header
-
-commit 9cb26a2eefe93e0ca162db917e34e784e703770a
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Feb 21 22:32:23 2013 -0500
-
-    sca: ensure SCA caller has correct callee CLI when callee is non-SCA.
-    
-    - previously only set when callee was also SCA
-
-commit 86771e45a92f6262a9fee1bd698c8e9dbe3b0b70
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Feb 21 18:55:02 2013 -0500
-
-    sca: remove misleading comment.
-    
-    - suggestion in comment has long since been implemented
-
-commit 3c5b0019bbe1589410d8744545b64a278a222761
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Fri Feb 22 00:51:33 2013 +0200
-
-    app_python: Bugfix for rewrite_ruri
-    
-    *) Fixed a bug in msg_rewrite_ruri discovered by "V Tone" <vtone001 at gmail.com>.
-    *) Removed 'python exception' when do_action returns error. Reason: it is not an exception.
-    *) Removed abort() if first_line type is invalid.
-
-commit 3bae735a5e38414bd53738928ba531a329290777
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Feb 21 17:00:31 2013 -0500
-
-    sca: prevent possible NULL-dereference in log message when NOTIFY fails.
-    
-    - sub struct may be NULL outside of else block. Use non-shmem req_sub from
-      incoming SUBSCRIBE packet instead.
-
-commit 0fd954bc6a8f94ac5e8087f6b8abdba372505c6e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Feb 21 11:34:25 2013 +0100
-
-    kamailio.cfg: fixed typos to speeddial
-    
-    - patch by Thilo Bangert, FS#268
-
-commit 77f99fc7c0252c5fa71ad5939f048742592f1d43
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Feb 21 11:25:39 2013 +0100
-
-    tm: add Max-Forwards header to local requests if not given as parameter
-    
-    - add the header to local generated CANCEL and ACK
-    - based on a patch by Morten Tryfoss
-
-commit 9e6f0268097d81c0e06c7fe33599d0763ed38179
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Feb 21 10:40:07 2013 +0100
-
-    core: dns - prevent queries for IPv4/6 address literals
-    
-    - prevent A queries for IPv6 address literals or AAAA queries for IPv4
-      address literals
-    - patch by Simon Perreault
-
-commit 4439b188634deeb3c0745a7a9664de8745d9272e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Feb 20 11:29:06 2013 +0100
-
-    Makefile.defs: version set to 4.0.0-pre2
-
-commit 164b8167855415771a82715ef59a300af8c2bafa
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Feb 20 09:59:56 2013 +0000
-
-    modules/outbound: Fix core dump crash
-    
-    - Reported by oej
-
-commit 8d10bcd44834fd6f2a0c41238fd2dc197143c06e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Feb 20 09:49:44 2013 +0000
-
-    modules/outbound: Fixes the crash but is logically incorrect for outbound
-    
-    - Not sure why the crash happened at all - but this fix breaks the outbound logic
-    
-    Revert "outbound Fix core dump crash"
-    
-    This reverts commit 6369444761d44526ded2620e33438abb182d2bdc.
-
-commit 6369444761d44526ded2620e33438abb182d2bdc
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Tue Feb 19 23:08:13 2013 +0100
-
-    outbound Fix core dump crash
-    
-    When we got a CANCEL without Contact the parse_contact was sent a null
-    pointer. Changing the "or" to "and" fixed this and Kamailio no longer cores
-    on Cancel coming on over websockets from jssip.
-    
-    Tested at SIPit 30. Core dumps and backtraces available.
-    Pdunkley - please check this patch
-
-commit 8524f32bc07bd121326369f432eb29a257856f41
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Feb 18 22:36:45 2013 +0100
-
-    maxfwd The default value is not 256, it's 16 in the source code.
-
-commit 3f05697f6503f682274fce7bd93eeeaaa9b58188
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Mon Feb 18 09:48:22 2013 +0200
-
-    dialog_ng: changed LM_ERR to LM_DBG in dlg_hash.c
-    
-     - dlg_set_leg_info() line 416 was incorrectly logged as ERR when it should be only DBG
-
-commit 2e58de7e16203c849cf1c445dfb33d304ffd3507
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Feb 15 21:13:29 2013 -0500
-
-    rtpproxy: when adding ICE relay candidates, always include RTCP candidate
-
-commit 05d02fd85b12f8e529f088e28cd1923351631e31
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Feb 15 20:12:56 2013 -0500
-
-    sdp: fix TABS and whitespaces
-
-commit b6e2a5c152de3f13251bca6a4f52f8bc9f725018
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Feb 15 12:08:20 2013 -0500
-
-    xhttp_rpc: cosmetic updates to header's web page
-
-commit c3db1a1b598416d1380d54e1a21e9991070a075b
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Feb 15 11:27:15 2013 -0500
-
-    xhttp_pi: fix default value for xhttp_pi_root param
-
-commit 8066d290b69a472fc46df248ae861487c932f738
-Author: Ovidiu Sas <osas at ubuntu.(none)>
-Date:   Tue Feb 12 15:13:05 2013 -0500
-
-    xhttp_pi: remove unused variable
-
-commit 36d0763385605c8174a538297dd8dfa94092e9c5
-Author: Ovidiu Sas <osas at ubuntu.(none)>
-Date:   Tue Feb 12 14:38:53 2013 -0500
-
-    xhttp_pi: remove unused variable
-
-commit 0a56f3b4c08236265dc66965e61d1a36a7594b36
-Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
-Date:   Tue Feb 12 10:44:46 2013 +0100
-
-    modules:sipcapture fixed LM_ERR. Sorry :-(
-
-commit 1690eafbb599842f0507ad41c1590fcbba8c7630
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Feb 11 23:40:53 2013 +0100
-
-    msrp: return proper value for $msrp(code)
-    
-    - internally there is an offset of 10000 to the value in the msrp reply
-    - reported by Peter Dunkley
-
-commit ae0183fe5af84ce986baa36b0e6a33f4e06f6803
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Sat Feb 9 16:39:49 2013 +0200
-
-    app_python: fixed compilation errors and warnings.
-
-commit f38eaeda810730a10a0b67ee42ae629642cdebc2
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 22:13:17 2013 +0100
-
-    imc README updates. Configuration files works with 4.0.0 now.
-
-commit a0c0b57d0bcede9144b8ddf71556f4bdb58baebd
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 21:58:50 2013 +0100
-
-    db_text change "openser" and minor edits
-
-commit d4f64eb262f73e316772955afc4153b84ba74954
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 21:41:11 2013 +0100
-
-    maxfwd Update README, fix typos
-
-commit 88b25387f5ddd83a6cb211a4e650191d268fd893
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 21:33:37 2013 +0100
-
-    mangler Update README for readability
-
-commit 022935946d2b66ab74d2fb3c4601b340cd57fe34
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 21:32:39 2013 +0100
-
-    ldap Add the README
-
-commit 28ee292ca10a8fc8428ac8cff763dbf57ed19db3
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 21:21:02 2013 +0100
-
-    ldap Convert an "a" to an "o"
-
-commit 3ce0e28280d4b7a5f4b991af861455114b829976
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 21:12:52 2013 +0100
-
-    kex Fix copy/paste typos and minor edits for readability
-
-commit a9ca3f4a05d0655b11ba90bc64d68b53c4ba039c
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 21:03:07 2013 +0100
-
-    ipops Minor updates to README
-
-commit 63653d7d18a7124ff3a33991f3db4cd8271a9e24
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Feb 8 20:56:06 2013 +0100
-
-    mi_fifo Typo fixes mostly
-
-commit beb5537e70bc36f459223633109d31306ae600f8
-Merge: e4ffcaf 80e8407
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Feb 7 22:05:42 2013 +0100
-
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    Arrrggh. My mistake.
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      registrar: Fixed typo in event_route name, 'usrloc:expired-contact'
-
-commit e4ffcaf671c93222a5aed846cf89fefaf72b2b4a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Feb 7 22:05:05 2013 +0100
-
-    outbound - Fix typos in example configuration
-
-commit 80e8407dedb06d386167924a40fbf47119708336
-Author: Giacomo Vacca <giacomo.vacca at truphone.com>
-Date:   Tue Feb 5 17:16:18 2013 +0000
-
-    registrar: Fixed typo in event_route name, 'usrloc:expired-contact'
-    
-    - (Instead of changing all the related documentation that refers to usrloc:contact-expired)
-
-commit 1c643eb26a25880669a719a29c1c8e984e32983d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Feb 7 11:04:00 2013 +0100
-
-    siptrace Fix bug in documentation
-    
-    The default database URL was mysql, not "", which caused me some strange issues.
-
-commit fcbf4a0329adab01b079d72408582c2b5d4390e6
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Feb 7 10:39:17 2013 +0100
-
-    sipcapture - update example configuration
-
-commit 7f5b6c26d4bf1f50b1890d177121f4c4fd65428c
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Feb 6 23:39:27 2013 -0500
-
-    xhttp_pi: documentation updates
-
-commit 0c970537a2d2aa66d24650e07efb587acd9edfc0
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Feb 6 23:37:53 2013 -0500
-
-    xhttp_rpc: documentation updates
-
-commit ce5aa2416d93d3626db8d69651530edf4575a569
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Wed Feb 6 18:05:05 2013 -0500
-
-    Revert "nathelper: add new option sipping_disable_bflag"
-    
-    This reverts commit dc9a06f7b33a758cb3a44fbc1d018e1a81a794a5.
-
-commit 23b84739a72c5cca1fd397fbe1a7468a621cc2e6
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Feb 6 23:08:02 2013 +0100
-
-    msilo: safety check for freeing tmp_extra_headers
-    
-    - it can be a static empty buffer
-    - reported by Stoyan Mihaylov
-
-commit 1d6b2ce07c6b661ed3e3a1c31b8ec408d68ed4e9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Feb 6 20:42:50 2013 +0100
-
-    xhttp_rpc Fix typo and minor formatting in README
-
-commit dc9a06f7b33a758cb3a44fbc1d018e1a81a794a5
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Wed Feb 6 11:38:57 2013 -0500
-
-    nathelper: add new option sipping_disable_bflag
-    
-    sipping_disable_bflag can be set on a per-registration basis
-    to disable NAT pings completely
-
-commit da298e85166b873f4825e4baa96db0d317771e20
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Feb 6 12:55:55 2013 +0000
-
-    modules/msrp: Fixed typos in MSRP README and added extra event_route example
-
-commit f56e82a286e00a17dbf02e9a5056ef73488b89b1
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Feb 6 12:36:52 2013 +0000
-
-    modules/msrp: Fixed error in msrp_cmap_lookup()
-
-commit 1e16eb9c892358a972ae71f05ec138fbe0d23126
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Feb 6 11:21:11 2013 +0200
-
-    modules/lcr: treat lcr_gw/ip_addr empty string value same as null value
-
-commit 62cd05a469f657b5371ecd1538f9c9b224f7e589
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Feb 5 10:06:47 2013 -0500
-
-    xhttp_pi: documentation updates
-
-commit af7d4496febf95e56b604849a8f818e688b21f53
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Feb 4 10:59:10 2013 -0500
-
-    lib/srdb1: while converting strings to int/bigint check for invalid characters
-
-commit 47276cf597ab941016fd49dbcfaaab3da8802834
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Feb 3 23:36:26 2013 -0500
-
-    ims_icscf: getting rid of "defined but not used" compiler warning
-
-commit d474abbb3d93c992ccff561909402ca1b52297bd
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Feb 3 10:50:47 2013 -0500
-
-    ims_usrloc_pcscf: remove unused variables
-
-commit 7d6d016c7556a3241d47801b0480c022ca2dd3c8
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Feb 3 10:31:55 2013 -0500
-
-    ims_usrloc_scscf: remove unused variables
-
-commit 622b01719bb8a95c5995c8412cd040787f0cd0a6
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Feb 1 19:45:28 2013 -0500
-
-    xhttp_pi: new commands in the pi_framework_sample:
-     - add
-     - update
-     - delete
-
-commit 60e60e26cebeea2d8e07ec4ffd036ab1f35e2f12
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Feb 1 11:45:32 2013 -0500
-
-    sca: restore correct table version number in db creation files.
-    
-    - Had been reverted by commit f636e215089a9b14daa113d93025831e827192b5
-      because the schema xml file had the wrong version number.
-
-commit 36c7b450889a8005af3f14b0edb55f4ede6f98a1
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Feb 1 10:14:26 2013 +0000
-
-    modules/websocket: moved example WebSocket configuration file to examples directory
-
-commit cdd23170e8fd6da4817619ee82ded0fa27936081
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jan 30 15:17:28 2013 -0500
-
-    sca: db table version incremented to 1
-    
-    - should have been part of commit adding record_route to table.
-
-commit 2eeb686ea57ce569d3c5eb05430c78d0fdbdd4eb
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 30 13:26:35 2013 +0100
-
-    tls Small modificiation in tls configuration example
-
-commit 147430e2f5849996fcfff4933795ef212fdfb83a
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Wed Jan 30 12:17:50 2013 +0100
-
-    Fix: We trust the IP in the media for calls from the network to the user
-    Fix: Rx-Configuration updates
-
-commit 50a041f5c04ef79d8812d5871903931b120c0812
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Wed Jan 30 11:55:42 2013 +0100
-
-    Fix linking for the IMS-QOS module
-
-commit 6729c79d7fe3778a889ef7e6777c0bbe2e011528
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Jan 15 11:17:45 2013 +0100
-
-    Cleanup of example I-CSCF config.
-
-commit ef63f7cd1a6966e3309d8f83e88a7e62b41bd4ed
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jan 28 16:54:44 2013 +0100
-
-    kamailio.cfg: use route(RELAY) instead of t_relay()
-    
-    - coherent exit from config when sending out
-
-commit a21750ff6fcf87d8e3f54597bdd3f1171846e6cb
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jan 28 13:08:02 2013 +0100
-
-    modules/sqlops: Check if pv_spec is available before trying to use it.
-    
-    Instead of segfaulting when the script writer has not specified enough PV
-    specs to hold all the query's result columns, bail out with an error message.
-
-commit ebe16f75b38c76dab141ca9583b10b67e4f45f57
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jan 28 13:06:08 2013 +0100
-
-    lib/srdb1: Fix compilation warning on 32-bit architectures
-    
-    On "bits-challenged" architectures, long != 64 bits.
-    Use long long instead, seems to work on 64-bit archs too.
-
-commit a0968999375227bf187bca374e544e359a9c4c5f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Jan 27 19:55:49 2013 +0100
-
-    tls README: Change "ser" and "sip-router" to "kamailio"
-
-commit e59acd4d006e5048610e75f2cfc2df30b2f7c968
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Jan 27 14:33:13 2013 +0100
-
-    tls Update README with RPC commands
-    
-    The selects are still missing.
-
-commit 6b212dc881dae76ab872c79e39f96b21ee4e6687
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Jan 26 21:10:03 2013 +0100
-
-    tls Update of README
-
-commit 78f0c33c3793a7c586860c65ed84e8442808d580
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Jan 26 17:56:51 2013 +0100
-
-    dispatcher - Fix typo in README and add return value information for ds_select_dst
-    
-    The return value was used in the example, but not documented.
-
-commit bc507d28e1168313772142925721b32e1a7b634a
-Author: Philippe Sultan <philippe.sultan at gmail.com>
-Date:   Fri Jan 25 20:59:23 2013 +0100
-
-    kamctl: added command for management of uid_domain records
-
-commit 9cb173699b25bc420ff5938214b3df81ed18a4ba
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jan 25 17:30:42 2013 +0100
-
-    core: made a wrapper forward_reply_nocb()
-    
-    - it forwards a reply without calling the callbacks from modules for sip
-      response handling
-    - fixes the issue of sl_forward_reply() looping when used in TM onreply
-      routes
-
-commit 0636b8a70109ee44b46ec0cc76d4513c87c18e3f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jan 25 17:29:46 2013 +0100
-
-    sl: use forward_reply_nocb() for sl_forward_reply()
-    
-    - otherwise it gets to looping if the function is used from TM onreply
-      routes
-
-commit d2d6b4b932c7df6e6620a256692be5ef049356a3
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jan 25 11:38:38 2013 +0100
-
-    core: end simple pv name (e.g., $xy) at end of line
-    
-    - cfg parser was throwing error if last token in a line was $xy as pv
-      with \n was not found
-
-commit c3987b2ef44c26b781d9b026d86370184e2a4ae3
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Thu Jan 24 13:45:18 2013 +0200
-
-    db_cassandra: Replaced 'openser' with 'kamailio'
-
-commit 139ae7966a0ff8e5e46a902d9e14dc8840934bd0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jan 24 11:45:31 2013 +0100
-
-    core: default compatibility set to SR_COMPAT_MAX
-    
-    - means that $xy is tried first as pv and if not, then is considered avp
-      (was default compat mode for default flavour in the past)
-    - you can still use:
-        - #!KAMAILIO in config to force SR_COMPAT_KAMAILIO (i.e., $xy must
-    	  be a pv, otherwise is error)
-        - #!SER is config to force SR_COMPAT_SER (i.e., $xy is avp/attr)
-
-commit 216029a609630a7d18ce3b77d3d9ae95f45d662c
-Merge: 2d129b5 f1b5145
-Author: Matthew Williams <mgwilliams at gmail.com>
-Date:   Wed Jan 23 11:27:54 2013 -0800
-
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-
-commit 2d129b5538b64acea788b502dcf97c5ffffdf949
-Author: Matthew Williams <mgwilliams at gmail.com>
-Date:   Wed Jan 23 10:49:52 2013 -0800
-
-    correct url to libjson in json and jsonrpc-c module docs
-
-commit f1b514596856889fa2a8e4b164178998177d7b59
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Jan 23 13:42:52 2013 +0000
-
-    pkg/kamailio/(centos|fedora): Removed old FC16 build
-    
-    - Fedora 18 is now out and I only plan to keep this .spec correct
-      for CentOS and Fedora working for current and previous OS releases.
-
-commit cb56b67788fc61f8de65d0335c6364c7aba15759
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 23 12:55:51 2013 +0100
-
-    lib/srdb1: update custom sql functions for uid tables
-
-commit 9a1d64bddbf3ec931d39a0e47370e8d46ec2aeb9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 23 12:49:16 2013 +0100
-
-    kamctl: added option to grant sql access from a remote host
-    
-    - set DBACCESSHOST in kamctlrc
-
-commit 1fd2b4ec865cbe738d92e72259fed27380d252ab
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 23 00:45:17 2013 +0100
-
-    kamctl: added option to creat uid-related tables
-    
-    - few more options to be able to create database only, grant or revoke
-      privileges from command line
-    - the extensions were added for mysql
-
-commit 71d1f9b233559e12970019819323cdfb9427b836
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jan 22 23:09:47 2013 +0100
-
-    kamctl: cleaned db creation
-
-commit 15e1ae6720136a698326a0b53f6db8eef73e3e5a
-Author: Richard Brady <rnbrady at gmail.com>
-Date:   Tue Jan 22 17:19:31 2013 +0100
-
-    json: proper handling of empty values for json documents
-
-commit 3e580e1ee24f9b9ec4b1fa151b23ebc84f3db1cb
-Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
-Date:   Tue Jan 22 15:45:38 2013 +0100
-
-    modules:sipcapture  Added PSQL schema, fixed columns length, fixed id column for PostgreSQL
-    
-    	Thanks Ovind Kolbu for schema and patch
-
-commit f76bd09d4800ea63552c11002d7f6f72569e78ed
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jan 22 13:40:11 2013 +0100
-
-    pua_reginfo: fix setting lengths of contact attributes
-    
-    - fix also for warning from FS#255 reported by Ovidiu Sas
-
-commit ff22a1cbc2b817d63611b3da967d8245e11cb84c
-Author: Richard Brady <rnbrady at gmail.com>
-Date:   Tue Jan 22 12:19:53 2013 +0100
-
-    siputils: fix decode2format fuction to handle ; in userpart
-
-commit 58417e5f23c50a1892584d368e49373c579af31e
-Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
-Date:   Tue Jan 22 11:41:43 2013 +0100
-
-    modules:sipcapture Changed authorization column to "auth". Now PostgreSQL should be happy.
-    
-    for old schema please use:
-    
-    modparam("sipcapture", "authorization_column", "authorization")
-
-commit c579bce3e6fa4efc29cf4fd8681f471a768a8e7c
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Jan 21 15:10:39 2013 -0500
-
-    kamdbctl: fix presence tables provisioning
-
-commit da007aaf6a2296c62189d30c6991e5cdb9f8a4ec
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Mon Jan 21 19:40:19 2013 +0200
-
-    app_python: reverted changes (dlflags)
-
-commit 36013e021dde6362bb335bbcadd41b6838151a45
-Merge: f50e910 288c597
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 20 20:13:40 2013 +0000
-
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-
-commit f50e910b9710fd1055aae7e445a0504b841413a3
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 20 20:04:45 2013 +0000
-
-    pkg/kamailio/fedora: added build files for Fedora 18
-
-commit 288c597bfba2ffba4c49e691488cee574d714a97
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Jan 20 16:58:59 2013 +0100
-
-    README remove "modules_k"
-
-commit 41fab9cb21af174734ef820da4bbf6d19d34d56a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Jan 20 16:55:23 2013 +0100
-
-    README-MODULES - merge listing of modules into one combined
-    
-    Thanks to Daniel for merging the directories.
-
-commit 4cc713182c4f5b53a00a8d2d6d3a21afca589b77
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Sun Jan 20 17:38:06 2013 +0200
-
-    app_python:
-        - fixed runtime warning: exports dlflags interface is deprecated and it will not be supported in newer versions; consider using mod_register() instead
-        - python routines can be called in any routes.
-
-commit 1d29c95e982244a5140f93c8ae886c8d457d8e24
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 20 15:07:59 2013 +0000
-
-    pkg/kamailio/(centos|fedora): updated kamailio.spec
-
-commit d934a2acd31408ae6afdf31007f2ebe4527d1f3d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 20 14:23:17 2013 +0000
-
-    modules/db_postgres: Fixes
-    
-    - Fixed submit_query() retry mechanism - connection errors now detected and retried.
-    - Fixed memory leak when raw queries contain > 1 SQL command.
-    - Fixes by Hugh Waite @ Crocodile RCS
-
-commit c059041a71a1b7175243c366316108ce370fffa7
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 20 14:18:55 2013 +0000
-
-    core: fixed bug in PV caching that broke the use of the $$ symbol
-    
-    - Found and fixed by Hugh Waite @ Crocodile RCS
-
-commit 9a3b3229e0b0f39489feca8da3c0a7aeeaae600e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 14:28:57 2013 +0100
-
-    Makefile.defs: version set to 4.0.0-pre1
-
-commit fedd38e03f6fcc4851d738cf2bd274b5290ae1ae
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 14:19:11 2013 +0100
-
-    Makefile: updated the names for perl modules
-
-commit e5e821150f53135e8c288f71ddd95c6c23e8d8d9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 14:18:02 2013 +0100
-
-    perlvdb: module renamed to db_perlvdb
-    
-    - it is a database driver module
-
-commit 63a09d8562a1ac3679dc34c409a37f1d6617e430
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 13:26:01 2013 +0100
-
-    modules/*: updated include paths
-
-commit 1abe29004193a348a1dcca72665fef1d390610b0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 12:57:52 2013 +0100
-
-    modules_k/*: moved k modules in directory modules/
-
-commit dbe58f4cff868f069bc417b3002c7ac75ce484a1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 12:51:29 2013 +0100
-
-    modules_k/: added placeholder for an empty directory
-
-commit ba3fa594f3ade8f8afd69606f92d1e4fa4685ede
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 12:47:08 2013 +0100
-
-    app_perl: perl module moved and renamed to modules/app_perl
-    
-    - same naming pattern as for the other embedded interpreters
-
-commit 0533e3f86bb605d4ce68ae60b80013dcf8540903
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 12:14:41 2013 +0100
-
-    perl: samples and documentation updated to use package Kamailio
-
-commit e3f78196b345ab22eaba8f4ade7492e660782485
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 11:59:00 2013 +0100
-
-    perl: xs file updated to use Kamailio instead of OpenSER
-
-commit 1be653e243b02094a93ef20509fc98326f160284
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 11:53:36 2013 +0100
-
-    perl: Perl packages renamed from OpenSER::* to Kamailio::*
-    
-    - part of patch from Stoyan Mihaylov
-
-commit f448282ec6775857f4bef733f4785dd571bfe081
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 11:47:48 2013 +0100
-
-    perl: renaming openser to kamailio in C source files
-
-commit 9d5cc7085e916bf348ba52828d5c9519652c61ae
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 20 11:34:20 2013 +0100
-
-    perl: renamed files and directory from openser to kamailio
-    
-    - part of patch from Stoyan Mihaylov
-
-commit 4e939748186c6dcff6744d36439b9620fe41a196
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Jan 19 22:33:18 2013 +0100
-
-    iptrtpproxy Documentation cleanup
-    
-    And a missing file from sanity module
-
-commit 80dc9107c5cd47cab24786a12d2612c25f714ff3
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Jan 19 20:07:08 2013 +0100
-
-    sanity Sanitize XML file names and formats
-
-commit 396de50105c29c102da1afb9fabe8ea1324a7282
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Jan 19 19:57:50 2013 +0100
-
-    xmlops Updating xml formats
-
-commit 67a0aafe4933d6ccbc04e6a86a21c34f62bae7fb
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Fri Jan 18 10:21:50 2013 -0500
-
-    tmrec: fix example given in docs
-
-commit 3cec800fb8e48b6f2dbc880c5a991e9d636c9f5c
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Fri Jan 18 14:33:53 2013 +0200
-
-    modules_k/statistics: fixed bug when using pvar as stat value (fixup function was broken)
-
-commit a865b622be84ddc1dacff35401adbb6937ec86b3
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Jan 18 13:32:55 2013 +0100
-
-    README - converted to Kamailio
-
-commit 5b6231d2d85f2a5a07b09e7e534f25e16f5e43b2
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Jan 18 09:41:42 2013 +0100
-
-    Update to current module set for 4.0
-
-commit ebde66ba5f97ff5587e36b8e952b19a1becd08ab
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jan 17 19:19:37 2013 -0500
-
-    carrierroute: fix cross-compilation
-
-commit 83eafc8d8f767f4705d5f76ad0ffd4349a06c927
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 16 22:37:08 2013 +0100
-
-    dialog: fix for is_in_profile()
-    
-    - function was broken, reported by Klaus Darilion
-
-commit ac2a3acddef3d5dd3a8033859f8a245624944d8e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 16 22:28:30 2013 +0100
-
-    Revert "First commit (raw code) of new module: app_java (Java Native Interface support for Kamailio)."
-    
-    This reverts commit 3cc85a3915ed69471966cf741d7cf2adee4f3b0b.
-    
-    - code in master is frozen for v4.0.0
-
-commit ebaab480a74fdde6036b471ec1175c4ad294c758
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 16 22:27:34 2013 +0100
-
-    Revert "app_java:"
-    
-    This reverts commit db74e5230a26fdfebbf88f9575ea8a7636719743.
-    
-    - code is master is fronzen for v4.0.0
-
-commit db74e5230a26fdfebbf88f9575ea8a7636719743
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Wed Jan 16 21:08:42 2013 +0200
-
-    app_java:
-        - code cleanup
-        - changed all *alloc to pkg_*alloc
-        - added examples module configuration file
-
-commit 3cc85a3915ed69471966cf741d7cf2adee4f3b0b
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Wed Jan 16 20:43:29 2013 +0200
-
-    First commit (raw code) of new module: app_java (Java Native Interface support for Kamailio).
-
-commit 588a1a4280840e40beaae77345533b40ef1c710d
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Jan 16 11:38:18 2013 -0500
-
-    xhttp_pi: adding note about using the provisioning interface with db_text
-
-commit c065b24620a9475a70a19de95231a814076eefae
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Jan 16 10:48:25 2013 -0500
-
-    xhttp_pi: more documentation updates
-
-commit 0f59c52cb1d21d07654f815af3636330dc02e164
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Jan 16 10:37:30 2013 -0500
-
-    xhttp_pi: documentation updates
-     - reported by Philippe Sultan <philippe.sultan at gmail.com>
-
-commit 32e73f99a3bab4bc673504d316831f0a8ff1f48c
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Tue Jan 15 09:46:22 2013 +0100
-
-    Starting to prepare README/INSTALL files for release
-
-commit 241681f6a2bc9d9647251963eee5f65386717edb
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Jan 15 09:03:25 2013 +0100
-
-    b/f: If no parameter is given, the "fixup_lir" method will never get called...
-
-commit 7f7e0d046cbaf59170605c21070eb476a28fbc18
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Jan 15 08:18:52 2013 +0100
-
-    b/f: Need to link librt (on OS non-Darwin)
-
-commit 04b1b6c94a69da8b4bf5134d890edfaf0c0ad153
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Mon Jan 14 19:28:27 2013 +0100
-
-    b/f: Modify IMS-Group Modulenames to reflect module-name changes.
-
-commit b87c9b03499e58d481cf6fe02302a378051272a0
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Mon Jan 14 17:46:08 2013 +0100
-
-    b/f: Do not remove lib*, only "real" libs
-
-commit b926764c5cfb6737407b2090a6c5659b46373237
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Jan 12 13:10:18 2013 +0100
-
-    registrar: fix event route execution warning
-
-commit a797eab732be6b17e3727ee604d21fcaddd5b35e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Jan 12 08:45:11 2013 +0100
-
-    xmlrpc Modify doc structure to kamailio-like
-
-commit 9bfc37fcc95da2d0b970efb6a3333e6d8e5f5bde
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Jan 12 08:33:25 2013 +0100
-
-    usrloc(k) Fix compiler warnings
-    
-    Thanks to juha for the reminder
-
-commit 4af97738081da634643f0fdfd681e7a94740a6d0
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 19:14:15 2013 -0500
-
-    xhttp_pi: make sure that cfg directory exists during install
-
-commit 11cedccfbc11c9efde566ecd2afb883246c64ba7
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 15:59:31 2013 -0500
-
-    lib/ims: fix cross compilation
-
-commit 35ba820e82840661d23c93e10bd289b8a6e14f5f
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 15:20:11 2013 -0500
-
-    sqlops: remove unused variable `sv'
-
-commit c8878c0c702173d44dd4d9fad263ea8e329e6897
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 15:13:16 2013 -0500
-
-    permissions: remove unused variable `count'
-
-commit 35d8fd13382fc5fa6256f17a0f43c396be7c638d
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 14:13:53 2013 -0500
-
-    outbound: fix cross-compilation
-
-commit 7bf23bc79b3ace2348c94bf284aac13dd917c3ab
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 14:13:36 2013 -0500
-
-    osp: fix cross-compilation
-
-commit d18997cd35d3ac03f446a61a7f198eb1b0704bd0
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 14:13:07 2013 -0500
-
-    websocket: fix cross-compilation
-
-commit c16ae05d5b91984a9d17ce6b643f29cf7b92cd75
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 14:12:49 2013 -0500
-
-    tls: fix ssl cross-compilation
-
-commit c9d8a66071efb77428ae74572d453c5b4ded4764
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 11 14:12:10 2013 -0500
-
-    auth_identity: fix ssl cross-compilation
-
-commit f350ec8cd45819ed6f60947bca2ac6e747f86541
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Fri Jan 11 14:22:57 2013 +0100
-
-    modules_k/uac: document RR append_fromtag requirement in auto mode
-
-commit 37c43f695fae346fde83690596150a84192ad0db
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jan 11 10:54:00 2013 +0000
-
-    pkg/kamailio/(centos|fedora): updated release tag in .spec
-
-commit 5a78a8b8ec104550a37d8e2ae9005bf87d21e00f
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Fri Jan 11 11:07:45 2013 +0200
-
-    dialog: fix bug when detect_spirals enabled
-    
-    If detect_spirals enabled and the caller sent an Invite which received a
-    negative response and then immediately sent another Invite with the
-    same callid and tag, the module did not create a dialog record for the
-    second Invite. It wrongly concluded that the Invite is spiraled. This
-    resulted in missing CDR for that call.
-    Behavior observed if the first Invite has a small Session-Timer interval
-    and receives a 422 reply. When the phone sent the second Invite with a
-    larger Session-Timer, which could have been successful, it was not recorded
-    by the dialog module.
-
-commit a1a197aa27a62426599d908870c60749e9941a03
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Fri Jan 11 10:47:44 2013 +0200
-
-    modules/ims_qos: update to correct binding name for ims_usrloc_pcscf
-
-commit b414cb1d7dc92e24ea98e5624060f9ba25726602
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jan 11 09:32:12 2013 +0100
-
-    Makefile.defs: version set to 4.0.0-pre0
-    
-    - marking pre-release phase
-
-commit 622640b85cbf681055c1a9c28d3f3ab61c13b36e
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jan 10 16:53:12 2013 -0500
-
-    ims_registrar_scscf: fix cross-compilation
-
-commit 2c70b76e122d061b62058623e85e42872cd003ac
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jan 10 16:43:29 2013 -0500
-
-    ims_registrar_pcscf: fic cross-compilation
-
-commit 7b483c4cd97d61c8eefc484d31ffb3ba43d03ca5
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jan 10 16:43:05 2013 -0500
-
-    ims_isc: fix cross-compilation
-
-commit f1e6a00c93f18871c5c069a08aac77fe783fd6cd
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jan 10 16:42:34 2013 -0500
-
-    ims_icscf: fic cross-compilation
-
-commit 5799a797c7e4d0e84aca20618ef61dbf1a33692c
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jan 10 16:42:08 2013 -0500
-
-    ims_auth: fix cross-compilation
-
-commit 52a773fb8bcd9a07f12dcb0de9bff8744ab386d3
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Thu Jan 10 22:45:09 2013 +0100
-
-    kamailio.cfg: describe log levels
-
-commit 6d34982c99060436bc9a3a07058eb805488fc34d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Jan 10 21:45:09 2013 +0100
-
-    mtree	Add RPC command mtree.summary
-
-commit 52331c6ba80f2eb862405e7987ab21d6f55549e0
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Jan 10 20:10:49 2013 +0100
-
-    mtree Bug fix - save number of nodes in mtree data structure at load
-    
-    Otherwise MI function doesn't report anything but zero nodes and memory
-
-commit 222166ef3a20c0c4a98a3c810112901c71ef275d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jan 10 19:01:47 2013 +0000
-
-    modules/rtpproxy: allowing rtpproxy_manage to take the flags parameter as a pseudo-variable
-    
-    - Feature added by Hugh Waite @ Crocodile RCS
-
-commit ef2b3a6ee84f75bd49a06635a486807eeaebc08a
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Jan 10 12:50:06 2013 -0500
-
-    kamdbctl: new command - kamdbctl pframework create
-     - creates a provisioning framework for the installed db tables
-
-commit 2793567c9f4f31e2d58e23faa092750f0d71a0c1
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Sep 29 18:47:46 2011 +0200
-
-    modules_k/cfgutils: add locking around gflags
-    
-    gflags are stored in shared memory and must thus be protected against
-    concurrent access.
-    
-    Reads from an int are atomic on most (all?) real world hardware, so only
-    modification of the flags is placed under the protection of the lock, not
-    reads.
-
-commit 6f0f560ec9bf67d93e18f932f572aa8b526ac955
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jan 10 16:00:46 2013 +0000
-
-    pkg/kamailio/(centos|fedora): updated .spec
-
-commit 3b575a618545dcd65362ea6de972222703d824d9
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Thu Jan 10 16:28:07 2013 +0200
-
-    modules/ims_qos: Added documentation
-    
-    Added admin documentation and README for ims_qos module
-
-commit e7b5f667a4b094c1aa1c426fe33648db782f9190
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Thu Jan 10 16:08:54 2013 +0200
-
-    modules/ims_usrloc_pcscf: Updated documentation
-    
-    Updated documentation and added README for ims_usrloc_pcscf module
-
-commit 743c1f7f9645ce760f5f1892fbee187f96c8513a
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Thu Jan 10 15:50:01 2013 +0200
-
-    modules/ims_auth:  Updated documentation
-    
-    Updated documentation and added README for ims_auth modules
-
-commit 0b476ea4981b750e3f5974f5fd1e3b8fb39ed8fa
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Thu Jan 10 15:40:00 2013 +0200
-
-    modules/ims_icscf: documentation updated
-    
-    Documentation for IMS ICSCF modules updated and README added
-
-commit 06fb17e57e871e99eb251e3243f70652e92a013d
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Thu Jan 10 15:25:56 2013 +0200
-
-    modules/ims_qos: Added IMS QoS module
-    	- This module provides Diameter Rx IMS interface between PCSCF and PCRF
-    	  functions
-
-commit cbf2cb0c1d0301d63154834fbd9220e334b9c64c
-Author: Jason Penton <jaybeepee at jaybeepee-laptop.(none)>
-Date:   Thu Jan 10 14:33:54 2013 +0200
-
-    parser/sdp: fast-access pointer for raw SDP stream string
-    	- basically a pointer to the raw SDP stream
-
-commit f0cb7735b766e14ba142a45064e254d82d079746
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Thu Jan 10 14:29:38 2013 +0200
-
-    modules/ims_isc: documentation added
-    
-    Added documentation including README for ims_isc module
-
-commit 8fb8b261fa76e5c3497b602f6b850fe02e5db48f
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Jan 8 19:09:48 2013 +0100
-
-    core: make database version table name configurable from script
-    
-    When kamailio is part of a bigger project and is sharing its database with
-    it, it is nice to have a less generic table name than "version".
-    
-    Also usefull when upgrading kamailio, where the new version has (backwards
-    compatibel) changes in the database definition. If each kamailio version uses
-    its own version table, they can all use the same database.
-
-commit 89a9db548f01eea54eb11ae57b76abcfb5e5c5f6
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Nov 5 13:33:27 2012 +0100
-
-    modules_k/kex: call pkg_proc_stats_destroy in module destroy function to free memory
-
-commit 2628e120432001c118eb89ac1b7023a9f5e795ad
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Oct 29 15:25:21 2012 +0100
-
-    modules_k/tmx: Add $T_reply_last, returning last reply code
-    
-    Make the last/previous reply on a branch available to the script via
-    $T_reply_last. Only available in TM_ONREPLY_ROUTE.
-
-commit a2d09db983aa0b9a54ee78d5a910ba92140b05f8
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Oct 11 18:43:07 2012 +0200
-
-    modules/rtpproxy: Add 'b' flag to add a branch specific string tot the call-id
-    
-    In a forking call, sometimes it is needed that each branch uses different
-    options to the rtpproxy. This patch adds a parameter that makes each
-    rtpproxy session unique to a branch by appending the value of a PV to the
-    call-id rtpproxy parameter.
-
-commit f11f35045f6eaffd153d767946399fbb397bc3eb
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jul 4 17:33:50 2011 +0200
-
-    modules/avpops: avp_db_query: treat BIGINT result as INT, disregarding the most significant 32 bits.
-
-commit 457d075d3aabcaff6b6d14b6dfbc01c8a91734ec
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Oct 11 18:28:34 2012 +0200
-
-    modules/tm: Remember per-branch onreply_route and onfailure_route settings
-    
-    The onreply and onfailure routes were set only per transaction. This means
-    that when the onreply and/or failure route is changed in failure route (serial
-    forking), late replies to earlier branches would use the new onreply and
-    failure route instead of the routes set for them.
-    
-    This commit copies the transaction's onreply and failure routes to the branch,
-    so the route set when the request is sent out is always chosen, no matter
-    how late the reply arrives.
-    
-    Because the per-branch setting is copied after running onbranch_route, it is
-    now also possible to set the routes per-branch instead of per-transaction.
-
-commit 0b9f84519dd018159d67bb827d7e5c7e1e4431e2
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Aug 29 18:44:20 2011 +0200
-
-    modules/tm: add option to check callid when matching transactions
-    
-    Use this if you don't want replies/requests from broken clients, which
-    send a mangled Call-ID, to match the transaction. For example when
-    the UAC won't recognise the response anyway because of changed
-    Call-ID, this setting will prevent accounting records to be created
-    or failure_route to be skipped.
-
-commit 9ff6a40fce5160f23a385693d79df508759f1a31
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Aug 25 11:16:18 2011 +0200
-
-    modules_k/trusted: no not open DB connections if db_mode==1.
-    
-    For cached operation, childs (except MI) do not need DB access
-
-commit d1a85fbb01a9ae5b23c7b4f58de4ec584295d611
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Fri Aug 26 11:16:45 2011 +0200
-
-    modules_k/nathelper: add return value 2 to fix_nated_sdp() indicating no ip's have been replaced
-
-commit 358f0b859cdb15afa0c1079009a67b7aa9349f2e
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Fri Aug 26 13:08:39 2011 +0200
-
-    modules_k/pv: make individial flags accessible via $Mf(idx), $Bf(idx) and $Sf(idx)
-    
-    The parameter is the flag number (or registered name). If present
-    allows setting and reading the corresponding flag. As each flag is
-    now available as separate PV, it can be used in logging, transformations
-    and, last but not least, in loading/storing individual flags
-    from/to a database with sql_pvquery().
-    
-    When setting, any value != =0 will set the flag, 0 will clear it. When reading
-    a set flag returns 1, cleared flag 0.
-    
-    example:
-    
-    xlog("flags: 0x$mF / $Mf(15) / $Mf(16)");
-    setflag(15);
-    xlog("flags: 0x$mF / $Mf(15) / $Mf(16)");
-    $Mf(16) = 1;
-    xlog("flags: 0x$mF / $Mf(15) / $Mf(16)");
-    $Mf(15) = 0;
-    xlog("flags: 0x$mF / $Mf(15) / $Mf(16)");
-    
-    output:
-    
-    flags: 0x00000000 / 0 / 0
-    flags: 0x00008000 / 1 / 0
-    flags: 0x00018000 / 1 / 1
-    flags: 0x00010000 / 0 / 1
-
-commit 847ea5b2bc81749a44de34b35e5ef8516819951a
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Aug 30 13:35:55 2011 +0200
-
-    modules_k/trusted: Free memory of old trusted list when the list has been reloaded
-
-commit 1411a5789139cc302179b7d9f3a2b678e2caef9c
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Fri Sep 16 13:48:59 2011 +0200
-
-    modules/mtree: Do not log an error when prefix not found.
-    
-    A not found prefix is already represented as a negative return code.
-    No need to log an error, as it may be perfectly valid that a prefix does not
-    exists.
-
-commit 58e81b6c42cc48bd2b4afe84491a1a12d9d4b973
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Sep 22 15:59:23 2011 +0200
-
-    lib/srdb1: store BIGINT result also as 32-bit integer if it fits
-    
-    BIGINT is always converted to string. Additionally it is now stored as INT too.
-    
-    MySQL (at least on 64-bit) is returning BIGINT for all "generated" INT values,
-    like COUNT(*). By storing thee results as INT (if possible), the config script
-    will be compatible with both 32-bit and 64-bit column values.
-
-commit d5898510adbe9c45d16a770531a3e7c95061956b
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Oct 3 15:55:42 2011 +0200
-
-    modules_k/tmx: Add active_transactions statistics
-    
-    An active transaction is a transaction that is still waiting for a reply.
-    If it has seen a reply but is existing just to collect retransmissions,
-    it is not counted (in contrast to inuse_transactions).
-
-commit 74c1a6224a0d55735f01e0b0800206eec002fab0
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Mar 27 16:44:23 2012 +0200
-
-    modules_k/dialog: Allow unset_dlg_profile also in REQUEST_ROUTE
-    
-    even if the function has no use in normal REQUEST_ROUTE, the route block
-    may be called from other route blocks like failure_route.
-
-commit 1109a4ff6c68d9b2a619198cf1150b3431565bf0
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jan 7 15:35:46 2013 +0100
-
-    modules_k/sqlops: eleminate string copy in sql_exec_xquery()
-    
-    xavp api will make a copy in shmem, no need to make a private copy first.
-    
-    Thanks to Juha heinanen and Daniel-Constantin Mierla for finding this
-    inefficiency.
-
-commit 9b3d4e192859d83d8ec990751a5ead29ff72dab1
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Nov 29 11:47:10 2012 +0100
-
-    modules/pv: Fix $snd(ip) for IPv6
-    
-    Result was always an empty string surrounded by []. Converted to use ip_addr2a().
-    This also prevents the surrounding [], which are not part of an IPv6 address.
-
-commit 0ba54b551aa5dd7c13d4c6c4c275fd4cba3b17b0
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Feb 23 23:48:16 2012 +0100
-
-    modules_k/htable: don't return expired values
-    
-    If an item has expired, it will be treated as non-existent.
-
-commit 87d10dc1dce72d5c6b3a658f1d1193d16633eb6c
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Feb 27 14:14:44 2012 +0100
-
-    modules_k/perl: Fix resetting of flags in sv2int_str
-    
-    According to the functions comments and its usages in the same file, the flags would only be or'red, not reset
-    
-    This fixes setting an string named avp with an integer value:
-    
-    OpenSER::AVP::add("string", 12345);
-
-commit dfe3f66fc7969a5c479f78b1ec000914c48bd9ff
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Feb 28 11:39:10 2012 +0100
-
-    modules/sanity: Fail if request uri can't be parsed
-
-commit 1be860ef1a766bf271e7f7f7efcdc1006fe5bde9
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Jun 7 14:20:01 2012 +0200
-
-    modules_k/pua_mi: when checking for 0-length string, check s.len, not s.s
-
-commit 1e1202d3a710eeec5f534fc11f0406ba3e449df6
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jul 16 15:24:37 2012 +0200
-
-    modules/auth: replace ser_time() wih time()
-    
-    The values returned by ser_time() deviate so much from time() (and thus
-    system time) that the module was creating expired nonces in challenges
-    and rejected valid nonces as being "from the future".
-    
-    See also FS#243
-
-commit bf7c1ee6d77e781e846504970a1c2d3ef9544908
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue May 15 12:29:14 2012 +0200
-
-    modules/rtpproxy: return -3 when no more rtpproxy nodes can be found
-    
-    Provide a unique error code for the case when no (more) proxy nodes
-    are availave in the set. This allows the script recognize it from
-    the more general errors (all -1) and do special processing (failover
-    to another set)
-
-commit d0d17a8b9c20bfd9e8ce78931dd9f52254242a74
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jan 7 15:16:27 2013 +0100
-
-    modules_k/uac: regenerate README
-
-commit f310fd10bda2da682dee9eaa91474c704ffd8c2c
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Jul 10 12:41:45 2012 +0200
-
-    modules_k/uac: uac_reg: add reg_retry_interval parameter
-    
-    The new parameter allows to retry failed registration attempts.
-    Instead of unconditionally marking the entry as disabled, the
-    registration will be retried after the set interval. Setting it
-    to 0 (default) retains the old behaviour.
-
-commit 7432aa5ee180851dd5d6d933cbfe7ced93396566
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Feb 28 15:23:17 2012 +0100
-
-    modules_k/uac: uac_reg: skip realm checking if realm is empty
-    
-    When realm is the empty string, do not check the realm, but accept anything
-    the UAS throws at us.
-
-commit 0507b848d0257b478b422b49eb339ade7b801579
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Feb 28 13:10:23 2012 +0100
-
-    modules_k/uac: skip realm matching when realm pv for uac_auth is empty or null
-    
-    This can be used if the realm used by the upsteam UAS isn't known in advance.
-
-commit eb1abe66b9f97a4f98386d294b538a53ec05c9a6
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Tue Feb 21 12:35:18 2012 +0100
-
-    modules_k/uac: Add reg_db_table parameter to specify table name for registrations
-
-commit d2bdfd325665a0bc2652cdaa237d0afda9e4e8f8
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Fri Sep 2 09:36:43 2011 +0200
-
-    modules_k/tmx: add t_is_reply_route()
-    
-    Function to determine if the top executed route block is a reply.
-    In line with t_is_failure_route() and t_is_branch_route().
-
-commit 87bce89fe77942146d03ce4a44e6330e4a8149e7
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Sep 1 17:18:03 2011 +0200
-
-    modules_k/tmx: add $T_reply_reason PV
-    
-    Especially for internally generated (faked) replies it was hard to
-    get the reason phrase. This PV provides just that.
-
-commit 43533b41f2a4fb23b24bcf98b01fca223c605cd9
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jan 7 17:10:18 2013 +0100
-
-    Makefile: add corex module to kstandard group
-
-commit 14ef60cf93f2e7d2a458f8a3ce287e52f1b497d6
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Mon Jan 7 14:04:57 2013 +0100
-
-    modules/tmx: set $T_branch_idx to sane values for more route types
-    
-    $T_branch_idx will now return a branch number (0-based) in more route types.
-    
-    BRANCH_ROUTE and TM_ON_REPLY_ROUTE: currently handled branch number
-    REQUEST_ROUTE and FAILURE_ROUTE: next branch number, will be increased by
-        every append_branch
-    
-    In FAILURE_ROUTE, the branch number of the winning reply can be retreived
-    with $T_rpl($T_branch_idx)
-    
-    All other route types will result in (the invalid) branch number -1.
-
-commit 397ef369d7092aa670d63f81aa86657daee47071
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Fri Oct 12 14:06:33 2012 +0200
-
-    modules/tm: Set branch_index to T_BR_UNDEFINED when outside BRANCH_ROUTE or TM_ONREPLY_ROUTE.
-    
-    The inconsistent value of $T_branch_idx between BRANCH_ROUTE and
-    TM_ON_REPLY_ROUTE was fixed in an earlier commit, but now the value 0 has a
-    double meaning (branch 0 or invalid branch). This patch makes the invalid
-    branch distinguishable by setting it to -1.
-    
-    Now $T_branch_idx will return the branch number (0-based) in BRANCH_ROUTE
-    and TM_ON_REPLY_ROUTE and -1 in other route types or if the message is not
-    part of a transaction.
-
-commit e23e51ee2d5390b903b9f3029b01181c0dc5a7ba
-Author: Alex Hermann <alex at speakup.nl>
-Date:   Thu Oct 11 16:53:55 2012 +0200
-
-    modules/tm: Make branch_index consistent in all route types
-    
-    The branch index was set one to high in BRANCH_ROUTE, leading to
-    inconsistent branch numbers in reply routes.
-
-commit aa454db1818220d6b05699b9ee6e01a8237ffcb1
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 22:21:45 2013 +0100
-
-    siptrace	Typo after test compilations. Bad luck.
+===================== Changes Since Version 4.0.0 ===========================
 
-commit a59b5bc19b2cc672794c959ee6eb4e42c461a3e9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 21:20:17 2013 +0100
+commit 4ffd05e4664ca0af4dd101bedf12b40b251446aa
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Dec 4 15:33:14 2013 +0100
 
-    cdp  Documentation updates
+    Makefile.defs: version set to 4.1.0
     
-    Read my lips: It's configuration, not confiuaragion or confirtuaration... :-)
-
-commit a6b038332e38e6f60fee32896ffd610cf76e11ee
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 20:43:00 2013 +0100
-
-    avp XML doc updates
-
-commit c79c33f14d9cf15444cdd024551c788679cf71bb
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 20:42:12 2013 +0100
-
-    avp 	Documentation typo fix and update (SER => Kamailio)
+    - new major release
 
-commit 66560d5ad5c136aa833db57ed32283d788f56611
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 20:18:42 2013 +0100
+commit 3ad1f6afffe8250a3695ac8233bdb746bcfdcecf
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Dec 4 15:02:22 2013 +0100
 
-    outbound(k) Minor edit of documentation.
+    doc/rpc_list: regenerated the lists of rpc commands
     
-    Please ignore, keep calm and carry on.
-
-commit 226c92425b266f1c1a5efb2286cf067ce0b7df22
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 20:13:26 2013 +0100
+    (cherry picked from commit 2ffeea75931600e2da70d696a9965a5b7329211b)
 
-    siptrace(k) Fixing a bad change in docs...
-
-commit 9b1c23481551ef74b6efeb0118c1119470a08826
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 20:09:39 2013 +0100
+commit ab21be6c76bc2b3010d937bbf1d0b2d2fd3a7e7b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Dec 4 14:34:04 2013 +0100
 
-    siptrace(k)	Add RPC command for turning on/off
-    
-    Copying the functionality of the existing MI command.
+    doc/rpc_list: added sctp in the list of modules exporting rpc commands
     
-    Also, setting the value of the trace_flag to 0 by default, as
-    documented in the documentation.
-
-commit fd77c500050073e019b0366fdcd3a6c125a20cb9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 20:04:29 2013 +0100
-
-    sipcapture: Fix typo in XML markup
-
-commit 9af31f9c44cc35a4cbe74accf79513c7272ec93c
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 19:50:12 2013 +0100
-
-    sipcapture Small cleanup in docs
-
-commit ba12e3893787a8340d21aa18ab6faa81e825713f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 18:38:54 2013 +0100
+    (cherry picked from commit 56c772fbd1490a7cef3f748c61d1c7d7be3167a3)
 
-    sipcapture  Small typo
-
-commit 8ebf2dbe6cc0e51b47c423227f5dcff14c7af4c3
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 18:37:43 2013 +0100
+commit 8f488c2ec4919052dfb12e8135b672411957c44e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Nov 15 10:08:12 2013 +0100
 
-    sipcapture	Add RPC command to turn on/off or check status
+    app_perl: docs updated with reset_cycles parameter and rpc commands
     
-    Kamailio RPC rocks - much more than IMS ;-)
-
-commit 70ca23583a136f2a401ce57d4b9f110e2f4db1fe
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Wed Jan 9 12:34:27 2013 -0500
-
-    pv(k): Remove read-only empty strings that might be attempted to be written to
+    (cherry picked from commit b1f4dbeef93511563164de2f030f510f5a2cf2d9)
 
-commit 2207618978f5d61c3afe65007c3460a2e1ef0d37
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 16:53:07 2013 +0100
+commit c1b11585f72c5b80efdf6c79d0b76391a4dbdef1
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Nov 15 09:52:29 2013 +0100
 
-    usrloc(k)	Add RPC for AOR lookup
+    app_perl: added rpc commands to set/get the value for reset_cycles
     
-    Copied from mi interface. RPC rocks!
-
-commit 875c5e71cf1ac077f17eb15030ce8cfb0d299e89
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 15:29:48 2013 +0100
-
-    usrloc(k) Reveal existing rpc command in README
-
-commit e1306157b324d2ad21d97af0edf14072769787d7
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 14:00:32 2013 +0100
-
-    db_cassandra Minor edits and typo fixes to README
+    (cherry picked from commit de2c39a1857d74443c6b1fa4f06cbb18d3dd8026)
 
-commit 8341030426fbe1f48e527b52d694b188ecdd48dc
+commit 6a654f18f579aaf812a325a0b1a678ace5236051
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 9 14:55:46 2013 +0100
+Date:   Fri Nov 15 09:28:25 2013 +0100
 
-    registrar: execute event route when a contact expires
+    app_perl: added mechanism to avoid leaks specific to persistent perl interpreter
     
-    - the name of the routing block is event_route[usrloc:contact-expired]
-
-commit ff18475e9fd3c6d4da4ca2e85c045fc761eb48e5
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Wed Jan 9 15:44:38 2013 +0200
-
-    db_cassandra: updated documentation
+    - it is not easy to track the scope of variables, especially in libs,
+      the solution being to re-init the interpreter
+    - new module parameter reset_cycles to specify the number of execution
+      cycles after which the interpreter is reset. Default is 0 - don't
+      reset at all
     
-    - added URLs for Thrift library and Cassandra
-
-commit b7fde2349a28e22cd9e02412d914d07ee8654f79
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Wed Jan 9 14:19:06 2013 +0200
-
-    db_cassandra: Improved documentation and config file example
+    (cherry picked from commit b5527627601c9e41ebbfaccb98bc2cf0bc003bdb)
 
-commit b2e1fdd5df2e52d1393ebe592869e54fb6ee734f
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Wed Jan 9 12:52:13 2013 +0200
-
-    dbcassandra Added schema files for domain module
-
-commit 3b9de69fcc60bf918413a8b79fb475067c1852b3
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jan 8 22:38:35 2013 +0100
-
-    dialog(k): bridge contact address can be set via parameter
-
-commit 644902198d7727d8c283109d84de36babf5544ad
+commit 8991684e94def6efa74d827753c2fe1c3e6d9d97
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jan 8 22:34:00 2013 +0100
+Date:   Thu Nov 14 23:00:32 2013 +0100
 
-    dialog: add contact header in REFER for dlg_bridge()
+    app_perl: declare extern environ variable
     
-    - some UAs reject the REFER if there is no contact header
-
-commit 0574a4833122a6f4c0b70e84dfbe7bb2f0f821ce
-Merge: fca96b0 d923afb
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Wed Jan 9 11:18:48 2013 +0200
-
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-
-commit fca96b0b6383198bbd95f0421e66bfb9cb1956f3
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Wed Jan 9 11:17:03 2013 +0200
-
-    modules_k/rr: updated README
-
-commit d923afb1737651cbb7e4aac2517445afd4625c6c
-Merge: d645d52 ead5275
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Wed Jan 9 10:35:22 2013 +0200
-
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-
-commit d645d525cc6e67ef17af31cbe7a54099134794e7
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Wed Jan 9 10:34:05 2013 +0200
-
-    examples/scscf/kamailio.cfg - fixed IMS modules names
+    - without it doesn't compile on darwin and it is recommended way to do
+    - provide some fake argc and argv to PERL_SYS_INIT3() to avoid compile
+      warnings
     
-    Updated SCSCF example cfg to use new IMS module naming convention
+    (cherry picked from commit 34ad8c295b45bc52cc5a071bf2b5651865389f94)
 
-commit ead52752c9b61c0fcadd95d3d39042498068c73c
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Wed Jan 9 10:31:51 2013 +0200
+commit 99c4af0c61994e59d902defcf985a865a8d6b8f0
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed Dec 4 11:46:29 2013 +0100
 
-    modules_k/rr: added feature to set custom username for Record-Route URI
-        - this is an AVP param that can be used to customise the default
-          username (Request-URI) added to the Record-Route URI before
-          calling record_route.
+    pkg/kamailio/deb: update changelog
 
-commit 9d394f9844b6043372b72539c69e9d56b0861d6d
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Wed Jan 9 10:29:25 2013 +0200
+commit fb7e342ce500cc21e9f15a15f51e3b0ecad29310
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed Dec 4 09:10:37 2013 +0100
 
-    examples/pcscf/kamailio.cfg - fixed IMS modules names
+    pkg/kamailio/deb: add new modules
     
-    Updated PCSCF example cfg to use new IMS module naming convention
+    (cherry picked from commit e043c3a44b163e511e62af5c7290fb587141b400)
 
-commit d3dee2b4579310fde42cfc727ebd5dc7537d8446
-Author: Richard Good <richard.good at smilecoms.com>
-Date:   Wed Jan 9 10:19:47 2013 +0200
+commit 983a1b29096c5bd2ef0db6f5cab80bfc1a5d326a
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Dec 3 16:46:32 2013 +0100
 
-    examples/icscf/kamailio.cfg - fixed IMS modules names
+    pkg/kamailio/deb: add jessie release
     
-    Updated ICSCF example cfg to use new IMS module naming convention
+    (cherry picked from commit daee150595e6fabdf53aa66425d32234ec7bbde7)
 
-commit 68d7468cf77e1831186ea0017ead15adb73c1328
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 08:37:41 2013 +0100
+commit 6fc672fc4153c85c3742928d7c7e897f1f7387c7
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Dec 3 16:11:00 2013 +0100
 
-    snmpstats(k) Change from OpenSER to Kamailio
+    pkg/kamailio/deb: Add dnssec module ( jessie only )
     
-    Note: Apart from code name changes, the MIB files and the objects
-    has changed names. This will affect all systems monitoring your
-    SIP server as you upgrade to 4.0.0
+    (cherry picked from commit 50b1c3a52c150201a563060cd1059a49ada89af2)
 
-commit 2b09c72457a1c84508d74feb9dbc2d86f682508c
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Jan 9 07:56:14 2013 +0100
+commit c11fb2733024d7739e183c842cef4a386e090131
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Dec 3 15:51:41 2013 +0100
 
-    htable(k) Add new RPC htable.listTables
+    pkg/kamailio/deb: add new modules app_java, autheph, sctp
     
-    This RPC list all defined tables and their settings
+    (cherry picked from commit 450d7ecb49a64e71dd28273b470911bd933bc209)
 
-commit 85ee107929a80b54d47eaabef6f25d7b2f0659e7
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Jan 8 20:58:03 2013 +0100
+commit 0a9055c1989aee3878d11a931daad8c971b15835
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Dec 3 16:42:06 2013 +0100
 
-    Added sample configuration files for Kamailio IMS Setup. IMS Rocks!
+    pkg/kamailio/deb/debian: fix mono deps
     
-    Greetings from the Dolomites, Italy, Carsten
-
-commit d21c7e32ceb52a90a9106fb3bba66cdd357a1fa6
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Jan 8 14:30:17 2013 -0500
-
-    pipelimit: fix documentation typo
-
-commit 3f8d1e2bdba6650d2541261a2184a0bef5b88b07
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Jan 8 14:21:46 2013 -0500
-
-    pipelimit: enhance return codes for pl_check() function
-
-commit 16784302104e5fc40b3873019938d140c402eff6
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Jan 8 13:08:44 2013 -0500
+    (cherry picked from commit f17c51fe48149a6b7634cee2e36ee463e1ee9fef)
 
-    module*/*/Makefile: libcurl dependencies build fixes
-
-commit 66cc4397e04591fd5b2af9798a1ab22d3dbaf7b6
-Author: Arnout Vandecappelle (Essensium/Mind) <arnout at mind.be>
-Date:   Tue Jan 8 12:42:40 2013 -0500
-
-    module*/*/Makefile: libpcre dependencies build fixes
-
-commit 79295e7a5820921646846eec062e1ff7c27fec9d
+commit a3169d02d7527110941fab8de25ba75aae759ce1
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jan 8 18:41:35 2013 +0100
-
-    kamailio.cfg: mention v4.0 in the header of config file
-
-commit ea4daadd16ff3d45c0c35d90df38bfcc33e8bfbe
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 8 16:21:19 2013 +0000
-
-    pkg/kamailio/(centos|fedora): Updated .spec file
-
-commit 60f177ba77647fb7203f5c3b92d34a196f237a09
-Author: richard <richard at richard-laptop.(none)>
-Date:   Tue Jan 8 17:32:11 2013 +0200
-
-    modules/usrloc_pcscf and modules/usrloc_scscf - removed unnecessary junk files
-
-commit 36a0cb38bcafcb4d4e2bfbc0977e0c1f25e74d14
-Author: richard <richard at richard-laptop.(none)>
-Date:   Tue Jan 8 17:23:29 2013 +0200
-
-    modules/ims* and modules/dialog2 - changed modules name to prepend ims_ to all IMS modules
-    
-    As per mailing list and offline discussions have prepended _ims to all IMS modules and renamed dialog2 dialog_ng
-    New modules name:
-    dialog_ng
-    ims_auth
-    ims_icscf
-    ims_isc
-    ims_registrar_pcscf
-    ims_registrar_scscf
-    ims_usrloc_pcscf
-    ims_usrloc_scscf
-
-commit 4c7ba37b7d8bf55d1983950812a3ae060e5ee3e4
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Tue Jan 8 16:47:13 2013 +0200
-
-    modules/cdp: Added kcore link for statistics
-
-commit 1ee54a1e511b98848fd2a6a5075009e2e0b4df06
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Tue Jan 8 12:52:44 2013 +0100
-
-    permissions(k) Add RPC function calls that match functionality in old modules_s module
-
-commit 82303dfad79c601767bb8e1a115fd30d1fb3a282
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 8 11:27:11 2013 +0000
-
-    modules_k/outbound: updated documentation
-    
-    - Fixed some mistakes in the Edge Proxy example
-    - Filled in more detail in the Registrar example
-
-commit f57ac2ddaf1a4bbb8178f9fdc2fc408819d41228
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 8 11:02:09 2013 +0000
+Date:   Tue Dec 3 23:38:41 2013 +0100
 
-    modules_k/rr: fixed typo in a diagnostic
+    core: don't increment failed dns query counter for reverse dns lookup at startup
     
-    - Thanks to oej for pointing this out
-
-commit a20893dd6cbf1a5fc7f48d9e8fd1823bbb1ba07f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 8 11:01:31 2013 +0000
-
-    modules_k/outbound: downgraded and ERR diagnostic to INFO
-    
-    - Thanks to oej for pointing this out
-
-commit 5fc244a81ff4749bd8cb0196a1baecd8a721191a
-Merge: ecba6cf 9a10ed3
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Tue Jan 8 11:01:37 2013 +0200
-
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-
-commit ecba6cf229f849dd6390bbb2b9e9e70628fd0bd7
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Tue Jan 8 11:00:16 2013 +0200
-
-    modules/cdp: added omitted statistics files
-
-commit 9a10ed3334804f520ecdab03f1019a19e13e0494
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 8 00:24:47 2013 +0000
-
-    modules_k/registrar: documented new "flow_timer" modparam
-
-commit e18905ea53c2c5d4a565de596e2c2913ede6466f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 8 00:24:13 2013 +0000
-
-    modules_k/registrar: Added modparam to allow Flow-Timer: to be set in 200 OK response to REGISTER requests
-
-commit 2aa85480330e368154e2d1c407380ba06f66d3f5
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Mon Jan 7 21:59:18 2013 +0200
-
-    modules/rtpproxy: removed LM_DBG that caused compiler warnings
-
-commit 329db6c3ace5e93a3b7ab7155481f2e9705119b3
-Merge: e7bb3af c9de09b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Jan 7 16:11:05 2013 +0000
-
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    - it can happen before counters are intialized, thus check that before
+    - reported by Hugh Waite, FS#375
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      core: when printing the listening sockets on startup print also the advertise-port
-
-commit e7bb3af61bea673af801a5b9280f50ec13958a3b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Jan 7 16:10:46 2013 +0000
-
-    modules_k/outbound: Updated the module documentation
+    (cherry picked from commit 89c6d73dd51eb9b96f50d3f04219612fa7725224)
 
-commit 4cb23b43c246cb227282474d2b7bd6d6ff9c2033
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Jan 7 16:10:17 2013 +0000
-
-    modules_k/registrar: Updated registrar module documentation to describe the outbound_mode parameter
-
-commit c486a9358f146ac2b3e5047021c197c3eb6b41d8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Jan 7 16:08:13 2013 +0000
+commit a165fa668378da5c312a0c268aaf158ff583127f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Dec 3 23:38:08 2013 +0100
 
-    modules_k/registrar: New outbound_mode parameter
+    core: added function to check if counters have been initialized
     
-    - Controls whether outbound options-tag is required in REGISTER
-      requests and whether they are added to responses to REGISTER requests.
-    - Needed so that an Outbound Edge Proxy can add a Flow-Timer: header
-      to 200 OK responses (to REGISTERs) that contain a Requires: header with
-      the outbound options-tag.
-
-commit c9de09b99b417aebb8fe84d44dec6c1bff1d8849
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Mon Jan 7 16:22:38 2013 +0100
-
-    core: when printing the listening sockets on startup print also the advertise-port
+    (cherry picked from commit 8161152b320f3b430523ea08e86a56f79405c2f4)
 
-commit da1d8d1a9315d187b050468aa33772253f10e47b
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Mon Jan 7 12:47:11 2013 +0200
-
-    modules/sipcapture: fixed defines for Solaris
-
-commit ff1c7f3756bf7c2175b7209ccc13ab0cbf6cb4f8
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Mon Jan 7 11:02:06 2013 +0200
+commit 48a3412afe166f5cbd41a057a22a3333337a2856
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Dec 3 13:00:55 2013 +0000
 
-    md5.h: fixed types for Sun Solaris
+    websocket: Set pointers to NULL when freeing ws connection strcutures
+     - Fixes double free crash FS#364
+     - Reported by Vitaliy Aleksandrov
+    (cherry picked from commit 95749afb7129e2909b449b79706f0de5d06a3c5d)
 
-commit 3dd44561692657027289ff320709ce5d4bff210e
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Mon Jan 7 09:56:24 2013 +0200
+commit a31988d657edef079525fa68096dc537e78708c5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Dec 3 12:54:00 2013 +0100
 
-    modules/cdp: housekeeping
-        - corrected copyright
-        - fixed timer code (latency thresholds)
-        - changed to KAMAILIO module interface
+    stun: refreshed readme file
 
-commit 0b108c83ba7138c760fa86c9274633c92b7193a1
-Merge: 9f63684 94e9bd8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 6 19:37:22 2013 +0000
+commit 41cc8aa248ea1e736bb3d069b32430cc1e54c0af
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Dec 3 12:50:29 2013 +0100
 
-    Merge branch 'master' into outbound
+    stun: updated docs to reflect that it no longer depends on external libs
     
-    * master:
-      pkg/kamailio/(centos|fedora): Updated ver and rel in .spec
-      sl: fix compilation warnings in sl_forward_reply()
-      dialog: fixed ka_timer linking
-      core: command line option -v replaced with -K
-      msrp: new parameter use_path_addr
-      msrp: added rpc command to list active connections
-      msrp: added internal map table to track msrp connections
-      pipelimit: implemented support for RPC commands
-      Makefile.defs: major version base updated to 4.0.0
-      sl: new function sl_forward_reply(...)
-      core: added function to remove an exiting lump structure from internal list
-      dialog2: generate and add missing README for dialog2 module
-      Do not bind with libser_cmd, this is not required.
-      Added Debian-Packaging for IMS modules
-      - Add group for IMS modules - Added convenience rule to build packages for current debian-stable
-      ims modules: don't link with -lrt on macosx
-      auth_ims: don't link with -lrt on darwin os
-      kamailio.cfg: xhttp left only in kamailio-oob.cfg
-      modules/rtpproxy: rtpproxy_manage can now add ice relay candidates
-      parser/sdp: fixed freeing of ice attributes
-
-commit 94e9bd8f15e192ee8b1c14d759129992b35435bf
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 6 19:36:39 2013 +0000
-
-    pkg/kamailio/(centos|fedora): Updated ver and rel in .spec
-
-commit 9f636841675f9cdd5a4baf768784564be71660b0
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 6 19:32:45 2013 +0000
-
-    modules_k/outbound: Updates to outbound module documentation
-
-commit 539e606d4ab88b837207fbe5a921f05756eba8a5
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 6 19:32:29 2013 +0000
-
-    modules_k/outbound: Fixes to outbound code arising from testing
+    (cherry picked from commit 305e7b5693e71d2027f8e6462129f8c9f01ad76d)
 
-commit b0ee720bec6d188615b98e8b107100fc5158e839
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 6 19:32:04 2013 +0000
-
-    modules_k/rr: Updates to rr module documentation for outbound
-
-commit a9d425f4aa8fe0fdc4aac3e158b6c98fd59a5776
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jan 6 19:31:41 2013 +0000
-
-    modules_k/rr: Fixes to loose.c from outbound testing
-
-commit 3f0f60d22d5577965b50821b1c7d0835c898c3f9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 6 15:28:28 2013 +0100
+commit 3c491913dac5060639278f1e645205b1a3959ad3
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Tue Dec 3 01:34:52 2013 +0000
 
-    sl: fix compilation warnings in sl_forward_reply()
-    
-    - reported by Juha Heinanen
+    pkg/kamailio/centos: Updated rel in .spec in preparation for 4.1.0 release
 
-commit ddcef074088df261ce3fb98adfbb1b76b73c30a6
+commit 23b582a7ea67c6a6fd8347533020e8b4c0de2dbd
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 6 15:24:39 2013 +0100
+Date:   Mon Dec 2 23:21:24 2013 +0100
 
-    dialog: fixed ka_timer linking
-    
-    - patch by Rinor Hoxha
+    kamailio.cfg: updated the comment about kamailio version
 
-commit 70d6cae27153d6641b2a781634aeb585b741d3a0
+commit 5dc07807bf08aca8b600c90f9d700b49ef0ad454
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Jan 6 00:00:40 2013 +0100
+Date:   Mon Dec 2 22:01:34 2013 +0100
 
-    core: command line option -v replaced with -K
+    kamailio.cfg: use set_contact_alias() instead of add_contact_alias()
     
-    - -v was exposing to misusage for -V (version), now is aliased to it
+    (cherry picked from commit 66ed11c90e38d948fd75f908b3edd409bca74134)
 
-commit 830af85c45933b3cdc3c48152667162fcf969a55
+commit 284f4ef38c3928516e9c4a78b4768de716b850b7
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Jan 5 23:51:07 2013 +0100
+Date:   Mon Dec 2 20:42:12 2013 +0100
 
-    msrp: new parameter use_path_addr
+    mem: malloc(0) should return a valid pointer for free according to specs
     
-    - specify host and port for usage in Use-Path header
+    (cherry picked from commit f61ff34aac7c7bae3a96fb698a899c8a0e692a9f)
 
-commit bc8b005ba4d4c89afa6152dd212eda9b6689bb86
+commit 0d0d230ab09da4cd2e6d8331d1feed5b6172cfa1
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Jan 5 23:36:43 2013 +0100
+Date:   Mon Dec 2 19:40:04 2013 +0100
 
-    msrp: added rpc command to list active connections
+    Makefile.defs: version set to 4.1.0-rc2
 
-commit ea3cacb10d2cc15f23c3a0c7fead151939873951
+commit f7ed69d75746dc55e5a48a7a18602124e73cd3cd
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Jan 5 22:00:55 2013 +0100
+Date:   Sun Nov 24 16:06:41 2013 +0100
 
-    msrp: added internal map table to track msrp connections
+    tmx: backup and restore existing T and branch pointers for t_cancel_callid()
     
-    - initial version
-    - the table can be enabled via config parameters
-
-commit f432022f943ad4f72d3643974f065c6007af6589
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Jan 4 21:34:50 2013 -0500
-
-    pipelimit: implemented support for RPC commands
-
-commit e03be11d30abd9f6a5a756ae142444395f09df93
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jan 4 19:29:30 2013 +0100
-
-    Makefile.defs: major version base updated to 4.0.0
+    - reported and initial patch by Guillaume Bour
     
-    - development version is now 4.0.0-dev8
+    (cherry picked from commit 60372d613544af1f8f06122eb77fa2a9636a6c3a)
 
-commit d01b11b0cbbbfb84ae3d10fb90c05aedf07c9ccc
+commit 09fb0aae62761ce4f251ab22c6ab9cde55e2c663
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jan 4 19:26:21 2013 +0100
+Date:   Sun Nov 24 16:05:49 2013 +0100
 
-    sl: new function sl_forward_reply(...)
+    tm: exported set_t() and get_t_branch() viam tm api
     
-    - forward the received reply fron configuration, before it would be done
-      by the core. It has the option to change the status code and reason
-      phrase
-    - the forwarding is statelessy, not affecting the tm states
-
-commit 7fd561975706676e61bb3d90968652edcb96f35c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jan 4 19:25:05 2013 +0100
-
-    core: added function to remove an exiting lump structure from internal list
-
-commit d2b805c8b13943f82240276f98f78145ac7572f9
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jan 3 16:44:03 2013 +0100
-
-    dialog2: generate and add missing README for dialog2 module
-
-commit 2ce18eee8cfb85d7c88187a419c8d3f81228a1f8
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Thu Jan 3 16:24:59 2013 +0100
-
-    Do not bind with libser_cmd, this is not required.
-
-commit 9cb6a84106aca0c998084c25b8b05d9d34a35ff2
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Thu Jan 3 15:03:46 2013 +0100
-
-    Added Debian-Packaging for IMS modules
-
-commit fc1706e0c3b53500a321c13bc3450a4ccbe6dd6c
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Thu Jan 3 15:02:40 2013 +0100
-
-    - Add group for IMS modules
-    - Added convenience rule to build packages for current debian-stable
-
-commit 539f97bdaa4b6c12fec3a943b6adb7902b748827
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 2 14:38:22 2013 +0100
-
-    ims modules: don't link with -lrt on macosx
+    - allows to backup and restore pointers to T and branch
     
-    - define MAXINT on mac os x
+    (cherry picked from commit 777dd5e28ff6b4fcc3b1c44e841eb415c974075f)
 
-commit cf93bf2097660c093645550f1d3b54fdc1154288
+commit f06c0421f2d08aa9ec15330dbe7c270b7c67eef4
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 2 14:22:39 2013 +0100
+Date:   Thu Nov 21 17:37:33 2013 +0100
 
-    auth_ims: don't link with -lrt on darwin os
+    tm: propagate reply/failure route indexes to local uac branch
+    
+    - affects the updates done in event_route[tm:local-request]
+    - reported by Pawel Sternal, FS#371
+    
+    (cherry picked from commit 715ba52de2031786fd9f05832d5bf73d17d46e47)
 
-commit 8660e2f031a159d0ac1edb87e20738f50a87d5c6
+commit d3a6f48d379097afc649b16237df46581b251084
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jan 2 14:09:53 2013 +0100
-
-    kamailio.cfg: xhttp left only in kamailio-oob.cfg
-
-commit 75fde552f1c4cdea736baa72ff1aa36e527e0215
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Jan 2 13:00:31 2013 +0200
+Date:   Mon Dec 2 18:17:34 2013 +0100
 
-    modules/rtpproxy: rtpproxy_manage can now add ice relay candidates
+    tls: clarified licensing based on development history
     
-    - The feature is activated by defining ice_candidate_priority_avp module
-      parameter.
-
-commit 35bc07e6a13e12aba519be8bde1a1e1dc06a1d94
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Jan 2 09:13:00 2013 +0200
-
-    parser/sdp: fixed freeing of ice attributes
-
-commit a117147b4c6563be21c0403eeeacf5ff0f3ba709
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 1 20:46:18 2013 +0000
-
-    modules_k/outbound: updated example
-
-commit 0a528b23bc39eabfaaf2874a74ce529955c21ff5
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 1 20:45:49 2013 +0000
-
-    modules_k/rr: outbound fixes
+    - some were c&p as they refered to files related to components that were
+      developed later than the (c) year (e.g., selects)
+    - added openssl exception to gpl parts based on agreement from the
+      developers of those components - most of the code was released long time
+      ago under BSD by iptelorg. Code was rewrote for 3.1 when asynchronous
+      support was developed.
     
-    - Use the OUTBOUND address in RR when using outbound
-
-commit 9b5c3a991942da005b8c56b049a1ebde5596042b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jan 1 20:45:24 2013 +0000
-
-    modules_k/outbound: fixes to use_outbound()
+    (cherry picked from commit 7771e9cdb58ea1cef008e2a70f53c5f183c26ebe)
 
-commit e2d144bd76f327ce7c52914ed0462f415e7d06a7
-Merge: 4a41827 ddfbbd7
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 17:12:01 2012 +0000
+commit 4ff3866652be6752e5167071ce02b888acda0e75
+Author: Federico Cabiddu <federico.cabiddu at gmail.com>
+Date:   Mon Dec 2 17:05:35 2013 +0100
 
-    Merge branch 'master' into outbound
+    permissions: re-init db connection for reload cmd
     
-    * master:
-      parser/sdp: added check on body length when looking for 'a=candidate:'
-      parser/sdp: added 'a:remote-candidates' media stream attribute
-
-commit 4a418276b50212feb3ef4d659c42e6772fc9fcd7
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 17:11:30 2012 +0000
-
-    modules_k/outbound: first draft of outbound module documentation
-
-commit 72d8e454f29174673cc80f9795ac8d564c2ca1bb
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 17:11:14 2012 +0000
-
-    modules_k/outbound: Corrected check on flow_token_key length
-
-commit ddfbbd7c0eb7fc1c7ffbb07d6260271ded8b42b3
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Mon Dec 31 18:18:05 2012 +0200
-
-    parser/sdp: added check on body length when looking for 'a=candidate:'
+    - some workers for specific mi/rpc commands may not have a db connection from the start
+    
+    (cherry picked from commit cb23be9456c178957399ec9d8ce8a1420d50fc32)
 
-commit 88a8eb348359f05a1ff14371f8e323cf086d6497
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Mon Dec 31 18:16:23 2012 +0200
+commit a5f8d36ac011be12a9582999a8d6480541106439
+Author: Camille Oudot <camille.oudot at orange.com>
+Date:   Tue Nov 26 16:08:35 2013 +0100
 
-    parser/sdp: added 'a:remote-candidates' media stream attribute
+    modules/ims_registrar_pcscf: fix log
 
-commit 5214a6e617bfc8f2471fcf0d02d8fa5cf0a9ce3b
-Merge: e00d77f 945b1fd
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 16:08:59 2012 +0000
+commit 424711ec889661a1212e63f9b0e9761a6e4ed069
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Thu Nov 28 12:16:05 2013 +0100
 
-    Merge branch 'master' into outbound
+    modules/ndb_redis: solved bug in second call to redisvCommand.
     
-    * master:
-      pkg/kamailio/(centos|fedora): Added IMS modules to RPM builds
-      parser/sdp: added partial parsing of a=candidate attributes
-      modules/sipcapture  README: added HEPv2/v3 to supported protocols
-      modules:siptrace changed include to hep.h
-      Added HEPv3 (UDP) support for sipcapture.
-      modules/registrar_pcscf: firs commit of registrar_pcscf module 	- registrar for P-CSCF functionality
-      modules/registrar_scscf: first commit of registrar_scscf 	- Registrar functionality for S-CSCF servers
-      modules/isc: first commit of ISC module (IMS Service Control)
-      modules/usrloc_scscf: first commit of usrloc_scscf modules 	- usrloc functionality for S-CSCF servers
-      modules/usrloc_pcscf: first commit of usrloc_pcscf module
-      modules/auth_ims: first commit of auth_ims module 	- This module provides IMS specific authentication/authorisation functionality.
-      modules/icscf: added I-CSCF module.
-      modules/dialog2: first version of dialog2
-      lib/ims: added some info to README on IMS library
-      IMS Internal Lib: added internal kamailio library for IMS extensions
+    (cherry picked from commit 52a34d269931f6f3a50b3fc532405624b9e38d23)
 
-commit 945b1fd62e1bb5c9d4aa066666d64ae63731c94a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 16:08:20 2012 +0000
+commit 0b85493f3c1bc7c6cbd48f39aea9d3ecc135d4ff
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Tue Nov 26 10:36:18 2013 -0500
 
-    pkg/kamailio/(centos|fedora): Added IMS modules to RPM builds
+    rtpproxy-ng: remove trailing double \r\n from multipart SDP
 
-commit e00d77f710fe36dca08f099306c837ef7e53309f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 15:36:00 2012 +0000
+commit 553d6aff9eecaec38547910d4dd46fcd71b57583
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Nov 22 09:39:40 2013 +0000
 
-    modules_k/outbound: filled in use_outbound() function
+    modules/avpops: Fix 'uninitialised variable' warning
+    (cherry picked from commit 54020b00893ee259baee714d7d17adc6d31f9112)
 
-commit 488bf3c94b2498e7539638202ee878c237fde567
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 15:35:32 2012 +0000
+commit 20822c5227962508d13bce48a653e594cbfaeff1
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Nov 22 09:35:55 2013 +0000
 
-    core: added parsing of ;ob for URIs and Contact: headers
+    modules/usrloc: Update contact field when updating a contact in the DB
+    - Fixes FS#368
+    (cherry picked from commit a55018deb431ef32ee2bcd45610903327850757d)
 
-commit b7a1ea4c8a88eea873bf6b4bfac5e1f477a19073
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Mon Dec 31 15:51:53 2012 +0200
+commit 18afdc79aeb2b46c6eda4b66e40efae49d524701
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Nov 22 09:28:38 2013 +0000
 
-    parser/sdp: added partial parsing of a=candidate attributes
+    modules/registrar: Invalidate temporary GRUUs when the Call-ID changes for a sip.instance
+    - Fixes FS#368
+    (cherry picked from commit 27eba09b603b265ce4213d238c132249189ae6e8)
 
-commit 9d9394d63c3ccdfa3ce7ba067ef29c4657f0eb37
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 13:44:19 2012 +0000
+commit b6c109a38f8fca82005166ed73d370a2f974a3db
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Nov 21 20:24:20 2013 +0100
 
-    modules_k/rr: handle outbound failing and outbound just not being used as separate cases
+    sl: README updated
 
-commit dccab57430d0014b386a8f97ca6c8506a81402e7
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 13:43:15 2012 +0000
+commit 93428405a7d9bba3aee3bf317ea76f232739c9af
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Nov 21 19:14:17 2013 +0100
 
-    modules_k/outbound: decode_flow_token() returns different values when an error occurs and when the string obviously isn't a flow-token
+    sl: docs updated to reflect usage of send_reply()
+    
+    (cherry picked from commit e7b73f7e0160eac1ca445201fbf796df0dd13ce0)
 
-commit a0a23aacc9a2d19b30f62702811c1eadc5671d98
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 13:28:06 2012 +0000
+commit 6125176d04c75d3a3f0b57119696eca2f63c3645
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Nov 21 19:09:43 2013 +0100
 
-    modules_k/rr: updated documentation for outbound support
+    sl: allow send_reply() in the route block types supported by t_reply() and sl_send_reply()
+    
+    - reported by Juha Heinanen, FS#362
+    
+    (cherry picked from commit c77aaf38eafe1d3549d266feebf76ac0b50738ea)
 
-commit 7d6d7f177f465e184e1ef612a82a7406ccadd45a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 13:25:36 2012 +0000
+commit 7e74944eb6a55a5e9a817a894af1ebbbc8ce9733
+Author: Timo Teräs <timo.teras at iki.fi>
+Date:   Fri Nov 15 16:06:25 2013 +0200
 
-    modules_k/rr: fixed typos in diagnostics and comments
+    modules/sca: fix hash entry deletion
+    
+    sca_hash_table_slot_kv_delete_unsafe() uses internally sca_hash_entry
+    but incorrectly called sca_hash_table_slot_kv_find_unsafe() to
+    initialize the entry. That function returns the node value, not the
+    node itself. Use instead sca_hash_table_slot_kv_find_entry_unsafe().
+    
+    Should fix the crash in FS#366.
+    
+    (cherry picked from commit 56e4f4518028e73f9ebd053242a100a5c3b7eb53)
 
-commit a0dd2a75dc763ebb5907573aac3b8653c5faf93a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 13:25:01 2012 +0000
+commit 85e9202d14eda0a43d566aa14c0df47a78eb24f3
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Fri Nov 15 09:08:03 2013 -0500
 
-    modules_k/path: fixed a typo in a diagnostic message
+    usrloc: fix crash while printing error log
+     - fix a copy/paste error that lead to a NULL pointer
+    (cherry picked from commit 10115f88637d1371a8ddeb5fe9c36c31ada49fc4)
 
-commit 6141b16fc5f619938472f6f56d0fb2e0e5456aee
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 12:55:06 2012 +0000
+commit 82d4a39a4f7cd81afbcaed8de8bec0e3a7747e53
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Nov 14 16:12:27 2013 +0100
 
-    modules_k/rr: tidied up error handling and comments relating to outbound
+    Makefile.defs: version set to 4.1.0-rc1
+    
+    - dedicated brach 4.1 has been created for release series 4.1.x
 
-commit 5ceef3cb48fc4b1e9c75abf91ba45f59f5125751
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Dec 31 12:54:37 2012 +0000
+commit 8c7aa83346e18792d9a622c63c83cff81dcc144b
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Nov 13 15:12:48 2013 +0200
 
-    modules_k/outbound: tightened up error handling in decode_flow_token()
+    modules/dialog_ng: fixed double shm memory free
+    	- happens when calling get_dlg function from cfg file
 
-commit 680173cfc89bc051ce026ddf4a62dab494aa20a0
-Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
-Date:   Mon Dec 31 00:33:16 2012 +0100
+commit 1710c596b9a9383d2aa48d3432b6ada429981863
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Nov 13 10:38:17 2013 +0100
 
-    modules/sipcapture  README: added HEPv2/v3 to supported protocols
+    Makefile.defs: version set to 4.1.0-pre2
 
-commit 13889dfc3274f86352c719276b52fd8a458c243f
-Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
-Date:   Mon Dec 31 00:27:22 2012 +0100
+commit 644ffab0450d49aa36cfa803a41eff9db1ddb13a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Nov 13 10:37:17 2013 +0100
 
-    modules:siptrace changed include to hep.h
+    Makefile.defs: enabled memory debugging
+    
+    - to be kept for the rest of testing period to spot eventual buffer
+      overflows
 
-commit 6eda5e28355df2f1085f0ab9d303309965c4cd4f
-Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
-Date:   Mon Dec 31 00:21:02 2012 +0100
+commit 254d0c43a84ec87801e58b4f990a2029c0e27c6f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Nov 12 21:03:01 2013 +0100
 
-    Added HEPv3 (UDP) support for sipcapture.
+    tm: init sock_str to null value if no sock pointer is set in branch
     
-    Many many thanks Dragos Dinu for your help!
-    
-    Happy New Year! Glückliches neues Jahr! С Новым Годом! La Mulți Ani!
+    - case of creating branches from a 3xx reply
+    - reported by juliabo [at] gmail
+    - identation made coherent with tm module style
 
-commit bd26883f8cf782a09dd115389b1a5cc60fdd2f83
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 22:40:27 2012 +0200
+commit 5d80155a69f3c9865196e377ac0ecef16cd39cfe
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Tue Nov 12 17:28:51 2013 +0000
 
-    modules/registrar_pcscf: firs commit of registrar_pcscf module
-    	- registrar for P-CSCF functionality
+    memcached: add section ids in documentation
 
-commit d274ee387a3aa27be808b11b879311793f840a40
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 30 19:31:24 2012 +0000
+commit a65ee19108b1cdff31ec93b25020af0c9eab8080
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Tue Nov 12 17:28:15 2013 +0000
 
-    modules_k/rr: Fixed return from process_outbound()
+    dmq: add section ids in documentation
 
-commit 4bbd8718667d5fed76b7b97b3e915647cf80e611
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 30 19:27:24 2012 +0000
+commit 35ae624ba939b736bb2f52cd5fb4908deec0a133
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Nov 12 15:50:51 2013 +0100
 
-    modules_k/rr: added decoding and using of flow token to loose_route()
+    pua_reginfo: fixed typo related to module name in docs example
+    
+    - reported by Marius Pedersen
 
-commit 200082fd140bcebc7cdbf1d5511f51aa6e6f304e
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:39:58 2012 +0200
+commit a9fc979c839b44411e3c34076591c64c16d2fe87
+Author: Øyvind Kolbu <oyvind.kolbu at usit.uio.no>
+Date:   Tue Nov 12 15:47:30 2013 +0100
 
-    modules/registrar_scscf: first commit of registrar_scscf
-    	- Registrar functionality for S-CSCF servers
+    core: respect order field in NAPTR, as required by RFC 2915
+    
+    - the beaviour is controlled by core parameter dns_naptr_ignore_rfc
+    - default is 1, preserving current behaviouf to ignore rfc requirements
+      (for backward compatibility)
 
-commit 49ef3f0279491020a334d93aeb7c76e723305564
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:36:41 2012 +0200
+commit 96e021babe6da540ac8e47f35b30bb0fd7146245
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Mon Nov 11 12:40:05 2013 -0500
 
-    modules/isc: first commit of ISC module (IMS Service Control)
+    rtpproxy-ng: remove code artifact that broke IPv6 received-from addresses
 
-commit f08bc36d878529410dcfafa69753f80ade261f6f
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:34:44 2012 +0200
+commit 3bcf5579c8e47422378fcf6dfaa361e3fd126ce5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Nov 11 12:23:29 2013 +0100
 
-    modules/usrloc_scscf: first commit of usrloc_scscf modules
-    	- usrloc functionality for S-CSCF servers
+    ChangeLog: set the content with changes since branching for 4.0
 
-commit eda0f25661a153dde09c91a371cd7e02e18d7b26
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:33:00 2012 +0200
+commit 7436e3f66782597d66d052ee9c87bdb3b91756ef
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Nov 11 11:21:21 2013 +0100
 
-    modules/usrloc_pcscf: first commit of usrloc_pcscf module
+    kamctl: regenerated db schema scripts
+    
+    - updated after mohqueue default date change
 
-commit 5e844cf90c0d288a4038f5b2ff7cbebeab856488
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 30 18:31:07 2012 +0000
+commit 8ebd2350ef97c6bac856850a3230ed3e245bd3ed
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Nov 8 20:30:08 2013 +0000
 
-    modules_k/outbound: changed some errors to info
+    tls: TLSv1.1 supported since openssl v1.0.1
 
-commit 1ecbbbbe2c2ee63553b47316f454ede3633a2189
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:29:22 2012 +0200
+commit 55dd8073c7d06f3af37cded55e520e64457c2b42
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Nov 8 16:41:30 2013 +0100
 
-    modules/auth_ims: first commit of auth_ims module
-    	- This module provides IMS specific authentication/authorisation functionality.
+    rtpproxy-ng: ids to sections in documentation
 
-commit 29e841d41f57fa24d79fef10ff1e20943fa068ec
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:26:09 2012 +0200
+commit 4060340d3af8112ad73ea881ab79270c06544476
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Nov 8 16:32:35 2013 +0100
 
-    modules/icscf: added I-CSCF module.
+    debugger: ids to sections in documentation
 
-commit 651dafa718cb96c15781134ed280812c664bd9dc
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:19:10 2012 +0200
+commit 5f1d6744aa20dc5774c8403bf918a9543afe6c75
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Nov 8 16:28:19 2013 +0100
 
-    modules/dialog2: first version of dialog2
+    avp: ids to sections in documentation
 
-commit b4189892a8fb61670da8d8c6a4fb91110e889799
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Sun Dec 30 20:10:53 2012 +0200
+commit 3e6bef55f91206d7cf956a61e0b426bab5469e7b
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Nov 8 16:03:25 2013 +0100
 
-    lib/ims: added some info to README on IMS library
+    avpops: ids to sections in documentation
 
-commit acc9e5a3dde72aedbb1eeba561987c5faf80800f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 30 17:56:55 2012 +0000
+commit 0e676d0062d7db0875ccc97053304807cbc5747e
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Nov 8 15:56:33 2013 +0100
 
-    modules_k/rr: add flow token to Record-Route: headers when needed
+    usrloc: ids to sections in documentation
 
-commit d55cce8e5f2558560bf38a8ff25ddbb80f697284
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 30 17:40:08 2012 +0000
+commit a88f9d4b79a40221e058c31bbdd21c8c25ba5003
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Nov 8 15:21:58 2013 +0100
 
-    modules_k/rr: do not double RR when outbound is in use for a request
+    app_lua: ids to sections in documentation
 
-commit b4f41ed842766e047d286da1ceefb783f6791a5b
-Author: root <root at jaybeepee-HP-EliteBook-8560w.(none)>
-Date:   Sun Dec 30 19:38:57 2012 +0200
+commit ae0e9eef521fa39ae306a2c64e4add61d5e8af6f
+Author: Robert Boisvert <rdboisvert at gmail.com>
+Date:   Wed Nov 6 14:12:10 2013 -0500
 
-    IMS Internal Lib: added internal kamailio library for IMS extensions
+    mohqueue: remove call from queue if caller does not exist
 
-commit 7c79ef5875787a1c05d263a83c803299489308fd
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 30 17:20:52 2012 +0000
+commit 456c387e08ce40ea2c0f1e5e5f94b367ff9fa361
+Author: Robert Boisvert <rdboisvert at gmail.com>
+Date:   Tue Oct 29 18:10:25 2013 -0400
 
-    modules_k/rr: bind rr to outbound module
+    mohqueue: remove sql table call_time column's default value
+    
+    it is not supported in some database properly, and it is not
+    really needed.
 
-commit 724847a226cd3a5e8c2aa766a17890f06d30d6ce
-Merge: 3efe73d 3d2c78d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 30 17:08:43 2012 +0000
+commit 04b457735f0bafa6ff214cb2d69afbe721d89bf1
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Nov 7 14:52:29 2013 -0500
 
-    Merge branch 'master' into outbound
+    modules/sca: restore correct check for NULL in SCA_CALL_INFO_EMPTY.
     
-    * master:
-      uid_gflags: default table for global attrs prefixed with uid_
-      libsrdb1/kamctl: added uid_global_attrs table
-      libsrdb1/kamctl: added uid_domain and uid_domain_attrs tables
-      srdb1/kamctl: added uid_uri and uid_uri_attrs tables
-      uid_avp_db: default table name prefixed with uid_
-      srdb1/kamctl: added definition of table uid_user_attrs
-      libsrdb1/kamctl: added definition of uid_credentials table
+    - should also suppress -Waddress error without relying on gcc _Pragma.
 
-commit 3d2c78df699a047d97f016a14c275c5559553fe5
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 16:42:09 2012 +0100
+commit 0fbdb8cf7a7687d6ecc8049dfdcb1244abd726af
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Nov 6 10:34:01 2013 +0000
 
-    uid_gflags: default table for global attrs prefixed with uid_
+    tls: Fix minor typo in documentation
 
-commit e5831f5896e79ad5b878208a408d61fb374f2715
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 16:39:29 2012 +0100
+commit fe914e16945caf6c5c11b81514dff89a0739b30e
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Wed Nov 6 09:14:45 2013 +0200
 
-    libsrdb1/kamctl: added uid_global_attrs table
+    modules/dialog_ng: Fix "CRITICAL bogus event 6 in state 2" problem
+    	Use TM callback TMCB_RESPONSE_READY instead of TMCB_RESPONSE_OUT to prevent race condition resulting in bogus event
 
-commit 5eaaaf9827bb951add1f45bc5d635a4889954f73
+commit cb66f43187ea3bcac36681b82630456deeabc64c
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 16:29:17 2012 +0100
+Date:   Tue Nov 5 15:10:29 2013 +0100
 
-    libsrdb1/kamctl: added uid_domain and uid_domain_attrs tables
+    kamctl: added shortcuts for dialog mi commands
 
-commit 907e13b7080c3ecbbbf8fa35c1adb4b3d9137ff5
+commit 082a6c43938cf8e3839d46fd070e391bd522d4ed
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 16:15:07 2012 +0100
+Date:   Tue Nov 5 10:33:55 2013 +0100
 
-    srdb1/kamctl: added uid_uri and uid_uri_attrs tables
+    dialog: init cseq to 0 if not available yet for one side
+    
+    - based on a report by Morten Isaksen
 
-commit c8b3aa436455314cc5b5591224cc2336c3060d9c
+commit 8d6a981543a044fddc3448c93dba9ed35afac0c0
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 16:00:27 2012 +0100
+Date:   Tue Nov 5 10:15:13 2013 +0100
 
-    uid_avp_db: default table name prefixed with uid_
+    pua_dialoginfo: fixed code formatting
+    
+    - patch by  Kristian Høgh, FS#360
 
-commit 4d060c204cb5d526b3e05d50131a725d2f931b39
+commit d48d36df40dee374e63ef9b6a6c1bafc4af0e8b0
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 15:58:06 2012 +0100
+Date:   Tue Nov 5 09:41:04 2013 +0100
 
-    srdb1/kamctl: added definition of table uid_user_attrs
+    dispatcher: typo and ids to sections in documentation
 
-commit 008f9242fd996d3c853b6844fa724473c4ffd4d9
+commit f33076415561d3efbfa9d804d00a4b0784898f50
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 15:36:51 2012 +0100
+Date:   Mon Nov 4 21:46:34 2013 +0100
 
-    libsrdb1/kamctl: added definition of uid_credentials table
-
-commit 3efe73dc002b4e02147a2f950c3058998f658a23
-Merge: 8f0ab91 8c512a5
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Dec 29 01:22:27 2012 +0000
-
-    Merge branch 'master' into outbound
+    sl: fix startup detection of event route
     
-    * master:
-      modules_s/usrloc: moved to obsolete folder
-      modules_s/registrar: moved to obsolete folder
-      modules_s/.gitkeep: added a placeholder to keep empty modules_s folder for a while
-      Makefile: make TAGS skips the obsolete folder
-      usrloc(k): fixed position of xavp_contact parameter in docs
-      usrloc: store per-contact attributes in database
-      core: fixed xavp level cloning function
-      core: added a fuction that adds an xavp with an xavp value
-      kamctl: regenerated database creation scripts
-      lib/srdb1: added location_attrs table
+    - patch by Sergey Okhapkin
 
-commit 8c512a504402594c3d78da8e3ebdbe05e7561a2f
+commit 90227fbf44ddc67bfb49f8f7e8fd7e1b33189349
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 00:19:53 2012 +0100
+Date:   Mon Nov 4 14:26:19 2013 +0100
 
-    modules_s/usrloc: moved to obsolete folder
+    presence_dialoginfo: check relevance of the state for single dialog notification
     
-    - use instead the other module with same name
+    - rework from a patch in tracker, FS#341
 
-commit f39b8bd436571b7f3ac40740a4a938739f9c6ad9
+commit 27a73a806cece55bc7c707735856770137c2d680
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 00:18:25 2012 +0100
+Date:   Mon Nov 4 11:21:27 2013 +0100
 
-    modules_s/registrar: moved to obsolete folder
-    
-    - use instead the other module with same name
+    Makefile.defs: version set to 4.1.0-pre1
 
-commit 96efc37844a8c128d520b9873aacb3633231e33f
+commit 8a246b06838b99e63d86fe186b23a23f57347548
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 00:17:10 2012 +0100
+Date:   Mon Nov 4 10:04:35 2013 +0100
 
-    modules_s/.gitkeep: added a placeholder to keep empty modules_s folder for a while
+    pua_reginfo: reflect use domain from usrloc
     
-    - it may be useful if some modules from obsolete folder are wanted back
-      (in the repo, or just locally)
+    - avoid duplicate contacts if domain is not considered
+    - patch by  Wonbin Cho, FS#350
 
-commit 8d5f8bbc2edaee9ccbe935d5f44fe4601281f060
+commit 16649609796ec336278b073d86045f72a9dd7886
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 29 00:09:47 2012 +0100
+Date:   Sun Nov 3 13:23:32 2013 +0100
 
-    Makefile: make TAGS skips the obsolete folder
-    
-    - use make TAGS-ALL to include all the folders
+    tls: ifdef to use TLSv1.1 only for openssl/libssl v1.0.0+
 
-commit 27570b56727e788da939fedc84304cf87fc1e179
+commit f4bf810a5af5b2d133df30e625691cc7b6ad2cf5
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 28 22:25:29 2012 +0100
+Date:   Sun Nov 3 13:15:31 2013 +0100
 
-    usrloc(k): fixed position of xavp_contact parameter in docs
+    tls: refreshed the README
 
-commit 5463e46f9c3fa2e3aa8345eceb79936de63b7222
+commit 1e2bb79a135bef9936fb5d5e0fb9a708589452b9
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 28 22:20:15 2012 +0100
+Date:   Sun Nov 3 13:14:31 2013 +0100
 
-    usrloc: store per-contact attributes in database
-    
-    - attributes table is the name of table used for save/lookup plus suffix
-      '_attrs' (e.g., location_attrs)
-    - feature enable only if xavp_contact parameter is set
+    tls: listed TLSv1.1 and TLSv1.2 as values for tls_method parameter
 
-commit 88dd1f30481d088b56a97a6fbb84a88f94261eb9
+commit ea32bf9d3cf36c3562ca34d572bbf07ed144e105
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 28 22:17:03 2012 +0100
+Date:   Sun Nov 3 12:55:08 2013 +0100
 
-    core: fixed xavp level cloning function
+    tls: extended supportd tls methods
     
-    - new function introduced recently for usrloc usage
+    - TLSv1.1 and TLSv1.2 (from openssl 1.0.1e on) added to the internal
+      list
 
-commit aea4043106b7b3e44529385293616b7af640c892
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 28 19:21:28 2012 +0100
+commit 26fa46a421e0bb5e00e32115b610100481e64e6d
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Sat Nov 2 21:45:04 2013 +0000
 
-    core: added a fuction that adds an xavp with an xavp value
+    pkg/kamailio/centos: Improvement to the CentOS init.d script
 
-commit f636e215089a9b14daa113d93025831e827192b5
+commit 039f52deb384c71ecfb578e2cd648153dd9937d1
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 28 19:18:09 2012 +0100
+Date:   Sat Nov 2 19:28:36 2013 +0100
 
-    kamctl: regenerated database creation scripts
-    
-    - target on location_attrs table
-    - affected xhttp_pi and sca
+    tls: include dprint.h where log functions are used
+
+commit 25ee7ea17b6553ce44eda6c0665ff80cfc41db35
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri Nov 1 21:27:31 2013 +0200
+
+    modules/mtree: added 'multi' param to mtree definition
+    - new 'multi' param makes it possible to store both integer and string
+      typed mtrees into single db table
+
+commit 66185905850cd2ac9ab933776184da0f0882e5ac
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Nov 1 15:33:08 2013 +0100
+
+    registrar: clean static values at pack_ci
+
+commit f67171cf3be1ade0e1c9dd013d560c87b3fd4359
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu Oct 10 15:21:47 2013 +0200
+
+    usrloc: db_update contact by instance + reg-id
 
-commit 060734a2acf96333ffaef8207812cc27bc127c76
+commit bc66a385e8a282638c8d5cfa566f971c62cd341b
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 28 14:55:35 2012 +0100
+Date:   Fri Nov 1 09:39:32 2013 +0100
 
-    lib/srdb1: added location_attrs table
+    uac: reset registration authentication flag
     
-    - store per contact attributes
+    - reported by  rene montilva (fs#352)
 
-commit 8f0ab9130af20ed1709b03fff8e831695cbdc64f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Dec 28 08:03:50 2012 +0000
+commit 1cc0144e434fdcf76013e9424d31928c260d4377
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Oct 30 22:11:04 2013 +0100
 
-    modules_k/path: only add ";ob" parameter when it is the the first hop
+    kamctl: updated dispatcher command to current db table fields
+    
+    - parameters flags, priority, attrs and description are optional
 
-commit 7fce787c316de12fd3294ca2a70d79d71ff2ad1b
-Merge: 11b7630 b2e5040
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 26 14:25:44 2012 +0000
+commit bfc2215d71734b09a1d7acd4dbdbe919b234c30f
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Oct 30 20:49:26 2013 +0200
 
-    Merge branch 'master' into outbound
+    Revert "modules/mtree: when loading data from db, load each tree separately"
     
-    * master:
-      core: check for IP in no_naptr_srv_sip_resolvehost()
-      core: try all srv protocols when not already set
-      registrar(k): restore the location contact xavp upon lookup
-      usrloc(k): option to store xavp per contact
-      core: extended xavp api
-      registrar(k): use only pre-existing branches in lookup_branches()
-      p_usrloc: clean memory in case of malloc error
-      Revert "Changing to kamcmd"
-      kamcmd changes
-      Changing to kamcmd
-      kamcmd Updating docs
-      Change "sercmd" to "kamcmd" in module documentation files - README
-      kamctl Fix typo that causes the "trusted" help to be printed twice and "address" zero times
-      kamctl Change "sercmd" to "kamcmd" in help texts
-      Fixing compiler warnings
+    This reverts commit 6fc84c2cf610791939ba73e38b8b5b3c0b5cd047.
 
-commit 11b7630b3f3423dd5697b9c1938f34ee851d325e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 26 14:24:58 2012 +0000
+commit 6fc84c2cf610791939ba73e38b8b5b3c0b5cd047
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Oct 30 17:31:04 2013 +0200
 
-    modules_k/path: Updated module documentation for outbound
+    modules/mtree: when loading data from db, load each tree separately
 
-commit b27311b5ecc189b8324075a3387382c144ad438b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 26 14:15:48 2012 +0000
+commit f0751ffa2d1d99c0a54707cfe22926bea9c07123
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Oct 30 17:12:05 2013 +0000
 
-    modules_k/path: Added outbound support to add_path()
+    modules/rls: Fix memory leak in rls
+    - Leak would occur in two error cases
+    - Also improved diagnostics to display uri on various failures
 
-commit a1501f0b44975057e752d0337fb074ed53fd6a54
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 26 14:15:18 2012 +0000
+commit 76536ec5332d7897cd4259b271508cc9d4e2bc2e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Oct 30 16:08:47 2013 +0100
 
-    modules_k/outbound: Added some includes to api.h
+    kamailio.cfg: removed modules_k from path for modules
 
-commit b2e5040fa324fa8c95c5b44a5fcab58ed84a4c55
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 26 12:32:00 2012 +0100
+commit 328350a0d718990f8a87f25f8c12f1c85d61220f
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Wed Oct 30 12:50:04 2013 +0200
 
-    core: check for IP in no_naptr_srv_sip_resolvehost()
-    
-    - catch IP addresses before attempting to do SRV query
+    modules/ims_charging: fixed failed reservation bug
+    	- Reservation checks dialog integrity with h_entry < 0
+    	- The hash that creates h_entry can return 0 - this check should be <= 0
 
-commit 17b3c70ea9cd21b71b44062dfff20cea7e67b349
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 26 11:20:46 2012 +0100
+commit a7037aad9963678347bf2b1c15c4994e95570f86
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Wed Oct 30 12:49:26 2013 +0200
 
-    core: try all srv protocols when not already set
-    
-    - patch to commit by Mihály Mészáros
+    modules/ims_charging: code clean up, removed duplicate timer init and dlg bind
 
-commit b21b5125c7c60775226a7a86dc411863477ed799
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Dec 24 10:04:15 2012 +0100
+commit a3db949272db7dbda4fa5fd1ad68d23d56deacc0
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Wed Oct 30 09:15:51 2013 +0200
 
-    registrar(k): restore the location contact xavp upon lookup
+    modules/tm: code cleanup removed unused method faked_resp and free_faked_resp
 
-commit e6ad428f6699621b7ee622984eeea3e3e2f6cb80
+commit 15a14440f07f787501e116ab4901ab5a53668f4a
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Dec 24 10:03:10 2012 +0100
+Date:   Tue Oct 29 22:00:18 2013 +0100
 
-    usrloc(k): option to store xavp per contact
-    
-    - stored only in memory for the moment
-    - the xavp can contain a list of xavps
-    - new config parameter to specify the name of xavp
+    kamctl: added new db tables in kamdbctl lists
 
-commit 6f31c603d1e540b1cd7ca7e81648e024acbd1388
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Dec 24 10:02:01 2012 +0100
+commit 2e033c85d2c66c47de15f355298012f012adb15c
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Tue Oct 29 15:30:36 2013 -0400
 
-    core: extended xavp api
+    rtpproxy-ng: fix extraction of multipart SDP body
     
-    - functions to add an avp last in a list or inserted at a specific
-      position, to extract an avp from top of the list
+    reported by: Jasmin Schnatterbeck
 
-commit be0f77ec7fa86f9387393609fbdffafd65a1afe3
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Dec 23 19:32:03 2012 +0100
+commit 355ab783a99e413eb96a385ab067336316aaafda
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Oct 29 12:40:42 2013 +0200
 
-    registrar(k): use only pre-existing branches in lookup_branches()
+    modules/cdp/acctstatemachine.c: fixed incorrect reservation expiry warning
+    	First check if acc state is OPEN before sending reservation expiry warning
 
-commit c50a8ba36aee8ae53d66a8128300085934d1a3f0
+commit c4a4b4f599ba428330899e804877e85d3fdcc3a4
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Dec 23 17:19:21 2012 +0100
+Date:   Tue Oct 29 11:08:49 2013 +0100
 
-    p_usrloc: clean memory in case of malloc error
+    kamctl: updated db creation scripts
 
-commit 7f7605bd38f76ab9adf1335b4a1de6fa40708486
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 16:26:16 2012 +0100
+commit ecc6e35b31d59e6e9995a03c6ab00f21a23b1be9
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Oct 29 11:07:03 2013 +0100
 
-    Revert "Changing to kamcmd"
+    srdb1: drop unique constrant on alias user+domain in dbaliases
     
-    This reverts commit 90432f0e672c5fb11b1e47b9655768bf20e45b89.
+    - it doesn't work for multiple branches when use_domain is set, reported
+      by Vassilis Radis
 
-commit 5c4bb10fc7a534b92b0dcd9c229ea1392da34cee
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 10:22:56 2012 +0100
+commit da3d48de7d52df83fcb568530441e7ac6475baae
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Oct 29 10:08:04 2013 +0100
 
-    kamcmd changes
+    pua_publish: more verbose output for error case when sending publish
 
-commit 90432f0e672c5fb11b1e47b9655768bf20e45b89
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 10:22:19 2012 +0100
+commit 73d509f04029dddc94bedba23460d43c81acc13a
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Oct 29 10:51:32 2013 +0200
 
-    Changing to kamcmd
+    modules/ims_registrar_pcscf: replaced incorrect LM_ERR with LM_DBG
 
-commit 9b745fbb0a065cf30b8069e950b4e6e9f2d8b20c
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 10:17:36 2012 +0100
+commit 41a9fbf38ba84e542a546893a6ce9c48f14f3aa3
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Oct 29 10:31:52 2013 +0200
 
-    kamcmd Updating docs
+    modules/tm: fixed placement of variable declarations to top of scope block
 
-commit 922e7f4a9a56b4c02b5fedb93bd3684b2c410881
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 09:31:28 2012 +0100
+commit 716932aa77a0f22f00d2ccee8a89cd84b6674f0a
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Oct 29 09:49:42 2013 +0200
 
-    Change "sercmd" to "kamcmd" in module documentation files - README
+    modules/tm: cosmetic fixes and comment fixes
 
-commit 334b6e7a2c0804a7ee4ce30761fc911a31682876
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 09:05:50 2012 +0100
+commit a7d9ea3ceda6b933807f0345e327849e60d0fa57
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Oct 29 09:42:45 2013 +0200
 
-    kamctl Fix typo that causes the "trusted" help to be printed twice and "address" zero times
+    modules/tm: last pkg_mem leak resolved for async replies (nonshm lumps)
 
-commit 3eeaa5af9107f3795aee714ac47380cfb2ef45c3
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 09:01:01 2012 +0100
+commit 3022220043bcc9c421ac175b2a3290950014a7fc
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Oct 29 08:34:29 2013 +0100
 
-    kamctl Change "sercmd" to "kamcmd" in help texts
+    kamctl: regenerated db script for mohqueue tables
 
-commit 95805adb74fbc17fe38f89bf9ec8dd57f31e9d91
-Merge: 35683cf 9b2cb40
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 08:49:50 2012 +0100
+commit 3eeeed2aeeb924afeabc3fc8337561624f0c41d0
+Merge: 946e1f0 b5638f7
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Mon Oct 28 15:03:08 2013 +0200
 
     Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    Do not read this message. It's not needed. Just a stupid swede making mistakes.
-    Do not read this message. It's not needed. Just a stupid swede making mistakes.
-    Do not read this message. It's not needed. Just a stupid swede making mistakes.
-    Do not read this message. It's not needed. Just a stupid swede making mistakes.
-    
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      modules_s/permissions: moved to obsolete folder
-      modules_s/textops: moved to obsolete folder
-      textopsx: added functions that operate on header value
-      modules_k/domain: bind_domain api function takes one param
-      modules_k/htable: removed unused variable
-      nathelper(k): new test 128 to check port in contact against source port
-      modules_s/nathelper: moved to obsolete folder
-      nathelper(k): added the select for rewriting the contact
-      core: proper pv buffer reinitialization
-      dialog(k): Reworked dlg_set_timeout_by_profile() code to change dialog timeouts outside of a profile lock.
-      modules/app_lua: Updated app_lua to support URI lookup in registrar
-      modules_k/registrar: Extended C-API to include a URI lookup
-      pkg/kamailio/(centos|fedora): Added more modules moved from modules_s to modules to the build
-
-commit 35683cfb90e68719205bef377a8bedad3e633f9d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 23 08:49:23 2012 +0100
 
-    Fixing compiler warnings
-
-commit b6b3acf9e2cf3283684773df325eb8ac6d2226c3
-Merge: 0c3d25f 9b2cb40
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Dec 22 17:03:25 2012 +0000
+commit 946e1f01889c67a835583f4df2c773d227693ea7
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Mon Oct 28 14:51:12 2013 +0200
 
-    Merge branch 'master' into outbound
-    
-    * master:
-      modules_s/permissions: moved to obsolete folder
-      modules_s/textops: moved to obsolete folder
-      textopsx: added functions that operate on header value
+    modules/tm: fixed pkg memory leak in TM which happens in async reply processing
 
-commit 0c3d25f4fba43ee66a6f1edf88b1abfde97668c8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Dec 22 17:02:01 2012 +0000
+commit b5638f712711deb8413d7e585369adf8f4a421ee
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Mon Oct 28 14:41:22 2013 +0200
 
-    modules_k/outbound: Improved flow token encode/decode.  Now should work properly with IPv4 and IPv6
+    modules/ims_qos: memory optimisation
+    	Fixed pkg memory allocation for framed IP AVP and flow buffer AVP
+    	Instead of repeatedly alloc'ing and free'ing pkg memory we allocate once and re-use
+    	Results in better pkg memory overhead
 
-commit 9b2cb40fdb0660b61e9d9bb2086100c54ac7066e
+commit 3856e9e81c8410b220b893a0dfe7114bba6bdc0d
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 22 14:29:55 2012 +0100
+Date:   Sun Oct 27 16:59:32 2013 +0100
 
-    modules_s/permissions: moved to obsolete folder
+    core: handle pv comparison with $null as when defined is used
     
-    - use the other module with same name
+    - reported by Victor Seva, closes FS#358
 
-commit 29b41dfd405f5e7de607b97d14f9481d4d91babb
+commit 3d716a94b620e0115381b164595ef0398c816856
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 22 14:28:23 2012 +0100
+Date:   Sat Oct 26 08:59:09 2013 +0200
 
-    modules_s/textops: moved to obsolete folder
+    kamctl: use a variable to set the now() function or a replacement for it
     
-    - use the other textops module or textopsx
-    - use config variable format ($varname(x)), instead of former xlog style
-      with %
-
-commit ba6119e3b4d84d8ba656c2a44fdafe3a2c31595f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 22 14:26:18 2012 +0100
+    - sqlite uses instead the string returned by 'date' call, as it doesn't
+      have now()
+    - reported by Peter Dunkley, FS#356
 
-    textopsx: added functions that operate on header value
-    
-    - imported from modules_s/texops and replaced the xlog-% style with
-      pvar-$ style
+commit 2a046e5fd3c47bc7753190425b911b4114667563
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Oct 24 20:44:03 2013 +0100
 
-commit 1db38af24d8808a9a2045c7bac25581199717a2b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Dec 22 13:07:58 2012 +0000
+    pkg/kamailio/centos: added app_java to CentOS RPMs
 
-    modules_k/outbound: Filled in functions to encode and decode flow tokens
+commit 9c765e89ea7647b1e9c5e36eb0b324eec1d92b7d
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Oct 24 20:13:11 2013 +0100
 
-commit 83d07c9a0f883ba08f863103127b96893d1bc92b
-Merge: 68e07fa 1a09692
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Dec 22 11:04:04 2012 +0000
+    modules/app_java: updated Makefile so that it builds on CentOS 6
 
-    Merge branch 'master' into outbound
-    
-    * master:
-      modules_k/domain: bind_domain api function takes one param
-      modules_k/htable: removed unused variable
-      nathelper(k): new test 128 to check port in contact against source port
-      modules_s/nathelper: moved to obsolete folder
-      nathelper(k): added the select for rewriting the contact
-      core: proper pv buffer reinitialization
-      dialog(k): Reworked dlg_set_timeout_by_profile() code to change dialog timeouts outside of a profile lock.
-
-commit 1a09692be74ef8c4f0dc56801bce6a2fb351536d
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Dec 22 12:26:29 2012 +0200
+commit 9a67a730df4f6c6584e8c52934d5feb16f86ee2e
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Thu Oct 24 12:34:05 2013 -0400
 
-    modules_k/domain: bind_domain api function takes one param
+    tm: fix possible segfault in cancel_branch()
 
-commit a60a7ca8010a66703a90768b42ae16342c50107d
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Dec 22 11:33:13 2012 +0200
+commit 9ca1648fbf167748bcf9155794f703632ca87503
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Thu Oct 24 16:36:01 2013 +0100
 
-    modules_k/htable: removed unused variable
+    htable: ht_dmq_handle_msg() - do not call parse_headers on cloned message
 
-commit bf3acaf0895d900c15e3455cba225226f3debf62
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 22 09:42:35 2012 +0100
+commit 2c990487a780bce2ee2fe64e155ec3f1bc1bdebf
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Thu Oct 24 16:15:10 2013 +0100
 
-    nathelper(k): new test 128 to check port in contact against source port
-    
-    - used for nat_uac_test()
-    - imported from ser flavour
+    memcached: revert earlier doc change regarding minimum library version (we now have backward compatibility built in)
 
-commit f7ef4b3d54dd462648330dfa4522d067376178ce
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 22 09:28:18 2012 +0100
+commit fc4f2216f867b00a6685abdf51b8165572f24f69
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Thu Oct 24 11:05:17 2013 -0300
 
-    modules_s/nathelper: moved to obsolete folder
-    
-    - use the other module with same name
-    - pings from config can be done with uac module, uac_req_send()
+    ims_charging: fixed deadlock when interim CCA timeout occurs
 
-commit b2ef844bfdcce46d6a1b88f60ff2fe4d1de30855
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 22 09:24:11 2012 +0100
+commit b0797b765af78f19d942a87ea978037027da57c3
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Oct 24 13:10:08 2013 +0100
 
-    nathelper(k): added the select for rewriting the contact
+    pkg/kamailio/centos: added memcached package to .spec
     
-    - exsting in the ser flavour version
+    - Also:
+      - updated README to remove memcached from list of unbuilt modules
+      - moved auth_identity into the tls package
+    - List of modules not built for CentOS is now:
+      - app_java: should be buildable but Makefile needs work
+      - app_mono: needs newer version of mono-devel than available in base or EPEL
+      - db_cassandra: needs specific versions of thrift (thrift not in base or EPEL
+        at all anyway)
+      - db_oracle: requires non-free Oracle client SDK
+      - iptrtpproxy: obsolete
+      - jabber: obsolete
+      - osp: requires OSP Toolkit which is not available in base or EPEL
 
-commit d52371ec0a6ce6f1fff4f4fc91df3a89e5983228
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Dec 22 08:32:31 2012 +0100
+commit adfa299a1a01aba1c69c1129d78170056d50db42
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Thu Oct 24 12:14:38 2013 +0100
 
-    core: proper pv buffer reinitialization
-    
-    - reported by Olle Johansson, FS#259
+    memcached: added alternate memory management wrappers for backwards compatibility with older libmemcached versions and added preprocessor check for the correct ones to use based on installed version.
 
-commit c9957ad5bf1b672a2661f4faeb9b781820a1f636
-Author: Alex Balashov <abalashov at evaristesys.com>
-Date:   Fri Dec 21 21:08:39 2012 -0500
+commit a067a3d33ad67c260a3bc377cd4203d41880ca6b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Oct 24 07:44:03 2013 +0200
 
-    dialog(k): Reworked dlg_set_timeout_by_profile() code to change dialog
-    timeouts outside of a profile lock.
+    tm: use internal flags field to mark suspended replies with FL_RPL_SUSPENDED
     
-    This is in order to avoid deadlock complications arising from lock/ref
-    count operations upstream.  It appears that when update_dlg_timer()
-    fails, it does not relinquish control back to the calling function, which
-    created problems with unreleased profile locks.
+    - it was set on cfg flags, resulting in messing up with what was used in
+      config file
+    - reported by Juha Heinanen
 
-commit 68e07faf94e6aa8664f3d7116026d136062136b1
+commit 6b8b8a050e4490302d1f1f940a7fda95784cce46
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Dec 21 23:38:28 2012 +0000
+Date:   Wed Oct 23 14:53:04 2013 +0100
 
-    modules_k/outbound: Removed nat_test from here
+    modules/xcap_server: fixed fetching of an element (GET with XPath)
     
-    - Will just use the one from nathelper when required.
+    - This is a mandatory part of XCAP and DELETE/PUT of elements (using XPath)
+      is supported in xcap_server.
+    - The code to get a node from a document was all in there but never called.
 
-commit 064120b137e05e3799399664dbc48d0d1d5ba01b
-Merge: 7b31e98 72bee68
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Dec 21 23:34:35 2012 +0000
+commit 3b028d308fac3a4f7ae1e74021882657753f2ee8
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Wed Oct 23 12:01:27 2013 +0100
 
-    Merge branch 'master' into outbound
-    
-    * master: (592 commits)
-      modules/app_lua: Updated app_lua to support URI lookup in registrar
-      modules_k/registrar: Extended C-API to include a URI lookup
-      pkg/kamailio/(centos|fedora): Added more modules moved from modules_s to modules to the build
-      db_text More instructive error message
-      modules_s/maxfwd: moved to obsolete folder
-      maxfwd(k): max_limit module param can be changed at runtime
-      uid_avp_db: fixed include from uid_domain module
-      app_python: fixed complilation warnings [-Wformat]
-      modules_s/uid_uri_db: moved to modules folder
-      modules_s/uid_domain: moved to modules folder
-      modules_s/uid_gflags: moved to modules folder
-      modules_s/uid_avp_db: moved to modules folder
-      modules_s/uid_auth_db: moved to modules folder
-      modules_s/pike: moved to obsolete folder
-      modules_s/uri_db: renamed to uid_uri_db
-      modules_s/gflags: renamed to uid_gflags
-      modules_s/domain: renamed to uid_domain
-      uid_auth_db: updated doc file to the new name
-      modules_s/avp_db: renamed to uid_avp_db
-      modues_s/auth_db: renamed to uid_auth_db
-      ...
-    
-    Conflicts:
-    	modules_k/nathelper/nathelper.c
-    	pkg/kamailio/centos/6/kamailio-build.appl
-    	pkg/kamailio/centos/6/kamailio.appl
-    	pkg/kamailio/fedora/16/kamailio-build.appl
-    	pkg/kamailio/fedora/16/kamailio.appl
-    	pkg/kamailio/fedora/16/kamailio.spec
-    	pkg/kamailio/fedora/17/kamailio-build.appl
-    	pkg/kamailio/fedora/17/kamailio.appl
+    dmq: Fixed bug/error in original code where sip_msg was parsed after cloning to shm, leading to memory errors. Also fixed several memory leaks.
 
-commit 72bee685f57ccd0637e1bc97093c9e5731c2d40f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Dec 21 23:10:05 2012 +0000
+commit eb97ddb20368c019b331cfd09e793a0431d49940
+Merge: f6d530e 58a3069
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Oct 22 20:59:26 2013 +0200
 
-    modules/app_lua: Updated app_lua to support URI lookup in registrar
-    
-    - Enhancement added by Hugh Waite @ Crocodile RCS
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
 
-commit 18a4a8a33939edc6e5d74fdc21c33d9835a62f61
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Dec 21 23:09:23 2012 +0000
+commit f6d530e68ffe9db11f5f148c51f8bff0b542f028
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Oct 22 20:57:52 2013 +0200
 
-    modules_k/registrar: Extended C-API to include a URI lookup
-    
-    - Enhancement added by Hugh Waite @ Crocodile RCS
+    modules/cdp: allow CDP child processes to respond to dynamic cfg changes
+    	- this for example allows dumping pkg memory using core cfg variables similar to SIP workers, etc
 
-commit 8030130f6b5819804dbe4d563abe197e13d1a54f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Dec 21 22:52:55 2012 +0000
+commit 58a3069927a2e37c327256cd3475d7a7f8a2f5c4
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Tue Oct 22 11:08:08 2013 +0100
 
-    pkg/kamailio/(centos|fedora): Added more modules moved from modules_s to modules to the build
+    pkg/kamailio/centos: updated README to remove mi_xmlrpc from the set of unbuilt modules
 
-commit 242527fe5b94902ed4e20adad054c16f1732d9fd
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Dec 21 23:11:40 2012 +0100
+commit d79cffa79ab740bc3e724fc0e9b8fc9f7236af44
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Tue Oct 22 11:07:40 2013 +0100
 
-    db_text More instructive error message
+    pkg/kamailio/centos: updated .spec to add mi_xmlrpc to xmlrpc package
 
-commit 3852f46576eab51198ebd089e555bf67d3b46eb0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 22:49:08 2012 +0100
+commit 05f0ed6d77602f3ee1a2cfc8cee1c760dc2f6800
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Tue Oct 22 10:45:56 2013 +0100
 
-    modules_s/maxfwd: moved to obsolete folder
+    modules/mi_xmlrpc: fixed compilation warning
 
-commit 9a9cbdc8257e1782f74aa393d7c0b2f4d7888f98
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 22:43:54 2012 +0100
+commit b3dedff1053a1d35e803f3824042732f07532b77
+Author: Muhammad Shahzad <shaheryarkh at gmail.com>
+Date:   Tue Oct 22 10:43:43 2013 +0100
 
-    maxfwd(k): max_limit module param can be changed at runtime
+    modules/mi_xmlrpc: patched so that it now builds for CentOS
     
-    - changed to use cfg param reload framework
-    - added aliases to existing functions to make them compatible with ser
-      flavour
-    - config functions can take variables as parameters
-
-commit 5374337d3b3504247b5846a37c998a4f1c61d4d8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 22:43:14 2012 +0100
-
-    uid_avp_db: fixed include from uid_domain module
+    - Patch by Muhammad Shahzad <shaheryarkh at gmail.com>
+    - Committed by Peter Dunkley <peter.dunkley at crocodile-rcs.com>
 
-commit 221da0463d31534c0103dc87931324ae0b3acc72
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Fri Dec 21 22:21:42 2012 +0200
+commit 11abcfd96f30aa5f0032385ac5893c27bdf6315b
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Mon Oct 21 14:40:10 2013 +0100
 
-    app_python: fixed complilation warnings [-Wformat]
+    memcached: added minimum libmemcached version required to documentation
 
-commit 9b5c2fec96a37069af9ede4ddc30e6303c1113a2
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 20:52:03 2012 +0100
+commit 4bffd1950e4481a734141ae6cf755458f341f45b
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Mon Oct 21 13:40:46 2013 +0100
+
+    pkg/kamailio/centos: updated README that explains which modules are not built for CentOS
+    
+    - The modules not built at this time are:
+      - app_java
+      - app_mono
+      - db_cassandra
+      - db_oracle
+      - iptrtpproxy
+      - jabber
+      - memcached
+      - mi_xmlrpc
+      - osp
+
+commit e3524fb816c1fad04b3c855e3fe88151b33e24c8
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Mon Oct 21 13:37:45 2013 +0100
+
+    pkg/kamailio/centos: updated .spec to build packages with dependencies that can be met by EPEL
+    
+    - This means the computer building the RPMs needs to have access to EPEL and
+      the appropriate dependencies installed from it.  However, there will be
+      no need to have EPEL dependencies installed on a running instance _unless_
+      you want to use one of the modules with an EPEL dependency.
+    - The modules supported with EPEL are:
+      - acc_radius, auth_radius, misc_radius, peering
+      - carrierroute
+      - dnssec
+      - geoip
+      - json, jsonrpc-c
+      - ndb_redis
+
+commit 9f08b58f58585559646b470ae9f4b9801617ba73
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Sun Oct 20 23:52:23 2013 +0100
 
-    modules_s/uid_uri_db: moved to modules folder
+    pkg/kamailio/centos: updated rel in .spec
 
-commit 3f535ff25cb67ef4f0f12ca1d8230fadaa3a832e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 20:51:33 2012 +0100
+commit ce9f46a3778cd6c79f2411b5934e3ad320cf6de4
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Sun Oct 20 23:46:35 2013 +0100
 
-    modules_s/uid_domain: moved to modules folder
+    pkg/kamailio/centos: removed out-of-date BoxGrinder appliance files
 
-commit 9f6d4d0797074ec37a629af974df97bfdafda68a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 20:50:15 2012 +0100
+commit 0de2ae72410f0672f174a8cae34d4ac12798a188
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun Oct 20 23:27:58 2013 +0100
 
-    modules_s/uid_gflags: moved to modules folder
+    pkg/kamailio/centos: updated documentation
 
-commit 1316bb1cd42cf34f03f9072037d6a138e2e10db4
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 20:49:36 2012 +0100
+commit 61ad39509ca1d739d00d0386ab5a991cf54477d8
+Author: Øyvind Kolbu <oyvind.kolbu at usit.uio.no>
+Date:   Sun Oct 20 22:04:16 2013 +0200
 
-    modules_s/uid_avp_db: moved to modules folder
+    fix dns srv failover when no UDP record is present
+    
+    - refactored code for srv lookup to have less code duplication
 
-commit b092e88730367444559408100a2c8d159259d6ed
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 20:49:02 2012 +0100
+commit 820046b04c2218273a11f905dc798812d7ca0ca6
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Fri Oct 18 09:21:02 2013 +0200
 
-    modules_s/uid_auth_db: moved to modules folder
+    modules/ims_registrar_scscf: added outstanding documentation
 
-commit 1183a546bd287c90cc485573df585fe9f624a7ab
+commit 37f284d2d9bbe6dac4888600d0b99ccc58d22eb9
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 20:47:53 2012 +0100
+Date:   Thu Oct 17 18:18:17 2013 +0200
 
-    modules_s/pike: moved to obsolete folder
-    
-    - use the other module with same name
+    Makefile.defs: version set to 4.1.0-pre0
 
-commit b79303dbfd781de9218f73b98ca72f25cf1d1054
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 19:51:19 2012 +0100
+commit 324e458ad68e97edaf2240e0f79b7380e77d268c
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Thu Oct 17 16:46:09 2013 +0200
 
-    modules_s/uri_db: renamed to uid_uri_db
+    modules/ims_qos: second iteration of ims_qos module
+    	- module now support media authorization over Diameter Rx (between P-CSCF and PCRF)
 
-commit bc780f6769581fd6260ba8d3f207ca2dd305970d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 19:43:53 2012 +0100
+commit d5c482ca06ff4b8529ea00d421484addd0203c37
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Thu Oct 17 16:44:46 2013 +0200
 
-    modules_s/gflags: renamed to uid_gflags
-    
-    - script flag functions got an 'u' in name to allow usage together with
-      cfgutils module
+    modules/tm: Edited documentation to show that t_suspend/continue can now be used on SIP responses
 
-commit e4eb153efa0e2d0c6e1478fbe664df87aa93c7ec
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 19:38:51 2012 +0100
+commit 16e763c32d7a2b9fc451185e028a90b3be758f65
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Thu Oct 17 16:41:15 2013 +0200
 
-    modules_s/domain: renamed to uid_domain
+    modules/tm: extended tm async support to SIP responses
+    	-t_suspend and t_continue functions now work with SIP responses as well as requests
 
-commit 6e8d115d48193c07977bf07638f237ff8518cf0e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 18:45:25 2012 +0100
+commit 8b8132c17c126ff4edb2f5c9544dbd30894f6108
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Thu Oct 17 16:40:07 2013 +0200
 
-    uid_auth_db: updated doc file to the new name
+    parser: defined new FL_RPL_SUSPENDED used for suspend on reply
 
-commit a5daf1797ff4edbb456d0d0b70138ce422d65d86
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 18:42:26 2012 +0100
+commit cc8bc36c67a0b8e7317c06c50a88e8e6aa15d790
+Merge: 217e508 2f368b6
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Oct 16 14:12:51 2013 +0200
 
-    modules_s/avp_db: renamed to uid_avp_db
+    ims_charging: Merge branch 'ims_charging' into master
 
-commit 0440bae1fd24700d83bd4728f662deea250ed716
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 18:35:19 2012 +0100
+commit 2f368b676acb026bf4647af02108a24e49e30581
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Fri Oct 11 00:07:18 2013 -0300
 
-    modues_s/auth_db: renamed to uid_auth_db
+    ims_charging: fixed bug causing dialog cb function to be called more than once
     
-    - the module is using uid based database schema
+    - removed possible race condition in dialog cb
+    - improved the way locking was performed
 
-commit 2eb7894a6d2b9ca0e62eb83865d5cf955366ce9c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 18:02:21 2012 +0100
+commit 217e5089df327215dd5078a72dd5b14526640191
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Thu Oct 10 16:04:49 2013 +0200
 
-    modules_s/print_lib: moved to modules folder
+    modules/ims_charging: restored an unlock that will cause deadlock if omitted
 
-commit bd263eea88e942a077dd0ef70138d1bbc704219f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 18:01:51 2012 +0100
+commit bae7fcb9be9a4cf88693e6c4180e3c1e6f4b6c1d
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Thu Oct 10 15:36:59 2013 +0200
 
-    modules_s/print: moved to modules folder
+    modules/ims_charging: fixed bug not initialise AVP string value for success CCA
 
-commit 8e806d4cb02049ffb447e3781d0ce864bb2bffb7
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 17:57:12 2012 +0100
+commit 6ccca97cba61e75e9da0b6d36f1ee38fc88e94f3
+Merge: db618dd 83add48
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Thu Oct 10 15:01:07 2013 +0200
 
-    modules_s/print_lib: added readme and xml docbook files
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
 
-commit 306459af5d4698e598a6842668faf701fe9b85f3
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 17:42:46 2012 +0100
+commit db618ddbdc2ec92a508acd913f2f847a4fb59cae
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Thu Oct 10 14:59:23 2013 +0200
 
-    modules_s/rr: moved to obsolete folder
-    
-    - k version offers the ability to work behind nat and preset route set
-    - adding params to record-route headers can be done with add_rr_params()
-      which has dynamic parameter
-    - accessing the route parameters can be done via script variables
+    modules/ims_charging: corrected default termination cause code to DIAMETER_LOGOUT
+    	- also corrected typo
+    	- added other termination cause code defines for future use
 
-commit b3773e4ae594fcff9de95a869695d2441d9628b8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 13:28:44 2012 +0100
+commit 83add48b7c1cdf0d9f64c24bcc134195699daac1
+Author: Robert Boisvert <rdboisvert at gmail.com>
+Date:   Thu Oct 10 08:25:05 2013 -0400
 
-    modules_s/cpl-c: moved to obsolete list
+    mohqueue: fixes
     
-    - use the other cpl-c module
+    * cleaned up all error paths (fixed crashes)
+    * added support for INVITEs that get stuck
+    * adjusted code to avoid compiler warnings
+    * PRACK only invoked if Require: 100rel set
+    * fixed bug that allowed a new call to be created more than once
+    
+    Documentation
+    * updated NOTES
 
-commit 69a7abb8703fab795071130b5f4cd7412124aab2
+commit ac5835c0aff657cae169432466851c9f2cbca8ad
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 12:39:00 2012 +0100
+Date:   Thu Oct 10 12:45:45 2013 +0200
 
-    cpl-c: added an optional parameter to cpl_run_scritp() to provide the URI
+    cfgutils: init probability pointer to NULL
     
-    - the parameter will be used instead of taking the URI from headers or
-      R-URI
+    - otherwise it can be an attempt to free it when the kamailio does not
+      start due to config errors
+    - reported by Dragos Oancea
 
-commit a403bd541bbca60fff6ab24a62c7bd2b31c6707e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Dec 21 10:29:54 2012 +0000
+commit a3bddf300ff82b9d811acb5dd6ec2e25f0eab07c
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Oct 9 17:55:20 2013 +0200
 
-    pkg/kamailio/(centos|fedora): Added moved modules from modules_s to the build
-    
-    - db2_ldap, db2_ops, and timer
+    module/tm: changed log level from WARN to DBG for informational message
 
-commit c2e4b20ecc2598bf5a440a50762e9dbd6a2ed61c
-Merge: 2930038 35a427c
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Dec 21 11:19:33 2012 +0100
+commit 2dc78738af4a0693e0a4d3f77e2174586d53d90b
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Tue Oct 8 15:52:09 2013 -0300
 
-    Stupid Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      Makefile: db2_ldap added to excluded modules list
+    ims_charging: removed session unlock function call when no lock was acquired
 
-commit 2930038a7e4ccf9abb1fe2465d1e59f3dfe9012f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Dec 21 11:18:55 2012 +0100
+commit dcce66b2a3db3aeaa5de1a87429320731ab3795c
+Merge: 121e828 639ce58
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Tue Oct 8 18:43:14 2013 +0200
 
-    db_text: Minor correction in error message.
-    
-    Tell the user what's wrong, not just that it's wrong.
+    ims_charging: Merge branch 'ims_charging' into Master.
 
-commit 35a427c6d452477478228885e1b2a2104633ce5d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 21 11:10:20 2012 +0100
+commit 121e828e2bedd3f76a1343f7257978153e78fc8f
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Tue Oct 8 02:37:43 2013 +0100
 
-    Makefile: db2_ldap added to excluded modules list
+    pkg/kamailio/centos: added mohqueue to CentOS build
 
-commit 9b9562a2bdc71e350702e21e25129444e6b805aa
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Dec 21 10:07:52 2012 +0100
+commit 03dbfd4c97290028212ddb04eea5faf5ef4ba007
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Tue Oct 8 02:27:24 2013 +0100
 
-    htable Minor correction to RPC docs
+    modules/mohqueue: created text README file from doc source
 
-commit 6ff072a307ddf0735ca9c38c1bc0c3ebdbc57a2b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Dec 21 09:40:06 2012 +0100
+commit a39adb3497b5b095126e835104d637669dee2a7e
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Oct 7 16:17:53 2013 +0200
 
-    htable Add RPC command for listing one item
-    
-    Also, add documentation for existing RPC commands.
+    ims_charging: Add statistic ccr_timeouts
 
-commit b6e2034d84dcb77bfda256af0de0c434cc83dbb7
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Dec 21 09:05:15 2012 +0100
+commit e4e84c80232a5acc60b64adb541b54b6967189f6
+Author: Timo Teräs <timo.teras at iki.fi>
+Date:   Mon Oct 7 17:09:59 2013 +0300
 
-    pike: Add error on bad argument
+    mohqueue: fix build error due to get_debug_level api change
     
-    Reported by Ovidiu Sas on the sr-dev list. Bug ported from modules_s/pike :-)
+    Should have tested better before merging. Should probably remove the
+    whole debug print helper and use core functions directly now that
+    the core supports per-module debugging.
 
-commit 7f532c2994a824c33c2e9e2348a10df734c1d3a7
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:59:59 2012 +0100
+commit 62860094af838710ee5b9892cfb9f99f615055f6
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Mon Oct 7 10:01:56 2013 +0100
 
-    sl Minor README updates (file name changes)
+    tm: Restore ruid value in sip_msg struct after creating transactions from branches
+    
+    - Fixes crash when freeing memory
 
-commit 6c8c42c92de26912c3c15007114967deca6bdc89
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:57:07 2012 +0100
+commit a4370dc336e5552b93d32314249d4d613d77ef99
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Mon Oct 7 12:49:00 2013 +0200
 
-    mangler: Minor doc update
+    modules/tm: missing lock initialisation for async_lock
+    	- related to commit 5ab44c7c2fc78038302bf455ff49e374fc79550b
 
-commit d36d4de28ad52763ef4e637393997bca44dc6fea
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:56:17 2012 +0100
+commit ca060f98bbecb407d5d29cbe19cec821d3990330
+Merge: 6e19deb 24f66ec
+Author: Timo Teräs <timo.teras at iki.fi>
+Date:   Mon Oct 7 11:18:02 2013 +0300
 
-    sanity  Minor README updates
+    Merge branch 'tteras/mohqueue'
 
-commit cbdadf3bff04e7837698ad84466fea2aed39b9c9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:48:19 2012 +0100
+commit 6e19debdf9b240c71ca90bfd6cadd46f0f57ace8
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Oct 7 10:15:11 2013 +0200
 
-    prefix_route doc file name changes
+    examples/pcscf: Removed dependency to Presence-User-Agent and SQLite.
 
-commit 75e18bc92fedc4d5a4ab0599ad16526928523b41
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:45:40 2012 +0100
+commit c9395e690435cdb8fc62b7fb13b378fe0a6ca8e5
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Mon Oct 7 07:52:21 2013 +0100
 
-    mangler Minor README edits
+    htable: update documentation for dmq integration
 
-commit 0156d9e3e46e592c951acbbe8924840b3ca7860f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:40:19 2012 +0100
+commit 6a20bf80ae014801667c5a23782b33af5467c409
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Mon Oct 7 07:44:38 2013 +0100
 
-    malloc_test Minor README edits
+    htable: initial dmq integration
 
-commit 326772a1524e3ad6e7c5927cf6edee1f85bc5a5b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:37:09 2012 +0100
+commit 24f66ecc72064c9bf40deeb324e666b6b95dfa83
+Author: Timo Teräs <timo.teras at iki.fi>
+Date:   Mon Oct 7 08:41:37 2013 +0300
 
-    db_flatstore Minor README edits
+    mohqueue: remove handwritten .sql, it is now autogenerated
 
-commit c060369e85e279c3eba8fe5caddc3be7a860d512
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:31:50 2012 +0100
+commit 1af34ca5b9f799b83242a9ecddf8abe9521114dd
+Author: Robert Boisvert <rdboisvert at gmail.com>
+Date:   Thu Oct 3 11:36:08 2013 -0400
 
-    blst Minor README updates
+    mohqueue schema files
 
-commit 98b4fd46fa5fb42422346793cad5406220f3992e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:28:34 2012 +0100
+commit f8f3d34ba5471742676831b22b1c872823a31cba
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Sat Oct 5 13:14:09 2013 -0400
 
-    avp Minor README xml file changes
+    modules/sca: fix compiler warning for macro.
+    
+    - correct "always evaluates to true" when using address of stack variable.
 
-commit c9497bf0653ffca09bd180ea01d7089a14f8f0e2
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:26:12 2012 +0100
+commit 2f0043b153c60380e35c8ec4c33a9bbc7fb2b05c
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Sep 19 13:49:24 2013 -0400
 
-    auth_identity README updates
+    modules/sca: fix return value of sca_call_info_uri_update()
+    
+    - return value of 0 can bubble up as return value of sca_call_info_update(),
+      causing early script termination (exported function returning 0 in script
+      is equivalent to "exit")
+    - report and patch from Timo Teräs
 
-commit bcb10c2952cbcd5e3aa500815b11d7cf45de47a2
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:20:58 2012 +0100
+commit 2efe3e365e1670cc3ac8b4900a1104c3720d44fb
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Tue Aug 20 15:54:17 2013 -0400
 
-    auth Documentation filename changes
+    modules/sca: AoR should not be treated as SCA if there are no subscribers.
 
-commit 78e1f3667d8fa553abde60d9078f395b9c4dcb9a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:18:34 2012 +0100
+commit 58a47ac21d09bf6feb1431bbe490643e9827c876
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Tue Aug 20 15:14:26 2013 -0400
 
-    cfg_db README edits
+    modules/sca: improved handling of host-only Contact URIs
 
-commit 88e55397a3036880d2af43aa44fda473c9284011
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:13:37 2012 +0100
+commit 3b1f87523bdc53538c1b6f409ba9470048572701
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Jul 22 00:48:46 2013 -0400
 
-    pike: README edits
+    modules/sca: restore missing prototype.
+    
+    sca_subscription_aor_has_subscribers
 
-commit e0ef312d376d7b7d3d7e8b8c522544e0fae865bd
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:12:42 2012 +0100
+commit 97653df1d93636771c7b2fa8e4f9aef002ee7e5b
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Jul 22 00:42:18 2013 -0400
 
-    iptrtpproxy Minor README edits
+    modules/sca: detect when an AoR is no longer SCA.
+    
+    Don't, for example, create an appearance for callees that do not send
+    a Call-Info header, and whose AoR also has no subscribers.
 
-commit e175629e7522350991bc4325f5141ecb68b05c3f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:11:59 2012 +0100
+commit a6f80374c4dd3d09fa7e25a8e6c59dab0bf2fae5
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Jul 22 00:37:32 2013 -0400
 
-    xmlrpc Documentation minor edits.
+    modules/sca: Clear stale line-seize appearances via timer.
+    
+    Some badly behaved/buggy UAs don't know when to say when.
 
-commit bf42fb7b6deef7926816c5ec8f9a4d0bf7393aed
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 20:07:58 2012 +0100
+commit 84d1981ce059fcdd7a5113428b0227fbb0b977ab
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Jun 13 16:06:10 2013 -0400
 
-    xmlops: Move to "book" and rename files to avoid collissions
+    modules/sca: fix regression: restore purge expired timer
 
-commit bb5527557c9d54f4ba63ddd491e4487b3fa0b063
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Dec 20 19:25:10 2012 +0100
+commit c0fb2a67a699e30fd3274c9f864918e6e02e1926
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Jun 13 15:34:00 2013 -0400
 
-    db2_ldap: defined -DLDAP_DEPRECATED to enable the old ldap api
+    modules/sca: clear appearance on receipt of out-of-dialog SUBSCRIBE
     
-    - reported by Ovidiu Sas
+    - If a call-info SUBSCRIBE with no To-tag arrives from a subscriber
+      with an active subscription, release any appearances owned by the
+      subscriber, on the assumption that the subscriber has lost track
+      of SCA (reboot, power/network loss).
 
-commit 2eee368b72c48e36af8af0f17fb29dc5d6310b08
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Dec 20 19:13:13 2012 +0100
+commit ef9b12d213416f910e0c11bdeecf9112032939f8
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Jun 13 15:30:40 2013 -0400
 
-    core: added prototype of no_naptr_srv_sip_resolvehost() to resolv.h
+    modules/sca: detect and clear orphaned appearances caused by answer glare
     
-    - fix compile warning, reported by Ovidiu Sas
+    - set appearance state created by SCA callee answer to ACTIVE_PENDING,
+      and promote to ACTIVE on ACK from caller. If no ACK from caller is
+      received within 30 seconds (enough time for retransmission to fail),
+      the ACTIVE_PENDING appearance will be cleared by the
+      sca_appearance_purge_stale timer.
 
-commit e964ce8f377cd368b1326ef42bc9bef36d192179
-Merge: 3ad60fe 80697ca
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 18:52:33 2012 +0100
+commit 1ef4587612806a94c7a81aac4f768b9bbe472b43
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Wed May 15 16:13:23 2013 -0400
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/sca: reconcile Contact and From URIs in ACK callback.
     
-    Arrggh. Need to clean up my working directory before xmas.
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      modules_s/timer: moved to modules folder
+    - fix Music-on-Hold in Polycoms when SCA caller has MoH enabled and SCA callee
+      does SCA hold/pickup with identical To & From URIs. Previously, module would
+      end up looking up an appearance for callee in ACK callback instead of caller.
 
-commit 3ad60fe1e229b3c1fc3a854d57eac223094294ad
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 18:51:52 2012 +0100
+commit 185bd40d1a197709d28d9b966ed8fd4b4c00faf9
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Tue May 14 16:25:06 2013 -0400
 
-    pike: Import pike.top rpc call from modules_s/pike
+    modules/sca: improved BYE handling.
     
-    Thanks to Ovidiu for pointers in the right direction.
-
-commit 80697ca8ab8fd06bb348fd9d9b17d8db39f9e274
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Dec 20 15:18:23 2012 +0100
-
-    modules_s/timer: moved to modules folder
+    - Clear appearances for both legs on BYE request if possible.
 
-commit 1c35849b76ea9257162d5977e839399027c9659b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 13:44:59 2012 +0100
+commit 36ad80745607fca859578b8423cbd767f4c5b095
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Tue May 14 16:23:46 2013 -0400
 
-    uac: Add note about only using uac_replace once in the same request
+    modules/sca: free previous appearance owner, callee, dialog if non-NULL.
 
-commit b56e823ed8e7ac2f88d1020677f5e94546a91516
-Author: Mihály Mészáros <misi at niif.hu>
-Date:   Sun Dec 16 13:03:18 2012 +0100
+commit bb21b5e0bc7aaf001799e259b81aebe28168afb1
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu May 2 15:12:16 2013 -0400
 
-    core/dns: fix an issue when using it without dns cache
+    modules/sca: change logging level for failed lookup by appearance-index.
     
-     - fixing an issue what caused that without dns cache we have to use a different function for srv resolution.
+    - appearance-index won't be found yet if SCA callee is answering, logging
+      at WARN is misleading.
 
-commit 61cae424125c4af11a69092cbf7b6870dbf26af0
-Author: Mihály Mészáros <misi at niif.hu>
-Date:   Wed Dec 5 12:55:24 2012 +0100
+commit 98b8ba06dfaec49331dbfc3164e02a490e0db214
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Tue Apr 30 23:31:12 2013 -0400
 
-    core: dns resolver patch bugfix
-    
-    - a small bug fixed.
-      Many thanks to Daniel (miconda at gmail.com) for reporting it.
+    modules/sca: space-separate dialog tags in sca.all_appearances output
 
-commit 63ef5f0edcfebe86cffe7489f3524186ed3400d4
-Author: Mihály Mészáros <misi at niif.hu>
-Date:   Mon Nov 12 16:02:48 2012 +0100
+commit 002dc46fee94edf8b7086d7d3bb0286979213532
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Tue Apr 30 23:10:10 2013 -0400
 
-    core/dns: dns SRV lookup, if no NAPTR available
+    modules/sca: track appearance times.
     
-    - Resolving the first most preferred and available SRV record if no NAPTR found.
-      It reuse the dns protocol preference scores. Sort protocols based on this preference.
-
-commit 7702ef8c2ec0fca97e11c621532bb9af3160dba7
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Dec 20 12:25:15 2012 +0100
-
-    modules_s/db2_ldap: moved to modules folder
+    Include time of last state chance in sca.all_appearances output.
 
-commit bebb0665ac795ea234e329a8a5b785ce5678da62
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Dec 20 12:21:39 2012 +0100
+commit ac298442533c048e5ccacf6b3ad0cb36d52c2eff
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Wed Apr 24 11:30:35 2013 -0400
 
-    modules_s/db2_ops: moved to modules directory
+    modules/sca: add sca.subscription_count to rpc exports list.
 
-commit bdb2368e5abd6dad0b203b67676701e515d59ae8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 21:23:50 2012 +0100
+commit 815d70e5156c2a878e59c59182ffa957f1d75a80
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Wed Apr 24 01:18:27 2013 -0400
 
-    modules_s/uri: moved to obsolete list
+    modules/sca: RPC: fix sca.show_subscription, add sca.subscription_count
     
-    - use siputils module instead
+    - sca.subscription_count will eventually be subsumed by sca.stats.
 
-commit e6a8bc85079389314f86cc4141cf827ecabeaf4a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 08:56:56 2012 +0100
+commit 2e0af20cd7a5b3e46ceb36ef3919df78c1bdf1df
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Apr 18 13:52:10 2013 -0400
 
-    iptrtpproxy Documentation updates (SER => kamailio)
+    modules/sca: fall back to tag lookup if lookup by index fails.
+    
+    - Fix appearance tracking for SCA implementations with inconsistent
+      Call-Info header inclusion.
 
-commit 5919b3b6c4078db7675c71d98f671feb58c68a2a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 08:46:24 2012 +0100
+commit a6f038343de57ca6bd257e442af41feae2b18c4d
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Apr 15 20:16:36 2013 -0400
 
-    ctl Updating documentation
+    modules/sca: add SCA_DB_DEFAULT_FETCH_ROW_COUNT
 
-commit 8b967b4b96765057bb0b8f62ee1dd5b04442b52d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Dec 20 08:41:00 2012 +0100
+commit 562e49dc6e6fb9adb47adecbda8bfb94f12d86aa
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Apr 15 20:11:08 2013 -0400
 
-    counters Updating documentation to "book" from "section"
+    modules/sca: use DB fetch queries when restoring subscribers from database.
     
-    Renaming files to avoid collission when aggregating documentation.
+    - Previously used standard query, exhausting pkg memory when subscriber
+      count is high.
 
-commit 6fd7eb7440e864df872a56ad9b2076614c08222e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 21:11:56 2012 +0100
+commit 92114b530e6a206af1fe173a948cb542a62717c2
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Apr 15 20:09:01 2013 -0400
 
-    modules_s/acc_syslog: moved to obsolete list
-    
-    - use acc module instead
+    modules/sca: only check if callee is SCA if callee_aor has a value.
 
-commit 12e1b5eab148559d00ce4461a7126e227ab7ae33
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 21:10:41 2012 +0100
+commit 1e9708462f0e709e795813490d56897d0f44997c
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Apr 15 17:17:05 2013 -0400
 
-    modules_s/acc: moved to obsolete list
+    modules/sca: add check for empty AoR in lock_shared_appearance calls.
     
-    - use acc module instead
+    - Sanity checking
 
-commit 7487c62ea79cdddb468f2090aeba39b1df0747cc
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 21:06:53 2012 +0100
+commit 6cdc9c4f3e915fbad5da1112b9e0553726e877f2
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Apr 11 22:34:10 2013 -0400
 
-    modules_s/uri_radius: moved to obsolete list
+    modules/sca: clear appearance on t_reply with error after receiving 18x.
     
-    - use misc_radius module instead
+    - Receiving a 18x provisional reply triggers line-seize subscription
+      termination. Releasing the seized appearance while processing a t_reply
+      with an error status *after* getting a 18x would fail because
+      sca_subscription_terminate could not find a matching line-seize
+      subscription. In that case, look up appearance by tags and release it.
 
-commit 685f526aa6d5b171a6731cec5aa67a97e12da1fc
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 21:04:38 2012 +0100
+commit 28978be4d825e08a455387209af6dda4aa4bdfde
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Fri Oct 4 18:40:42 2013 +0100
 
-    modules_s/auth_radius: moved to obsolete list
-    
-    - use the other module with the same name
+    dmq: fix memory leak in dmq_send_message()
 
-commit 38d126621a09b3a149bcc10e3d07a176ba84068b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 21:02:49 2012 +0100
+commit cf4275d4cb16dce4cbac48ca946a66e9f1626c35
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Fri Oct 4 14:57:39 2013 +0100
 
-    modules_s/avp_radius: moved to obsolete list
-    
-    - use misc_radius to fetch attributes per user from radous server
+    memcached: fix memory leak, discovered on a report by Dragos Oancea
 
-commit d7e1ff882bcca3369edd74a7540cf252ef08760c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 21:01:11 2012 +0100
+commit 0f3a566dd699090cf6a558edc3aefac2c41e24e5
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Fri Oct 4 14:47:06 2013 +0200
 
-    modules_s/acc_radius: moved to obsolete list
+    memcached: comment clarification for wrapper for libmemcache callbacks
 
-commit 51cba8039863a92a5050b6932bb8a9155edcf39b
-Author: Alex Balashov <abalashov at evaristesys.com>
-Date:   Wed Dec 19 13:23:09 2012 -0500
+commit 0978c77d694cecd1b7813775a498f6495ae844dc
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Fri Oct 4 14:22:39 2013 +0200
 
-    dialog(k): Fixed typo in loop in set_dlg_timeout_by_profile() so that
-    _all_ the dialogs actually get killed, not just the first one.
+    avpops: add a note to the docs that avp_db_query is deprecated and sqlops is better
 
-commit 27e5fdc60110c4c89cee642317f5d92b7f0b734d
+commit 673243a06200b8961756ebe3957bf9bd9059c2bb
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 19 12:52:13 2012 +0100
+Date:   Fri Oct 4 13:11:23 2013 +0200
 
-    kamailio-oob.cfg: new config file to collect more out-of-the-box use cases
-    
-    - the file can be used to add more complex routing logic and show how to
-      use various features of kamailio
-    - it should offload kamailio.cfg from getting too complex as a starting
-      point
+    nathelper: updated docs with udpping_from_path
 
-commit f1449adfb91727112e2a44f406e7de63965595d6
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Dec 19 12:17:19 2012 +0200
+commit 565ba8d4b71ae5a43027c51e3caf06f20a10b14d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Oct 4 13:07:44 2013 +0200
 
-    modules/mediaproxy:  README fix and edits
+    nathelper: new mod param - udpping_from_path
     
-    - AVPs are available in Kamailio reply routes without setting any tm param.
+    - enable sending UDP pings with raw sockets from Path address
+    - patch by Marcus Hunger
 
-commit 70b3ea024d9eb42f974b4de37a555bcb384405e9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 19 01:48:17 2012 +0000
+commit 9bb88b5b22901b258fdbcd874264b823a8443869
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri Oct 4 14:04:22 2013 +0300
 
-    pkg/kamailio/fedora/17: Updated boxgrinder appliance
+    dialplan: improved debug messages so that used dpid is shown
 
-commit c5b67ce5965d37c4851b6c33b9020cf88a4b85f3
+commit 88e2da3c54a1cef967d96a5753b1f7f014ba689e
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 18 23:29:21 2012 +0100
+Date:   Fri Oct 4 12:14:25 2013 +0200
 
-    modules_s/ldap: renamed to db2_ldap
+    acc: time_format parameter documentation
     
-    - it is a SRDBv2 API database driver
+    - eclosed exaples in dotted lines like in most modules to highlight them
+      on text output
 
-commit 3e3b0350cd5408822cb7c35aa83d1c3e305a98c1
+commit df4fbc220efd333fa638831167dd4fe5e69a89a2
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 18 23:23:38 2012 +0100
+Date:   Fri Oct 4 12:02:32 2013 +0200
 
-    modules_s/db_ops: renamed to db2_ops
+    acc: new parameter acc_time_format
     
-    - it implements only SRDBv2 API
+    - specify the format to print time as string for acc_time_mode=3 (using
+      localtime) and acc_time_mode=4 (using gmtime)
+    - default value is "%Y-%m-%d %H:%M:%S"
 
-commit c38b4361c35ce4bf2abcc6b2480d76ca3029abfd
+commit fed0a07d86c9e4d365cb7a5e25d4aaacb4b9adf2
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 18 23:11:26 2012 +0100
+Date:   Thu Oct 3 10:00:22 2013 +0200
 
-    modules_s/oracle: moved to obsolete folder
+    dialog: fixed typos in log messages
 
-commit d1bf22612ce24f20ba360a5f1077fa5ce3c1e27e
+commit f12aa1b3c16b475029f0a3474b30f3b17ea18056
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 18 23:05:10 2012 +0100
-
-    modules_s/bdb: moved to obsolete folder
+Date:   Thu Oct 3 09:58:04 2013 +0200
 
-commit 7f5d581b42139a16f6c3730ed9c54b1d36f6b58a
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 17 15:17:28 2012 -0500
-
-    modules/db_cassandra: no need to link against kmi library
-     - no MI commands exported
+    dialog: decode alias parameter from contact address and use it as dst uri
+    
+    - makes dialog module to work with set_contact_alias() as first hop
+      after a nat router
 
-commit 928dab69601e1bb56e3abbc81a1ed55d77e8b298
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 17 15:06:49 2012 -0500
+commit a41cb60d5171566e13f18b45f50d173f38d206c0
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Oct 3 09:37:54 2013 +0200
 
-    modules/db_flatstore: replace mi command flat_rotate with rpc command flatstore.k_rotate
+    nathelper: documentation for set_contact_alias()
 
-commit 53b6903007caf13ea9543be6c545a4d9cd6d437f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 17 21:10:48 2012 +0100
+commit 58659b0cabb623c6420c186755c968b4550ff09c
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Oct 3 09:16:38 2013 +0200
 
-    blst Update docbook XML to "book" from "section"
+    nathelper: set_contact_alias() new function for adding alias parameter to contact uri
     
-    Trying to standardize the documentation into one format
+    - similar to add_contact_alias(), but this works like
+      fix_nated_contact(), in the way that new contact uri is immediately
+      visible to other modules (e.g., dialog, presence)
 
-commit 1f28ea63990f016a5828321f3514a029c5a2a18a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 17 20:58:57 2012 +0100
+commit 217f9fddbca31e06075132dd75a645d612d7af93
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Oct 3 09:13:39 2013 +0200
 
-    avp Modifying docbook to "book"
+    core: helper functions to add or restore alias parameter to an uri
 
-commit 1e0ee74dae6da3a962f46f8d3305368c0754d56d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 17 20:56:25 2012 +0100
+commit 639ce584258f2c2ad4331bbd9ae2599a86edc80b
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Thu Oct 3 11:56:13 2013 -0400
 
-    auth_identity Moving to "book"
+    ims_charging: read diameter AVP MAC value dynamically from $avp
+    
+    - $avp(ro_mac_value) can be either present or not. In case it is not, default value is used
+    - $avp(cca_result_code) now supports interpolation
 
-commit f3f279234622c18ab847fc5ff0e8473f3cd23fd4
-Merge: 52a9f00 5519cae
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 17 20:52:34 2012 +0100
+commit 753e93d3ad1658c104963c208c4e36b23c1dd307
+Author: Robert Boisvert <rdboisvert at gmail.com>
+Date:   Thu Oct 3 09:22:54 2013 +0300
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/mohqueue: pull changes from upstream
     
-    Sorry. Sorry.
+    Merges up to upstream commit a3f679430d853d5b1b71ba92d8547ca2c86509ec.
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      modules_k/drouting: documentation updates for mi -> rpc command migration
+    Changes in code:
+    * fixes RTP stop not being sent
+    * use pcbp->req instead of -> in rtp_destroy
+    * fixed uninitialized varbs
+    * use close_call () for no response on INVITE
+    * changed to return handled if reINVITE sent
+    * switched to using fixup_svpe functions
+    
+    Documentation:
+    * added comment about rtpproxy limit
+    * adjusted to remove hold sequence in transfer out
 
-commit 52a9f00806de700f1b0288ea22b388a27ab707c0
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 17 20:52:03 2012 +0100
+commit 9978906d39071908234f0236ea8693844a3c5ba1
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Thu Oct 3 05:59:09 2013 +0100
 
-    auth: Converting to book docbook format
+    dmq: regenerated readme
 
-commit 0d41e1ba82c22a6e62f997add0a266ef4b2ed0ed
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 17 20:42:47 2012 +0100
+commit 3f6445f4620e3866dc859b9cfb6710e28bd407e5
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Thu Oct 3 05:54:01 2013 +0100
 
-    xprint: Change to docbook book, instead of section
+    dmq: add content-type header
 
-commit 502675ecb60f6943ca4fa8480b057a4bfef9dc2b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 17 20:40:33 2012 +0100
+commit 127bf3d5be959a1287ae0fac91cf89e27ed01f42
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Oct 2 22:14:15 2013 +0100
 
-    xmlrpc: Modify docbook format to book and add title
+    pkg/kamailio/centos: put core files in /tmp on CentOS
 
-commit 5519caedc2ebcfb44a660bcd13e4033116e24f50
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 17 13:37:16 2012 -0500
+commit b2c5c598a38c770c2c4a7aef7c8267ad43fc6cd7
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Oct 2 20:39:22 2013 +0300
 
-    modules_k/drouting: documentation updates for mi -> rpc command migration
+    modules/db_mysql: use autocommit var to start and stop transactions
 
-commit d4733ab7e27be0cf472db7157dcdbe6390e269b6
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 17 13:04:42 2012 -0500
+commit f5aec1db89664ad3b1a5d20ac81da4acda7d1d92
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Oct 2 17:21:11 2013 +0200
 
-    drouting: mi commands migrated to rpc
+    ims_charging: docs: Fixed linebreaks in examples, regenerated README
 
-commit 745e44e7555d0df789ecfae3b460650a43ecbf8c
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 17 12:04:49 2012 -0500
+commit 6faf12653c1db9f011b1826061824c831bda3f58
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Oct 2 16:43:35 2013 +0200
 
-    module_k/db_text: making some error probes visible
+    memcached: use pv buffer to clone the memcache value in pv strucutre
+    
+    - avoid leak occured by usage of pkg_str_dup()
+    - reported by Dragos Oancea
 
-commit b7f51d5d2b24063037ae18e82fb046b066cc52a0
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 17 12:03:11 2012 -0500
+commit 9909e05d46d0cdd22227b3b8c1b1d60253a135e2
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Oct 2 16:43:12 2013 +0200
 
-    modules_k/db_text: documentation updates for db_text.dump rpc command
+    memcached: use pkg-config if available for flags and libs in Makefile
 
-commit 82a03cb5af01c1275bc9a1664643cf3645c4b87a
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 17 12:01:49 2012 -0500
+commit 3f3c865ed04e1b0b8eb3762622662a76ce92b2e2
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Oct 2 14:23:53 2013 +0200
 
-    modules_k/db_text: new rpc command 'db_text.dump'
-     - allows forcing a write back to disk for modified tables
+    core: helper function to get source address as uri or proxy format
 
-commit 5ece7e315ee8d3c3529eed94179fcb4e08d41c66
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Mon Dec 17 11:56:24 2012 -0500
+commit 5db86a941a909c17a0f9ee1b04febbe4c60033bd
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Oct 2 14:15:18 2013 +0200
 
-    parser/digest: use next_sibling_hdr() instead of hand-rolling it
+    core: skip dns srv for websocket after check if domain is ip
+    
+    - reported by Peter Dunkley
 
-commit 624a9bbf777a1c1d44400eec78911a9714872977
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Sun Dec 16 15:06:32 2012 -0500
+commit 49720ce99e72ded34c67a9ee4d17a9cedaf0a0f4
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Oct 2 10:04:35 2013 +0100
 
-    parser/digest: Fix hunting for Auth header in rare cases
+    xcap_server: Fix memory allocation check bug in xcap_misc
     
-    Fix a bug where find_credentials() would fail to find the correct
-    Auth header when multiple headers are present, the one being looked
-    for isn't the first and the full message had been parsed already.
+    - Would cause crash if out of package memory
 
-commit 3cfaf089c1472f1397580a365360579c671c7796
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Dec 14 13:55:39 2012 -0500
+commit 93af236644058b4e97162eae689f9b32b8076691
+Author: Timo Teräs <timo.teras at iki.fi>
+Date:   Wed Oct 2 09:05:22 2013 +0300
 
-    xhttp_pi: properly handle NULL values
+    mohqueue: new module
+    
+    module to queue up calls in music-on-hold and then retrieve them
+    
+    imported from https://github.com/rdboisvert/mohqueue
+    commit f796f259ed1728e19adb31d76af5f6c3f548f021
+    
+    excluding LICENSE which is redundant now that the module is part
+    of the kamailio source tree.
 
-commit ec617a27352ba719184cf617bb564631d5152df5
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Fri Dec 14 13:47:08 2012 -0500
+commit fd9fcd75c222b73a2b70793e5d79c7494f757a1e
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Oct 2 01:30:37 2013 +0100
 
-    xhttp_pi: fix query operation for db w/o fetch support (like db_text)
+    modules/auth_ephemeral: Added MI commands for shared secret management
+    
+    - Can add, remove, and display shared secrets with MI commands
+    - This means you can add/revoke secrets without a restart
 
-commit 7fc74e46a5d5b4e2b0cbbe5bdc1627e672867164
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 14 00:43:04 2012 +0100
+commit 6c7a0f3cdaee5ea0300d014f07e4d68f45c6e20b
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Oct 2 01:29:45 2013 +0100
 
-    dialog(k): reset default value for optional parameter
+    modules/websocket: tidied up MI commands
     
-    - some rpc transports set a static string for missing optional
-      parameters, causing invalid value
-    - dlg.bridge_dlg proper handling of optional parameters return code
+    - Fixed leak in error situations
+    - Improved error responses
 
-commit 840d23197e91c70f7b02072e144ec396f5f8f386
+commit 1c74725dc14fc40d9b553950e212241821351878
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 14 00:20:08 2012 +0100
+Date:   Tue Oct 1 23:18:07 2013 +0200
 
-    dialog(k): fixed dlg.end_dlg rpc command
-    
-    - missing of the optional paramter causes negative return code
+    core: don't attempt srv lookup for proto ws or wss
 
-commit c1fa174ddc4d499548bdc3d5f75e36125541ade9
+commit 2934e46a18d9cfba05e657bc1dbbaa559a31b103
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Dec 13 22:52:39 2012 +0100
+Date:   Tue Oct 1 23:03:32 2013 +0200
 
-    modules_s/exec: moved to obsolete directory
+    registrar: fix compile warning after previous patch
 
-commit dab6e5b5af4d7b98553ee620d2f9114d17592c9a
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Dec 13 16:10:31 2012 -0500
+commit 6cfd13cbddd1869ffbc947fdecd77d18a3fcb886
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Tue Oct 1 10:52:01 2013 +0100
 
-    sca: fix regression omitting call-info NOTIFYs on INVITE 200 reply.
+    core: fix TCP connection leak
     
-    - Restore call-info NOTIFY with appearance-state=active when callee answers.
-    - Reported by Robert Boisvert.
-
-commit 7e8913d0a8a8f1865777615cdf53f71adfd94baa
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Dec 13 17:48:16 2012 +0000
-
-    pkg/kamailio/(centos|fedora): Added xhttp_pi README to installation
+    - patch provided by Vitally Aleksandrov
 
-commit 63b5065ccf776ce3bbc5b51f19f72041442467cb
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Dec 13 17:47:57 2012 +0100
+commit b5b570f278124bf0456d43a36a7c0eb5eaa9efe6
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Oct 1 09:34:17 2013 +0200
 
-    xhttp_pi: add missing README
+    tm: added t_use_uac_headers() to documentation
 
-commit 4509d6ce4160083959cd152887c47290a6753889
-Merge: 8997007 3198bec
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Dec 13 16:43:15 2012 +0000
+commit 0e71fec1e108e1c9b97486ced8c1328738ca13c2
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Oct 1 09:27:46 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    tm: new function t_use_uac_headers()
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      modules/mediaproxy: restrict opening of dispatcher connection
+    - set internal flags to tell tm to use UAC side for building headers for
+      local generated requests (ACK, CANCEL) - useful when changing From/To
+      headers using other functions than uac_replace_[from|to]()
 
-commit 8997007145ad777d9967589cefb1477843541efb
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Dec 13 16:42:29 2012 +0000
+commit 5ac033cf85921b4c364d6d463bc75ebd22c5721a
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Mon Sep 30 23:38:56 2013 +0100
 
-    pkg/kamailio/(centos|fedora): Updated kamailio.spec to install xhttp_pi framework examples
+    pkg/kamailio/centos: Added ims_charging module to .spec
+    
+    - Removed cdp package and put cdp and cdp_avp modules into ims package
 
-commit 3198beccbc2ce350bb0af2a1cedec72ccb7c9277
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Thu Dec 13 13:57:46 2012 +0200
+commit 576dce3cfdbf3cfa36fcac4f26aa3312f4add37a
+Merge: 1c3e761 f96c7f5
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 22:38:42 2013 +0200
 
-    modules/mediaproxy: restrict opening of dispatcher connection
+    ims_charging: New module for Diameter-Ro-Operations (IMS-Charging), Merge into Master
     
-    - restrict opening of dispatcher connection to sub-processes (patch
-      provided by Emil Kroymann)
+    Credits go to:
+    - Jason Penton (jason.penton at gmail.com)
+    - Carlos Ruiz Diaz (carlos at ng-voice.com)
+    
+    Merge branch 'ims_charging'
 
-commit c837bba9f6808141e6d23daaecdea06fee39fa8a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Dec 13 11:58:34 2012 +0000
+commit f96c7f5a44e510dbc0e3483d98c8484a6a603c23
+Merge: 8b3d53b 792fc3c
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 22:36:35 2013 +0200
 
-    modules/websocket: Fixed resource leak and infinite loop in websocket module
+    Merge branch 'tmp/ims_charging' of ssh://git.sip-router.org/sip-router into ims_charging
     
-    - Can occur when TCP connections go away without the WebSocket being
-      closed properly.
+    Conflicts:
+    	modules/ims_charging/README
+    	modules/ims_charging/doc/ims_charging.xml
+    	modules/ims_charging/doc/ims_charging_admin.xml
+    	modules/ims_charging/mod.c
 
-commit 4daf033f3a8e98834cef39d9a339a007f1e1f217
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Thu Dec 13 07:56:51 2012 +0200
+commit 8b3d53b35f22c2de2203450af23dd8282ba8a7bc
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 20:46:30 2013 +0200
+
+    ims_charging: Beautified XML-Doc for IMS-Charging
+
+commit 1200242cadb445988b7e582fe62a3662caf99586
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Mon Sep 30 14:40:54 2013 -0400
+
+    ims_charging: added some stats
+    
+    - billed_secs
+    - ccr_avg_response_time
+    - ccr_responses_time
+    - failed_final_ccrs
+    - failed_initial_ccrs
+    - failed_interim_ccr
+    - final_ccrs
+    - initial_ccrs
+    - interim_ccrs
+    - killed_calls
+    - successful_final_ccrs
+    - successful_initial_ccrs
+    - successful_interim_ccr
+
+commit 4a050987a20a7489f08d9b7e88566439a764d013
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:30:41 2013 +0200
 
-    modules/tm: updated README on serial forking related vars and functions
+    ims_charging: Regenerated README after documentation update
 
-commit ca450b4be77150ce23ce825d795d697b4dea808f
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Dec 12 17:33:56 2012 -0500
+commit a0bdd980634635ca00a3ce87ac0ea03070b2a6ea
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:30:38 2013 +0200
 
-    xhttp_pi: install framework samples
+    ims_charging: Fixed minor typos in ims_charging-documentation
 
-commit c3c84162a96f6ff110c575d151543ec28b827752
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Dec 12 17:10:01 2012 -0500
+commit e9c7039efe2df811ba6e09829e7b713e5a25a808
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:24:51 2013 +0200
 
-    xhttp_pi: new target for makefile to generate framework templates
+    ims_charging: Regenerated README after documentation update
 
-commit c976e9e0f360da6696eefdc5b39bf019b004d3f4
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Dec 12 17:07:34 2012 -0500
+commit 46e1160be51d5c731fa1380f23d9d6dd0ca76f26
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:23:05 2013 +0200
 
-    xhttp_pi: generate templates for all kamailio tables
+    ims_charging: Fixed minor typos in ims_charging-documentation
 
-commit aa8e96f45c875b714336d121a3f89ba8e381030d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 12 16:09:20 2012 +0000
+commit c689a44ad13b430ac425e0efd46badf4ad021950
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:21:04 2013 +0200
 
-    pkg/kamailio/(centos|fedora): Updated .spec file
-    
-    - Added mangler module to build
-    - Tidied up make commands used to build and install
+    ims_charging: Fixed minor typos in ims_charging-documentation
 
-commit 1c36a534096e6ba37395e2ce1676526a02d1dac3
-Merge: 8ec3068 2d53d99
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 12 15:25:53 2012 +0000
+commit 5b3ef601025eeeda556b433b6257beaf88a7ee91
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:20:04 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      modules/tm: forgot to commit new version of t_funcs.c
+    ims_charging: Fixed minor typos in ims_charging-documentation
 
-commit 8ec30688617a260d478402e59ef465c69e8247d9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 12 15:24:38 2012 +0000
+commit ad7fb226901ca6ebc6119df0994054ba51100951
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:16:20 2013 +0200
 
-    parser/sdp: Fixed double free
-    
-    - Found and fixed by Hugh Waite @ Crocodile RCS
+    ims_charging: Fixed minor typos in ims_charging-documentation
 
-commit 2d53d99abcf9ae218fa547d572aee3f55dbba79b
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Dec 12 17:03:42 2012 +0200
+commit b9c8f31cfba447326869c32c87cb728c04ec0e28
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 12:58:56 2013 +0200
 
-    modules/tm: forgot to commit new version of t_funcs.c
-    
-    - reported by Peter Dunkley.
+    ims_charging: Documentation updates.
 
-commit 9c7edfe9edc02ea8b62c40349262b035f0b21510
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Dec 12 16:59:12 2012 +0200
+commit 792fc3cbc1a1181a482659ea5743681f1a52b911
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Mon Sep 30 15:57:23 2013 -0400
 
-    modules/tm: forgot to commit new version of t_funcs.h
-    
-    - reported by Peter Dunkley.
+    ims_charging: updated documentation
 
-commit 74a9baf6fd2903efc874edc48dd99d6a11afc83b
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Dec 12 16:11:50 2012 +0200
+commit 6fdc83ecd7fa5313635a0041e76498704b0c8225
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 20:46:30 2013 +0200
 
-    modules/tm: added outbound support to t_load_contact()/t_next_contacts()
-    
-    - added new function t_next_contact_flows()
-    - readme not updated yet
+    Beautified XML-Doc for IMS-Charging
 
-commit 89ac4ae40234e02d71f619c2f750ed34333c9d5d
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Dec 12 16:10:34 2012 +0200
+commit ef073a82f81af6e51dff19dcadfe4a8cb760c07d
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Mon Sep 30 14:40:54 2013 -0400
 
-    modules_k/registrar: lookup now handles also instance and reg_id
+    ims_charging: added some stats
+    
+    - billed_secs
+    - ccr_avg_response_time
+    - ccr_responses_time
+    - failed_final_ccrs
+    - failed_initial_ccrs
+    - failed_interim_ccr
+    - final_ccrs
+    - initial_ccrs
+    - interim_ccrs
+    - killed_calls
+    - successful_final_ccrs
+    - successful_initial_ccrs
+    - successful_interim_ccr
 
-commit 55e7820686cbfb6392e707e0ee4fae96b22670bb
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Dec 12 16:06:52 2012 +0200
+commit 1c3e761fbd087ee578ce305d89f6b8ee4e9ab79d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Sep 30 16:49:26 2013 +0200
 
-    parser: added instance and reg_id fields to sip_msg_t
+    app_perl: use local buffer to print dynamic string in pv_sprintf()
     
-    - also added set_instance and reset_instance functions
+    - avoid pkg malloc for temporary need
+    - fix leak in case of fmt parse error, discovered on a report by Dragos
+      Oancea
 
-commit dccf5ede42eaf2b2f030d8c5a730418ce0517ec2
+commit 0696e668d75be14922980dbc9f67aa91eaf688fd
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Dec 12 11:08:45 2012 +0100
+Date:   Mon Sep 30 15:54:44 2013 +0200
 
-    core: added comments to xavps structures
+    registrar: simplified getting value for max_contacts xavp
 
-commit bb1894ed7b868862402a63b858f52165d5deb463
+commit 308f2920df586065e0bf8ef02d7c77b1c94a4836
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 11 22:39:01 2012 +0100
+Date:   Mon Sep 30 15:49:10 2013 +0200
 
-    modules_s/mangler: moved to common modules directory
+    registrar: option to take the socket from an xavp
+    
+    - child named "socket" of xavp named by xavp_cfg parameter
 
-commit a4b0267cd57255a2f5c24bf466181e592841b6f7
+commit 89bd52a84d5e0d75572caff61346d0c3750c868a
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 11 22:36:14 2012 +0100
+Date:   Mon Sep 30 15:47:30 2013 +0200
 
-    modules_s/eval: unused module moved to obsolete directory
+    core: helper functions to get xavp child nodes
     
-    - use core config expressions
+    - one function to get the $xavp(rootname=>childname) in code
+    - wrappers for child node, child node with int value and child node with str value
 
-commit 5028c86d306a3f9ccec6e46d1fcf5f6a03f1d6ee
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Tue Dec 11 22:17:14 2012 +0100
+commit e266b01116513a4fcea5df1c761ef1981e17f8f8
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:30:41 2013 +0200
 
-    modules_s/options: moved to obsolete/ folder
+    Regenerated README after documentation update
 
-commit 47a9b7cf8b0d9f178f8905afc9434f0cd2d8f2f1
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Tue Dec 11 21:44:45 2012 +0100
+commit e98012e859ea6dd2c198d650f272d3e489758a22
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:30:38 2013 +0200
 
-    modules_s/speeddial: moved to obsolete/ folder
+    Fixed minor typos in ims_charging-documentation
 
-commit fc486d312ea11b6ff26c091e8649d9fe2228f931
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Tue Dec 11 21:30:41 2012 +0100
+commit 1265420b8b700eec9c96fd7752a5c3d528a51c32
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:24:51 2013 +0200
 
-    modules_s/uac: moved to obsolete/ folder
+    Regenerated README after documentation update
 
-commit cc9b6cad1130891c54b94b44bebb2b6cdf397b1a
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Tue Dec 11 16:29:30 2012 +0200
+commit bcdc27641fbec8176cea19fd4cefad1830a5c4db
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:23:05 2013 +0200
 
-    mod_python: Changed Loggers.py to use recent changes (python abstraction layers).
+    Fixed minor typos in ims_charging-documentation
 
-commit 63f0618dd47975afafb7757fe9e156534f05d468
-Merge: 230919a 669dc7b
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Tue Dec 11 16:08:25 2012 +0200
+commit ba0299bd965de8d513d70151c11bf13c4ec11560
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:21:04 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    Fixed minor typos in ims_charging-documentation
 
-commit 669dc7b72f76af715b2f34a0fbe64350202f8aff
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 11 14:57:24 2012 +0100
+commit e8a054d0e684b8f73bd0733d7d00d5e6b5e9b23f
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:20:04 2013 +0200
 
-    modules_s/msilo: moved to obsolete folder
+    Fixed minor typos in ims_charging-documentation
 
-commit 230919ad2e414f0c070a710cb85b3b2b3dfea741
-Author: Konstantin Mosesov <ez at voipgroup.org.ua>
-Date:   Tue Dec 11 14:24:08 2012 +0200
+commit 364dc576f602db40e93f446443e278290609237b
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 13:16:20 2013 +0200
 
-    app_python: Moved all python scripts to 'python_examples' folder.
-    app_python: Applied a few recent patches for better stack trace.
-    app_python: Fixed a possible segfault on double free.
-    app_python: Added python abstraction layers Router.Core, Router.Ranks, Router.Logger.
-    app_python: Moved all logging stuff to layer Router.Logger, e.g., Router.Logger.LM_ERR(...).
-    app_python: Added 'ranks' constants and moved to Router.Ranks, e.g., Router.Ranks.PROC_MAIN.
+    Fixed minor typos in ims_charging-documentation
 
-commit 5a3bc7a8f37a16f8194d117b7642ee532ee9e177
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Tue Dec 11 09:04:29 2012 +0100
+commit 4af2d9a46f1b7be273c079040989bd0d0c884feb
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Sep 30 12:58:56 2013 +0200
 
-    debugger: Minor README edits
+    Documentation updates.
 
-commit 27d02adf7bd3405cd67d2331ab7aa05b53d97c50
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Dec 10 17:08:51 2012 -0500
+commit 3c7f8ba5e3febe4dc2c8eec003436492efefdf2d
+Merge: 5ab44c7 b50888c
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Mon Sep 30 11:21:31 2013 +0200
+
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+
+commit b50888cf447ea3a3315e665c97f71a07bb687337
+Author: Øyvind Kolbu <oyvind.kolbu at usit.uio.no>
+Date:   Mon Sep 30 11:15:13 2013 +0200
 
-    sca: ignore transport parameter in RURI when processing SUBSCRIBEs.
+    core: resolve down to A/AAAA records when no naptr records
     
-    - Fix AoR hash lookups when client subscribes over TCP, TLS or SCTP.
-    - Report from Robert Boisvert.
+    - try all protocols, not only UDP
 
-commit 7a86ec5e7f9d4ef6a72da741b336c909109f3c88
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 10 13:55:13 2012 +0100
+commit 5ab44c7c2fc78038302bf455ff49e374fc79550b
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Mon Sep 30 11:14:54 2013 +0200
 
-    ratelimit: Adding a reference to the pipelimit module in README
+    modules/tm: extended async usage
+    	- enables resuming of tx in orginal route block tx was suspended, not only failure route
+    	- dedicated lock to prevent multiple invocations of suspend on tz (reply lock used to be used)
+    	- extra flag (T_ASYNC_CONTINUE) to mark a transaction that is being execute post suspend
 
-commit 4ff67e61e5b94fd5c842cf94b71dd723d41e7bf1
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Mon Dec 10 11:26:25 2012 +0200
+commit 6cdae87e29bc4c62651cf843ace680e9a6999d66
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Sat Sep 28 00:30:50 2013 +0100
 
-    modules_k/usrloc: added +sip.instance and reg-id to mi_usrloc_show_contact
+    pkg/kamailio/centos: updates to CentOS 6 build
+    
+    - Improved startup scripts
+    - Updated .spec
+    - README listing and explaining which Kamailio modules are not built for
+      CentOS
 
-commit 4f8d9b589df0c40f88fb34658f3735a222b0f545
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Dec 9 20:01:55 2012 +0000
+commit 32e26c3e914366636e4dcc6e8872eea16740e090
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Fri Sep 27 16:05:17 2013 -0400
 
-    pkg/kamailio/(centos|fedora): Updated .spec
+    ims_charging: added async support
     
-    - Changed rel to dev7
-    - Moved xlog from modules_k to modules
-    - Added avp, sca, and xprint modules
+    - Ro_ccr is now called asynchronously and resumed on an external custom cfg route
+    - Interim and final CCR are now also async
 
-commit a3ad00fea92f54aacf2425a0c2aaa9f78046d38e
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Sat Dec 8 18:22:15 2012 +0100
+commit 257ca31bb89cb4cb74cad226998574469873bc3b
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Sep 26 23:59:53 2013 +0100
 
-    modules_s/pdt: moved the module to obsolete folder
+    pkg/kamailio/centos: updated .spec for CentOS 6
     
-    - pdt(k) has support for multidomain
+    - Added gzcompress
+    - Updated rel to dev9
 
-commit bfa4d86a7a18b321a14b65c90d32c5aed32c10d3
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Sat Dec 8 14:20:43 2012 +0100
+commit ac5d846e2e472b1c097992bc2bdcfb58100c6eaa
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Sep 26 23:27:31 2013 +0100
 
-    pdt(k): added pdt.list command to dump memory structure via rpc
+    xhttp: cache the URL string when performing transformations so sequential transformations on the same string do not require a reparse.
 
-commit 6904d8c80b2089d01a69c3c0217c76c8e0132bac
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Sat Dec 8 14:19:30 2012 +0100
+commit 96c9a85b607e5c42ec0f0709a2807a60e7d5b1c4
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Sep 26 23:26:38 2013 +0100
 
-    dispatcher(k): use the right pointer to rpc context
+    pv: tweaked {param.} transformation so that if the (optional) delimiter parameter is changed between runs the param string is reparsed
 
-commit ad5cbdc7aa6156e072f0dd859421fc36b66227c0
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Dec 8 18:19:43 2012 +0100
+commit ed23dbde621a4b60d35639d3c61284b658fb6ad1
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Thu Sep 26 20:21:11 2013 +0200
 
-    ratelimit: Typo fixes, minor edits
+    Move assert_identity to ims_usrloc_pcscf as we may have more than one IMPI per Port/IP/Proto
 
-commit 181561c7dc50c0c4e6ac84b53b33d8a5bc6dd053
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Dec 8 16:09:40 2012 +0200
+commit 78d25dd11a64f36c5372cff3fe5d8a65a0e13396
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 26 15:10:22 2013 +0200
 
-    modules_s: migrated append_branch in cpl-c, exec, and registrar modules
+    db_mysql: unlock tables at the end of transaction if they were locked
 
-commit e8210c30ef79a5a6f6fa88a2cb47bf29ca50bfe0
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Dec 8 16:00:34 2012 +0200
+commit 8e35cef8716bbd0caa406a5080e93acb3c881c41
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 26 13:23:46 2013 +0200
 
-    modules_k/pv: fixed compilation error in define
-    
-    - removed extra ';' from km_append_branch define
-    - thanks to Daniel-Constantin Mierla for reporting
+    presence_xml: updated docs about integrated_xcap_server
 
-commit 440bcec4b5694ac79cd8dfb134defd472e96c60e
-Merge: 1cfa90d ca7b188
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Dec 8 14:12:15 2012 +0100
+commit baa4fccc2870df102a66089d6e9b6ca1ff47fc25
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 26 12:59:59 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    mi_rpc: compatibility with libxmlrpc-c3 library on wheezy
     
-    Sorry, still can't fix this. Working on it. :-)
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      core: restored USER_AGENT and SERVER_HDR defines
+    - patch by Muhammad Shahzad
 
-commit 1cfa90d171a72ad5e2b224ae0d6f2eb92d3eeb55
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Dec 8 14:10:48 2012 +0100
+commit 378bd71de3b035b497469f89a640931d0792ce4f
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Sep 25 16:12:50 2013 +0100
 
-    nathelper: add force_socket documentation (moved from rtpproxy module)
-    
-    The rtpproxy module did not have a force_socket parameter, but  nathelper did.
+    xhttp: added transformation to break a URL into "path" and "querystring"
 
-commit ca7b18825ed478b2d23a092f681939a233183003
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Dec 8 14:44:38 2012 +0200
+commit 454a28dad2fef3f1adaf0acec9a7f1c320fe6571
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Sep 25 16:11:57 2013 +0100
 
-    core: restored USER_AGENT and SERVER_HDR defines
+    pv: updated param transformations so that you can (optionally) specify what the parameter delimiter is
     
-    - they were changed by accident by previous commit
+    - default behaviour unchanged
+    - this allows HTTP URL parameters to be decoded
 
-commit 571e4e3fceeff5b4d32d1ac34649e9c4031d6543
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Dec 8 14:17:46 2012 +0200
+commit e0abe290c6ff287574e2abcadcc7a0f11197e268
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Sep 25 16:11:23 2013 +0100
 
-    core and several modules: instance and reg_id in branch_t
-    
-    - added instance and reg_id fields to branch_t
-    - added instance and reg_id arguments to append_branch function
-    - modified append_branch calls in core and several modules
-    - did not touch obsolete or modules_s modules (which are to be
-      removed from next release)
+    core: updated parse_param so that the delimiter for parameters can be user-defined
 
-commit 21b42fc14562758ac1dec5946a7b07a127054f47
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 23:28:40 2012 +0100
+commit b6b5b7bf5d08ad20cc00cf89ef3d2f03e913c882
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Sep 23 21:30:32 2013 +0200
 
-    modules_s/dialog: moved to obsolete folder
+    avpops: refresh README
 
-commit d560a18e44a9822fb1afa7f2047c82338838962e
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 23:26:33 2012 +0100
+commit 3abb169001022567aa0be629677b9e445d1c3ca5
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sat Sep 21 11:26:45 2013 +0200
 
-    modules_s/fifo: moved to obsolete
+    avpops: update avp_check documentation related to xavp vars as parameters
 
-commit 46f2a4300c1d9d96057d239dda1dc24c7caaf4d8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 23:25:49 2012 +0100
+commit dd049bad86eca2371b8f6ae1fd73656ff56e4e15
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sat Sep 21 10:49:57 2013 +0200
 
-    modules_s/unixsock: moved to obsolete folder
+    avops: avp_check() xavp as first parameter
 
-commit 04d77c20b80337019f71228dd0d9efe30d62db60
+commit 8a6a4f5d38ac693e7a79e0e761521375f3f5405b
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 23:17:11 2012 +0100
+Date:   Mon Sep 23 20:06:20 2013 +0200
 
-    modules_s/dispatcher: moved to obsolete folder
+    gzcompress: removed empty section in functions chapter
+    
+    - use deflate overall config example
 
-commit f817987eb7f50de7f6d0666620c6bb7fb50462fd
+commit 65783f24859f5da45678f2c8a005ca867cc02b86
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 23:14:53 2012 +0100
+Date:   Mon Sep 23 19:01:10 2013 +0200
 
-    modules_s/osp: moved to obsolete folder
+    gzcompress: added a small usage example in docs
 
-commit a40cea9f419b25aaeaabcd550ccf9106e9a029d7
+commit 3c65fd74f2473e857996ae1abf2d8fb8dcfaaaab
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 23:13:25 2012 +0100
+Date:   Mon Sep 23 18:50:14 2013 +0200
 
-    modules_s/xcap: moved to obsolete directory
+    gzcompress: readme updated to reflect default encoding value to deflate
 
-commit 8d70ccaf18683c0d594a00e804f5f43df2f50b7d
+commit d1263e418b7acbcc6ac798e25fc8bbcd8483fcec
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 23:08:11 2012 +0100
+Date:   Mon Sep 23 18:49:06 2013 +0200
 
-    presence_b2b: moved to obsolete directory
+    gzcompress: default encoding header value set to deflate
+    
+    - it is what UA use for this zlib compression algorithm
 
-commit 860c45f34190b57adfade0539f807fb1134662f9
+commit adf32ec8b3e6329d1c75f158a11395a077fc54ea
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 22:56:24 2012 +0100
+Date:   Mon Sep 23 18:42:54 2013 +0200
 
-    modules_s/diversion: moved to obsolete
+    core: aliased http_reply_hack to http_reply_parse
     
-    - modules_k/diversion is including its features and some extra ones
+    - a more relevant name for the core parameter that enables parsing http
+      replies
 
-commit a1c1fb0ab72a51fcfa9907e53e2b14cb79fdddc0
+commit d84a95b2dff1c373add8822ae7f1d9da495b5cd5
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Dec 7 22:53:21 2012 +0100
+Date:   Mon Sep 23 18:41:51 2013 +0200
 
-    modules_s/dbtext: moved to obsolete directory
+    gzcompress: enable compression for http messages
     
-    - not maintained, it does not compile
+    - tested replying with compressed body to an HTTP request from FireFox
 
-commit 08c872ed6935396cd6ea87af52af6393987d6d7d
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Fri Dec 7 02:05:49 2012 +0200
+commit 33557b2de1631601be9b03447e3167d06e8ce1cb
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Sep 23 18:40:48 2013 +0200
 
-    modules_k/registrar_k: added check that reg-id is not zero
+    parser: added macros to check if it is a SIP or HTTP reply
 
-commit d684d1ac49f740d32df5f82add584aeb396e26a4
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Fri Dec 7 01:33:52 2012 +0200
+commit bd716593efb83d4124c0c0cb824bf158d547ca0d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Sep 21 00:10:43 2013 +0200
 
-    modules_k/registrar: ignore reg-id if instance-id is not included
+    gzcompress: new module to compress/decompress SIP message body using zlib
 
-commit 5d3e8b9ff526246a8abe768a1d970dce70658dbe
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Dec 5 16:59:50 2012 -0500
+commit dcfa15de586e28a025e34590e800571b0e3abddf
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Fri Sep 20 21:07:30 2013 +0100
 
-    sca: update sample kamailio.cfg in README with small CANCEL fix.
-    
-    - Reported by Robert Boisvert
+    dmq: code cleanup, remove redundant includes
 
-commit 86c499e249bf43571d1cebca08821d30bff12dad
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Dec 5 16:22:47 2012 -0500
+commit 4b53052e3c912c927927529cd98a05957e02ab18
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Sep 19 09:19:16 2013 -0400
 
-    sca: add missing braces for CANCEL handling in sample config.
-    
-    - t_check_trans() if-block for CANCEL had no braces, but needs them
-      after addition of route(SCA) before t_relay of CANCEL.
-    - Reported by Robert Boisvert
+    presence_conference: fix what it looks like a copy/paste error
 
-commit 69dec26c718928f2cfc08bbae98658e145f8b04b
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 21:00:45 2012 +0100
+commit 1af47db737d8ca6fcfc43f4abb3d3768f5a8257c
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Sep 19 09:01:04 2013 -0400
 
-    modules_s/textops: updated path to xprint module
+    pdb: fix warning dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
 
-commit e722ab91eb90003741d236a9fecc6bbe954e21d3
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:59:27 2012 +0100
+commit 6592870dbd2b388b3884d85b9cc69e323f1d175a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 20 15:00:14 2013 +0200
 
-    modules_s/eval: updated path to xprint module
+    sl: use global variable for event route index for local response
+    
+    - rt should have been no longer used after previous commit
+    - reported by Ovidiu Sas
 
-commit ff7bd782a6e5f4c18f15ac429af313b54be38936
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:55:17 2012 +0100
+commit 8ca99e58442becd4513bb03730806c37f86f0d8f
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Sep 20 13:38:29 2013 +0200
 
-    modules_s/db_ops: path to xprint module updated
+    pv: use pv_get_buffer on pv_core
 
-commit 556c1e19ae5fd6139c6b0d7d3a5055d949583438
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:47:25 2012 +0100
+commit 039081166803f4be4226026e51f43ee9793876a3
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu Sep 19 13:27:21 2013 +0200
 
-    modules/avp_db: moved back to modules_s/ because it depends on local domain module
+    pv: get all values for second key for xavp
 
-commit b17e84ad3e5f781b83b1a8a80572ea4d24835b56
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:37:39 2012 +0100
+commit 16f87ae1b1f78938ed56a7c9a336a2853022b86c
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 20 13:39:15 2013 +0200
 
-    modules_s/avp_db: moved to modules/avp_db
+    sl: lookup event route for local response at startup
+    
+    - group lookup of sl event routes in one function
 
-commit 171f3dcf4287b7104a47b75e125174c374a457d5
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:34:25 2012 +0100
+commit f8697d13be92a79bdfcfd6a824d5e312f7b0d9e0
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 20 11:20:42 2013 +0200
 
-    modules_s/avp: moved to modules/avp
+    Makefile.defs: version set to 4.1.0-dev9
 
-commit 66840add8c37c110a8d08674f6a5f42d75a40287
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:33:40 2012 +0100
+commit e35fe9c6095361414565b1099dea1ad5950fb38d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 20 11:18:09 2013 +0200
 
-    modules_s/xprint: moved to modules/xprint
+    registrar: note about empty value for received_param
 
-commit 3d9ee6962f1ceeacbffd903064aa0779199f7ee6
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:32:29 2012 +0100
+commit 2f213e313a86e16665f6d0acfec959bf23f72b7d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 20 11:15:16 2013 +0200
 
-    modules_k/xlog: moved to modules/xlog
+    registrar: if rcv_parm value is empty, don't add received to contacts in 200ok reply
+    
+    - otherwise results in malformed value
 
-commit d91d49a026aba9092e9feda1d561d03c32f37e6d
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:25:16 2012 +0100
+commit 664b2f30de6518636085d676a32247c7d46bd2da
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 20 11:09:15 2013 +0200
 
-    modules_s/osp: internal occurences of xlog changed to xprint
+    registrar: list of allowed route blocks updated for save()
 
-commit 1d76de2a046e0d978e0b0155008dbed75dfc1067
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:24:54 2012 +0100
+commit e2376e34fbabd929d0736bddb8e82ceb25cc3738
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 20 11:07:31 2013 +0200
 
-    modules_s/ldap: internal occurences of xlog changed to xprint
+    registrar: relax usage of save() for failure route
 
-commit c560c7a6d0eeba3231e9f7caa0b5135160f75efe
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:24:36 2012 +0100
+commit 0968ce561b3bb8ea2ad2c7c53c03091e8518a6fe
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Sep 20 11:08:52 2013 +0200
 
-    modules_s/timer: internal occurences of xlog changed to xprint
+    avpops: allow xavp semantics on second parameter
 
-commit 7cf360fd63904e70441470f50164352b8867c9bd
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:24:21 2012 +0100
+commit df472fa9bdaa1a796dd220c99a64b1539c8854b5
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Sep 20 11:07:14 2013 +0200
 
-    textops: internal occurences of xlog changed to xprint
+    pv: Move pv_xavp_name_t declaration to core pvar.h
 
-commit 4c5c75ee46c38d47e01839eb6f1a8bc73441a507
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:24:02 2012 +0100
+commit 5acf191aee9d10b26b730df20d622e527c656db3
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Sep 18 17:10:10 2013 -0400
 
-    modules_s/permissions: internal occurences of xlog changed to xprint
+    xcap_client: fix what it seems to be an old copy/paste error
 
-commit f74575e551672d4defd2d7d34ef29cf285bcf9ec
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:23:26 2012 +0100
+commit 11ea7e73f0b541c2759d89a125b69a23cecb9ba9
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Sep 18 16:57:56 2013 -0400
 
-    modules_s/eval: internal occurences of xlog changed to xprint
+    xcap_client: fix what it seems to be an old copy/paste error
 
-commit 307a97dbd735e0a337b1019a6309c14e260f25c9
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:23:00 2012 +0100
+commit e45df83ddb68a90e91cc99fcdbb364f7b09ea541
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Sep 19 18:15:21 2013 +0100
 
-    modules_s/avp_db: internal occurences of xlog changed to xprint
+    modules/auth_ephemeral: many improvements
+    
+    - Some general tidying up of the code
+    - Support for both draft-uberti-rtcweb-turn-rest format usernames
+      and the original format
+    - New non-digest authenticate function that can be used to authenticate
+      WebSocket handshakes (based on URL and Cookie: contents) - this means no SIP
+      level authentication is required for WebSocket traffic
+    - Check functions to verify that the From:/To: URIs match the user-string part
+      of ephemeral usernames
+    - Check function so you can re-check the timestamp (for example, when caching the
+      ephemeral username during WebSocket handshakes you may want to check it is still
+      valid when a SIP request arrives)
 
-commit cf49d5daf9a29c44224472ae52bd7a6017cfbeee
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:22:25 2012 +0100
+commit f7fe8b68ffb100fbaa27344e4bee7ba69c760584
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 15:59:18 2013 +0200
 
-    modules_s/db_ops: internal occurences of xlog changed to xprint
+    pkg: kamailio - provide -f $CFGFILE to init.d config check function
+    
+    - reported by Grant Bagdasarian
 
-commit 6909bcae92e5f50fc247fd46eaf4b2b71d295c6b
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 20:21:39 2012 +0100
+commit 7730b5c3cf6b889f34de6004ce87341c746968ca
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 15:50:29 2013 +0200
 
-    modules_s/avp: internal occurences of xlog changed to xprint
+    core: msg_ldata_t field is memset to 0 in the shm clone
 
-commit 5144b151340da72272c0272bd0f45d0d4864173c
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:58:34 2012 +0100
+commit 859a322a1f664fcdd9563619fa0448be2911aa07
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 15:49:48 2013 +0200
 
-    modules_s/xprint: more of xlog rename to xprint
+    outbound: updated access cached flow through local data structire in sip_msg_t
 
-commit 948558abe33913fefd44d7601a14bac3d8594871
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:13:39 2012 +0100
+commit 4b99ad9e3bc364745d21eef11a392168eeb17077
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 15:49:17 2013 +0200
 
-    modules_s/xprint: internal log messages updated to reflect module name
+    tm: reset local data structure for faked request after failure handlers
 
-commit 5e2290c6625049ea42eaccc21c8686756f3a4156
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:11:31 2012 +0100
+commit 949e1f3c3e1f1afa02c696403399a093905c3f0a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 15:45:43 2013 +0200
 
-    modules_s/textops: bind to xprint API
+    parser: refactored a bit sip_msg_t struct for extra fields needed per process
+    
+    - a new structure to keep cached decoded flow for outbound, previously
+      was declared inline
+    - easier to reset it for shm clone and tm faked environment
+    - new fields that are needed inside the sip_msg_t but not cloned in shm,
+      must be added in the msg_ldata_t structure, accessible via ldv field
 
-commit 1a1337be4b9f2612375488d072301f43ce71e91c
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:11:05 2012 +0100
+commit a3a8457e9bfe4dea48c0acd7421952014346a907
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 15:17:38 2013 +0200
 
-    modules_s/eval: updated for xlog(s) to xprint rename
+    core: fix for warning dereferencing type-punned pointer will break strict-aliasing rules
+    
+    - related to timer list operation
 
-commit 88b7ea9f926605c98676dd6b039965dff295d9c7
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:09:37 2012 +0100
+commit 10cc1dd7a3f4481c677022e7ff0da87f004077f0
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 15:12:29 2013 +0200
 
-    modules_s/db_ops: use xprint module instead of xlog
+    parser: added note about new fields in sip_msg_t
 
-commit ceb2d50ff29d8b9f95660e4b520f458bb74853e2
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:09:04 2012 +0100
+commit 659b920399ee2a75973c610f5dec4c6292903f67
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 13:25:41 2013 +0200
 
-    modules_s/avp: switched to usage of xprint module
+    core: set to NULL the pointers to several sip msg fileds in cloned structure
+    
+    - instance, ruid and location_ua are reset to null for the clone in shm,
+      otherwise they point to pkg and the shm can be used from other
+      process, resulting in crash
+    - reported and credits for testing and troubleshooting to Alex Balashov
 
-commit c26533bb2b7f06e72366f2d920dc1e63d3eb159f
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:03:25 2012 +0100
+commit cebbacc3167f0fd4a4f3fd96393b5cf85e13d861
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 13:24:57 2013 +0200
 
-    modules_s/xprint: update defined value in header file
+    tm: faked request fields are freed using wrapper functions from core
 
-commit 3a1625d021d9ee46ad7beeb49c9d5ae2c933f970
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Dec 5 19:00:10 2012 +0100
+commit cae9659766c84e9451e4ea41e61bf85337c89693
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 13:23:53 2013 +0200
 
-    modules_s/xlog: renamed to xprint
+    parser: use wrapper functions to reset fields in sip_msg_t
     
-    - the modules is used by other ser modules for evaluation of strings
-      with %spec specifiers
-    - for printing log messages, better use the xlog module from now on
-    - xlog/xdbg functions are now xplog/xpdbg
+    - used for freeing the structure
 
-commit 6d0f635b0bbf338fca0ddc2c7d8e79bc686e5040
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Dec 5 14:00:12 2012 -0500
+commit deb007275ae6444037e74c82a48fc879a0cc98ad
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 12:34:33 2013 +0200
 
-    sca: modify SCA_STR_EMPTY macro to fix -Waddress compiler warnings.
-    
-    - Reported by Ovidiu Sas
+    parser: ppi/pai - fix warning dereferencing type-punned pointer will break strict-aliasing rules
 
-commit c8772fc3eea75f5caad64770c6bbe6823ad7f1ef
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Dec 5 13:24:20 2012 -0500
+commit aa9f500c80cb5372c40f1eb7f18b4e33dcd6acf5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 12:27:35 2013 +0200
 
-    modules_s/domain: remove unused variable
+    core: a bit of cleaning in sip_msg_t comments
 
-commit 753d1d885d7c2f0e1a30df939455fcb4349a7506
-Author: Ovidiu Sas <osas at dbn>
-Date:   Wed Dec 5 13:17:23 2012 -0500
+commit 8bb61ea287ccf670ef9cfe990d319249eafbe7c5
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Sep 18 21:58:12 2013 +0100
 
-    modules_s/registrar: remove unused variable
+    modules/app_lua: Fix off-by-one error in modf
+    
+    - Fixes calling sr.modf with additional parameters
 
-commit 96c39e3c31f416bbe42b434a8bbf3ece88a8ab52
-Author: Ovidiu Sas <osas at dbn>
-Date:   Wed Dec 5 13:12:02 2012 -0500
+commit 771e9093e343951e12f4875692e9ecc567a277a1
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Sep 18 21:34:16 2013 +0100
 
-    qos: remove unused variable
+    modules/sdpops: Check for valid sdp body in sdp_remove_line_by_prefix
+    
+    - Fixes crash when used on requests with no body
 
-commit 263aae0a48f3a92a0e8c0ce43a7d6f610ea8a239
-Merge: 8b73129 e819eaa
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Dec 5 15:13:48 2012 +0000
+commit b9c6e70871085e63add429984eac8ee7afc9e49e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 19 00:09:55 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    README: updated version number
     
-    * 'master' of ssh://git.sip-router.org/sip-router: (268 commits)
-      xcap_client: fix cross-compilation
-      utils: fix libcurl dependency
-      core: print debug message instead of info message when trying to resolve    something that is not domain name.
-      Makefile: adding xhttp_pi to the list of excluded modules (depends on libxml2)
-      xhttp_pi: fix installation of the pi_framework.xml file
-      sca: fix DB updates
-      sca: sca_subscription_print now logs at debug level
-      tls: fix cross-compilation
-      Makefile: fixed the option of setting some variables from command line
-      Makefile.defs: version set to 3.4.0-dev7
-      Makefile: default FLAVOUR set to kamailio
-      sca: more cleanup of SCA example kamailio.cfg
-      sca: include sample kamailio.cfg in docs, update function examples
-      sca: move working example SCA kamailio.cfg to doc subdirectory
-      app_python: better printing stacktrace
-      app_lua: fix cross-compilation
-      app_python: expand log facilities
-      sca: remove public IP from example cfg
-      sca: add working example kamailio.cfg
-      carrierroute: fix cross-compilation
-      ...
+    - bits of formatting for ToC
 
-commit e819eaa0b0be61b3a818422c0ced244b5250295c
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Dec 5 09:23:45 2012 -0500
+commit 89969601d66422fd4dab50b0bb303bb17465c193
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Sep 18 22:23:41 2013 +0200
 
-    xcap_client: fix cross-compilation
+    pua_reginfo: documented the parameter for reginfo_handle_notify()
+    
+    - reported in FS#340
 
-commit a1e462c1695013d3c74e1c1ec443df7697bb6607
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Wed Dec 5 09:16:15 2012 -0500
+commit 9ee44c6079c8d30138ece619295974e17993aa04
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Sep 18 22:17:55 2013 +0200
 
-    utils: fix libcurl dependency
+    pua_reginfo: add ruid for location records
+    
+    - patch by Wonbin Cho, FS#339
 
-commit 87456bae50b55501c25f33a6728f4469639e0599
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Dec 5 10:26:29 2012 +0200
+commit ed6884e854cdae63c4f62871a32bdcdcddb8853e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Sep 18 22:02:04 2013 +0200
 
-    core: print debug message instead of info message when trying to resolve
-       something that is not domain name.
+    pua_reginfo: unlock udomain only when aor is set
+    
+    - patch by Wonbin Cho, FS#338
 
-commit 205e8545dca12bebf742b23eba592d2713623a66
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Dec 4 17:03:15 2012 -0500
+commit 3bc87f139bc9635e23a4e92b03d24e00b97706dd
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Wed Sep 18 13:39:23 2013 -0400
 
-    Makefile: adding xhttp_pi to the list of excluded modules (depends on libxml2)
+    ims_registrar_scscf: fixed bug caused by uninitialized global variable
+    
+    - "rerrno" variable was not initialized and caused corruption in transaction states
 
-commit 7a63bbed0ccc1a2a85b26d127e775f832efaa2a7
+commit 96e760147469a385a0b5512f74afcff8f56cafd1
 Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Dec 4 16:18:12 2012 -0500
+Date:   Tue Sep 17 09:24:51 2013 -0400
 
-    xhttp_pi: fix installation of the pi_framework.xml file
+    dispatcher: fix mi/rpc reload command
 
-commit 5871982d3c76a4b42cd05e4b8dfb0e6128acb799
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Dec 4 17:04:11 2012 -0500
+commit 5e775ff328b73b816e61a0a4718b194591a98251
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed Sep 18 14:15:17 2013 +0200
 
-    sca: fix DB updates
-    
-    - if a subscription were updated before being inserted into the DB, the
-      next DB sync call would incorrectly try to UPDATE instead of INSERT.
-    - no effect on SCA functionality, but subscriptions are no longer lost
-      across restarts.
+    avops: use pv_cache_get instead of pv_parse_spec.
 
-commit a289c6167f39f14af85d78392a8bef91da81d858
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Dec 4 16:47:39 2012 -0500
+commit 519de2cdd1ed7fb969d3bb2cf5792d4180078cbb
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Sep 18 08:18:33 2013 +0300
 
-    sca: sca_subscription_print now logs at debug level
+    modules/lcr: fixed checking of IPv4 address in to_any_gw_2 function
     
-    - previously logged at info level for every incoming SUBSCRIBE.
-
-commit 389bbe3410018e6d58befb486f0db2ec4ff7ece6
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Dec 4 15:58:03 2012 -0500
-
-    tls: fix cross-compilation
+    - Patch was provided by Reinier Boon.
 
-commit e5dbe686bcbf15ac59ebbcb84f3bb9b17568c030
+commit af8923703276bb41ea269cc19a7812fea325a250
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 4 21:59:16 2012 +0100
+Date:   Tue Sep 17 15:00:37 2013 +0200
 
-    Makefile: fixed the option of setting some variables from command line
+    debugger: reset_msgid parameter was in functions sections
     
-    - resulted in mixing names for config files
-    - issue added in previous commit
-    - reported by Ovidiu Sas
+    - added some section ids
 
-commit 94dde4a5b0f146914d124367ef73c5940cbb7d97
+commit 2710177c2673034d3f026dfa79432e986b8c3a90
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 4 10:48:23 2012 +0100
+Date:   Tue Sep 17 14:55:07 2013 +0200
 
-    Makefile.defs: version set to 3.4.0-dev7
+    debugger: documentation for cfgpkgcheck parameter
 
-commit 4af2262b88918c316ee3bb9b45a716504f2f8db4
+commit d1e456b251602e1336e4dbede1e9f8b5d1c19415
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Dec 4 10:28:03 2012 +0100
+Date:   Tue Sep 17 14:47:49 2013 +0200
 
-    Makefile: default FLAVOUR set to kamailio
-    
-    - switching to the flavour with packages and docs
+    debugger: new parameter cfgpkgcheck to do pkg memory check before each action
 
-commit b8007d985660b4df5ea9d5ea4347adf65b7f90fa
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Dec 3 23:59:50 2012 -0500
+commit af7c3a816529cde599af9a62bfd174b2de3a2fb6
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Sun Sep 15 18:10:06 2013 -0400
 
-    sca: more cleanup of SCA example kamailio.cfg
-    
-    - remove unused xhttp event route
+    xmlrpc: fix warning: âc.lenâay be used uninitialized in this function [-Wmaybe-uninitialized]
 
-commit a635a80df762e13373ad59a6d746530c2163c2a6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Dec 3 23:59:51 2012 -0500
+commit 78a1c7e972b66c882e9466404d1cb6c08982eb91
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Sun Sep 15 18:06:18 2013 -0400
 
-    sca: include sample kamailio.cfg in docs, update function examples
+    ipops: fix warning: variable âtâet but not used [-Wunused-but-set-variable]
 
-commit 0a2fc3f7490088b02861d9dace0f039ceab54af7
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Dec 3 23:59:49 2012 -0500
+commit aa15067b8a1f44d57551f646acd5058c08abe41f
+Author: Mikko Lehto <mslehto at iki.fi>
+Date:   Sun Sep 15 16:55:04 2013 -0400
 
-    sca: move working example SCA kamailio.cfg to doc subdirectory
-    
-    - will also be included in README and xml docs for convenience.
+    rtpproxy(-ng): patch: has_sdp() does not exist
 
-commit 97fe5fec90999491d455b10b1fea7529e786719b
-Author: Konstantin M <evilzluk at gmail.com>
-Date:   Mon Dec 3 22:35:21 2012 -0500
+commit d1219dc0d0c5e2eab0672a439aa7ce6486c31ba3
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Sun Sep 15 16:38:34 2013 -0400
 
-    app_python: better printing stacktrace
+    xhttp_pi: fix crash when checking bad configs
 
-commit d41c9a91afdd7a5a2c5e689f3302211c6bbeffb6
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 3 18:39:19 2012 -0500
+commit a68e48bc3c322be79a608d91f40d10329c2e9664
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Sep 16 20:31:44 2013 +0200
 
-    app_lua: fix cross-compilation
+    corex: new pv $cfg(key) - return attributes for config file
+    
+    - $cfg(line) - the line of the current action.
+    - $cfg(name) - the name of the current conf file
+    
+    Example of usage:
+    
+    append_to_reply("P-Cfg-Line: $cfg(line)\r\n");
 
-commit acbeda46ac94e6c5c215a03bd803e10b2c7540db
-Author: Konstantin M <evilzluk at gmail.com>
-Date:   Mon Dec 3 18:26:36 2012 -0500
+commit ca568ee6996cc93e8518f277cf34111bc0c78299
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Sep 16 09:53:15 2013 +0200
 
-    app_python: expand log facilities
+    core: added wrapper functions to return cfg line and name for current action
 
-commit 5b63e94e49feb0a35b093a5eb3a86c9e5c1a0ba7
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Dec 3 17:15:47 2012 -0500
+commit 4294b7bf3b67f1405869e865c171e268e60d5ee7
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Sep 15 22:35:38 2013 +0200
 
-    sca: remove public IP from example cfg
+    core: store current executed cfg action in a global variable
+    
+    - can be retrieved by module to access name of config file and the line
 
-commit c40883a7aa96a1a7fab1060bf9dfab2987971c89
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Dec 3 17:14:14 2012 -0500
+commit e63af00eaa92eed106356cbb1dd6afd8b09f3e69
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Sun Sep 15 23:38:56 2013 +0100
 
-    sca: add working example kamailio.cfg
+    dmq: added dmq_load_api to exported functions
 
-commit f9c0980c4f85d8b728eb36e6b5768173750c6964
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 3 12:55:25 2012 -0500
+commit 923d09f0c1ece04c8d3c2755b5b201b3a2cd2deb
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Sun Sep 15 23:38:45 2013 +0100
 
-    carrierroute: fix cross-compilation
+    dmq: regenerated readme
 
-commit 175934a802cf863f26f84f9e11a2eec4606ecfd1
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Dec 3 08:43:01 2012 -0500
+commit b44f00adbf57cb4306a0dcde7a8a1425afe40a8f
+Author: Charles Chance <charles.chance at sipcentric.com>
+Date:   Sun Sep 15 23:38:30 2013 +0100
 
-    db_postgres: fix cross-compilation
+    dmq: updated documentation
 
-commit e09b92893fd35baf672541143951337b103bb65b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 3 08:10:34 2012 +0100
+commit 102074ce6085f963ac03dcb087e1c00941c0337d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Sep 14 09:46:50 2013 +0200
 
-    mqueue: README update
+    tm: readme regenerated
 
-commit c29773967e83c4b3977b76a43805dd622bc018a9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 3 08:06:27 2012 +0100
+commit f328b864418020b1e166b13804fe173110500d75
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Sep 14 09:46:23 2013 +0200
 
-    mqueue: minor edits to README
+    tm: added missing documentation for t_check_status()
 
-commit 287c02de1491019fbf085742b82fc7040ea72886
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Dec 3 08:01:06 2012 +0100
+commit 6a51d9e87ac2e51a3c0473e11b3347739ec33dd8
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 13 13:47:00 2013 +0200
 
-    corex: minor documentation edits
+    textops: free result of subst transformation when is larger than target buffer
 
-commit 6a45c8eba310afa9b8173c0522d77e7a574ddc52
-Author: Konstantin M <evilzluk at gmail.com>
-Date:   Sun Dec 2 22:21:05 2012 -0500
+commit 56d02f02627bb1d2eca7befaaefbed17ced1f52f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Sep 13 11:08:48 2013 +0200
 
-    app_python: fix compiler warnings
-     - patch provided by "Konstantin M <evilzluk at gmail.com>"
+    usrloc: fixed xml tags and regenerated readme
 
-commit 10fc575cc383093953d71c69e8d9a0065f33bdfe
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 16:00:17 2012 -0500
+commit 605360798fbad43cbd3ef1aca3ae76cd9c95c50f
+Author: Vitaliy Aleksandrov <vitalik.voip at gmail.com>
+Date:   Fri Sep 13 11:05:07 2013 +0200
 
-    lcr: fix cross-compilation
+    usrloc: update connection id for registration refresh
 
-commit 291df73af6f35526e4c43c1c7d8b8ea15e93aa64
-Merge: 9b67242 e1faa05
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 2 21:27:22 2012 +0100
+commit f3190358e02141c98304c4c0019bba95490da32c
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Sep 12 22:54:35 2013 +0100
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    pkg/kamailio/centos: moved stun from it's own RPM to the main RPM
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      xcap_server: fix cross-compilation
-      regex: fix cross-compilation
-      pua_xmpp: fix cross-compilation
-      pua_usrloc: fix cross-compilation
-      pua_reginfo: fix cross-compilation
-      pua_dialoginfo: fix cross-compilation
-      pua_bla: fix cross-compilation
-      pua: fix cross-compilation
-      presence_xml: fix cross-compilation
-      presence_reginfo: no need to link against libxml2
-
-commit 9b67242978cb6aab702ccf4715e9152ac8f719c8
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 2 21:26:54 2012 +0100
+    - stun no longer has external dependencies and doesn't need to be in its own
+      RPM
+
+commit 291d6ece47d164d64487c8545de87c64fdc31718
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Sep 12 22:41:37 2013 +0100
 
-    auth: README update
+    Makefiles: moved stun to the standard module group now that it has no external dependencies
 
-commit 25600feab7d5d3b30420a05fd4c899f0bbbff667
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Dec 2 21:24:13 2012 +0100
+commit 42722f3e70d3316b7c6881907b626b02303d58a6
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Sep 12 16:36:28 2013 +0100
 
-    auth: Documentation corrections
+    modules/stun: removed dependency on OpenSSL
 
-commit e1faa0591c05482be95eb81016c37b9a5be57d14
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 15:09:24 2012 -0500
+commit 0d0c4cc11022a62edfcf5041b36fe4cf5ca95a4d
+Merge: 5651be2 6cea922
+Author: Carsten Bock <Carsten.Bock at silentcircle-llc.com>
+Date:   Thu Sep 12 17:16:09 2013 +0200
 
-    xcap_server: fix cross-compilation
+    Added support for HTTP-Post to utils: http_query
+    
+    Merge branch 'carstenbock/utils_post'
 
-commit 50f4cd86ccebab713c2b9895cdffbd619e84955e
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 15:07:28 2012 -0500
+commit 5651be2fa5a5d923a89aa70a050d23bcbfda9c38
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Sep 11 13:09:31 2013 +0100
 
-    regex: fix cross-compilation
+    pkg/kamailio/centos: CentOS build updates
+    
+    - CentOS .spec is now separate from Fedora .spec. This is because I no
+      longer have a Fedora system to test/maintain this on. Old .spec with
+      Fedora support is in pkg/kamailio/fedora and can be taken on by
+      someone else if needed.
+    - Updated rel in .spec to dev8
 
-commit beb3425e309b0f7d1b2bccee942c35f541a2dd7d
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 14:53:44 2012 -0500
+commit 0f7bc9da0d132720531f3176ee216466f5877146
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Sep 11 11:30:50 2013 +0100
 
-    pua_xmpp: fix cross-compilation
+    core: Raspberry-pi builds now work without needing to specify extra flags
 
-commit c9d7fc58a19afdeb77fb3b496068d3f79ef95c67
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 14:52:16 2012 -0500
+commit 6f17209a70e84d91976ea42b476ae248b9b37501
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 10 14:14:52 2013 +0200
 
-    pua_usrloc: fix cross-compilation
+    kamdbctl: added missing dbuid tables group creation
+    
+    - patch by elactrum [at] jamailca.com
 
-commit e5a49d909d582fe601cabbccf4f9ce2efa814414
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 14:47:33 2012 -0500
+commit abf0026782c0ba4643feb25ded022e8c12725584
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Sep 9 16:52:47 2013 +0200
 
-    pua_reginfo: fix cross-compilation
+    uac_redirect: get_redirect() check reason value before using it.
+    
+    This fix a core dump when get_redirects() config fuction is called with just
+    the one parameter.
 
-commit 417c7d9f4ba5e709e8bf65aa413584ad2bcae277
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 14:44:52 2012 -0500
+commit 774752e4d12bd03f01362af55a5e422eade690b2
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Thu Sep 5 19:10:15 2013 +0200
 
-    pua_dialoginfo: fix cross-compilation
+    Another Fix for the ims_charging Module:
+    - Use P-Asserted-Identity instead of From-Header
+    
+    fixed by Carlos Ruiz Díaz (carlos at ng-voice.com)
 
-commit d4f5465efae12c0ef66cb519ece3b3558b10ea5f
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 14:42:19 2012 -0500
+commit 6dc04484e39ceab4887b375d2510f35892d695eb
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 5 11:54:03 2013 +0200
 
-    pua_bla: fix cross-compilation
+    acc: for time_mode=1, save timestamp in time_attr and microsecs in time_exten
+    
+    - database records stores time as datetime value
+    - new parameter time_exten to allow customization of attribute name
 
-commit 528d518494c73883fd77acd8e438bb16d2de5d3e
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 14:38:42 2012 -0500
+commit 367a0e72be1d5e5de0fa84ca2a8d11f7d5b54abe
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 5 11:08:17 2013 +0200
 
-    pua: fix cross-compilation
+    acc: fixed c&p typo of parameter name in docs
 
-commit d749894cae84112b4ffcc47d385d877961787a46
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 14:35:15 2012 -0500
+commit a722cee262664162f183e00788c2d53c4c98b217
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 5 10:04:57 2013 +0200
 
-    presence_xml: fix cross-compilation
+    kamctl: added scripts to define table acc_cdrs
 
-commit 8a5164c47ac85e87dd092eb2ac56c0161759861c
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sun Dec 2 13:56:36 2012 -0500
+commit b91f07fce16f5feb0c31f7af59ab9351e274221f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 5 10:04:14 2013 +0200
 
-    presence_reginfo: no need to link against libxml2
+    lib/srdb1: added id for definition of column start_time in acc_cdrs table
 
-commit 3aa1929ac18d747b24a14b6e9f6decbf7ed1a137
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 23:27:44 2012 -0500
+commit dd3c6f19c18cf0c2844f2b2ce155e3f5d7af447a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Sep 5 10:02:01 2013 +0200
 
-    presence_conference: fix cross-compilation
+    lib/srdb1: initial db schema for acc_cdrs table
 
-commit b19700f17de38e1bffd93bbbd897044e0c696d40
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 23:25:50 2012 -0500
+commit 9b44e4b48862947f2ea634c6dd611ce7c07546a2
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Sep 4 22:59:13 2013 +0200
 
-    presence_dialoginfo: fix cross-compilation
+    registrar: reset r-uri pointer after backup in lookup_branches()
+    
+    - otherwise can be invalidated by next branch lookup
 
-commit 46ce25ceda08916a355328682768699b6cff4d36
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 23:24:06 2012 -0500
+commit 37e63951b2b05875f07a1d30b8352e3f10a99072
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Sep 4 18:20:20 2013 +0200
 
-    presence: fix cross-compilation
+    Bug-Fixes:
+    - Use P-Asserted-Identity instead of From-Header as User in CCR
+    - Store RURI in the ro_session structure (it may have been changed by an Application-Server)
+    
+    Fixed by: Carlos Ruiz Díaz (carlos at ng-voice.com)
 
-commit 5ffd8eda41567f12c7224d68e32a1a20779d22a6
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 23:21:44 2012 -0500
+commit 96c85efbc40a6d0571e8122cbad30410d2274b24
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Sep 4 14:27:47 2013 +0200
 
-    rls: fix cross-compilation
+    Initial structure for the docs of the IMS-Charging module (incomplete)
 
-commit 58bfbd3259587b29b7b509a360aa889924dec8de
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 23:18:47 2012 -0500
+commit 20399521b7df9e808f0999275132cc5460a0104b
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Sep 4 14:00:01 2013 +0200
 
-    cpl-c: fix cross-compilation
+    add IMS-Charging to Makefile.groups
 
-commit bc9dca0a9d05915a0f4634b7014b26958e81e21b
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 16:59:56 2012 -0500
+commit 29cb7be4445995f73e9f425d99c9c5ee818c92de
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Sep 4 12:04:18 2013 +0100
 
-    db_mysql: fix cross-compilation
+    modules/rtpproxy-ng: Allow PV in second rtpproxy_manage parameter
+    
+    - Incorrect fixup function caused a crash when the second parameter was given
 
-commit c31fd10ee20ff09115ae745792db4a0e03eb9e07
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 16:54:38 2012 -0500
+commit 362d374a61953aee3cf9f96eadaef63c5f22763e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Sep 4 13:04:23 2013 +0200
 
-    cdp: un-used variable commented out
+    topoh: safety check for missing To header
+    
+    - based on a patch by Michel de Weerd, FS#303
 
-commit 8321d1fadb50017b52bcfebd1857982a60915dfe
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 16:52:19 2012 -0500
+commit acbbae2af3cb2ad1a5b07a7305c5f9761bc78389
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Sep 4 12:52:16 2013 +0200
 
-    cdp: fix cross-compilation
+    modules/ims_charging: new module for IMS charging
+    	- currently supports Ro interface
 
-commit e45d706ba82ff9a36602cc7c2a28a55502abf99f
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 16:46:10 2012 -0500
+commit 7abd496560c6274680d451f49355ad1f6a14a6a7
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Sep 4 12:33:45 2013 +0200
 
-    xhttp_pi: fix cross-compilation
+    db_postgres: use variable for make tool in module Makefile
+    
+    - fixes builds in BSD systems
+    - patch by Victor (coyote), FS#335
 
-commit 7abf33373b0bfa0bc709286b01e9a7da2200659b
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 16:42:15 2012 -0500
+commit 2aa5095252f9434c7c2a63ecb130bdaf1346fde9
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Sep 4 11:44:23 2013 +0200
 
-    dialplan: fix cross-compilation
+    rtpproxy: updated rtpproxy_manage() to handle PRACKs with sdp
 
-commit 8b6f3c51d7636905ea8a6f4754673ba569404cd7
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 16:38:16 2012 -0500
+commit 72996942662b944b74e6632e1670c989402bf8af
+Author: Vitaliy Aleksandrov <vitalik.voip at gmail.com>
+Date:   Wed Sep 4 09:56:28 2013 +0200
 
-    cdp_avp: there's no xml dependecy for cdp_avp
+    usrloc: detect lost tcp connnections on timer and set associated contact as expired
+    
+    - new module parameter to control this feature: handle_lost_tcp
+    - at this moment it is not implemented for db only mode
 
-commit 10de949af0f9f01b0585db0fd53d53452f97e067
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Dec 1 11:18:08 2012 +0100
+commit 392a59ab1c12efee1072581f9519fc258444d086
+Author: Vitaliy Aleksandrov <vitalik.voip at gmail.com>
+Date:   Wed Sep 4 09:55:23 2013 +0200
 
-    sqlops: Fixing typo in documentation, minor edits
+    registrar: propagate tcp connection id in contact info structure
 
-commit 99521dafd452e56d7974fcbf8c32bd3679ccc4c9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Dec 1 11:05:57 2012 +0100
+commit ea45a9b0ff6851d01e09aa62dfe9e7e006552609
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 23:16:50 2013 +0200
 
-    pua_usrloc: Minor edits, typo fix
+    pua: basic framework for handling xcap-diff event
 
-commit fe6508d6d56a7f739c7fc0ae2220e509abb337e1
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Dec 1 10:49:11 2012 +0100
+commit 0c15125767f8a9001e9c892fee18df3dbad56d2f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 23:15:55 2013 +0200
 
-    sdpops: Typo fix, minor edits
+    presence_xml: basic framework for handling xcap-diff event
+    
+    = can be diabled via modparam disable_xcapdiff
 
-commit a7522f0d648470e36a82357660fc169628b2f506
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Dec 1 09:50:31 2012 +0100
+commit 70ec02cfc9a203ea100d6550be3aa5f51f4fa473
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 16:16:30 2013 +0200
 
-    utils: Minor update to README
+    acc: option to write dialog-based cdrs to database
     
-    XML changes already committed.
+    - new module parameter cdrs_table has to be set and classic db
+      accounting enabled at compile time and db_url set
+    - cdr_log_enable - new parameter to turn off writing cdrs to syslog,
+      cdr_enable being now used as top level control flag for both cdrs to
+      syslog or db
 
-commit 4fda56162c3b174033ea81ffd7c2af4a6e7f10f2
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 01:30:24 2012 -0500
+commit 4812b91a3c00e71a3ac9636b88bc75e5368fa657
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 15:11:47 2013 +0200
 
-    xmlrpc: fix cross-compilation
+    acc: increment crt position when adding extra time value
 
-commit c4b91489ac3f2e2fcbe16413f56ef8cb8e7e2dde
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 01:28:03 2012 -0500
+commit 4c917438596852b3870ce0236bad8cbd04961270
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 14:31:58 2013 +0200
 
-    utils: fix cross-compilation
+    Makefiles.defs: version set to 4.1.0-dev8
 
-commit a419c74d065156a2c9626b2475beaf08e130137e
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 01:24:24 2012 -0500
+commit ea6514c2af00561643af6a2b671fbd4411048ca1
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 13:47:24 2013 +0200
 
-    xmlops: fix cross compilation
+    acc: updated readme with the new parameters
 
-commit 983dd207a51be5ea2bd2a71d546280f8e4389408
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Sat Dec 1 00:12:34 2012 -0500
+commit ede2d6747aabf32538797dfedf13682c5c242831
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 13:35:08 2013 +0200
 
-    kamailio.cfg: adding xhttp modules to the default config
-                  three new defines: WITH_XHTTP, WITH_XHTTP_RPC, WITH_XHTTP_PI
+    acc: cast to double for safer conversion in time_mode==2
 
-commit 209317a81d845ba781964205242849ab12bbc0c2
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 30 21:38:48 2012 -0500
+commit d7884500e89d32bffd34e915b473458645c6dedf
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Sep 3 13:28:54 2013 +0200
 
-    sca: fix snprintf buffer size for Expires header in replies to SUBSCRIBE.
+    acc: new parameter time_mode
     
-    - reported by Robert Boisvert.
+    - store additional time value in time_attr attribute/db column
+    - if time_mode==1, then time_attr stores the microseconds
+    - if time_mode==2, then time_attr store the seconds.miliseconds
+      (proposed by FS#163)
+    - if time_mode==0 (default), then it is like now, only timestamp stored
+    - time_attr value can be set via parameter with same name - it
+      represents syslog value or db table column
+    - for db accounting, when time_mode==1, the type of column has to be
+      int, and for time_mode==2, the type of column has to be double
+    - features implemented only for syslog and db accounting
 
-commit 8632a265c3703e19cad9253f84527a913ee9cdd5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 30 14:42:19 2012 -0500
+commit 1cec15e057bdec4455e70af951def19e36a78e8e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Sep 2 14:09:18 2013 +0200
 
-    sca: support Record-Route
+    kamctl: added commands to set extra columns in subscriber table
     
-    - Save Record-Route values from SUBSCRIBEs to ensure NOTIFYs traverse
-      correct path to subscriber.
-    - Update SCA DB schema & creation scripts: add record_route column,
-      increment sca_subscriptsion table version.
+    - useful to deal with columns added for load_credentials of auth_db
+      module
+    - 'sets' - sets a column with string value
+    - 'setn' - sets a column with numeric value
+
+commit 7e44ff0be6cbb48c9360bee8601ec3dbff050c02
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Sun Sep 1 19:56:57 2013 -0400
+
+    Fixed potential bug in exceptional condition when max-time updated is called
 
-commit 1da2a76be4e374ddb4296a1d54963fe344dc0970
+commit 2685cd9bb6933c2d4b4b97e3b4ed6b98005255c9
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Thu Aug 29 17:05:41 2013 +0300
+
+    parser/fline.c: syslog message cleanup when request line parsing fails
+
+commit fbcee0221cd6e22477dc9d1d5a7767c1e572235a
 Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Fri Nov 30 14:00:09 2012 -0500
+Date:   Wed Aug 28 15:03:01 2013 -0400
 
-    core/corex: move send()/send_tcp() to corex module
-    
-    As suggested by miconda on sr-dev, move send() and send_tcp() out of core
-    and into the new corex module in order to make them support pseudo variables.
-    This changes:
+    rtpproxy-ng: fix possible segfault in rtpproxy_manage
     
-    - drops SEND and SEND_TCP tokens from config parser
-    - remove related config parser code relying on SEND_T and SEND_TCP_T
-    - augment corex module to provide the functions removed from core
-    - update corex docs
+    Reported by Hugh Waite
 
-commit 3376e3b8c54a7c9bc13f87368baeaaa145a9ced5
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Nov 30 09:31:47 2012 +0100
+commit e0e0a753d1365d340c17f33bd868085bee304910
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Aug 28 12:02:34 2013 +0200
 
-    htable: Update documentation on mod-init
-    
-    Based on Daniel's answer in sr-dev on a question about lua. The Lua environment
-    is initialized in child processes, so it's not reachable in mod-init.
+    dialog: fixed typo related to module name inside log message
 
-commit cf97967489f1b61c5bf0a841f9f650e40fc9911e
-Merge: d02070d 514875d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Nov 29 22:01:05 2012 +0100
+commit bf68c071723bda24b07e64660f77872e2bceff1b
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Aug 27 18:43:39 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    permissions: fix ws support on allow_trusted function.
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      kamctlrc: adding sca to the list of extra modules
+    Thanks to Alex Hermann <alex at speakup.nl>
+    Reminder: Never commit with more than one glass of wine.
 
-commit d02070dbef121525b320487d4ad2fbfda55aa62d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Nov 29 22:00:19 2012 +0100
+commit 14835f89fc2b761f73a0caad67d229ec3fedba29
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Aug 27 14:44:17 2013 +0200
 
-    ipops: Minor documentation changes
+    core: set to-params pointer to null after freeing
     
-    Use the IPv6 documentation address in examples if possible - 2001:DB8::/32
+    - avoid potential double freeing issues or invalid pointer access
 
-commit 514875de53e19cfd4a208da3d778e454ce12a6f4
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Nov 29 15:42:26 2012 -0500
+commit 727aa357d9ee8abcb8471733e22886d2cff386db
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Aug 27 14:00:17 2013 +0200
 
-    kamctlrc: adding sca to the list of extra modules
+    kamdbctl: new command add-tables
+    
+    - creates only tables that are groupped under same id, thus have the sql
+      script in a file
+    - syntax: kamdbctl add-tables <gid>
+    - there has to be a <gid>-create.sql script
+    - eg: kamdbctl add-tables lcr
 
-commit 14333d9360273c073473c144c198496a314e2e73
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Nov 29 21:18:14 2012 +0100
+commit a075383454c92bed225b7904920090f515a938d5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Aug 27 11:16:52 2013 +0200
 
-    utils: Fixing typos
+    kamctl: use FIFOPATH instead of OSER_FIFO in kamctlrc
     
-    Typos that I missed in the first check...
+    - no longer relation to former project name, however OSER_FIFO can still
+      be set to keep the compatibility with older deployemnts, but will be
+      used only when FIFOPATH is not explicitely set
 
-commit 1ab39cf866600ce155db3d5454981167d001d285
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Nov 29 21:15:53 2012 +0100
+commit 8097c2bccb2161f63900bbd5fb87a10eacdd282c
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Aug 27 00:07:58 2013 +0200
 
-    utils: Minor documentation changes
+    permissions: update allow_trusted documentation.
 
-commit 010ea5d4b71308cb18cd759db70ac48f081a672e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Nov 29 20:52:27 2012 +0100
+commit 573c9031a44168df356818f572f10f69791a1458
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Aug 27 00:03:49 2013 +0200
 
-    LDAP minor documentation changes
+    permissions: fix ws support on allow_trusted function.
 
-commit aca01e149445a0c6f87a9ed97974bcba612e426f
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Thu Nov 29 09:57:48 2012 -0500
+commit b2a536f0f577026ffa57d0b603c60e6232bc8e78
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Aug 23 21:04:06 2013 +0200
 
-    sca: adding missing sca db utils files
+    tm: readme regenerated
 
-commit cc3bc9669a2c528db9a8ada5e13cd553be9d2f1e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Nov 28 23:23:48 2012 -0500
+commit ef9b69bbb54302e9985dd37d79831b6f80463fc1
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Aug 23 21:03:13 2013 +0200
 
-    sca: remove old SQL table creation file
-    
-    - use make dbschema to generate sql from xml table schema instead.
+    tm: removed note about no-implentation for no-reply flag for t_relay_to()
 
-commit 7575c853b1786fc09965238ea68bca4400bd7c5f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Nov 28 22:50:30 2012 -0500
+commit 6073949aa224ea7a973058891a88a58cc0841860
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Aug 23 21:02:24 2013 +0200
 
-    sca: add db schema files and kamctl table create SQL file.
+    tm: updated xml docs with t_set_disable_internal_reply()
 
-commit eddd6b80432a3feda925ccb629bf55892d4b175f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Nov 28 12:02:53 2012 +0100
+commit 0f2f9c85eff0b6ad35b4c58dfcde74c8a65559d6
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Aug 23 20:53:55 2013 +0200
 
-    group: Minor changes to documentation
+    tm: re-added the option for no-internal reply on error
+    
+    - new function t_set_disable_internal_reply(0|1) to disable|enable this
+      option per transaction
+    - t_relay_to() flags re-enabled for this option
 
-commit 7b5f56e05482ea060dc1c093db599fd8cda22f9e
-Merge: 2536a10 358cfb7
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 27 15:13:21 2012 -0500
+commit 7255693f73bae008e5c7b6b560c52394f7c85308
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Fri Aug 23 17:29:43 2013 +0200
 
-    Merge branch 'master' of git+ssh://git.sip-router.org/sip-router
+    Very basic DNS-Zone file-example for IMS (for use in the online-tutorial on howto install IMS with Kamailio)
 
-commit 2536a10c516b7c569d04e431b74bbd88964603a7
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 27 14:06:23 2012 -0500
+commit 6cea9227c7dc973757d03150685e322fcff115b9
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Thu Aug 22 16:36:48 2013 +0200
 
-    sca: fix potential leak of parsed To body
-    
-    - if msg->to wasn't parsed, sca_subscription_from_request called parse_to,
-      but never called free_to_params.
-    - make the subscription to-tag independent of the parsed to_body with a
-      pkg_malloc'd copy, freed in the caller.
+    Define missing fixup_functions.
 
-commit 358cfb781a4854a3943b96ede552e46ccb1ccc77
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Nov 27 13:28:03 2012 -0500
+commit b23a74a4732f276315176d9b438bd2596e616799
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Aug 21 20:14:16 2013 +0200
 
-    modules_k/dmq: add newline at end of file (peer.c)
+    Fix fixup functions.
 
-commit 9ef5345481a526e2417ce59ebc13f19132e02934
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Tue Nov 27 13:25:12 2012 -0500
+commit 8017fa7c67dbb3dd4bdd937be9b841097a44674e
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Aug 21 20:02:23 2013 +0200
 
-    modules/tm: add newline at end of file (test.c)
+    Add support for sending POST-Requests to http_query() method.
 
-commit 777c3e3e388f4267744cd5368956900cea296b07
-Merge: 141fc56 5908a9e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 27 00:32:43 2012 -0500
+commit 134158df11ebf9b6c3deaf71b6010588535eb386
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Thu Aug 22 20:39:41 2013 +0100
 
-    Merge branch 'admorten/sca'
+    pkg/kamailio/(centos|fedora): Added rtpproxy-ng module to the build
 
-commit 5908a9e88242a166c71b03bce77b326c2f27f5a6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 27 00:28:28 2012 -0500
+commit c2ccd37891167fb691b2aabc44e12c45cea7d1da
+Merge: fd68623 dd76f37
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Thu Aug 22 14:19:31 2013 -0400
 
-    sca: move to modules directory
+    rtpproxy-ng: adding module
     
-    - moved after removal of usrloc dependency per miconda's request on sr-dev
+    Merge branch 'rfuchs/rtpproxy-ng'
 
-commit 95cf6e358b2be210b61e6d060df0604e3e36a043
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 27 00:24:11 2012 -0500
+commit fd68623bebb7053f4b652d7fe58d676b6a019d7c
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Aug 22 17:51:49 2013 +0200
 
-    sca: update docs
+    core: efectively run the event_route[core:receive-parse-error]
     
-    - "domain" modparam no longer required.
-    - usrloc no longer a dependency.
+    - reported by Juha Heinanen
 
-commit 959b2c423a70395c97437d0bcef7950762c4a9b5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 27 00:09:06 2012 -0500
+commit 0efe5a4d9adb08575938d2c4eb83ec3a79d38e20
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Thu Aug 22 11:16:31 2013 -0400
 
-    sca: remove dependency on usrloc.
+    Added support for max-time update of monitored calls
     
-    - usrloc callbacks in practice were only useful for expired
-      registrations, and even in that case our expired subscription
-      timer is likely to have purged the stale subscription.
+    - updated example config file
+    - updated documentation
 
-commit 141fc56f5a46f26e40e8e19e4f5eb02844d192d7
-Author: Ovidiu Sas <osas at voipembedded.com>
-Date:   Mon Nov 26 23:18:02 2012 -0500
+commit 86bdfaa3efe7804bcfde3da4f63b252c74e417b7
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Aug 22 15:44:05 2013 +0200
 
-    socket_info: add #include "linux/types.h"
+    core: fix condition to lookup envet_route[core:receive-parse-error]
+    
+    - reported by Juha Heinanen
 
-commit 0af64c92263b82dc4b487c4da5199c8b150b0517
-Author: Andrew Mortensen <admorten at umich.edu>
-Date:   Mon Nov 26 16:50:43 2012 -0500
+commit 2d826efb7dbcf9b3b49c376bcd079ab1e7642a44
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Aug 22 13:01:55 2013 +0200
 
-    sca: eliminate need for "domain" modparam
+    core: execute event_route[core:receive-parse-error] block on error of initial sip message parsing
     
-    - Extract domain to be used in idle appearance from subscription AoR instead.
+    - note that the SIP message is broken in this case, but it gets access
+      to source and local socket addresses (ip, port, proto, af) as well as
+      the whole message buffer and its size
 
-commit 76885b5c67ca7467d6681b81841f0323dca6ab35
-Merge: 17d1934 cceb39f
-Author: Alex Balashov <abalashov at evaristesys.com>
-Date:   Mon Nov 26 08:18:48 2012 -0500
+commit d03651fb4c3a6b50923029e121eed201fb1ff550
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Thu Aug 22 08:20:52 2013 +0300
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/lcr: added some linefeed chars missing from syslog messages
+    
+    - Patch provided by Kevin Scott Adams.
 
-commit 17d1934cebd1c96c7f3689be33ccae2a981f6b2c
-Author: Alex Balashov <abalashov at evaristesys.com>
-Date:   Mon Nov 26 08:17:18 2012 -0500
+commit 3ccf4b43e81bd2654cb306a3c2cc21b97cb51f62
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Aug 22 00:14:53 2013 +0200
 
-    dialog(k): Added dlg_set_timeout_by_profile() route script function.
-    
-    This function allows the same dialog timeout to be set across all
-    the dialogs in a profile (with or without values).
+    core: print src address details if initial message parsing fails
     
-    The intended use-case is to allow the user to conditionally end or
-    expire from tracking a user's/caller's/account's calls.
+    - reported by Juha Heinanen
 
-commit cceb39f9fb8a55ab7e43f4a546d3d524f5acccd4
+commit fe24ed17b0620bd9446d741ea3f65b7b0cb8b765
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Nov 26 14:14:37 2012 +0100
+Date:   Wed Aug 21 11:20:07 2013 +0200
 
-    mem: check debug info only when joining the next packet
+    kamailio.cfg: use is_first_hop() for adding alias parameter to contact uri
     
-    - it was checked even it was not freeand not the case for a join
+    - done for natted devices
 
-commit 45d8d3ccd943caad37570ae013118536d38a8457
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Nov 26 13:53:22 2012 +0100
+commit bbecaa597aa4fb3fa08773cd6cd9b8558c7ce3a8
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed Aug 21 11:04:08 2013 +0200
 
-    Makefile.defs: version set to 3.4.0-dev6
+    avpops: allow use of avps as second parameter on re operation at avp_check function
 
-commit d96401668cefade5e251b101eb93f07faae091ad
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Nov 26 13:51:53 2012 +0100
+commit c86b04459a716af353d0ca40a793d6b13c6a6fe7
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Aug 20 10:24:53 2013 +0200
 
-    Mkefile.defs: default memory manager set to q_malloc
-    
-    - debug option is left unset (no DBG_QM_MALLOC)
-    - lower memory chunk overhead with faster join
+    fixed spelling errors catched by lintian
 
-commit 15a0b9c23e4b4f829bbb88f73e8042371f3f38a2
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Nov 26 13:42:07 2012 +0100
+commit 64e39dbf89bc1581722abeaadf7811e0883390bd
+Author: Elena-Ramona Modroiu <ramona at asipto.com>
+Date:   Mon Aug 19 17:43:16 2013 +0200
+
+    htable: updated readme with rpc command htable.stats
 
-    Makefile.defs: added MEMMNG to allow selection of memory manager
+commit d33106994516e27944657c3bf17c3ccb5a521a50
+Author: Elena-Ramona Modroiu <ramona at asipto.com>
+Date:   Mon Aug 19 17:39:26 2013 +0200
+
+    htbale: added rpc command htable.stats
     
-    - MEMMNG=0 => fast malloc is used (f_malloc)
-    - MEMMNG=1 => quick malloc is used (q_malloc)
-    - MEMDBG is used now to set the debug mode for each of the managers
-    	- 0 - no debug info
-    	- 1 - debug info enabled
+    - print stats about htables: name, number of slots, number of items, max
+      number of items per slot, min number of items per slot
 
-commit 8acb59ee4de31ab76763a021acaf7b5a13e02f23
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Nov 25 21:54:32 2012 +0100
+commit ee7dcac57501cd0563c69ae967ba785cec035062
+Author: Elena-Ramona Modroiu <ramona at asipto.com>
+Date:   Mon Aug 19 16:48:01 2013 +0200
 
-    dialog(k): safety check for callid parameter in mi commands
+    htable: lifted limit for max number of slots to 2^31
     
-    - if not provided properly, it may result in crash
-    - reported by Ricardo Martinez
+    - there can be systems with large amount of memory
+    - clarification in docs about the case when the value is out of exected
+      range
 
-commit d43fbf2a5a5464a4a499282b88d58a1fc97b9c7e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Nov 25 16:38:27 2012 +0100
+commit 71594a81f012432782d1f7b6f59c725130928ee7
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Mon Aug 19 13:41:45 2013 +0200
 
-    sanity Sanity-checked spelling. Minor corrections.
+    cdp: fixed spelling and removed some erroneous code
 
-commit b8e877889a99b03f190a82acf101681a23ca11d6
-Author: Andrew Mortensen <admorten at umich.edu>
-Date:   Sun Nov 25 09:09:59 2012 -0500
+commit ea442b3155bf25ff48f7fd125b2ffa72a5631852
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Sun Aug 18 17:47:08 2013 +0200
 
-    Use project-wide gitignore instead.
+    Only update received info, if a contact is "new" contact. In case of multiple registration for one AoR, each registration will have a different contact.
 
-commit 1dad8ba9cceb4de3131fe358c643833fa20b484f
-Author: Andrew Mortensen <admorten at umich.edu>
-Date:   Sun Nov 25 09:08:42 2012 -0500
+commit ec1c1bab23e4fff3bd5cd60c2f254e646dcbc9ee
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Fri Aug 16 17:08:15 2013 +0200
 
-    Remove leftovers from standalone repo.
+    Do some debug output, when searching for user based on IP/Port/Proto.
 
-commit 9e4b7e56f471c7923100905d0221b0d7b19f4949
-Merge: a708dcb 579299c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sat Nov 24 22:06:22 2012 -0500
+commit 157a466d46f6cccaf790ca3ad3d400489ebdd1ed
+Author: Peter Dunkley <peter.dunkley at crocodilertc.net>
+Date:   Wed Aug 14 21:30:45 2013 +0100
 
-    Merge remote-tracking branch 'sca/master' into admorten/sca
+    pkg/kamailio/(centos|fedora): Updated .spec
 
-commit a708dcb5ad90ec517db481fea0570ec53863b471
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Nov 21 17:22:31 2012 +0100
+commit 9061cf2a85ac89cf403910b7b4fa93b29dccb350
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Aug 13 11:45:02 2013 +0200
 
-    lib/kcore: reset time value for faked msg
-    
-    - reported by Uri Shacked
+    modules/debugger: refresh README
 
-commit 579299cb8f95512dda6663e963769231887c43de
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 20 23:13:35 2012 -0500
+commit 5cbedc6b515b50f9ade7457abedba18747d98f75
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Aug 13 10:14:42 2013 +0200
 
-    Regenerated README after fixing typos and documenting more RPC commands.
+    modules/debugger: Added module parameter reset_msgid. Added RPC command dbg.reset_msgid
+    
+    The message id ($mi) will be reset but internally there is no change. This can be
+    useful for unit tests cases.
 
-commit b6cebc5147bf44d85d9c312fb170bb6d6c748c07
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 20 23:10:59 2012 -0500
+commit b0e9132ccd1e8385b8b4faf72db806320d48e2f5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Aug 13 09:37:21 2013 +0200
 
-    Document sca.seize_appearance and sca.release_appearance RPC commands.
+    usrloc: safety checks to catch empty ruid
 
-commit 38d134a0d34b5335fb7a826585ce08d72d462bcc
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 20 23:08:38 2012 -0500
+commit 66c8e730d59f9816f09573f5300e4463e5997876
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Aug 13 09:19:02 2013 +0200
 
-    Update sca_call_info_update ex. to make clear it should be call for To URIs.
+    usrloc: more verbose log messages in case of failure to update db records
 
-commit 7e29507f68d4fda9b785c35651f1195991fda99b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 20 23:08:05 2012 -0500
+commit d1cda7ca9a64cf818b82f7b777fa2dd640717c53
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Mon Aug 12 11:15:55 2013 +0100
 
-    Fix typo: "line_seize" -> "line-seize"
+    presence: Iterate correctly around presence updates
+    
+    - timer_send_notify should increment the subset by one on each loop
 
-commit c5fac4809aac489163bcd9c4fbf6636092000f85
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Nov 20 23:41:04 2012 +0100
+commit 4f42993660c52c757918ca2806f7ffe6af0674ce
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Mon Aug 12 11:05:55 2013 +0100
 
-    kamctl: new command 'db showg'
+    rls: Fix memory leak in rls notify.c
     
-    - uses \G at end of sql query, resulting in line-formated output (at
-      least for mysql)
+    - xml is leaked in an error case
 
-commit 61472e04704e99836743c833eb66c33ea0d81724
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Nov 20 23:10:28 2012 +0100
+commit e88af0a02de79fac583c126f08d762f7ef3f1b01
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Jul 16 10:51:29 2013 +0100
 
-    sdpops: added sdp_content()
+    outbound: Fix freeing null pointer in destroy function
     
-    - return true of there is a sdp part in the body of sip message
+    - Only appears in error cases, e.g. syntax check
+
+commit 0c590e00796573681fd7ee0a99dd324919a9e4e9
+Author: Dragos Dinu <dragos.dinu at 1and1.ro>
+Date:   Wed Aug 7 17:29:06 2013 +0300
+
+    Fixed two bugs related to new capture_mode changes.
 
-commit 6df74c2fb208c364b5d50e9d87f80120de93c945
+commit 93c39f86ce0cd337212579bd7bd1e58cabed79ca
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Aug 7 01:20:43 2013 +0200
+
+    Fix previous commit (forgot this file)
+
+commit 25240becdd83801a788b65f52eada5dd63665e8c
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Tue Aug 6 22:48:39 2013 +0200
+
+    Extension to the API: lookup_terminate_dlg(unsigned int, unsigned int, str hdrs)
+    - Terminate a dialog using the API by providing h_entry and h_id (similar to the MI-Function)
+
+commit e6e0419a46c3e5127d07c95390931d10b2a01c3b
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Nov 20 21:55:51 2012 +0100
+Date:   Sun Aug 4 14:22:41 2013 +0200
 
-    sdpops: internal function w_get_sdp renamed to w_get_sdp
+    imc: wrap bit shift defines in parenthesis
     
-    - match the exported name pattern
+    - avoid priority conflicts when using the defines
+    - reported by Shankar
 
-commit 5d2cba306439adfa36c1e01ccd6473f372ac7e5e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:29:24 2012 -0500
+commit 6a981d3d922c914054d4c8dc7e672bb6a4ddb5f5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Aug 1 15:58:59 2013 +0200
 
-    Remove redundant message logged when removing subscriber after failed NOTIFY.
+    db_flatstore: free id pointer if no more space for table name
     
-    Subscriber removal on failed NOTIFY is currently disabled.
-
-commit 742bc69927eee2df330a85d248144b308aa3a08e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:28:17 2012 -0500
+    - related to previus commit on this module
+    - keep table name null terminated
 
-    Remove debug log message from usrloc callback.
+commit 8fb0f711aaa611eac8b2776c7e5ae3c5e19243ac
+Author: Federico Cabiddu <fcabiddu at orange-vallee.net>
+Date:   Mon Jul 29 07:59:34 2013 +0200
 
-commit ba394704868ad9e788ca1fb6a3a8e769f91c628a
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:27:03 2012 -0500
+    db_flatstore: fixup for new_flat_id function
+    
+    - locally copy table's name
 
-    Make purge expired log message more readable.
+commit 4bc07b15ae9a490273b2696b2860f78ebbd18104
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Aug 1 14:35:16 2013 +0200
 
-commit 6c0f220013450894a2b2076b3414857a8fa0b592
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:25:55 2012 -0500
+    kamctl: shortcut command to do q query to a database based on key and value
+    
+    - kamctl db smatch table key value - return the record from table that
+      has column key matching the value as string (quoted value)
+    - kamctl db nmatch table key value - return the record from table that
+      has column key matching the value as non-quoted
+    - examples:
+    
+    kamctl db smatch subscriber username test
+    kamctl db nmatch subscriber id 123
 
-    Remove leftover debugging in show_subscription routine.
+commit 9a0147b8e050bb8ac7b443e4a3139bb326308cba
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Aug 1 14:12:30 2013 +0200
 
-commit f9b4ef27e5336e235f6f79506ca115f188e6101d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:24:57 2012 -0500
+    acc: remove comment from previous patch
+    
+    - references to tracker should be in comments of the commit, not in the
+      code
+    - use tabs for indentation
 
-    Remove debug log message enumerating subscribers in hash slots on NOTIFY.
+commit 341f810dca0cc0596e22f2ac1bca86de0b8d142d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Jul 31 12:22:12 2013 +0200
 
-commit f76d90abae5fe6a3df4225d54d38170c854f3771
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:24:02 2012 -0500
+    app_perl: push the sip msg structure to perl after initializing it
+    
+    - reported by David Cunningham
 
-    Remove debug log message leftover from early testing.
+commit 7ba6cbfcaf70cb546ea3a9f148a0f0b0bc38c16d
+Author: Federico Cabiddu <fcabiddu at orange-vallee.net>
+Date:   Mon Jul 29 07:59:13 2013 +0200
 
-commit 4ad1c196b5a92ded7aa625db4bf583a2563cf900
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:22:32 2012 -0500
+    acc: acc_db_set_table_name fixup
+    
+    - add termination char to db_table_name_buf
 
-    Log error when building Replaces header and dialog to replace is not confirmed.
+commit 1bf5c8328e8b4ed13f6404bf617cac9e26c05e63
+Merge: 0e9b4b3 fb3a5f7
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Mon Jul 29 09:49:57 2013 -0400
 
-commit 0870c8b926b3ef63d1fb8e20aaf625de375fde7d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:18:00 2012 -0500
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
 
-    Updated with typo fixes from docbook xml.
+commit 0e9b4b351e70323fd8581d298f1a7d682f2310fe
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Mon Jul 29 09:46:35 2013 -0400
 
-commit 88c4680aed5a13a33a3c2c3cd6a21d2b2eaf6c9e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:12:37 2012 -0500
+    Modified cnxcc_set_max_credit behavior
+    
+    - Updated documentation
+    - Updated examples
 
-    Forgot to add doc Makefile to repo.
+commit fb3a5f7022ebd20fc516b5b8303a0274bda18258
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Jul 26 14:55:38 2013 +0200
 
-commit 277dc5ef0233fa95746b7e9556e6e11ee3aa4da4
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 22:11:05 2012 -0500
+    acc: safety check for accounted values not to be NULL
+    
+    - based on a patch by  Federico Cabiddu, FS#327
 
-    Fix typos and formatting.
+commit 3d33733f299dda595704108aef73a2912dc3069f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Jul 26 14:52:21 2013 +0200
 
-commit 78ba61f271998ca2b6e54cbdd2be5caf47838493
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 17:17:44 2012 -0500
+    uac_redirect: fixup for using acc table parameter
+    
+    - set reason parameter for acc function
+    - based on a patch by  Federico Cabiddu, FS#327
 
-    Add simple installation instructions.
+commit 1aea13af9b3eea3788e90411bd94cb9e0b0c4ea3
+Author: Camille Oudot <camille.oudot at orange.com>
+Date:   Tue Jul 23 11:11:01 2013 +0200
 
-commit ce6a9ca274c7d38faba2f1ff49e2f09896a9e6a4
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 16:47:06 2012 -0500
+    modules/ims_registrar_scscf: safety check in async_cdp_callback
 
-    Add copyright comments to all source files.
+commit 6ff74701652a11497bd82ee3ba2ac7547d1ce666
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 25 10:14:55 2013 +0200
 
-commit a6b36b03f107be84e8c7bfd9f30f782c51e4f600
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 16:40:44 2012 -0500
+    app_perl: move initialization of SIP message var after initialization of temporary environment
+    
+    - upon a report by David Cunningham of a leak in operating system
+      memory
 
-    Add GPLv2 license
+commit da057e5730dd9f82101437e0ee3ceca02b64602c
+Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
+Date:   Tue Jul 23 10:37:03 2013 +0200
 
-commit b1465456aae950c1a70928a2e596cbc6b34c2ccf
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 16:10:36 2012 -0500
+    modules/sipcapture:  Added support for multiple capture modes.
+    			(c) Dragos Dinu (1and1)
 
-    Regenerated to include mention of usrloc dependency.
+commit ab601ea9a1b2561c2eaa860583cdeed478b9ea8d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Jul 20 10:01:25 2013 +0200
 
-commit 0bef7be9bf745e73230f14637e54defae3e5afe5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 16:10:03 2012 -0500
+    Makefile: sercmd renamed to kamcmd in uninstall option
 
-    Include usrloc dependency.
+commit 2a77bcd36a2b8b91a6d4af3f6ee6828265af39a5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 18 20:59:54 2013 +0200
 
-commit 2708f57b8a464905e909409e475dd731b413a5b9
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 16:08:15 2012 -0500
+    Makefile.defs: removed SCTP conditions for core locating libsctp
+    
+    - the code is now in a module, only generic hooks are in the core, that
+      can be turned on/off by SCTP variable (no lib dependency)
 
-    Add docbook-generated README for sca module.
+commit d3a0a8b15af59846fdaee5d9ceae61484f1d7301
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Jul 17 20:19:28 2013 +0200
 
-commit 3a7771c9c6c4225cbb380a20a28b6ce5b9ffda2e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 16:07:32 2012 -0500
+    uac: restrict check of multiple from/to header changes to request route blocks
+    
+    - it can occur many times in due to branch route usage
+    - reported by Andrew Pogrebennyk, FS#323
 
-    Add failure_route example.
+commit 6624d10b5edbfaf32726875fbbf2ac2221807c84
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Jul 17 12:26:11 2013 +0200
 
-commit 23a02a761da2e408a5bea914a66842a85e2260f0
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 15:58:31 2012 -0500
+    uac: $uac_req(sock) - new attribute to set local send socket
+    
+    - local socket can be set for generated requests:
+    
+    $uac_req(sock) = "udp:127.0.0.1:5060";
 
-    Remove quotes from integer values.
+commit 9a3aa5e6e7949dd08146910a301fbeebdf052742
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Jul 17 12:24:42 2013 +0200
 
-commit 6e35d942926837176f74cee843d989753897f8be
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 15:50:28 2012 -0500
+    tm: enhanced local request API to set send socket
 
-    Fix typo leaving XML comment unterminated.
+commit 6335d07c4c77ed60fb8c2b5acc84d7c4b503221c
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Jul 17 12:22:31 2013 +0200
 
-commit 4b0e0e4b81becde2769f69539fa23a15f69099f2
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 15:47:01 2012 -0500
+    core: helper functions to lookup local socket from proto:host:port
 
-    Add Exported RPC commands section.
+commit 716ffd2787a68734a21a1374c3dc6dd4783844bd
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Jul 17 00:04:06 2013 +0200
 
-commit fb03bbe9469aeec92bf729abe5b8a8b181d99766
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 15:27:01 2012 -0500
+    presence_dialoginfo: add schema to entity
+    
+    - patch by Pawel Sternal, FS#324
 
-    sca module doesn't export any functions.
+commit acd0bfb5acc98e791ab6cf011dfa758efba2be8f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Jul 16 21:40:06 2013 +0200
 
-commit 296bb6d07b9f6a62848ae14f02382ffd95516a15
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 15:26:41 2012 -0500
+    usrloc: fixed type for db_ops_parameter
+    
+    - reported by Alex Hermann
 
-    Add functions section.
+commit d07e4f709ceaccc84bbab42dfd55d10992e84a3b
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Tue Jul 16 18:02:50 2013 +0200
 
-commit 6d66ec1cd80eb0cd7878c37d6f0c216d1439c3b5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 14:40:51 2012 -0500
+    Example-Configs: Fixed config due to last updates
 
-    Add sca module parameter documentation.
+commit 9a2b943bfccea83ac52ecb63f39c724f4b9504d4
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Tue Jul 16 18:00:51 2013 +0200
 
-commit d4f35ceae85f2ae72f0e384188c677f272c4a544
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 13:06:15 2012 -0500
+    ims_registrar_pcscf: Bug-Fix for pcscf_assert_identity (minor)
 
-    Add module Dependencies section.
+commit b4c3b811d33846dd0900922bbe5a3d9472839663
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jul 15 23:45:33 2013 +0200
 
-commit 006f822bf9921bf3ae84e14cd62d413057fd2d56
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 12:59:55 2012 -0500
+    ipops: documented dns_query()
 
-    Correct typo.
+commit 257225e6918c1387049b74663225ee9b3b722ddf
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jul 15 23:38:25 2013 +0200
 
-commit 60e1602829b1926576998f36d06a487304d4c964
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 12:58:54 2012 -0500
+    ipops: reset address types for new dns queries
 
-    docbook Overview documentation for sca module.
+commit 20f3846d6d39e8fd599464d1e5ce48bfec326586
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jul 15 23:32:33 2013 +0200
 
-commit 835fcebe45854daac2ccbc942732cba8f5231fa5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Nov 19 12:56:27 2012 -0500
+    ipops: new function dns_query(hostname, pvid)
+    
+    - store the result of dns query in a variable $dns(pvid=>key)
+    - dns query is using getaddrinfo()
+    - $dns(pvid=>key) - new pv allowing to navigate through the result of a dns query
+    - key can be:
+    	- count - number of addresses
+    	- ipv4 - set to 1 if at least one ipv4 address (otherwise 0)
+    	- ipv6 - set to 1 if at least one ipv6 address (otherwise 0)
+    	- addr[index] - the address as string from position index in the list (0 based indexing)
+    	- type[index] - the type of address from position index in the list (0 based indexing), the value is 4 for ipv4 and 6 for ipv6
+    - example:
+    
+    	if(dns_query("test.com", "xyz"))
+    	{
+    		xlog("===== number of addresses: $dns(xyz=>count)\n");
+    		xlog("===== ipv4 address found: $dns(xyz=>ipv4)\n");
+    		xlog("===== ipv6 address found: $dns(xyz=>ipv6)\n");
+    		$var(i) = 0;
+    		while($var(i)<$dns(xyz=>count)) {
+    			xlog("===== #[$var(i)] type ($dns(xyz=>addr[$var(i)])) addr [$dns(xyz=>addr[$var(i)])]\n");
+    			$var(i) = $var(i) + 1;
+    		}
+    	}
+
+commit dd76f37bfff59d5ae07b34346d0ab0a81136649b
+Merge: 66c7553 9ac9b5c
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Fri Jul 12 12:27:06 2013 -0400
 
-    Add docbook stub for sca module.
+    Merge branch 'master' into rfuchs/rtpproxy-ng
 
-commit 15fdde4fa1d662228568cc92e375d94dd86f2578
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Nov 19 15:53:17 2012 +0100
+commit 66c7553c1131fda7b83807891110f7de393be098
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Fri Jul 12 12:26:07 2013 -0400
 
-    AUTH minor documentation updates
+    rtpproxy-ng: implement second parameter to rtpproxy_offer/answer/manage
 
-commit 139acd4a3ba4117d218c8ef4d95710dc15fb8bc7
-Merge: eace40e dc0bc9d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Nov 19 15:45:38 2012 +0100
+commit 9ac9b5c35858efd7c71163c604d18a1fa35e3a02
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Jul 12 18:09:09 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    ipops: added dsn_int_match_ip(hostname, ipaddr)
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      core: handle '\r' as end of included file name
-      pkg/kamailio/(centos|fedora): turned on MEMDBG for development builds
+    - function that uses the internal resolver to match a hostname with an
+      ip (similar operation like 'scr_ip=="hostname"')
+    - rename dns_nc_match_ip() to dns_sys_match_ip() to be more suggestive
+      about what kind of resolver is used
 
-commit eace40eb04ff038fce0f81dc1c08864e1e966e98
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Nov 19 15:44:54 2012 +0100
+commit ccebf9e536d7d5ea8fc824ea089d501e888b37c8
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Jul 12 13:31:12 2013 +0200
 
-    auth	Update documentation for the "secret" parameter
+    ipops: new cfg function dns_nc_match_ip(hostname, ipaddr)
     
-    Thanks to Carsten Bock for finding this in the 1.5 documentation.
+    - do dns query for the hostname and compare the result to see if is a
+      match with ipaddr
 
-commit dc0bc9de9528e80cd8bc61201ce82db1a785baf4
+commit 9a25e712529cb7aacbae8e64a2e1be4da3c9a8c3
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Nov 19 10:45:41 2012 +0100
+Date:   Fri Jul 12 10:22:33 2013 +0200
 
-    core: handle '\r' as end of included file name
-    
-    - reported by Pirjo Ahvenainen
+    dispatcher: allow pv in ds_is_from_list(setid) parameter
 
-commit ddfeee6a0c0145d52f42e79cffe71b7cee1750e6
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Nov 17 00:12:04 2012 +0000
+commit 80935f9e8bbe20e5c320828183999b5d395ec34c
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Jul 12 00:44:51 2013 +0200
 
-    pkg/kamailio/(centos|fedora): turned on MEMDBG for development builds
+    core: avoid doing dns srv again after naptr function that includes srv lookup
 
-commit 4451d7af26b4f663fba408714296e79e05e312dd
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 16 17:25:52 2012 -0500
+commit 3823001dd83902d97f3dda9c9f51c370ab04073d
+Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
+Date:   Fri Jul 12 10:14:31 2013 +0200
 
-    Remove logging or change to debug level as required.
+    modules/sipcapture: a sip message must be stored after bad parsing also.
 
-commit 043fc21accd62e5b8fb84d505ae0b32a3ea02fc2
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 16 17:05:39 2012 -0500
+commit 25b6241ce310ca0ae67896fec2bb50d4c8d80fcb
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 21:57:58 2013 +0200
 
-    Remove ADMORTEN debugging line.
+    dialplan: don't free attrs pvar at shutdown, it is core pv cache reference
+    
+    - reported by Juha Heinanen
 
-commit d5ac2a71160b4d9b724cd1d8bd61600b1c2f3faf
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 16 17:01:53 2012 -0500
+commit ecb0ede7b20f24af97a42c4d034c46709c3ec38c
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Thu Jul 11 22:47:37 2013 +0300
 
-    Remove unused function.
+    modules/tls: config param can now specify a file or directory
 
-commit 21c02b5ca43340adb4ba1282ec2bfbbacee4e9b3
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 16 16:45:06 2012 -0500
+commit eba7dcbe6b3ba7b88c0fa0b231cb265a68995e47
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Thu Jul 11 15:36:54 2013 -0400
 
-    Remove 3xx handler, since 3xx responses are pass-through.
-    
-    At least with Polycoms, caller does not release appearance prior to
-    INVITE for redirection target.
+    rtpproxy-ng: implement $rtpstat and document start_recording()
 
-commit ed9f09efc26c671832629d8eae2089336fd2cfd9
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 16 16:09:51 2012 -0500
+commit d7d27cd803284ced4d709da543e64e553e0547ca
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 20:43:54 2013 +0200
 
-    Fix formatting from copy/paste.
+    Makefile.defs: version set to 4.1.0-dev7
 
-commit 96a5ba1f819cb136a7de69502c4aa4c28540af34
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 16 16:06:09 2012 -0500
+commit ca8facabe26f081d1cededeb78ceaa96e4ea9ff2
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 16:47:47 2013 +0200
 
-    Connect to DB on demand only once per-process.
-    
-    Practically, this means only in the DB writeback process and on
-    sip-router shutdown.
+    db_unixodbc: fixed typo added by previous commit
 
-commit 9e2a6583d2fb9d5ab83c44e3dced2c78e68dd6a6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 16 14:49:44 2012 -0500
+commit c6819b9a02d59b3ad8640fbaaf2fc0b9ef3d5021
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 16:43:31 2013 +0200
 
-    Parenthesize all values in bind macros. Define subscriptions table version.
+    db_unixodbc: renamed files with reserved name on some oses
 
-commit 5dfde0036ec5d954b451a811654617a82e10e82d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Fri Nov 16 16:21:02 2012 +0100
+commit aa0156ea441644545236a349cc62afb4983b5476
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 16:26:15 2013 +0200
 
-    Fixing typo
+    disptacher: added documentation for parameter attrs_pvname
 
-commit 0f94abc79a47a4068e9e943f39c9c3b1ef6f035b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Nov 15 14:42:27 2012 -0500
+commit 09a7a4cd718c0e26d3a948515ec4f6f6a68c64c4
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 16:25:06 2013 +0200
 
-    Add sca_subscriptions table version check.
+    dispatcher: new parameter to specify the pv where to store attrs for matched address in ds_is_from_list()
     
-    Permit future sca_subscriptions table schema changes.
+    - attrs_pvname can be set to get attributes of matched address in
+      config file
 
-commit 09205865f98136e0354539f09f4961ca016a915b
-Author: Timo Teräs <timo.teras at iki.fi>
-Date:   Thu Nov 15 16:11:41 2012 +0200
+commit 617a444fcbe84290a701228bd78e279bbde4818e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 15:27:16 2013 +0200
 
-    modules_k/db_sqlite: fix crash with computed fields in custom queries
-    
-    Computed fields do not have decltype available, so guess the proper
-    field type based on the result type of the first row. This does not
-    work if the first row has null type as result, but is the best we can
-    do easily and fixes gives right result in most cases.
+    pv: added transformations for url encode/decode
     
-    Reported-by: Pedro Antonio Vico Solano <pvsolano at amper.es>
+    - patch by JoshE, FS#311
 
-commit 22b6ead91e37b17163d0f95bd58efe76f7b4c3e4
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Nov 14 11:56:06 2012 -0500
+commit 12a5a409e7e196e1d0401b125b2de72a9f2e5aff
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu Jul 11 15:03:08 2013 +0200
 
-    Properly bind expires value for DB deletion of expired subscriptions.
+    modules/nathelper: removed natping_proceses limit
 
-commit 1ec90cc4364fe6b972d21f6ae0e24ca914296eb6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Nov 14 00:43:04 2012 -0500
+commit 0c6fef5fdc2a586ebfa607d3b5344266c08ca996
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 14:36:02 2013 +0200
 
-    Delete expired subscriptions from DB. Only update DB when subscribers change.
+    pipelimit: avoid double locking when changing pipe via rpc
 
-commit dc5e0d0905ec438c17e92a864e17340c03311ca3
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Nov 13 17:08:53 2012 -0500
+commit 04fd56dc1b84b70a04438ccbf719eb85177524ad
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 11 14:32:48 2013 +0200
+
+    pipelimit: avoid double locking when changing pipe via mi
+    
+    - reported by Krischan Udelhoven, FS#315
 
-    Subscription state is now stored in DB and restored on restart.
+commit 4a425a88be796c4b2c8447e6eafc53652ddf8e72
+Author: Elena-Ramona Modroiu <ramona at asipto.com>
+Date:   Sat Jul 6 19:03:49 2013 +0200
 
-commit a30d64af62684c8bba61bbb842209046daab97d5
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Tue Nov 13 15:45:18 2012 +0100
+    htable: sht_lock() and sht_unlock() documented in readme
 
-    Exec module: Documentation update, typo fix
+commit bc5cc684efad11f9affe648f3d0f6da98e43ad25
+Author: Elena-Ramona Modroiu <ramona at asipto.com>
+Date:   Sat Jul 6 18:31:17 2013 +0200
 
-commit 114d674da5383edf3970093618d2fb98768e2aff
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Tue Nov 13 15:37:18 2012 +0100
+    htable: two new functions to lock htable slots based on item name
+    
+    - sht_lock("htable=>key") and sht_unlock("htable=>key")
+    - useful to update existing items without aditional locks
 
-    registrar Documentation update
+commit ddea262fd70521eec450e57519f63a63880a94df
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Tue Jul 9 12:28:48 2013 -0400
 
-commit d888e7d83559b1b97cf55d47329a932497ff02f3
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sun Nov 11 23:21:58 2012 -0500
+    rtpproxy-ng: initial checkin
 
-    Restore subscriptions from DB on startup.
+commit 8cd7a48479594052b6b6e70d48946e8963e1625d
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Jul 9 17:50:06 2013 +0200
 
-commit 3eecc9197dd13a23cec1dd76ba6fa8f578bb482e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sun Nov 11 23:18:37 2012 -0500
+    modules/app_lua: added param to sr.xavp.get to choose between all the values (default) or just the first ones.
 
-    sca_db type not used.
-    
-    yet.
+commit 4a79fcdd9965c6c3195601baeb82d489d970aa12
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Tue Jul 9 15:55:35 2013 +0200
 
-commit 04773cd4b74bd1a18bd50ff681d7244999baca6e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Nov 11 09:13:59 2012 +0100
+    modules/app_lua: fix sr.xavp.get. Get all the values not only the first one.
 
-    dialplan Documentation updates, typo fixes
+commit 01c2fa43da42a4efab59fe787c332dbf9e318399
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Tue Jul 9 14:55:22 2013 +0200
 
-commit c414cc4df415be391a5dcaaa5be9e309dfa3cd85
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Nov 11 08:51:29 2012 +0100
+    modules/sipt: deleted unused method
 
-    diaplan - Fixing typo in name of rpc command
+commit edc838f04fd182b8997f94c50effd5b0c0153a25
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Tue Jul 9 11:21:52 2013 +0200
+
+    modules/sipt: ss7 messages are now modified in place
     
-    Sercmd lists the dialplan.dump command, that doesn't exist. Changing
-    name to dialplan.translate so that the module and the documentation
-    agrees on the name.
+     - lumps are now used to modify individual ss7 headers instead
+       of rebuilding the full body from scratch.  This should result
+       in a performance increase
 
-commit 79e03e5622ec28a5577bed700ee416b9630c7d58
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sat Nov 10 20:36:54 2012 -0500
+commit e03462112b108bd0615465f45258fd70c2704100
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sun Jul 7 07:25:34 2013 +0200
 
-    event should be INT. subscriber, not aor, should be UNIQUE.
+    modules/debugger: refresh README
 
-commit e19c603417411c29dfe038a8339883d29fe65afe
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 9 22:02:55 2012 -0500
+commit 9f363d37ba9e1c72b5abf25ec69ba9d367d6be99
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sun Jul 7 07:24:30 2013 +0200
 
-    Add sca_subscriptions mysql table creation script.
+    modules/debugger: add dbg_pv_dump config function documentation.
 
-commit 0b02fefeff53dc7fd3d66f2bd12b85a6ad883f51
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Nov 9 16:08:46 2012 -0500
+commit 77f5db57c4d5bf5a5e37985a228c8693ec685a6d
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sun Jul 7 07:23:11 2013 +0200
 
-    DB backing initialization and setup.
+    modules/debugger: add dbg_pv_dump config function.
+    
+    It dumps the content of pv_cache on json format.
 
-commit 8b731296ce80a8fcee582066ce3aad4a2bf95ed3
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Nov 9 20:54:14 2012 +0000
+commit faf2f6b9897c3b9acf69a1bbe22b827f386a863e
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sat Jul 6 15:13:00 2013 +0200
 
-    modules/msrp: Updated MSRP example
+    modules/sdpops: refresh README
 
-commit 6d2015a050f9d0bee80058e46732dd8da577c4d8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Nov 9 10:43:33 2012 +0000
+commit 2a855d384d37b5a83c879663780441b2f533fced
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sat Jul 6 15:09:47 2013 +0200
 
-    pkg/kamailio/(centos|fedora): Updated rel in .spec file
+    modules/sdpops: update documentation sdp_[with|remove]_transport
 
-commit f25202a6d1a8713524985f83304230556c036da7
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Fri Nov 9 12:28:19 2012 +0200
+commit c252677700bdc81241a39816a3febee70f729344
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Sat Jul 6 15:00:49 2013 +0200
 
-    modules_k/xcap_server: fixed length of pres-content AUID
+    modules/sdpops: added sdp_with_transport/sdp_remove_transport functions.
 
-commit b255c406ba09ff229361a3bc14cc1c9fd076b52e
+commit 97781390e663116f9e5d11f5644e1145487b6cfb
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Nov 9 11:03:46 2012 +0100
+Date:   Fri Jul 5 09:23:32 2013 +0200
 
-    core: tcp - proper handling of '\n-' sequence for detecting end of MSRP frame
+    dialog: added timer process to clean unconfirmed dialogs older than 5min
     
-    - in some cases it could go in wrong reading MSRP state
-    - reported by Gavin Llewellyn
+    - timer runs every 90sec (customization to be added in the future)
+    - safety procedure for cleaning dialog list
 
-commit d5120187eb41e709c840b3cfbb0dc1803f61b036
+commit 647a99bd21f6059505ea1ee65ac93c6c00fc8c8d
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Nov 9 08:41:55 2012 +0100
+Date:   Thu Jul 4 22:34:41 2013 +0200
 
-    dialog(k): use proper scan string for optional headers parameter in rpc commands
-    
-    - credits to Kristofer Signer for report and troubleshooting
+    textopsx: updated docs for msg_apply_changes() and added sections ids
 
-commit ddac5a16da60b0bbb6f58aa9e4fd26db3015c10d
+commit 85f6a45e6d74044488b63a89ce8feaaf3c4b00bb
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Nov 9 08:18:06 2012 +0100
+Date:   Thu Jul 4 22:29:06 2013 +0200
 
-    Makefile.defs: version set to 3.4.0-dev5
+    textopsx: enable usage of msg_apply_changes() for sip replies
 
-commit e916a4680d37f481167770fff27a710088cb5d3d
+commit 8248a1b2ed725933f84a343b4936ed4fdef4a869
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Nov 9 08:07:42 2012 +0100
-
-    Makefile.defs: arm compiler flags update
-    
-    - patch by Matthias Klose <doko at debian.org>,
-      http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=5;bug=690388
+Date:   Thu Jul 4 22:27:32 2013 +0200
 
-commit ac97e3a86d8e4f4c7d0abdffd84bb2ec4ff31ad4
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Thu Nov 8 17:56:41 2012 +0100
-
-    b/f: When the shortcut "x" is used, only add IE/EI once
-
-commit 97b829acd0954f7356db2d7c9e59435c539e91d5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Nov 8 00:03:03 2012 -0500
+    core: helper function to generate sip reply content without removing top via
 
-    Add srdb1 lib to Makefile for db API.
-
-commit 22eb98280f82fc10202862097d954d099b605700
+commit d4cef7f5e49105c65df9651a1ad086b035f8ffdb
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Nov 7 23:56:49 2012 +0100
-
-    msrp: fix compile warnings for 32b
-
-commit 738ce9354b61590f6a54b389d2b11348840c846c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Nov 7 14:34:10 2012 -0500
+Date:   Thu Jul 4 11:48:26 2013 +0200
 
-    Tentative fix for [SIPR-793]: Music-on-hold breaks SCA hold/pickup.
+    tm: avoid double execution of response-in callbacks
     
-    MoH changes hold semantics. Detect on-hold SDP in holding party's ACK,
-    and update state & send NOTIFYs as needed.
-
-commit 5154c90b60d54ad6c993eacaadea29740c12e82b
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Wed Nov 7 09:12:33 2012 -0500
-
-    modules_k/siputils: Fix memory leak in uri_param() function
+    - double execution of response-in callbacks could happen when using tm
+      pvs inside core reply route, being done in transaction matching
+      function, which is executed again by tm reply received function
 
-commit 7c37f8d4dc311c64c12e0b03b5e312892f9d886c
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Wed Nov 7 13:55:55 2012 +0000
+commit 230a138991b25f7f9b07b4f9cbeffbdd6acef2e8
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jul 4 11:47:18 2013 +0200
 
-    allow freeing of NULL pointer to behave like standard free() function
+    core: new internam sip msg flag FL_TM_RPL_MATCHED
     
-    The memory functions provided to openssl needs to behave like standard
-    memory functions, i.e. free(). Therefore, ser_free must accept NULL
-    pointers, see: http://openssl.6102.n7.nabble.com/Custom-free-routine-is-invoked-with-NULL-argument-in-openssl-1-0-1-td25937.html
-    As shm_free() aborts on null pointers, we have to check for null pointer
-    here in the wrapper function.
+    - mark sip reply when matched first time by tm
+    - used to avoid double execution of response-in callbacks
 
-commit 5e77d14b9f0304942517e031406a147a668adec3
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Nov 7 00:13:20 2012 +0100
+commit 27474179bdeef0ddaba05389f510446a387d85e1
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Thu Jul 4 10:31:46 2013 +0100
 
-    usrloc - Documentation updates (mostly typos and smaller fixes)
+    modules/websocket: Fix connection leaks
     
-    Based on feedback during SIP Masterclass - Jared and Anthony. Thanks!
+    - Decrease the TCP connection reference count after each use
 
-commit 897dfc4c0a7bad253cfe672e58d665e9b3deb34e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Nov 6 23:28:55 2012 +0100
+commit ffdae5987b99b9bfd39992d407a3a0a33aa772ab
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Thu Jul 4 10:30:51 2013 +0100
 
-    (core|modules/tm): corrected ambiguous error messages.
+    core: Fix connection leak with websockets
     
-    - As per Henning's suggestions.
-
-commit 5b6f68ae0dc50c05902ace37f1081b19bda0320e
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Nov 6 16:32:50 2012 +0100
-
-    RTPProxy: Documentation improvements
-    - added a note about compatibility with different implementations for the "x"-flag (namely RFC 4091 and RFC 6157)
-    - made more clear, that "x" is only a shortcut for the "IE" and "EI" flags of RTPProxy
+    - Decrease connection ref count after using connection
 
-commit b6bb5d0f67881bafd8ac0e4a189bd7e5ae228e5a
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Mon Nov 5 08:44:17 2012 +0200
+commit fb4dc4b7b866239a90a4d6441ed319664697edab
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Thu Jul 4 09:33:56 2013 +0100
 
-    modules_k: added support for PV as possible value for update_stat.
-        - this will allow things like: update_stat("my_stat", "$BM_time_diff")
+    core: Improve tcp stats output
+    
+    - Add connection ref count
+    - Add websocket protocols
 
-commit 6805fcb2f60180dd11bd14fb611ad44ebb068de9
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Nov 1 16:48:26 2012 -0400
+commit d0f88e19577d9b914922f83049075b7786f3d8df
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Jul 3 10:46:44 2013 +0100
 
-    Fix [SIPR-783]: respect answerer's app-index instead of using next available.
+    modules/websocket: Fix pkg memory leaks
+    
+    - Fix pkg memory leaks in error cases
+    - Fix incorrect memory allocation size for ws connections
+    - Fix typo in websocket stats
 
-commit 53135e42d0048670a25908532bdb26706db48b7a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Nov 1 15:54:51 2012 +0000
+commit 074f12c5a444188aa023797ac70e2d38d225cb18
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Jul 3 10:39:32 2013 +0100
 
-    core: Fixed typo that broke the build
+    modules/tls: Free TLS data for secure websocket connections
 
-commit 4ef839851ef518815df38a9ae73e948719784e89
+commit c5081ad634742d88e56e4fcc097b756098119e4e
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 31 20:21:07 2012 +0100
-
-    kamailio.cfg: add option to set pstn gw port
-
-commit 7b3f234106adebd0a3ab069add170f0d23f1f592
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Oct 31 17:48:37 2012 +0000
+Date:   Wed Jul 3 23:23:40 2013 +0200
 
-    modules/tm: corrected a mis-leading error message
+    uac_redirect: fetch all contact headers in redirect replies
+    
+    - only first header was considered for redirect handling
+    - based on a report by Geoffrey Mina
+    - generate fake ruid (used as instance and user-agent) to satisfy the
+      requirements of t_load_contacts()/t_next_contacts()
 
-commit 014d1000055d8ee93ef35336b1701674fe23a675
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Oct 31 17:48:17 2012 +0000
+commit fa0339b1906690f009786fc9ed92c73a8c9e6520
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Jul 2 23:32:37 2013 +0200
 
-    core: corrected some mis-leading error messages
+    dialog: detect if no trasaction is created after config execution for new dialogs
+    
+    - release the dialog to avoid endless storage in state 1
 
-commit 03c080376e26aeae8261d2ff12fc290a3925ef91
+commit b4682cac2e2f151288a411018da077b6d1526eca
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 31 14:40:25 2012 +0100
+Date:   Tue Jul 2 21:40:32 2013 +0200
 
-    kamailio.cfg: updated wiki link to match the version
+    kamailio-basic.cfg: added basic cfg config file
+    
+    - get the same set of configs as expected by former ser flavour
 
-commit 3ce2efce27983e0fe818ff4e139c9589dbbfeb4a
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Wed Oct 31 15:36:05 2012 +0200
+commit 6cf3ab0ca6f38d1d2e60dbc644bb4d2fb563919a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jul 1 15:22:33 2013 +0200
 
-    modules/msrp : small documentation fix
+    dialog: increment cseq in early stage for PRACK and UPDATE
+    
+    - rework from a patch by Halina Nowak
 
-commit 8a00d03a9328fd5ab4740f52ac47070e64f05236
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Oct 30 22:35:45 2012 +0000
+commit 71d7dc6bc750406d510e0571e05da3966911cfea
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jul 1 14:51:03 2013 +0200
 
-    modules_k/xcap_server: Enhanced org.oma.xcap-directory implementation
+    dialog: avoid realloc of memory for cseq when setting leg info
     
-    - Can now use a modparam to force the scheme in the listing URLs to a specific
-      value (default is to work out based on whether the connection is TCP or TLS).
-    - Can now use a modparam to force the hostname in the listing URLs to a
-      specific value (default is to work out based on the (mandatory) Host: header
-      or destination IP address and port).
-    - Updated README
+    - free already allocated structs when needed
+    - has part of a patch by Halina Nowak
 
-commit 953a1d12685a917de68aff31c7172792dd816302
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Oct 30 17:21:27 2012 +0000
+commit ed6dbb0ca11206049bee9ab515ce071eb70e7b63
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jul 1 14:44:45 2013 +0200
 
-    pkg/kamailio/(centos|fedora): Updated .spec and BoxGrinder appliances
+    dialog: fixed callee cseq reference
     
-    - Added xhttp_pi module
+    - part of patch by Halina Nowak
 
-commit 18220b91255f9a563ce56f1d05fe97905e7fe2d9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Oct 29 21:57:32 2012 +0100
+commit 1123ed46ee847be83f35aa485a1ef6712566bc09
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Jul 1 13:37:42 2013 +0200
 
-    UAC: Documentation updates and typo fixes
+    core: Also consider PROTO_WS(S) in forward().
 
-commit c244c7aeac06e4707ae76571dc73b804af31640f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Oct 29 19:50:48 2012 +0100
+commit 8f6dc39a0fcd9035a2bd5bff01e51fc3fc7671fd
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Mon Jul 1 11:47:50 2013 +0200
 
-    uac Fixing formatting
+    dialog_ng: include dialog function dlg_get in dialog_ng
+    	- In first iteration of dialog_ng module the dialog function dlg_get was not included
+    	- This function is now included; it searches and sets current dialog based on Call-ID, From-Tag and To-Tag
 
-commit 7bd4eda6d169c89e8a42cbd94e8d008700109ceb
-Merge: 212cf0d c70f884
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 28 21:12:03 2012 +0100
+commit b252d4ec79446bd915fe2eb6bcf8556d3275343c
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Sun Jun 30 16:06:16 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      modules_k/nathelper: add_contact_alias ipv6 fix
-      lib/srdb1/schema: use &ip_addr_len; entity in address and lcr_gw schema
+    memcached: document new memory parameter for memory manager setting
 
-commit 212cf0d3c0d220affbafa545795ff5d0bf03b97d
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 28 21:09:51 2012 +0100
+commit 736fab01bafba394f4b81aa20a63bf827baa2a13
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Sun Jun 30 15:50:29 2013 +0200
 
-    permissions - change openser => kamailio
+    memcached: update module docs, patch from Charles Chance, charles dot chance at sipcentric dot com
 
-commit c70f884988c3f9298fa4d40ef12c69eea9da26a5
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sun Oct 28 16:07:25 2012 +0200
+commit df41d7f4e0cd8bd0c328f94360a6b3a3f3e9d59b
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Sun Jun 30 15:42:17 2013 +0200
 
-    modules_k/nathelper: add_contact_alias ipv6 fix
+    memcached: fix crash during shutdown, make used memory manager configurable
     
-    - When add_contact_alias() is called without arguments, it now adds brackets
-      around received ipv6 address in order to make $du syntactically valid.
+    * fix a crash during shutwdown, as reported from Dragos Oancea, droancea at yahoo dot com
+    * make memcache client library memory manager configurable, as default use
+      the one from the system as this is probably the most tested configuration
+      in the field
+    * the internal memory manager should provide a better performance in this case,
+      but as the old library has some issues with the internal one, we better stay
+      with this
+    * documentation will be provided in the next commit
 
-commit dba0691a98a329be489d83dfc1cd9560419bc35e
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sun Oct 28 14:32:36 2012 +0200
+commit 811ed09b1c8cff014d3135967c8a3cda1bec569d
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Jun 25 15:42:44 2013 +0200
 
-    lib/srdb1/schema: use &ip_addr_len; entity in address and lcr_gw schema
+    modules/ims_icscf: updated documentation
+     	- updated documentation to use route blocks after async diameter
 
-commit 0c130b85e8081af15188ec87d5e55d70c96de46f
-Author: osas <osas at centos.(none)>
-Date:   Sat Oct 27 12:08:49 2012 -0400
+commit 8f1904fd0a0b305b2c528df0d1d3c27d5eef0c7d
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Jun 25 15:41:42 2013 +0200
 
-    fix default db in docbook
+    modules/ims_auth: updated documentation
+    	- updated documentation to use route blocks after async diameter
 
-commit e4453d91f612a8d651176d62529bc24edb54bf59
-Author: osas <osas at centos.(none)>
-Date:   Sat Oct 27 12:05:18 2012 -0400
+commit bf08aa1a3859766caf0842fdd30b9fc2f4a4ff43
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Jun 25 14:11:13 2013 +0200
 
-    fix test directory after openser to kamailio migration
+    IMS example config files: update icscf and scscf config files to correctly use async route blocks
+    	- This fix updates the example ICSCF and SCSCF config files to correctly use route blocks for the replies of any asynchronous Diameter messages
 
-commit 923b738f8f021c349b0d0ba4faaac1b0c6bcf246
-Author: osas <osas at centos.(none)>
-Date:   Sat Oct 27 12:00:28 2012 -0400
+commit 0d5622531d71d0b0ab3fb25a13c3ea1f46581512
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Jun 25 14:09:00 2013 +0200
 
-    more openser to kamailio migration
+    modules/ims_icscf: execute route block on async reply to UAR and LIR
+    	- Changed this to make the use of async CDP cleaner
+    	- Fixes inconsistencies we are experiencing with async TM and not using route blocks
+    	- Note this fix is for UAR replies called from I_perform_user_authorization_request() and LIR replies called from I_perform_location_information_request()
 
-commit e7a75db1982a48efb83bd9ba96036dbb6da541e1
-Author: osas <osas at centos.(none)>
-Date:   Sat Oct 27 11:39:29 2012 -0400
+commit 6af810edde27d087c86432f42d9aec0636b3a740
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Jun 25 14:07:12 2013 +0200
 
-    xhttp_pi: new web provisioning interface module
+    modules/ims_auth: execute route block on async reply on REG MAR
+            - changed this to make the use of async CDP cleaner
+            - Fixes inconsistencies we are experiencing with async TM and not using route blocks
+            - Note this fix is for REG MAR called from ims_www_challenge()
 
-commit 70f5cefa6dcc8562d58e58e7531d6021dbd88912
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Oct 27 00:08:54 2012 +0100
+commit 87ea473c15454742fc9f3a0cedd46cf09c663f3c
+Author: Richard Good <richard.good at smilecoms.com>
+Date:   Tue Jun 25 14:04:46 2013 +0200
 
-    modules/websocket: Updated example kamailio.cfg
-    
-    - More tweaks to MSRP over WebSocket
+    modules/ims_registrar_scscf: execute route block on async reply on REG SAR
+    	- changed this to make the use of async CDP cleaner
+    	- Fixes inconsistencies we are experiencing with async TM and not using route blocks
+    	- Note this fix is REG SAR called from save()
 
-commit 5a8b8da4abda5b20599add078efe4681aeb8dfa7
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Oct 26 16:09:09 2012 +0100
+commit 584508d5374726bf523a23693da86f0763b34767
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Jun 23 05:37:34 2013 +0200
 
-    modules/websocket: Updated example kamailio.cfg
+    core: allow c++ style of one line comments
     
-    - Better MSRP over WebSocket support
-
-commit e804a70e47f938338e6d93930c297ff958f16e22
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 21:36:28 2012 +0100
+    - can make easier the read of config files with defines and comments
 
-    modules_k/xcap_server: Tidied up example
-
-commit c062817d0833a0d24a6afacc928f980298be1d60
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 21:35:57 2012 +0100
+commit 756620fd0c1912e492781f05fde944f9035d95b3
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Jun 24 22:13:26 2013 +0200
 
-    modules/websocket: Updated example kamailio.cfg
-    
-    - Reflects latest MSRP related updates
+    examples: Make S-CSCF more quiet
 
-commit 682f002698c761c5570e587db5c48653668a1bb8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 21:34:23 2012 +0100
+commit 14ef8ff8d460bc22f0df4793e11455487ea91aab
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Jun 24 22:10:33 2013 +0200
 
-    modules/msrp: Updated example in README
-    
-    - Use new pv_www_authenticate() variant to pass in $msrp(method)
-    - Send responses to SEND that we are relaying to clients
-    - Handle REPORTS as end-to-end requests (that are not responded to)
-    - Send 501 for requests that are not AUTH, SEND, or REPORT
+    auth_ims: New option to store authentication vectors using the IMPU only, instead of IMPI/IMPU.
+    (this is required to work with some SIP-clients)
+    - added some more debug info
+    - replaced the hashing function with core_hash from Kamailio-core
 
-commit 6b9e4fcc176e3141f25c74f17f599b88d30f8ff9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 21:09:40 2012 +0100
+commit 9fc55badeaa54d2cfde7a152459b957f8ae5a192
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Jun 24 18:08:29 2013 +0200
 
-    modules/msrp: Better fix for the relay problem
+    Added missing parameters to documentation
 
-commit f61a61e44168a213a065e4a7dc1c751a874fbce3
-Merge: a4f28b9 a0b36a9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 20:35:13 2012 +0100
+commit 72d79d20964ac192dbe1cbe35f48c21ec749c39a
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Mon Jun 24 18:08:05 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      Makefile.utils: add rule to create man page dir
+    Fixed Editor note
 
-commit a4f28b9707b2c55af87138cca531fdb1badd7023
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 20:17:48 2012 +0100
+commit bd1a534515678f69385d00b08699b434e1fab8df
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Mon Jun 24 15:24:49 2013 +0200
 
-    modules_k/xcap_server: Added explicit parsing of headers before looking for HTTP ETag and Host headers
+    modules/ims_registrar_scscf: execute route block on async reply of unreg. SAR
+    	- changed this to make the use of saync CDP cleaner
+    	- fixes inconsistencies we are experienceing with async TM and not using route block
 
-commit a0b36a905afda1476085a645faf29bd534ed4949
+commit 678ab425062e6c6a30b5f1d37025c2bbdcd5425d
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 25 21:16:26 2012 +0200
+Date:   Fri Jun 21 04:23:38 2013 +0200
 
-    Makefile.utils: add rule to create man page dir
+    auth: set ids for elements in the documentation
     
-    - reported by Peter Dunkley
-
-commit 067051b8c9da440566cbd09d80bb1abd424f68de
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 20:17:05 2012 +0100
-
-    modules/websocket: Added explicit parsing of all headers before searching for WebSocket specific headers
+    - split checks parameters in own section for easier reference
 
-commit 6273279621dd4a8e6f6fe6a2faa548755a3eacd6
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 19:59:31 2012 +0100
+commit fc83d3b1f1dd0934e5638b91d11e27f47880b411
+Author: Carlos Ruiz Diaz <carlos.ruizdiaz at gmail.com>
+Date:   Thu Jun 20 17:34:49 2013 -0400
 
-    modules_k/xcap_server: Removed some test debug that was left in by mistake
+    Added support to limit number of calls per customer/profile
+    
+    - added function cnxcc_set_max_channels() per customer/profile
+    - added function cnxcc_get_channel_count() per customer/profile
+    - added function cnxcc_terminate_all() to terminate calls per customer/profile
+    - added select @cnxcc.channels["customer/profile"].count
+    - added modified version of kamailio-cnxcc.cfg to reflect changes and examples
 
-commit 53175995fb7fe7d760c063c4d542e991c1513344
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 19:45:04 2012 +0100
+commit 8f261c5baeb01d5bee0437249b7f6d3d81bee209
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu Jun 20 08:34:05 2013 +0200
 
-    modules/app_lua: Updated because of recent changes to auth and auth_db
+    modules/dialplan: allow xavp vars as parameters.
 
-commit 5c71412cf3530f19edc4bee38cc9c3857ddc1eb0
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 19:44:32 2012 +0100
+commit 6b27e0d5519f8e29bc31c553a67367975acfe7ec
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu Jun 20 08:32:47 2013 +0200
 
-    modules_k/auth_db: Added an optional parameter for method to www_authenticate
+    modules/dialplan: use pv_cache_get function instead of create pv_spec_t
 
-commit 3f35106f791cf0f6638128539fd147ad2f44da27
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 19:43:55 2012 +0100
+commit 1207edd603937e3e43ce20207bfeae0284f16489
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jun 17 14:48:52 2013 +0200
 
-    modules/auth: Added an optional parameter for method to pv_www_authenticate()
+    pv: $xavp(name) is marked as PVT_XAVP type
 
-commit 558e5294f697519917b58ddc451408b3d71aff4f
-Merge: 0ed33c0 019ab5e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 18:22:21 2012 +0100
+commit 424691bfae61b00fa6d5f1f75e95fe60bf823526
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jun 17 14:47:56 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    core: define PVT_XAVP as type for xavp pseudo-variables
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      resolve.c: make dns query only on name that has valid syntax
+    - they may need special handling for debug purposes
 
-commit 0ed33c0c3332ed3868509d8ae0b035d9420a7df4
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 18:21:41 2012 +0100
+commit c5573dddc4c11898fb68365e9a311aff0f1690c8
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jun 17 11:00:29 2013 +0200
 
-    modules/msrp: Fixed a problem with relaying that I added when I put in WebSocket support
+    pipelimit: fixed typo in module parameter name
+    
+    - patch by Krischan Udelhoven
 
-commit 019ab5e2d6730b764b20a890f9a3b5f9237b6338
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Thu Oct 25 19:50:17 2012 +0300
+commit 03188db86347013ef43d3615c12be4b696349098
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Jun 17 10:48:45 2013 +0200
 
-    resolve.c: make dns query only on name that has valid syntax
+    modules/app_lua: fixed runtime warning: exports dlflags interface is deprecated
 
-commit aebeeee1993e4cce0d3288f1ccd8d17f3efee925
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 17:34:39 2012 +0100
+commit 4f3d04d547c66a1b59398cf80e93974175141514
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Jun 16 17:17:36 2013 +0200
 
-    modules_k/xcap_server: Updated example event_route[] in README
+    topoh: safety check for To header
     
-    - Now includes:
-      - updating of RLS subscriptions when RLS documents change
-      - pidf-manipulation
-      - clean handling of org.openmobilealliance.search
-      - org.openmobilealliance.xcap-directory support
+    - protection for the case when sanity module checks are not enabled
+    - reported in FS#303 by Michel de Weerd
 
-commit 4d48c5d485c9c1155b8b7471fbda56a80a218d48
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 17:33:46 2012 +0100
+commit 330aeda83dc7ed927cf994e4b21ff44ab2d2c215
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Jun 16 16:40:59 2013 +0200
 
-    modules_k/xcap_server: Added support for the org.openmobilealliance.xcap-directory auid
-    
-    - Directory listing worked out on-the-fly based on DB contents
+    mtree: fixed typo in log function name
 
-commit f6a38aa7f80cdc02431bdd3d314c82663a3d33a4
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 25 17:32:43 2012 +0100
+commit 69c409e14c568fae45e449122e5b4efbf009bf41
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Jun 16 16:39:14 2013 +0200
 
-    modules_k/xcap_client: Added new #define for xcap-directory auid
+    core: added function to get the pv cache table
+    
+    - pv cache struct moved to header file
 
-commit 5f813fdab34cb7507bc4dcc1b66ff87f90f69c9a
+commit ea772b354f84eccff0190234025f057879ff33ed
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 25 10:56:41 2012 +0200
+Date:   Sat Jun 15 22:03:58 2013 +0200
 
-    xcap_server: use a static table to keep the list of supported auids
+    kamctl: new commands can be defined in separate files
+    
+    - write new kamctl commands either in CFGDIR/kamctl.newcmd.ext or
+      ~/.kamctl/kamctl.newcmd.ext
+    - 'newcmd' has to be replaced with the name of the command
+    - the file must include cmd_newcmd() function which is executed with the
+      parameters after the command name
+    - example: adding new command 'sample'
+    	- content of ~/.kamctl/kamctl.sample.ext file:
+    
+    usage_sample() {
+        echo
+        mecho " -- command 'sample' - kamctl sample extension command"
+        echo
+    cat <<EOF
+     test ............................... print test message
+     help ............................... help text
+    EOF
+    }
+    
+    cmd_sample() {
+        case $1 in
+            test)
+                echo "message from sample test command"
+            ;;
+            *)
+                usage_sample
+            ;;
+        esac
+        exit 1;
+    }
+    
+    - new command 'sample' can be executed with:
     
-    - adding new auid requires an entry in this table and define of the
-      internal type
+    kamctl sample test
 
-commit 3bd01c035d5f4c6be55a9995103c0da689d5df18
+commit 0b82af2019d523c680d156d9b95ae33043c79bd0
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 25 10:01:08 2012 +0200
+Date:   Sat Jun 15 19:33:50 2013 +0200
 
-    acc(k): fixed typo in acc_db_request() example
-    
-    - reported by Bernie Höneisen, FS#251
+    kamctl: set internal version to 4.1.0
 
-commit 22f9a675863f85d934afa5e7c09061c66497042b
+commit af6a5d7422b614e5a143bc987806181086360c34
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 25 09:25:17 2012 +0200
+Date:   Sat Jun 15 19:31:43 2013 +0200
 
-    core: use cloned value to parse pv name for caching
-    
-    - patch by Hugh Waite
+    tm: readme updated based on latest docbook
 
-commit 9bacc95d2a0c949e81032dd0cc392dfaa7c0a2c1
+commit 5f1b144a7e63b464af3e5e0e7b74cf7e7e1e8668
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 24 12:17:30 2012 +0200
+Date:   Sat Jun 15 19:30:59 2013 +0200
 
-    kamctl: use kamcmd instead of sercmd
+    tm: documented dn_reuse_rcv_socket parameter
 
-commit c93d2d1b290c030f969ce1f62f106059226457ea
-Merge: c4b3b04 7e67e6b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Wed Oct 24 11:47:41 2012 +0200
+commit 30e26f22600c3f50f0ea556bf2872ef7b0807c6a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Jun 15 19:08:38 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    I don't really know what this means and why this commit happens...
+    tm: new module parameter - dns_reuse_rcv_socket
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      .gitignore: added few more patterns to ignore
-      pkg/kamailio/rpm: specs updated for rename of sercmd to kamcmd
-      sercmd: added basic man page
-      sercmd: builds and installs as kamcmd when FLAVOUR=kamailio
-      Makefile.utils: new target to install manpage for util tools
-      kamctl: replaced openser with kamailio in variable and function names
-      core: print modparam type id in log when parameter not found
-      modules/rtpproxy:  added 't' flag to rtpproxy_destroy and force_rtp_proxy - Added new flag 't' to rtpproxy_destroy function that makes it possible   do delete whole call even when To tag is present in request/reply.  In   force_rtp_proxy the flag is ignored.
+    - control reuse of the receive socket for additional branches added by
+      dns failover
+    - if 1, the rcv socket is used, if not it depends on mhomed - when that
+      is 0, the first socket is used, otherwise will be selected based on
+      routing table
+    - default is 0
+    - therefore beware when setting this parameter and mhomed=1
+    - based on discussion for FS#313
 
-commit 7e67e6bad8f56e8ed25673b24f132e0f5d9d17fc
+commit 350f4f8971a679f0d6566361b2a7bb17956a6a7e
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 24 08:39:59 2012 +0200
+Date:   Sat Jun 15 18:54:59 2013 +0200
 
-    .gitignore: added few more patterns to ignore
+    tm: copy tm routing blocks ids for new branches added by dns failover
     
-    - kamcmd binary and second vi swap file
+    - patch by Jasmin Schnatterbeck, part of FS#313
 
-commit 02b389ec2bca98dc158cd6ce255ad8c4aa1f570e
+commit e7da9f72beb1c97b79a516ecdd19db8971dea508
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 24 00:16:58 2012 +0200
+Date:   Sat Jun 15 18:23:48 2013 +0200
 
-    pkg/kamailio/rpm: specs updated for rename of sercmd to kamcmd
+    kamailio.cfg: route subscribe for event message-summary to voicemail server
 
-commit e6bdf8a0317c1a62931c07a8bd40fbc65fa1398e
+commit da016636be6e0ca9a65b645b6e30ec0b1dafeef4
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 24 00:06:48 2012 +0200
+Date:   Fri Jun 14 08:42:37 2013 +0200
+
+    kamctl: added show command to display user attributes in subscriber table
+
+commit 519fe88fc41cae4674ce4bc943b84eb522af654b
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed Jun 12 15:58:29 2013 +0200
 
-    sercmd: added basic man page
+    core: do not repeat key names on xavp_get_list_key_names function result
 
-commit e7e131d5b5abec9440f0963375abd1940d65e3f4
+commit b5538401a01057318063a4e4646c9e7a2fb967c0
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 24 00:05:13 2012 +0200
+Date:   Wed Jun 12 08:50:26 2013 +0200
 
-    sercmd: builds and installs as kamcmd when FLAVOUR=kamailio
-    
-    - avoid packaging conflicts with ser (both packages attempt to install
-      same file)
+    mtree: print more details if the record in db is broken
 
-commit e378b3c1038eab768a0d1304166a7aa2ef6e361a
+commit 862e267267ccd58e096f267ac5aab03cee042b7c
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 24 00:04:11 2012 +0200
+Date:   Tue Jun 11 18:47:54 2013 +0200
 
-    Makefile.utils: new target to install manpage for util tools
+    mtree: make log message on not maching character a debug instead of error
 
-commit e102ae728214192184397b8e802228f9695f45f2
+commit 407608dfef8e80ef0beaefc61df96e40060b952f
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 23 16:49:29 2012 +0200
+Date:   Tue Jun 11 18:41:05 2013 +0200
 
-    kamctl: replaced openser with kamailio in variable and function names
+    registrar: readme regenerated
 
-commit 22dd8d6524a95b8bf0246adca99f0049c16fb76f
+commit c228851e068a080050c79107c760f8ab5ffae967
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 23 16:17:24 2012 +0200
+Date:   Tue Jun 11 18:39:31 2013 +0200
+
+    registrar: fixed typo in example of xavp_rcd parameter
 
-    core: print modparam type id in log when parameter not found
+commit 9589466916305146fb4f982542c3f3a51126dcef
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Jun 11 18:37:32 2013 +0200
 
-commit d8d80082aad32fd28484d30b2c4e0c98853cda31
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Mon Oct 22 12:15:54 2012 +0300
+    registrar: more debug messages when adding ruid xavp
+    
+    - free local ruid xavp if cannot be added to root list
 
-    modules/rtpproxy:  added 't' flag to rtpproxy_destroy and force_rtp_proxy
-    - Added new flag 't' to rtpproxy_destroy function that makes it possible
-      do delete whole call even when To tag is present in request/reply.  In
-      force_rtp_proxy the flag is ignored.
+commit 106916abc67d2badc43eac03ef175efbbac4f6d1
+Author: Camille Oudot <camille.oudot at orange.com>
+Date:   Tue Jun 11 16:34:49 2013 +0200
 
-commit c4b3b04eb59de8b1b72675decfa06ff3cb779934
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 21 20:09:07 2012 +0200
+    modules/ims_isc: several safety checks
+    
+    - fixed potential buffer overflow
+    - fixed potential crash if regcomp fails
 
-    mtree Documentation fixes
+commit bddb9a5bf38d4904a9e18dc187fc8c0507001ab5
+Author: Camille Oudot <camille.oudot at orange.com>
+Date:   Tue Jun 11 16:24:15 2013 +0200
 
-commit 8818925e7974cd5d826ad105b77a59f17636badf
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 21 19:13:50 2012 +0200
+    modules/ims_isc: fix several compiler warnings
 
-    pua: Fixing documentation typos, adding reginfo
+commit 4af0bc13901525a5638c2c64b863f377e033903f
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Mon Jun 10 12:14:54 2013 +0200
 
-commit 9683068672ffb4679b6caa3d1a3a8b51aeedffd9
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 21 19:02:56 2012 +0200
+    app_lua: solve crash when setting a variable not convertible to string.
 
-    sipcapture Fixing typos in documentation
+commit b5f0a62a2acfbf0f4ce9cd146cb342d717e662a9
+Author: Camille Oudot <camille.oudot at orange.com>
+Date:   Tue May 28 17:53:07 2013 +0200
 
-commit 4ba7d41bc078e554d48316b2c3e0b6435b55f60a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 21 18:54:33 2012 +0200
+    modules/ims_registrar_scscf: safety check for log line when recieving an SAR_UNREGISTERED_USER response
 
-    SDPops Typo fixes in documentation
+commit fd8dfb71d0eeae891ad0c83ff332929d54f3a3ec
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Fri Jun 7 12:09:38 2013 -0400
 
-commit 2aa02e80cd76f38e812bfddf32326248e9b74cf8
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 21 18:49:43 2012 +0200
+    Makefile: update de-stable target: squeeze -> wheezy
 
-    Ratelimit: Fixing typos
+commit e41230071e367015ecf794c147c60fda0bcd1907
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Jun 6 15:21:19 2013 -0400
 
-commit ca3f80f76ca5be83407f8d8b542c8390982459d4
-Merge: 84f6596 a041479
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 21 18:32:33 2012 +0200
+    registrar: print bogus AoR in error log
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      modules/rtpproxy: some README improvements
-      pkg/kamailio/fedora/16: More tweaks to .spec
-      pkg/kamailio/(centos|fedora): Updated boxgrinder appliance definitions
-      pkg/kamailio/fedora/16: added SCTP dependencies to .spec
-      pkg/kamailio/fedora/16: Updated .spec file
-      Makefiles: Updated Makefiles to use db2x_docbook2man when docbook2x-man is not installed
-      pkg/kamailio/fedora/16: Updated .spec to set ownership of /etc/kamailio to kamailio.kamailio
-      modules/websocket: Updated example configuration file
-      modules/msrp: Updated MSRP configuration example
-      rtpproxy: allow flags parameter to rtpproxy_destroy()
-
-commit 84f6596ccbb107563386acb52a2c60fd3cc0df22
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 21 18:30:32 2012 +0200
+commit ea6354c53c8871e4e117b7434645ab4fee811612
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jun 6 15:58:58 2013 +0200
 
-    TLS Documentation updates
+    acc_radius: exit at startup if radius_config is not set
 
-commit a041479bd7153b3a3b665a3ed27a4da12cb9b1d1
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sun Oct 21 17:29:44 2012 +0300
+commit 8e937d260d0ff41f50be56e0a46ede44554f3f99
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jun 6 11:47:10 2013 +0200
 
-    modules/rtpproxy: some README improvements
+    cfgutils: updated docs to specify correct time unit for usleep
+    
+    - it is microseconds, pointed by David K
 
-commit 6135c98b472a755015aacc640b65e9a5c202c122
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sat Oct 20 17:47:32 2012 +0200
+commit c4b29f6fac6155b9b087737df5956b687ff4e36a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jun 6 09:09:14 2013 +0200
 
-    Documentation updates
+    kamailio.cfg: reset $du for voicemail re-routing in failure route
 
-commit e39b774a4f0aec0bc6a6fe07b0eace7378b0bcbb
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Oct 20 03:55:01 2012 +0100
+commit c8e928a2c78ee963f807791bea5aacdd31e05936
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Jun 6 09:05:28 2013 +0200
 
-    pkg/kamailio/fedora/16: More tweaks to .spec
+    siputils: added new function is_first_hop()
     
-    - The auth_diameter and malloc_test modules were being built during install
-      instead of in the build section
+    - detect if it is first hop after original sender
+    - added section ids for functions, remove a duplicate content for
+      is_rpid_user_e164()
 
-commit 4b7d47321fa4648452040e27ba619dee72e0b6b5
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Oct 20 03:12:05 2012 +0100
+commit 0193489cca56f58b512f5379c078c98a366c17e2
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Jun 5 22:44:13 2013 +0200
 
-    pkg/kamailio/(centos|fedora): Updated boxgrinder appliance definitions
+    kamailio.cfg: few updates related to nat traversal
+    
+    - added "co" flags to rtpproxy_manage() to change all IPs in sdp, many
+      phone get confused if only media ip is changed
+    - add nat=yes parameter only for in branch route to avoid multiple
+      occurences
 
-commit b4e7d304ad7149d10d69c85454141e393c6d0fb7
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Oct 20 03:06:30 2012 +0100
+commit 4b65964dbe1f38bcf867301d43933f9bbf91ab7d
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Jun 5 08:58:29 2013 +0200
 
-    pkg/kamailio/fedora/16: added SCTP dependencies to .spec
+    module/ims_auth: protection against crash if there is no auth vector initialised.
+    	- patch submitted by Camille Oudot
 
-commit 113c0e63686e8d3cdca21e9a6399dce727ee866f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Oct 20 02:38:18 2012 +0100
+commit 2e466866468a71d4a6e7589cae69ae606b194716
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Jun 5 08:46:13 2013 +0200
 
-    pkg/kamailio/fedora/16: Updated .spec file
-    
-    - Added installation of auth.7.gz for Fedoa now that manpages are built for
-      Fedora
-    - Added "make utils" to build section
-    - SCTP and STUN now included in build
-    - Removed kamailio-tls package - tls module now in main Kamailio RPM as that has
-      openssl as a dependency for STUN
+    modules/ims_isc: Add support for P-Serverd-User header
+    	- This header allows a triggered Application Server to know the IMS user for who it was
+    	triggered, and in what state (originating/terminating, registered/unregistered)
+    	- Thanks to Camille Oudot for patch!
 
-commit c9088190cf29b7d561ca2bded6266b3e21d51d8b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Oct 20 01:23:51 2012 +0100
+commit cb4cfa492aa977df3f80b7d93001559ecb1bcdec
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Jun 4 23:21:11 2013 +0200
 
-    Makefiles: Updated Makefiles to use db2x_docbook2man when docbook2x-man is not installed
-    
-    - db2x_docbook2man is what Fedora contains
+    sercmd: pass OS define at compile time
 
-commit eb45b8ccb4d859e7726889a4fae50941bd6c8e43
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Oct 20 00:29:07 2012 +0100
+commit af1c2af129edeb49c6f2c826ec2c675e72c2486d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Jun 4 22:17:52 2013 +0200
 
-    pkg/kamailio/fedora/16: Updated .spec to set ownership of /etc/kamailio to kamailio.kamailio
+    sercmd: possibility to enable EXTRA_DEBUG via compile time option
     
-    - Means that file-based DB (e.g. sqlite) files kept in /etc/kamailio can be
-      written to by processes (including kamailio itself) run by the kamailio user.
+    - should get rid of empty DBG() resulting in unused init variable
 
-commit ae485d398f17ae7040ac1a0799842e6bb0e42bd8
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Oct 19 17:24:44 2012 -0400
+commit 0f54ee9c29faf767a5ec38de9f70bfaab8836ac9
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Tue Jun 4 10:44:36 2013 +0300
 
-    Remove unused variables and debugging.
+    modules/lcr: use pv_cache_get
     
-    Quiet compiler warnings.
+    - Applied patch by Victor Seva.
 
-commit cbc6e06cb95b69502095971c55b7a83a683c0537
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Oct 19 17:16:59 2012 -0400
+commit 76709d2ea2eb3c05cf62a3368310f50e8bfee355
+Author: Klaus Darilion <klaus.mailinglists at pernau.at>
+Date:   Mon Jun 3 22:13:20 2013 +0000
 
-    Fix [SIPR-723]: must release appearance when script sends error w/ t_reply
-    
-    Using callback for TMCB_RESPONSE_READY event, which is invoked with a
-    FAKED_REPLY when t_reply() is called.
-    
-    This still means that the SCA_UPDATE route will need to be called early
-    enough in the configuration so that the callback is registered when the
-    script calls t_reply().
+    modules/auth_db: regenerate README
 
-commit cb74d38f52d77f6ee11d7083ab0adabe5e6f34a9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Oct 19 14:34:54 2012 +0100
+commit 2940d5012250a134745a2cf9abed2f88ed95576e
+Author: Klaus Darilion <klaus.mailinglists at pernau.at>
+Date:   Mon Jun 3 22:10:20 2013 +0000
 
-    modules/websocket: Updated example configuration file
-    
-    - Use qop="auth" for MSRP authentication
-    - Support Expires: header in MSRP AUTH requests
-    - Add Expires: header to 200 OK responses to MSRP AUTH requests
-    - Authenticate MSRP AUTH requests off subscriber DB
+    modules/auth_db: document authentication return values
 
-commit 70b0875fb968ef4747636c9f01882bf92138388a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Oct 19 14:25:35 2012 +0100
+commit 5bed1c2f9721405d5e6e0678f583aee474d4b9b9
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Jun 3 23:23:15 2013 +0200
 
-    modules/msrp: Updated MSRP configuration example
+    Makefile: added install-initd-centos target
     
-    - Enabled qop="auth" for authentication (mandated by RFC 4976)
-    - Added support for Expires: header in AUTH requests
-    - Added (mandatory) Expires: header to 200 OK responses to AUTH requests
+    - install centos specific init.d scripts
 
-commit 13c2616d6b8a9f9f82979a531bac664832043597
+commit a17a32e5f7a3120c200d6e48fe91d7aa1dfd28b1
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Oct 19 11:53:17 2012 +0200
+Date:   Mon Jun 3 20:53:05 2013 +0200
 
-    rtpproxy: allow flags parameter to rtpproxy_destroy()
+    dialog: shift next timer run for keepalives of dialog
     
-    - it is optional parameter, but was not allowed by c code
-    - reported by Juha Heinanen
+    - reported by Daniel Tryba
 
-commit 12d95216e12c5e5bab351921524b4029a126854b
-Merge: da72036 5e886db
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Thu Oct 18 18:39:15 2012 +0200
+commit 26b15ad0006defeb8df17dff090fd93ffa11ede6
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Jun 3 18:43:51 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/debugger: fixed last commit.
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      all: OPENSER_MOD_INTERFACE replaced with KAMAILIO_MOD_INTERFACE
-      all: fixed matrix doc generation and updates for &defaultdb;
-      all: replaced db_url static value with &defaultrodb; in docs
-      all: replaced openser with kamailio in license and comments
-      dialog(k): run event route after setting cfg dlg vars
-      rtpproxy: regenerated readme for flags x and 3
-      rtpproxy: documented flag 3
-      rtpproxy: propage flags from rtpproxy_manage() to unforce_rtp_proxy()
-      pkg/gentoo: Added ebuild for v3.3.2
-      Makefile: added uninstall target
-      modules_k/db_sqlite: fix memory leak in sqlops query
-      kamailio.cfg: handle UPDATE through nat traversal logic
-      auth_db(k): new function is_subscriber(uri, dbtable, flags)
+    - checked malloc result on dbg_init_pvcache.
+    - checked result of dbg_init_pvcache on mod_init.
+    - removed commented code.
 
-commit 5e886dbbef6896ab2b1c0f6941587912a3b8694b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 18 15:46:13 2012 +0200
+commit 2312e2adc626f42d36d240a417bb488f19e95017
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Jun 3 15:10:27 2013 +0200
 
-    all: OPENSER_MOD_INTERFACE replaced with KAMAILIO_MOD_INTERFACE
+    modules/debugger: new parameter log_assign
     
-    - OPENSER_MOD_INTERFACE still works if used in module Makefile
+    This parameter enables logging every single assign action on the config.
 
-commit 0d9eec94cea33aeeb7dee79664bab512194316b1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 18 14:46:37 2012 +0200
+commit 5d45ea50a7ebb53cfcfb04553a3152e61d1e6831
+Author: Elena-Ramona Modroiu <ramona at asipto.com>
+Date:   Mon Jun 3 11:13:56 2013 +0200
 
-    all: fixed matrix doc generation and updates for &defaultdb;
+    htable: documented the new rpc commands
+    
+    - htable.sets and htable.seti
 
-commit f5ccfeaade8d4e7137c52b578fe52d1deff88fd8
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 18 14:36:46 2012 +0200
+commit 83eb9b7d7a9b4e1e2bf35d4e2b00573c176c8290
+Author: Elena-Ramona Modroiu <ramona at asipto.com>
+Date:   Mon Jun 3 11:05:58 2013 +0200
 
-    all: replaced db_url static value with &defaultrodb; in docs
+    htable: added rpc commands for setting items in a hash table
     
-    - regenerated the readmes for modules/ and modules_k/
+    - htable.sets - set to a string value
+    - htable.seti - set to an integer value
 
-commit 6c7802254f146f97b1548645d363a0aee9c0d7d4
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 18 14:18:19 2012 +0200
+commit 7cb062ce8eb9935b69298b61aa6a59450b97dbaf
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Sat Jun 1 17:47:58 2013 +0300
 
-    all: replaced openser with kamailio in license and comments
+    modules/usrloc: rpc statistics command update
     
-    - some files were forgotten during renaming
+    - ul.db_users and ul.db_contacts now deal with unexpired records only
+    - new command ul.db_expired_contacts tells number of expired contacts
 
-commit 2cdded28d9968a0b78f5ec8329ae6983d9ea77a9
+commit 09cc2207b265d51dcbc28279623bf9c597fa3b46
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Oct 18 09:54:53 2012 +0200
+Date:   Fri May 31 17:05:40 2013 +0200
 
-    dialog(k): run event route after setting cfg dlg vars
+    pua: release lock on not finding temp dialog
     
-    - in this way they (e.g., $DLG_lifetime) should be accessible in event
-      route
+    - patch by Halina Nowak
 
-commit 5b597906be44996344e11edfc1b3b60e8f47dc75
+commit d5c4dda7932e8efe018beb77f8ca2e29a44aa185
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 17 21:41:40 2012 +0200
+Date:   Thu May 30 17:59:01 2013 +0200
 
-    rtpproxy: regenerated readme for flags x and 3
+    core: don't free pvar spec - is reference to cache
+    
+    - reported by Peter Dunkley
 
-commit 63d577731291c3c2079544ce105521dda7bd8ebb
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 17 21:33:45 2012 +0200
+commit 0577abba2abd869a0c3fb051289068e79986e6cd
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:47:21 2013 +0100
 
-    rtpproxy: documented flag 3
+    documentation: Rebuild all modified READMEs
 
-commit 393893a9d6b1fe586abe2a6cfa03680d494bb871
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 17 21:25:00 2012 +0200
+commit f67f6880bfa9f7a9f31b4a46106482ff41120c3c
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:46:40 2013 +0100
 
-    rtpproxy: propage flags from rtpproxy_manage() to unforce_rtp_proxy()
-    
-    - unforce_rtp_proxy() can take flags 1 or 2, previously it didn't take
-      any
-    - ignore all the other valid flags for rtpproxy_manage() in
-      unforce_rtp_proxy()
-    - added flag 3 - add first via branch if it request (like flag 1) or add
-      second via branch if it reply (like flag 2) - suitable for auto-pilot
-      usage with rtpproxy_manage() function
+    uid_uri_db: Fix TOC in documentation
 
-commit 131e70db763aec71670466cc399e088bf96561f7
-Author: Claudio Furrer <elcaio at gmail.com>
-Date:   Wed Oct 17 14:38:52 2012 -0300
+commit 7bf8e5a0f125cf1878fbd7a81504ab67659fa3a9
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:46:24 2013 +0100
 
-    pkg/gentoo: Added ebuild for v3.3.2
+    uid_gflags: Fix TOC in documentation
 
-commit 04b9fdd2b8d6dac67948f1cb5a76b4d34a65f228
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 17 12:52:34 2012 +0200
+commit 0882e6f8c2217b75f8d5082e1df5bf8f9291e125
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:46:04 2013 +0100
 
-    Makefile: added uninstall target
-    
-    - it prints hints and commands to perform uninstall when installation is
-      done from sources
+    uid_domain: Fix TOC in documentation
 
-commit ecf95eb0ada8bfacb93af7b82f39347c841229e4
-Author: Timo Teräs <timo.teras at iki.fi>
-Date:   Wed Oct 17 09:00:14 2012 +0300
+commit db6762f45eb2f5809487b254e35edb55ea097fc1
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:45:49 2013 +0100
 
-    modules_k/db_sqlite: fix memory leak in sqlops query
-    
-    Seems that most other database drivers release the database
-    resource only at free_result time, which I some how missed.
-    
-    Since we are doing a deep copy in store_result(), we can
-    just release the sqlite resources immediately raw_query().
-    
-    Reported-by: Pedro Antonio Vico Solano <pvsolano at amper.es>
+    uid_avp_db: Fix TOC in documentation
 
-commit c76035255e556d8272097281d3e0fd0ab918c608
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 16 21:59:28 2012 +0200
+commit 0bf496b9e9368d564835d5f97827ba7a7fcc8242
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:45:28 2013 +0100
 
-    kamailio.cfg: handle UPDATE through nat traversal logic
-    
-    - BYE is handled via branch route as well
-    - set tm routes only if they are not set, allowing better plug and play
-      config snippets
+    uid_auth_db: Fix TOC in documentation
 
-commit 1a3a35fd19d4b9ec04d84b7b8fa1e1cb43092bd9
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Oct 16 15:41:26 2012 -0400
+commit 402d1fb0036cab8588e94acf3ea6d80ccf1a00b0
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:44:45 2013 +0100
 
-    Notes on t_reply, subscription deletion on NOTIFY failure.
+    xprint: Fix TOC in documentation
 
-commit a9f1f9e3cd62d296bcbf4c3618da96d077aacd86
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 16 21:28:46 2012 +0200
+commit 06369a4f2b2dbe3b58ca2c34c0cf2f228a343fd7
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:44:28 2013 +0100
 
-    auth_db(k): new function is_subscriber(uri, dbtable, flags)
-    
-    - check if URI corresponds to a subscriber record in dbtable and load
-      credentials for it
+    xmlops: Fix TOC in documentation
 
-commit 15a2a5ae02948961f1e26e545e284d9659510c42
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Oct 16 14:47:10 2012 -0400
+commit 631e2450beb3cba5a0f3b85ecfd319a8ba98db00
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:44:09 2013 +0100
+
+    tm: Fix TOC in documentation
+
+commit 528098292d5a5dc43052f0d9f59105622c064f74
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:43:57 2013 +0100
+
+    tls: Fix TOC in documentation
+
+commit 6ea032c426e09a932c260842cf884cdd1cca69e5
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:43:42 2013 +0100
+
+    timer: Fix TOC in documentation
+
+commit f198c3248b152e407313462619a402a730f9f29e
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:43:24 2013 +0100
+
+    textopsx: Fix TOC in documentation
+
+commit e1a98837a273921a307518d0f83c690adabfa201
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:43:09 2013 +0100
+
+    sms: Fix TOC in documentation
+
+commit c0b97566f8cfd0038a8fc5ea514dd7cf3b37f831
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:42:54 2013 +0100
+
+    sl: Fix TOC in documentation
+
+commit 87e43eead7d3d6c8740bd397e512629a4230bf30
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:42:35 2013 +0100
 
-    Use standard hashes.h header instead of libkcore hash_func.h path.
-    
-    All hash routines are moved to sip-router/hashes.h as of 3.3.x.
+    sanity: Fix TOC in documentation
 
-commit 06bb391cef6c59285b5e2eff1ea7857485b33e0c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Oct 16 14:27:39 2012 -0400
+commit d99ffcd886b12a8b3adb43549d0603a86ef803da
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:42:20 2013 +0100
 
-    Ensure upstream 302 redirects are not treated as errors.
+    print_lib: Fix TOC in documentation
 
-commit c9088726bee111154cdede26c9f92566241f1757
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Oct 15 22:22:26 2012 -0400
+commit 762d01b4783b9d9e1b97420a7e0ab901b84eb243
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:42:05 2013 +0100
 
-    Fix [SIPR-708]: loss of state on call transfer
-    
-    Module was blindly releasing appearance indices on BYE without checking
-    for dialog match. Simple call-id check is enough.
+    print: Fix TOC in documentation
 
-commit 8ff7fce98a15afe4ca1bf7c2d9206f1d75add66a
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Oct 15 21:41:36 2012 -0400
+commit c8a00e093aa009cff5069cfa683b3efc361497d7
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:41:51 2013 +0100
 
-    Remove debug line.
+    prefix_route: Fix TOC in documentation
 
-commit da720367972b18e0a6664dfa47d1e65a648099a8
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Oct 15 19:51:21 2012 +0200
+commit cc15d526784ec2f734db452bc3f5157493225416
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:41:28 2013 +0100
 
-    async Forgot to rebuild the README
+    mangler: Fix TOC in documentation
 
-commit b68fade258f29ad427950b42b44d706b95db4150
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Oct 15 19:47:52 2012 +0200
+commit 5829244ff407abd8cb0735b998dcd7ffb351f87b
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:40:54 2013 +0100
 
-    Async typo fix
+    malloc_test: Fix TOC in documentation
 
-commit f9ab230357fcd551252a6bc151b278e792bcb54e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Oct 15 19:45:02 2012 +0200
+commit eabae931b7fcf1c4dae9bce2945a55c9dd48fee8
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:40:31 2013 +0100
 
-    textopsx - typo fixes, minor corrections
+    iptrtpproxy: Fix TOC in documentation
 
-commit e09af3559bf1c0a39e87eb1fa489c1e996c56b8e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Oct 15 12:56:53 2012 -0400
+commit e8ab0f1552c4bd0fbeb8f2bb42b79bb8acbce57e
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:40:06 2013 +0100
 
-    Ensure unlinked hash entries have NULL next and slot pointers.
-    
-    Not fixing any known issue, just being a bit more defensive when
-    unlinking entries.
+    db_flatstore: Fix TOC in documentation
 
-commit 5d9d4d017d79d4e9269bbeb019460b3c8d8695d0
-Author: Dragos Dinu <dragos.dinu at 1and1.ro>
-Date:   Mon Oct 15 18:29:48 2012 +0300
+commit 9ca893c26257caf8d80e7fae25128a6e28f37518
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:39:45 2013 +0100
 
-    modules_k/siptrace Fixed crash when using HEP v2
+    db2_ops: Fix TOC in documentation
 
-commit 7d4ed54b5748d70761f2c574a05b7df1c07010b6
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Mon Oct 15 14:35:10 2012 +0200
+commit 2a743dcd16f2546dabf41a5b0de498a6faaf00ed
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:38:43 2013 +0100
 
-    INSTALL - Fixing spelling error
+    db2_ldap: Fix TOC in documentation
 
-commit d926b2f942e8fd207c9f50ff9e1edd27a39866bd
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 21:57:24 2012 +0200
+commit 09c617d4e3bd17e5f2234aac03f90f4fa25c3bb6
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:38:25 2013 +0100
 
-    registrar Fix typos in README
+    ctl: Fix TOC in documentation
 
-commit 68a650ef2b1be78084463c88e9b527ae498b7943
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 21:40:36 2012 +0200
+commit a966e236f5d4ae9d98048d5432978658c70a7f26
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:38:07 2013 +0100
 
-    pv Fix typo in README
+    counters: Fix TOC in documentation
 
-commit 93c6567011162468c684fa0e673b9efaa2910a3a
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 21:32:56 2012 +0200
+commit 48c393f24a0a6c9a2841f7710cfdbc475c90d214
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:37:45 2013 +0100
 
-    dispatcher small documentation updates
+    cfg_rpc: Fix TOC in documentation
 
-commit a86074046ebf5e325413662d099711c00ee24930
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 21:02:52 2012 +0200
+commit c1cb95ee9e29f4373973f7676a224d2892a8902e
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:37:26 2013 +0100
 
-    p_userloc Fixing the database URLs as entities
+    cfg_db: Fix TOC in documentation
 
-commit 2040896f2b4fd5d955af783fa9c8851572186785
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 19:54:19 2012 +0200
+commit 216d3f4c8d8b3a40867b4f8438e8ac5027cf1bdf
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:37:03 2013 +0100
 
-    Revert "Changing database URL example to use entity"
-    
-    This reverts commit 827e2d4bbab047fd4bbe4ada266327a823fc1cd3.
+    blst: Fix TOC in documentation
 
-commit 827e2d4bbab047fd4bbe4ada266327a823fc1cd3
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 19:38:47 2012 +0200
+commit 84a96c85d21a34c9082efd6622bccd73bfb1a2b5
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:11:23 2013 +0100
 
-    Changing database URL example to use entity
-    
-    Making it easier when we change from "openserrw" to "kamailiorw"
+    avp: Fix TOC in documentation
 
-commit ba1aba0c8ffa992eb99b2004f3cf14fe1a6fa3d1
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 18:58:16 2012 +0200
+commit e59a2b0fa195fc2360049ccd438dc02ee19aedf3
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:10:31 2013 +0100
 
-    dialog: minor typo fix
+    auth_identity: Fix TOC in documentation
 
-commit 2522a1ce3886a764c6cf09d8cc55b8c6dd1bf57e
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 18:20:42 2012 +0200
+commit 985cee9f4e904e92d473efecb15f4211c8a75501
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed May 29 14:09:08 2013 +0100
 
-    siputils: README typo fixes
+    auth_ephemeral: Minor documentation improvement
 
-commit ef0f8fd65b34ef9d7006be30f7cef0353c1c529f
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 18:11:29 2012 +0200
+commit ffe8aa173c6106844707bcf5d0f8da4f28631921
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Wed May 29 12:38:10 2013 +0200
 
-    uac: README typos
+    DB scheme: remove default MySQL engine definition
+    
+    * remove default MySQL engine definition from table definitions
+    * if nothing is specified then MySQL server will choose the default from its cfg
+    * if you like to specify it, change the MYSQL_TABLE_TYPE define in
+      lib/srdb1/schema/entities.xml and run "make dbschema" in the top level directory
+    * the stylesheet doesn't check the engine type, Kamailio supports MyISAM and InnoDB
 
-commit 4c45f67a42ea76c909893bd684cac03fde8d5c2b
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 18:02:45 2012 +0200
+commit 5aa71845f630f6b933b0a415749a7b1dae66605a
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Wed May 29 12:30:58 2013 +0200
 
-    SL doc: fix typos
+    Revert "DB scheme: as discussed on sr-users list, change default mysql engine to InnoDB"
+    
+    This reverts commit fa49fe070adadfff893b338f2a2d69776c043653.
 
-commit d22fb8987131f6ee94406632913885a52098b49c
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 17:54:53 2012 +0200
+commit a21137507bea759d4945402dc47486ac324724db
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed May 29 12:25:50 2013 +0200
 
-    TM docs: fix typos
+    core: added helper function pv_cache_get_name() in order
+     to get the name of a pv_spec_t on pv_cache.
 
-commit 4090bfc2e4eb76a9b6c03d99446619d2723fa222
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 17:45:41 2012 +0200
+commit a2316f35deef2586f79dc575367224af853e9b70
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed May 29 12:25:09 2013 +0200
 
-    tm: Updates of README, spelling errors
+    core: Add callback to be able to log assign actions.
 
-commit 6339389bae85814264a923ebbf938d70fa22c4db
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 17:24:21 2012 +0200
+commit 6fba3230222214fccb72fd07817f29693d98b877
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Wed May 29 12:24:00 2013 +0200
 
-    async: Speling erors fixed
+    core: use pointer to pv_spec_t on lvalue union. Use pv_cache_get() on interpreter.
 
-commit f8e02b3bbe83315d8228005d4388434b62473c61
-Author: Olle E. Johansson <oej at edvina.net>
-Date:   Sun Oct 14 17:13:01 2012 +0200
+commit fa49fe070adadfff893b338f2a2d69776c043653
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Wed May 29 11:49:59 2013 +0200
 
-    msilo: Updating docs
-    
-    Fixing a typo and while at it updating some texts.
+    DB scheme: as discussed on sr-users list, change default mysql engine to InnoDB
 
-commit 4d71456df4b47a131cb6df2a21608ba291e30b95
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Oct 12 14:35:12 2012 -0400
+commit b480ac55508e5d9b92cc9560e0b1d338d04f3b11
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed May 29 10:49:40 2013 +0200
 
-    Fix [SIPR-728]: stuck lamp on multiple inbound calls
+    topoh: safety check for Via header when removed from script
     
-    BYE response handler was trying to lookup remote party's Call-Info
-    state using from-tag instead of to-tag.
+    - reported by Guillaume Bour, FS#300
 
-commit 9fc31d82f47a0fb526f25864ff093c1b5a55b057
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Oct 12 13:37:30 2012 -0400
+commit 8cba441b17c75cd078a499c24268c8a60c6b1771
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue May 28 15:48:22 2013 +0200
 
-    Add simple install-and-bounce-sip-router script.
+    misc_radius: updated readme
+    
+    - from a patch by Victor V. Kustov
 
-commit 3b09b31be29ca06b959b92a3837f5fd56435488f
+commit 355490abd8c6e82a45cb96338ceca938c99ed744
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Oct 12 15:40:24 2012 +0200
+Date:   Tue May 28 15:43:27 2013 +0200
 
-    kamailio.cfg: load corex module to get same cfg api as so far
+    misc_radius: handle IPv4 returned attributes
+    
+    - populate attributes for negative replies when common_response is set
+    - patch by Victor V. Kustov
 
-commit 5e5213287009b8dda79017ddbd52ff129df9c44c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Oct 11 17:00:28 2012 -0400
+commit 6a92939ee4b7db6216814dc88e57eccefabb05af
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Tue May 28 00:46:26 2013 +0100
 
-    Improve encapsulation when sending NOTIFYs.
-    
-    When sending NOTIFY to subscribers list, only build headers for the
-    NOTIFY once.
+    modules/auth_ephemeral: updated to use SHA1_DIGEST_LENGTH #define from openssl/sha.h
 
-commit c43bb19418cbf6a80dcd935491d02d891e5651a6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Oct 11 16:21:36 2012 -0400
+commit ec893a2c6cb5c0fd21207cbf0ffab09f65418df2
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Tue May 28 00:27:37 2013 +0100
 
-    Remove debug sanity check.
+    modules/auth_ephemeral: tidied up the headers and tidied up more debug
 
-commit 2c968f5c36db7609c16521a43fd4694de2cc83d1
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Oct 11 16:18:24 2012 -0400
+commit ba2a6ac4230dd9169943f55a9c06af3faa694356
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Tue May 28 00:20:20 2013 +0100
 
-    Move from doubly-linked list with tail insertion to singly linked list.
+    modules/auth_ephemeral: updated to handle usernames from the web-service that just consist of timestamps
     
-    Reduce complexity, especially where unlinking is concerned.
+    - tidied up the diagnostic output
 
-commit 309918272df6110453cf2b9af4afd7e816590cbe
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Oct 11 16:16:16 2012 -0400
+commit a435f770e7162f73aea560a77851f8fb639a495a
+Merge: 45227df 74bf08e
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Mon May 27 17:58:33 2013 +0300
 
-    Improve appearance index unlinking.
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
     
-    The double pointer unlinking method is much more elegant.
+    - i did pull , but there was race conditions with somebody else's push
 
-commit d1897658f85f45ff900b7c2fc9a0e6cbe8aa1522
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Oct 11 16:13:23 2012 -0400
+commit 45227df1bc87e448c74fe31c001e85f525c654a0
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Mon May 27 17:57:07 2013 +0300
 
-    Only store one appearance_list per AoR.
+    modules/usrloc: renamed ul.users and ul.contacts rpc commands
     
-    sca_appearance_register was not checking to see if an entry for the AoR
-    already existed in the hash table, blindly appending an empty list for
-    each client subscription. Things worked because the hash table collision
-    handling inserted new entries at tail instead of head.
+    - new, more descriptive names are ul.db_users and ul.db_contacts
 
-commit 2f240d5f5d1e647cbc6ee55893a65058bf950cda
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 11 12:58:38 2012 +0100
+commit 74bf08ef30cf18fb609c2c067584f1515ede23da
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon May 27 16:54:02 2013 +0200
 
-    modules/msrp: Added support for WS transport
+    core: enclose uri in angle brakets for redirect contact header
     
-    - Updated parser to recognise/decode ";ws" as a transport
-    - Updated netio code to route MSRP messages destined for a
-      WebSocket connection through the websocket module (instead of just
-      tcp_send()ing them).
+    - safer for uri with parameters and no q
+    - reported by Dan Bogos
 
-commit 132509a7affe0f0bffd87f3606513b1475e98a03
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 11 12:57:26 2012 +0100
+commit d0d298070fdbb015a96f209fa3c925ba71e3a37b
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Mon May 27 13:54:23 2013 +0300
 
-    modules/websocket: Added support for MSRP WebSocket sub-protocol
+    modules/usrloc: added two new rpc commands ul.users and ul.contacts
     
-    - Prototype of draft-pd-msrp-websocket
-    - Enables session based chat and group chat from HTML5 clients
+    - for accessing number of different AoRs and contacts in a location table
 
-commit baf9486e80018206d4edcdfb666b393d8b43aadf
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Thu Oct 11 10:59:45 2012 +0300
+commit 6531b8d495ead58a85cb101d914b5bf18c2ecddb
+Author: Klaus Darilion <klaus.mailinglists at pernau.at>
+Date:   Mon May 27 10:44:51 2013 +0000
 
-    core: fixed small issue w/ include directive
+    modules/dialog: regenerate README
 
-commit 728f6033a7ee663f3e46717c8ea49703135d3c12
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Wed Oct 10 19:15:10 2012 +0200
+commit 68209cc2b15c2c0674d7cf4529607e148e3fc1b4
+Author: Klaus Darilion <klaus.mailinglists at pernau.at>
+Date:   Mon May 27 10:44:03 2013 +0000
 
-    core: disable build of DNSSEC (patch from Marius)
+    modules/dialog: improve documentation of DID matching
 
-commit 98ceaec93a6c69399ea4bfcf47a82e01610d848e
+commit ace89166f84657b2ea4a70e8d9e2ccfbd032b1ba
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Oct 10 18:00:51 2012 +0100
+Date:   Mon May 27 00:49:46 2013 +0100
 
-    modules/msrp: Updated typo in MSRP example
+    pkg/kamailio/(centos|fedora): Added RPM for auth_ephemeral module
 
-commit d9c2638bd27c50a7cba4a96ee7b5592d05f39c90
+commit 2a29b2ba260584634f05c684ef39ab45e2dc51b6
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Oct 10 16:15:32 2012 +0100
+Date:   Mon May 27 00:32:19 2013 +0100
 
-    modules/msrp: From-Path: not updated correctly in msrp_relay()
-    
-    - When the last To-Path-URI is pre-pended to the From-Path: header the first
-      two characters of "From-Path: " are skipped, leaving "om-Path: ".  11
-      characters should actually be skipped.
+    core: updated groups to include new auth_ephemeral module
 
-commit 73103df8fcffa0f92dfc4699c52d5dd9474084ea
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Wed Oct 10 17:53:02 2012 +0300
+commit 0bea7f63afa0fd544ad93465db94ddef4ed67a00
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Mon May 27 00:25:03 2013 +0100
 
-    Core: added DNSSEC support for DNS queries
-    
-    This is available by setting the USE_DNSSEC compile flag. It requires libval-threads and libres (part of dnssec-tools dnssec-tools.org)
-    The custom resolvers were replaced by val_gethostbyname, val_gethostbyname and val_res_query (for SRV).
+    modules/auth_ephemeral: new module for ephemeral credential based authentication
 
-commit 10dafd75873f9f58037680e4d72cafc4c877583f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Oct 10 10:49:16 2012 +0100
+commit 375d878b5f318acc08b155c29398e4abb74edbd5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 26 17:11:25 2013 +0200
 
-    modules_k/xcap_server: Fixed small mistake in last xcap_server fix
+    sctp: added rpc commands to module documentation
 
-commit e71435b0276c89ef756fecf1bbd5e339b80e804c
-Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
-Date:   Wed Oct 10 10:02:00 2012 +0200
+commit ca923db8727333ad7df14126bb377418a829cce3
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 26 17:04:23 2013 +0200
 
-    tcp: fix connection alias replacing
+    sctp: rpc commands are prefixed with sctp
     
-    When the TCP_ALIAS_REPLACE is set and an alias has to be added to
-    a connection that had 0 aliases (it can happen due to
-    TCP_ALIAS_REPLACE flag), the connection aliases count was wrongly
-    forced to 1.
-    For more details see:
-    http://lists.sip-router.org/pipermail/sr-users/2012-October/074932.html
+    - no longer part of core and proper matching of the module
+
+commit 352a7dccf2570af857d7e2e50fed600c4762278d
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 26 16:14:51 2013 +0200
+
+    topoh: safety check for SIP messages
     
-    Patch-by Jijo
+    - received callback can be executed for non-sip messages
+    - reported by Julia
 
-commit d29cfab1584b8bc2672b4242a2626d9dc90c77a2
+commit dfd8ec8c1e9f0a5c3c7aad6ec984e7a664e5af49
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Oct 9 21:07:10 2012 +0100
+Date:   Sun May 26 13:54:15 2013 +0100
 
-    modules_k/xcap_server: Fixed segmentation fault
+    pkg/kamailio/(centos|fedora): Added rpm for sctp module
     
-    - Occurs when attempting to do an etag compare when there is no document/etag
-      in the database.
+    - Also updated release to dev6
 
-commit b12c2df6ccb903e2ca22d34bb968f3ebc2712b89
+commit 1977645ceb12ca2d0f2f767046606f6c5ae2c3bb
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 9 16:30:24 2012 +0200
+Date:   Sun May 26 10:43:24 2013 +0200
 
-    core: reset params pointers if there is a failure in parse_params()
+    dmq: many safety checks for mem mallocs and function return codes
     
-    - patch by Jijo
+    - added license header in the files
 
-commit 038780fdf40c8d5d3694538f199411810fad7a0e
+commit a85e7e5c192e4f597d17c98f4036d83639c6bc1f
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 9 12:29:09 2012 +0200
+Date:   Sun May 26 10:12:24 2013 +0200
 
-    tm: set log level to debug for negative return code of run_top_route()
+    core: safety check for initialized SCTP API
     
-    - it returns the code of last execution action, negative return is not
-      necessary an error
+    - reported by Juha Heinanen
 
-commit 753f511f281b0f4406908086547225c5c0bc0d23
+commit 59c4a6550862ed7c3e8c63a3a5d5c1dcd404bd6d
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 9 11:39:16 2012 +0200
+Date:   Sat May 25 21:28:33 2013 +0200
 
-    rtpproxy: safety check for rtp stats pv
+    tm: return current branch id if sending fails and tm_failure_exec_mode=1
     
-    - if the rtpproxy is not responding, there is no returned value and
-      could cause crash when doing strlen(NULL)
-    - return $null in case of various errors, being safer to check returned
-      PV value in the script against $null, rather than having undefined
-      value
-    - reported by J. Gallart
+    - reported by Juha Heinanen
 
-commit 146873cf2b101d6363bb20c235b7dcdb8bb54134
+commit 93d97e53741d786692903bd9df9622cd55e4cfea
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 9 09:13:15 2012 +0200
+Date:   Sat May 25 21:04:43 2013 +0200
 
-    msrp: fixed copy&paste issue for getting To-Path size
-    
-    - the parsing of From-Path was used instead
-    - reported by Peter Dunkley
+    sctp: documented module parameters
 
-commit 971386c346d72a016d00c8808059bd4f0a050059
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Fri Sep 7 07:01:11 2012 -0400
+commit 2e6675bd92968fd96865ee266ca4ba10c7cc1cdc
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat May 25 17:14:23 2013 +0200
 
-    core: Fix parser sdp bug. Reset connection IP for each stream.
-    
-    If connection IP is not reset, then when a stream has no IP connection,
-    it uses former stream one instead of session default one.
+    Makefile.defs: version set to 4.1.0-dev6
 
-commit f86ab01f7e3c6a4b196c5fe42543b18168f6d969
-Author: Dragos Dinu <dragos.dinu at 1and1.ro>
-Date:   Mon Oct 8 17:42:20 2012 +0300
+commit c4cf64ea992e0f0f46f1c6fc23c6f38c05a80b0f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat May 25 17:05:58 2013 +0200
 
-    modules/sipcapture: Fixed crash in module initialization
+    sctp: added skeleton files for docbook module documentation
+
+commit 25c3df171d219eb71c63f4832b69f33b470c9c96
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat May 25 16:42:21 2013 +0200
+
+    Makefile.groups: added compile group for sctp module
     
-    Leaving the default table_name parameter caused a segmentation fault
-    Reported by Juha Heinanen
+    - depends on libsctp-dev
 
-commit 1371eeab4ca3d3f666e52bb42d904059ce77c4ac
+commit 1bdbdb64e4862ddb69c2bf13be0f9be93968bb1e
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Oct 6 09:56:06 2012 +0200
+Date:   Sat May 25 16:30:33 2013 +0200
 
-    utils/misc/vim: added Makefile to install vim scripts
+    protoshoot: use Makefile pattern for utils
     
-    - 'make install' copies the files to home .vim folder
-    - updated README to reflect the new command
+    - link to libsctp if SCTP support is enabled
 
-commit 007ca3c30b02e7a57cd229ea4b63573ef81f8c81
+commit a2afc3d42224d0c35e4867ad50251e7aa6231879
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Oct 6 09:52:37 2012 +0200
+Date:   Sat May 25 15:42:14 2013 +0200
 
-    pv: two new functions- typeof(...) and not_empty(...)
+    core: filled sctp core api
     
-    - typeof(pvar, vtype) - test the type of the pseudo-variable
-    - not_empty(pvar) - test if the type is string and the value not empty
+    - cleanup of not needed members
 
-commit 780decb3b0f8cf140ffdf522abc61e68388ee6a7
+commit 61f5f6a63409f856a03b48e9ced22ad5c724acb2
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sat Oct 6 09:38:57 2012 +0200
+Date:   Sat May 25 15:41:27 2013 +0200
 
-    core: added mod fix helper fixup_pvar_none(...)
+    sctp: register sctp core api
     
-    - first parameter is PV and the rest are not fixed up
+    - done in mod_register() function
+    - initialize the sctp options before modparams
 
-commit ad67ccfec1a1f99483b544f9c9e354bc43af1afe
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Oct 5 16:05:47 2012 -0400
+commit e9f7980602cadcc179425cad57a4d0f89c63fb55
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat May 25 15:39:13 2013 +0200
 
-    Fix [SIPR-737]: calls not reaching voicemail
+    core: remove sctp options init from core
     
-    Non-SCA to non-SCA would cause a function called from sca_call_info_update
-    to return 0, which sca_call_info_update would then return to the script.
-    A return value of 0 from a function called in the script means "stop script
-    processing" in sip-router, so PRACKs were never getting relayed to the
-    caller. Fixed by resetting return code to non-zero before returning.
+    - will be done in mod_register() from sctp module
+    - don't print anymore info about sctp unsupported socket options in
+      output of -v, they are known now only in sctp module which is not
+      loaded at that time
+    - sctp will print a warn message in mod init about unsupported socket
+      options
 
-commit 83e31eaadd549132103899a201cdf100ab669b6e
-Author: Claudio Furrer <elcaio at gmail.com>
-Date:   Fri Oct 5 03:32:16 2012 -0300
+commit cbbaf9abd5f34b50c47ac2ac350c77d3f36b511b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat May 25 11:57:02 2013 +0200
 
-    pkg/gentoo: version bump, added ebuild for v3.3.1
+    sctp: exported sctp parameters via module interface
 
-commit 019bcdc56533e7ccd0e1cc7d45b1d2d8ebc868ae
+commit e549d96b571ae509a67984be789b281ed2230bc3
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Oct 5 14:34:13 2012 +0200
+Date:   Sat May 25 11:24:22 2013 +0200
 
-    nathelper(k): nicer handling of no sdp in sdp_1918(...)
+    core: readded conditions for core sctp forwarding functions
     
-    - don't print error message if there is no sdp body
+    - typo fixed in log message
 
-commit 4cea90421731e13c79a663f5119e3f3007588662
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Oct 4 23:59:10 2012 -0400
+commit 66e90f9888daefdb92dcebd28e188ce7f912a4f9
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat May 25 10:56:11 2013 +0200
 
-    Finish fix for crash on hash entry unlink.
+    core: added sctp callbacks api
     
-    Replaced core_hash references with more modern get_hash1_raw.
+    - functions needed in core - callbacks to be set by sctp module
 
-commit 7b31e989487c3c728fcbf8daf73feb228f807706
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Oct 4 14:38:47 2012 +0100
+commit d60d41136575408ea7ea9031c735476967755e46
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat May 25 10:54:33 2013 +0200
 
-    pkg/kamailio/fedora/16: Fixed typos in .spec
+    sctp: add module interface for sctp transport
+    
+    - sctp support is now implemented as a standalone module
+    - the core still needs SCTP=1 (now default) and -DUSE_SCTP to get the
+      hooks enabled
 
-commit 8de2a607b99b51d4f4030518ebd08613f187e953
+commit af2473d426870650a0f4a2cb820894ee4dd793d0
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 3 20:25:52 2012 +0200
+Date:   Sat May 25 10:53:04 2013 +0200
 
-    auth: new function pv_auth_check(...)
+    Makefile.defs: don't link to libsctp on Linux for SCTP support
     
-    - equivalent of auth_check(...) from auth_db, but taking the password
-      from a PV -- combines pv_proxy_authenticate() and
-      pv_www_authenticate()
-    - new module parameter use_domain that controls whether the domain part
-      of URIs should be used or not to make the identity checks upon
-      authentication with pv_auth_check(...)
+    - only sctp module needs to link to it
 
-commit 490df85a12a49f440ac6eb8b35be5f4c954b7b1b
+commit f91c9696cc92ec4b74dd2494c39bbf2ffe062fab
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 3 20:25:15 2012 +0200
+Date:   Sat May 25 09:35:22 2013 +0200
 
-    auth_db(k): moved the authorization checks flags to auth api
+    core: added file sctp core interface
 
-commit 1a0d7653139c04d2ab32fa68c86513faf82d5c17
+commit 7f8e7a8568740be65eada1cbd59110bb765f4d5a
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 3 14:58:44 2012 +0200
+Date:   Sat May 25 09:33:39 2013 +0200
 
-    auth: new function has_credentials(realm)
+    sctp: new module for SCTP transport
     
-    - returns true if an authorization header matching the realm is found
+    - moved the sctp specific code from core to a module to make it easy to
+      enable/disable sctp by loading/not loading the module instead of
+      recompiling
 
-commit 7982d66c29e40548cb8282a1de6b7fdddece5ddb
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 3 14:26:12 2012 +0200
+commit 6287caecc438ace98a3ce3dc7a53e6064d7894dc
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Fri May 24 15:38:03 2013 +0200
 
-    kamailio.cfg: show how to include a local file if exists
+    core: remove syn_branch functionality for calculating Via branch parameter
     
-    - kamailio-local.cfg is attempted to be loaded if exists in the same
-      folder, allowing to set defines/paramters inside it without changing
-      main kamailio.cfg
+    * remove syn_branch parameter and functionality from core and tm module for
+      calculating the Via branch parameter
+    * reported from Richard Brady, rnbrady at gmail dot com to sr-dev
+    * kamailio is not standard compliant with this setting enabled (RFC 3261,
+      17.2.3 and 16.11) for stateless forwarding of replies
+    * the performance reason that motivated this functionality are today not
+      valid anymore, even embedded systems have more than enough power to
+      calculate MD5 and other modules uses more expensive operations anyway
+    * adapt a bunch of example and test configuration that used this parameter,
+      it has been also removed from the core cookbook wiki
 
-commit 727203559c98d648e7da4f0d54d65a05317b14f5
+commit 28942a00bc7be5194625b9ed08facd2f95ebea81
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 3 14:21:11 2012 +0200
+Date:   Fri May 24 00:36:57 2013 +0200
 
-    kamailio.cfg: test if DBURL is already defined before defining it
+    pv: added $_s(format) variable
+    
+    - evaluate the format as a dynamic string
+    
+    $var(x) = "sip:" + $rU + "@" + $fd;
+    
+    is equivalent of:
+    
+    $var(x) = $_s(sip:$rU@$fd);
     
-    - allow to set it via command line with -A DBURL='...'
+    - it can be more compact sometimes in config
 
-commit 0193d296e39a9fc095e90682f5335a2907403474
+commit 76c883eb88359f6075712f648a1dfc675872487a
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Oct 3 14:20:27 2012 +0200
+Date:   Thu May 23 12:06:45 2013 +0200
 
-    mem: fixed MDBG() parameters
+    auth: add chapter tag around sections for Admin Guide
     
-    - log level is not necessary for this macro
+    - the ToC isn't properly generated otherwise
+    - reported by Andrew Pogrebennyk
 
-commit 4b656a8f6ee3056986687ca923436639e2fc1653
-Merge: 7b6234a 43e1a79
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Oct 3 09:29:32 2012 +0300
+commit b3c69488bf80e76c2359f6d9611cbcf2edf6c67f
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu May 23 09:45:03 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/debugger: update documentation. This is Kamailio!
 
-commit 7b6234a3e8d0427c767942327aff57ade676eb5e
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Oct 3 09:27:38 2012 +0300
+commit 169e92b86d6a1a98be92d0012bd831785855b968
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu May 23 09:07:53 2013 +0200
 
-    mem/f_malloc.c: downgraded print free(0) warning from LOG to MDBG.
+    modules/debugger: refresh README
 
-commit 43e1a79272b451588d9f9b97fdf1d661e18a45a0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 2 21:53:22 2012 +0200
+commit 6417ac9f99a0c97254206797070bbe3095002847
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu May 23 09:04:12 2013 +0200
 
-    uac(k): documented the new parameter restore_dlg
+    modules/debugger: use cfg framework to be able to activate/deactivate debug per module.
+    add missing files from commit.
 
-commit 0d299fea8a642887305797203536e1340cdf74f9
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 2 21:50:59 2012 +0200
+commit feb00c92297eb2d4520a59f1a676cf998add1b5d
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu May 23 08:58:38 2013 +0200
 
-    uac(k): new paramter restore_dlg
+    modules/debugger: use cfg framework to be able to activate/deactivate debug per module.
     
-    - if set to 1, then the module uses dialog variables to store the
-      initial and new values for From/To headers
-    - default set to 0 - otherwise all calls that have changes to From/To
-      headers must be tracked by dialog
-    - result of checking a report from Alex Balashov
+    mod_hash_size has to be set with a value > 0 on startup.
 
-commit 41fa8653157a989ed1a77f72b25a20fd984b999d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 2 21:24:09 2012 +0200
+commit 31880a46d7f634b568cc192bec6db3d969e738ef
+Author: Klaus Darilion <klaus.mailinglists at pernau.at>
+Date:   Tue May 21 12:39:15 2013 +0000
 
-    mem: enhanced the warning message for free(0) of QM in debug mode
+    modules/auth_db: detailed documentation of URI checking in auth_check function
 
-commit 765b6e06fee81901e458bd5e9a4be26df79fb95b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Oct 2 11:31:25 2012 -0400
+commit 2669197352bfc20bc916c00f74ac14380f8a62f8
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Mon May 20 21:03:30 2013 +0300
 
-    Only send NOTIFYs to caller group on receipt of first 18x response.
+    modules/usrloc: fixed unregister bug in db_mode=3
     
-    Forked calls could mean multiple 18x responses from any of the callee
-    endpoints. The module was sending a NOTIFY to all members of the caller
-    group every time a 18x response arrived.
+    - Commit ce1d16ce1c8009918c294307de53f35378868b52 introduced unregister
+      but that appeared in db_mode=3 when db_ops_ruid param is not set.
+    - Reported by Peter Dunkley.
 
-commit 28300568875f9d8d89bd03166518595e03b4bf12
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Oct 2 11:07:52 2012 -0400
+commit c9448d9657f0e5792072c6803643c8d9075d711a
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Mon May 20 18:33:52 2013 +0100
 
-    Move method check to top of sca_call_info_update routine.
-    
-    Reduce processing for methods we don't handle.
+    modules/rr: completely reverted after_strict() to its pre-outbound form
 
-commit 666ccbf2deb43dc9fff3fe759de460a24f56acae
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Oct 2 11:06:59 2012 -0400
+commit f0ae598a3e63e62d12a143c6cd42b698ad1f2eed
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 19 23:56:06 2013 +0100
 
-    Removing some debug logging.
+    modules/websocket: Improved module_loaded() check for nathelper and outbound so it only fires when the SIP subprotocol is enabled
 
-commit 79b2fad8e89460cf08c8b7ed1a4736425bcdb9ac
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Oct 2 10:56:12 2012 -0400
+commit 45d4e808f0551a5eeb832574327a2b5b7aecf2c5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 19 23:18:19 2013 +0200
+
+    uac: reorder fileds in uac structure
+
+commit 97a899e37acda1ef0c70a009f4fd9d221ee8a58e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 19 23:16:55 2013 +0200
+
+    seat: removed no longer necessary init of tm uac struct
+
+commit b867893d0bbdda0c926a7cd0b6b3a46d4324631e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 19 23:15:42 2013 +0200
 
-    Include callee in appearance output.
+    dialog: remove unnecessary tm uac struct init
 
-commit 575e3dde9706b657e375814507ffc9b3fa4e6886
+commit 94833f8b8b94398566991713730b66a792b57056
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 2 16:05:38 2012 +0200
+Date:   Sun May 19 23:09:52 2013 +0200
 
-    sdpops: added new function sdp_remove_line_by_prefix(string)
+    tm: initialize the uac structure to 0 for local generated requests
     
-    - removes lines from SDP body that matches the prefix
-    - patch by Mikko Lehto
+    - safer for adding new fields to it not set via set_uac_req()
 
-commit c1d1b82d326ebda28f2b3e57b4066aa1c90e1286
+commit a53580d39c2fadf2ddc6f9805f15ac833cfd4c20
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 2 16:02:05 2012 +0200
+Date:   Sun May 19 14:55:52 2013 +0200
 
-    parser/sdp: exported extract_field(...)
+    tm: new parameter - failure_exec_mode
     
-    - part of patch for sdpops by Mikko Lehto
+    - specify whether to consider or not execution of failure routing blocks
+      for braches that had local delivery error (e.g., no open tcp
+      connection and set_forward_no_connect() used in config)
 
-commit 745e30c92336bfc3f8682b2c23e02862db688d9e
-Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
-Date:   Mon Oct 1 11:55:16 2012 +0200
+commit 78669def2790205270032f9a750b19cc86f3d560
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 19 10:22:10 2013 +0200
 
-    tcp: fix _wbufq_insert bug
+    tm: added icode to uac_client structure
     
-    When _wbufq_insert was called on a connection that had already
-    some data added to the write buffer (another process was faster
-    and added some data before the process that created the connection
-    had a chance to do it), a wrong size was used in a memmove.
-    This could lead either to corrupted messages or even crashes (if
-     the messages were big enough to cause a buffer overflow).
+    - store internal processing code, to give hints of what happened
+    - could be used to map sip warning codes
+      http://www.iana.org/assignments/sip-parameters/sip-parameters.xml#sip-parameters-5
+    - delivery failure on case of no connection mapped temporarly to 908
+
+commit cbcf86a036e6f8607f783ce18491121b0d58d2b0
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 19 10:16:40 2013 +0200
+
+    tm: keep uac_client structure aligned on 32b
     
-    Many thanks to Jijo for debugging it.
+    - otherwise it may create troubles on restrictive archs
+
+commit 90c69665edcfc9aebf265f280375251306442b98
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun May 19 10:03:02 2013 +0200
+
+    tm: use - instead if _ in branch-failure examples
     
-    Reported-by: Jijo
+    - it is what is expected by module
 
-commit ec07471c1fdddbc8490d57d089a283ab1a07288f
-Merge: b60d3f7 aea31fc
+commit 1a099f704ffbb93f5c6389e86daa5af90aeb72f1
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Sep 28 23:08:46 2012 +0100
+Date:   Sat May 18 22:20:57 2013 +0100
 
-    Merge branch 'master' into outbound
+    pkg/kamailio/(centos|fedora): Updated changelog in .spec
 
-commit aea31fcdebe13004dbcea3afeabe4a045fefcc9c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 28 23:40:01 2012 +0200
+commit 5cff9062807ed181eae3a1db2d70fa625f647a4c
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 22:17:22 2013 +0100
 
-    ldap(k): updates for usage of pv cache for pv_elem_t
+    pkg/kamailio/(centos|fedora): refactored .spec
 
-commit 111bb96a0f18a3a1366e60deed54a4bd54ba865b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 28 23:31:50 2012 +0200
+commit 7ebf6affca7b2585353baa91f1560ff606979973
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 20:43:05 2013 +0100
 
-    carrierroute: updates for usage of pv cache in pv_elem_t
+    modules/websocket: Updated documentation
 
-commit b60d3f76cb4d13a28cc38efabe1cebbf00d18d23
-Merge: 962fbef f71d76c
+commit 20438793a5199ea90f0261a3b72b1b70e9566a30
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Sep 28 21:50:16 2012 +0100
+Date:   Sat May 18 20:42:53 2013 +0100
 
-    Merge branch 'master' into outbound
+    modules/outbound: Updated documentation
+
+commit 6dc38a3618b2ad08bbc6feeee1c44ca19e0c5bd6
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 20:42:24 2013 +0100
+
+    modules/msrp: Updated documentation
+
+commit a1136bf809e7d088332d54440a72edee4e30c26a
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 20:27:45 2013 +0100
+
+    modules/outbound: moved the check for "Supported: outbound" to after the checks on the Route: header
     
-    Conflicts:
-    	pkg/kamailio/fedora/16/kamailio.spec
+    - In the scenario when a call comes from a non-outbound end-point to an
+      outbound end-point the outbound options-tag will not be present, but outbound
+      should still be used on the final leg between the edge-proxy and the
+      end-point.
 
-commit f71d76c0f39f2c6b0e070e1246f371f17b45b2dd
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 28 14:38:42 2012 +0200
+commit 8750305d4686ccae3a168454c4191f9b05d93ee3
+Merge: e81b3aa abdf40d
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Sat May 18 13:59:07 2013 +0300
+
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
 
-    app_mono: fixed c&p typo names in examples
+commit e81b3aac19ab567813d6cb21fcba3d9bd6e1cc90
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Sat May 18 13:56:22 2013 +0300
 
-commit 505f157c2777fa5e62815ccb4ef68ceb0ab7a023
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 28 11:02:04 2012 +0200
+    parser/sdp: Fixed segfault in sdp_print() when no SDP body.
+    
+    - Failed scenario:
+    remove_body();
+    msg_apply_changes();
+    sdp_print("1");
+    
+    - Result: sdp=0x0
 
-    usrloc(k): table version increased internally
+commit abdf40dabb7e7d44398056b9c2c72c0615debb52
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Sat May 18 10:07:25 2013 +0200
+
+    core and modules: make IPv6 default, remove compile time flags
     
-    - it was done only in db schema by commit
-      78dae896127ce6762e3fa7c2541e1b5f9b8a9023
-    - reported by siklub
+    * Make IPv6 the default in the core and affected modules
+    * it has been default switched on since a long time, and was introduced in 2002
+    * even on embedded systems one probably want now proper IPv6 support
+    * there was an issue in cygwin in 2008, but IPv6 is there also available since v1.7
+    * remove over 160 #ifdefs, cleanup the code a lot and removes many of rarely
+      tested alternative code paths to ease support of the codebase
+    * note for gentoo maintainer: please review your packages, they will maybe not
+      work now correctly anymore if somebody specified -ipv6 in the use flags
 
-commit 83cdd718fab4e244c5362df5102481ce32f75ae1
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Thu Sep 27 19:16:47 2012 +0300
+commit 1b0ad814aec79a44b865ad2d3552c4693fe2ea6d
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 00:18:43 2013 +0100
 
-    modules_k/pua: always use_table before making db queries
+    modules/{various}: updated because there is now an extra parameter on the append_branch() function
 
-commit a24ce948f9f1758440b58d328eb8654efabfbbea
+commit 42063cacea9bf0f001f44b11216572b4f46e6e2d
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Sep 27 16:29:03 2012 +0100
+Date:   Sat May 18 00:17:48 2013 +0100
 
-    modules/websocket: Updated documentation and fixed typo in configuration file example
+    modules/ims_registrar_scscf: use #define from core .h to specify the maximum UA length
 
-commit 927a8a1aa705438d210fc244066a8c5a5b84a746
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Sep 27 14:57:51 2012 +0200
+commit 3ec65f1cfebad258e7ef0cc622ed143284c3edf1
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 00:15:59 2013 +0100
 
-    core/mem: moved safety check for null before range check in *free()
-    
-    - affects only when memory debug is enabled at compilation
-    - apparently libssl has some free(0) which makes it not possible to work
-      with memory debugging (reported on irc channel)
+    modules/tm: copy user-agent string retrieved from usrloc into branches when serial forking
 
-commit cbeb136c60d4890599d39665a2d27d865ae29b76
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Sep 26 12:11:36 2012 +0200
+commit 5aeef2c932581a67d535ade10995cc35ff85640a
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 00:15:21 2013 +0100
 
-    userblacklist: updates for new pv_elem_t structure
-    
-    - safety checks to detect dynamic vs static string parameters
+    modules/registrar: store user-agent string retrieved from usrloc in msg and branch structures
 
-commit 0420d14dc23ae63a043650da0fa82654aab82bb6
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Sep 26 12:10:23 2012 +0200
+commit 7bb5f98d7fd77ca6c21fb11e16d69116ef12cbb2
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 00:14:07 2013 +0100
 
-    auth_db(k): load_credentials is using the cache for pvs
-    
-    - results in less used private memory
+    modules/pv: added PVs to provide access to the user-agent string retrieved from usrloc
 
-commit 2895dbdc0ba7c86b855fdffce178e3ca072a631a
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Sep 26 12:09:10 2012 +0200
+commit 8ca114df0fad44e4819cf80840f90e526ff655b4
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat May 18 00:13:11 2013 +0100
 
-    core/fixups: updates to reflect usage of pv cache for pv_elem_t
+    core: added fields to message structure and branch structure to hold user-agent string retrieved from usrloc
 
-commit bd5353dff6e955830b816fe2f3d2bfedd02bf83b
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Sep 26 12:07:19 2012 +0200
+commit 381a052a8864198a62057dc307fdf39bbffe5436
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Fri May 17 21:35:59 2013 +0300
 
-    core/pv: use pv cache for pv_elem_t
-    
-    - reduces use of private memory for repetitive PVs
+    modules/sdpops: Added new function sdp_get_line_startswith(avpvar, string).
 
-commit c79dffa959b325da2c579b2dce94511beac83f00
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Sep 26 10:20:11 2012 +0200
+commit 121c5a49f81effdac42977d716332215d6a95e4f
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Fri May 17 21:14:29 2013 +0300
 
-    xlog: use the function from core to get term color codes
+    uac: Added ability to set Call-Id through $uac_req(callid).
 
-commit b6642a1af48b3d00ca55d5d7712c842efd2f384a
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Wed Sep 26 10:19:51 2012 +0200
+commit 012816e404b52de697514e4f897ec8a8abe42abc
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri May 17 17:49:14 2013 +0200
 
-    core: exported dprint_term_color() function
+    modules/debugger: refresh README
 
-commit 5b1f81c72b40a0f7609aac32a8ce6e7325a70396
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 26 09:17:00 2012 +0200
+commit dbefbe319ba13b008ad46576dbc8a00d305e9910
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri May 17 17:48:17 2013 +0200
 
-    pv: new transformation {s.stripto,c}
-    
-    - remove the prefix until meeting 'c'
-    - "abcdef"{s.stripto,d} => "def"
-    - the char can be given in a pv
+    modules/debugger: Added dbg.mod_level RPC command
 
-commit eebb2eb640992298c8119f4b5ac54e2370bff3a3
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 25 22:11:14 2012 -0400
+commit e46e0c78ee4f535cd09b8ee9fcdba4ee7bb5b518
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Fri May 17 13:31:19 2013 +0200
 
-    Remove unused struct _appearance_list members max_index and next_index.
+    modules/uac: update README
 
-commit 20c436df0c81b38777052b4ba6fb425577f5c707
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 26 00:18:49 2012 +0200
+commit fed1818b65c6cbab89cd7aa64ad8f5f6535d706c
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Fri May 17 13:30:05 2013 +0200
 
-    registrar(k): some contact attributes were not in $ulc(...)
-    
-    - ruid, reg-id and instance were not returned by $ulc(...)
+    modules/uac: upgrade doc to module.type.name format
 
-commit ed5859fcd482d803cb2896cf58e3ef19ad8c2a2d
+commit 257366739a7087953c0ff9e0dff82f3d2cf7c8b4
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 25 23:43:48 2012 +0200
+Date:   Fri May 17 10:13:06 2013 +0200
 
-    pv: new pv class - $K(key)
-    
-    - return the value for internal constant keywords
-    - key can be:
-    	- IPv4 - returns AF_INET
-    	- IPv6 - returns AF_INET6
-    	- UDP - return PROTO_UDP
-    	- TCP - return PROTO_TCP
-    	- TLS - return PROTO_TLS
-    	- SCTP - return PROTO_SCTP
-    - it can be used to compare the values from other pvs, such as $af(id),
-      $snd(af), $snd(proto), ...
+    Makefile.defs: version set to 4.1.0-dev5
 
-commit a2de5aba014c34fa0d37c1d527ff241e3969e897
+commit 86fce4b7b5e8bb56c65d628409ee50ecfb2756c4
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 25 23:13:50 2012 +0200
+Date:   Fri May 17 10:12:00 2013 +0200
 
-    pv: new pv class - $af(key)
-    
-    - return address family for received message
-    - key can be:
-    	- id: return integer representation for IPv4 or IPv6 (value of AF_INET and AF_INET6)
-    	- name: return "IPv4" or "IPv6"
+    debugger: documented new parameters related to per module log level
 
-commit daf65bac9d276598d932c7f905c30587ccb5a855
+commit 72f1b495c42933fea96a019e140dc6333fda2eb3
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 25 22:20:21 2012 +0200
+Date:   Fri May 17 09:58:19 2013 +0200
 
-    nathelper(k): removed set_rtp_proxy_set() from docs
+    debugger: option to set debug level per module
     
-    - the function is now part of the rtpproxy module
+    - new parameters:
+    	- mod_hash_size - size of internal hash table to store levels per
+    	  module (used to compute power of two with it)
+    	- mod_level_mode - enable/disable per module log level
+    	- mod_level - specify module log level
+    modparam("debugger", "mod_hash_size", 5)
+    modparam("debugger", "mod_level_mode", 1)
+    modparam("debugger", "mod_level", "core=3");
+    modparam("debugger", "mod_level", "usrloc=3");
 
-commit 7943249ea75d8103d1364bcb4b6a63a2e685e88a
+commit 34378c35b7cd037051af71081a9fa4d8b188c157
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 25 13:52:05 2012 +0200
+Date:   Fri May 17 09:56:34 2013 +0200
 
-    utils/misc: few updates to vim syntax highlighting
+    core: updated dprint api to enable support for debug level per module
+    
+    - a callback can be registered to return the log level based on module
+      name
 
-commit 779addb9df44434448f78ab17d2daa756d31d3c0
+commit e081c2880b46174ad836ab1f56e3062bb17b4332
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 25 11:31:17 2012 +0200
+Date:   Fri May 17 00:46:42 2013 +0200
 
-    sanity: fix to parameter type in example
+    core: fixed printing function name in log message
+    
+    - based on http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
 
-commit 7ed66b101602e2317c7cc95bf8fb8c039c227b8f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Sep 24 16:39:17 2012 -0400
+commit a4fb559b5634f91259bb96af991c5574719e6871
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri May 3 09:21:04 2013 +0200
 
-    Remove debugging, basic appearance-uri escapes are working.
-    
-    Does not currently attempt to escape user or host in URI itself.
+    utils/kamctl: Add contact path parameter
 
-commit e72a438d015e1f1afe1e3da83e3e6483c84373f0
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sun Sep 23 22:15:48 2012 -0400
+commit ad0e5daa8865024440ea37a9e978eeeb7577602f
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu May 2 18:30:50 2013 +0200
 
-    Fix doubly linked list corruption.
-    
-    Forgot to assign next node's prev element on unlink.
+    modules/usrloc: use 6th param to set the contact path
 
-commit 03dbe404cea02b7a6e252eedbaa34dad7a0a8aff
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Sat Sep 22 21:58:23 2012 -0400
+commit c454e4b0129695c7647f6af8e42a38d785d58a7d
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu May 2 16:56:45 2013 +0200
 
-    Initialize subscription-from-request's appearance index to 0.
+    Fix ul.dump q output value
 
-commit 31e886ed712d4bc2c3b3e59953eae02b30a00fa8
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Sep 21 16:31:30 2012 -0400
+commit f66912d541403dc2b7e2ed0846a553ff76cec3ed
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Thu May 16 12:11:36 2013 +0200
 
-    When unlinking a hash table entry, ensure the entry's next pointer is NULL.
-    
-    Possible cause of subscription corruption crashes.
+    modules:uac updated README after avoiding quotes in display.
 
-commit c4b4ec30ce06b2517643ff8fca5d69b7e3ad6d7f
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Fri Sep 21 12:55:36 2012 +0300
+commit 251c0218e7d5e09f43a2b834a5450c20bb4f6d60
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Thu May 16 12:06:55 2013 +0200
 
-    modules_k/nathelper: add_contact_alias() now accepts parameters
+    modules/uac: avoid adding double quotes in uac_replace_* functions
     
-    - Function add_contact_alias() can now be given ip addr, port, and proto
-      as parameters.
+    - updated uac doc with a note and examples.
 
-commit e8501b8eb592fa799af1fd1cfba8fa628cbfa800
+commit fe7e4a5152674aa9c81c09dd2fc9938d9e9e762e
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 21 09:44:21 2012 +0200
+Date:   Wed May 15 22:45:18 2013 +0200
 
-    topoh: use L_DBG instead of L_ERR for some debugging messages
+    pv: clone result of several string transformations
     
-    - reported by Miguel Baptista
+    - it is safer for assigning back to the same variable on which the
+      transformation was applied
+    - reported by Martin Mikkelsen
 
-commit 900dee77178bf5f2c9dd9f2e67d4a467c5d4be1f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 22:52:14 2012 -0400
+commit 9330607f1d1132d4e7719d6a92fd26f4ff06665a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed May 15 19:02:58 2013 +0200
 
-    Fix [SIPR-716]: place both endpoints on hold, unable to pick up.
-    
-    Code was always setting call state to active on 200 reply to INVITE if
-    callee was SCA. Patch sets state to active on 200 only when seizing a line.
+    misc_radius: documented common_response parameter
 
-commit c60d8bb016314a5a6855a6e37dc52f85804addc0
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 22:22:11 2012 -0400
+commit 0eb9ef443db58109f5ed2f3ae7851ad368082bb8
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed May 15 18:58:01 2013 +0200
 
-    NOTIFY cseq wasn't getting set from saved subscription.
+    misc_radius: new parameter common_response
     
-    Use less error-prone syntax for getting desired hash slot.
+    - get the radius response specific attributes in avps
+    - patch by Victor V. Kustov
 
-commit f403aa7a974e47b92dbfc63ba18ab5eedd2879eb
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 22:11:42 2012 -0400
+commit 6038bae188863f541994976d299c38f50b0a699b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue May 14 19:52:45 2013 +0200
 
-    Use copy of appearance owner URI when NOTIFYing on receipt of 18x.
-    
-    Don't FFS use a shm struct after unlocking.
+    utils/misc: updated vim syntax file
 
-commit d19f648201eeb9fc186bcd5e2459987b7da08163
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 17:17:47 2012 -0400
+commit ce1d16ce1c8009918c294307de53f35378868b52
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Tue May 14 11:05:00 2013 +0300
 
-    No need for lock in sca_hash_entry struct. Locking happens at slot level.
+    modules/usrloc: reduce work if contact attributes are not in use
 
-commit c49fa3c36f8ba139516101955b33c389b2790977
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 16:47:33 2012 -0400
+commit 6c3853981a7574cd162117ef0d98dba205193d1b
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Mon May 13 15:26:57 2013 +0300
 
-    Possible fix for [SIPR-712]: inadequate locking in sca_handle_subscribe.
+    modules/usrloc and registrar: added possibility to unregister without aor
+    
+    - added possibility to unregister without aor if usrloc uses db_mode=3
+    - added new usrloc api function delete_urecord_by_ruid()
 
-commit 4369f7752984ca3f2511ef2f7f223076bc3dc0c8
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 16:46:09 2012 -0400
+commit 65881c31b9a8aa1d4646891e8ea20d22646ce850
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon May 13 11:01:28 2013 +0200
 
-    Add sca_hash_table_index_kv_find_unsafe.
+    Makefile.defs: devel version set to 4.1.0-dev4
 
-commit a22482e4dd26db613eb646fb57c210bd5ef67a5d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 16:44:14 2012 -0400
+commit 8e644b8e1ccd9c4d6383a2863f9bf247f789a987
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon May 13 11:00:08 2013 +0200
 
-    Add stub functions for PRACK and REFER with Call-Info.
+    tm: fixed warning related to failure branch routing block execution
     
-    Must ensure Call-Info headers are stripped before they're sent to the
-    callee, as it can confuse the Polycoms about the state.
+    - routing blocks id are >=1, the condition was always true because the
+      field in tm struct is unsigned int
+    - gcc warning was: comparison is always true due to limited range of data
+      type
 
-commit f34fe7395a8191437e359572823c6628cb6f07d3
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 13:56:35 2012 -0400
+commit 80e8058d9acea7c994819d043456fd1b449b048b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon May 13 10:59:20 2013 +0200
 
-    Ensure that the c_uri.user is empty if there's no contact header.
-    
-    Possible fix for SIPR-715.
+    core: debug message to show mapping of routing block names to ids
 
-commit c9ea26924267ea260a2b10506db8de899d26b78e
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Thu Sep 20 12:08:03 2012 -0400
+commit 32951506dff11df32c03230c1548553838140574
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon May 13 10:35:35 2013 +0200
 
-    modules/ctl: remove limitation on number of message chunks
+    msrp: cache in a local variable if tls module is loaded
     
-    binrpc uses an iovec to send out replies, which is limited in size and so
-    severely limits the number of elements that can be returned. This patch adds
-    a callback function to send out and empty the iovec array every time it gets
-    full while it's being populated.
+    - avoid looping at runtime through the list of modules
 
-commit 8a05e548456e3c6703bf37342a081269432de6d5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 01:24:13 2012 -0400
+commit 0ca1a789e52e5d559983c3cfb4d851ae375c7758
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 14:18:13 2013 +0100
 
-    Removing unnecessary sca_update routines.
-    
-    Using P-Asserted-Identity accomplishes what the UPDATE packets failed
-    to do, which is to update the caller's display with the correct remote
-    party info.
+    modules/outbound: reduced the level of some outbound related diagnostics
 
-commit a8c5b2080c1c3221d232dcbf4aed009e87fdfda8
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 01:23:06 2012 -0400
+commit b0b3887b099fd16906d9e42fcc05d2f899574426
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 14:17:55 2013 +0100
 
-    Committing for future reference before removing from project.
-    
-    Able to accomplish what was needed with P-Asserted-Identity header instead.
+    modules/rr: reduced the level of some outbound related diagnostics
 
-commit 472854e9908c6ff2cf4a39d064004e2683ef2bb8
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 01:16:31 2012 -0400
+commit 4fafe7bd6d781748722de4fb565808063c8f6c4d
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 14:10:24 2013 +0100
 
-    Fix [SIP-710]: SCA-to-SCA caller shows own DID instead of remote party's.
-    
-    Inject P-Asserted-Identity header with correct information in 200 OK
-    response to SCA pickup of held call.
-    
-    Also fix regression removing NOTIFYs to caller on 18x replies, and
-    update calls to update appearances to include display info.
+    modules/rr: reduced the level of an outbound related diagnostic message
 
-commit 03c9725b6d5b7c6f14405c69e8cf9755659ad131
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 01:14:35 2012 -0400
+commit ee2847c5f508fc8757221e5772c03b62d07f172a
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 14:09:58 2013 +0100
 
-    Add sca_uri_display_escapes_count.
+    modules/path: reduced the level of an outbound related diagnostic message
 
-commit ec35eb22e8d1c98c73fd35499c7afb4b914de733
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Sep 20 01:12:39 2012 -0400
+commit 116ba23c60be15f5fdc1e0cf0f9a9a7affdd32b3
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 14:09:28 2013 +0100
 
-    Include escaped callee display info in appearance-uri attribute.
-    
-    Currently using escape_common function from strcommon.h, found in
-    sip-router's libkcore.
+    modules/websocket: Added check to stop Kamailio starting if WebSocket is loaded without xhttp
 
-commit 35baaf51504a2ba496a06830fe1b7da9a1d5b3a0
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 19 21:44:01 2012 +0200
+commit afdae93c5eba15496498be292c0c99608d801757
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Sun May 12 16:10:40 2013 +0300
 
-    Makefile: added new target 'printvar'
+    modules/presence: downgraded unsupported event syslog message
     
-    - prints the value of a Makefile variable whose name is provided in
-      variable 'v', e.g.,::
-    	make printvar v=exclude_modules
+    - Downgraded unsupported event syslog message from error to notice.
 
-commit 46cf25d2e18d14640624c35cf11d5dd7a6b1224d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 18 16:18:04 2012 -0400
+commit 116daef9b55d82a016d1fd3e3d877a2468c55d1a
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 13:57:44 2013 +0100
 
-    Pass To/From headers' display info and URI when updating appearance.
-    
-    Preparation for including display info with appearance-uri attribute.
+    modules/msrp: Use "msrps://" URIs for the server when TLS is loaded. TLS is mandatory for MSRP relays.
 
-commit c2eab9b90b9d34b147d8f7c420ab10e35ccb5245
-Merge: 942229d 8456325
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Sep 18 20:43:29 2012 +0200
+commit 30c8ead0b18678950b7596d4247d51cb56614d42
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 13:57:00 2013 +0100
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/msrp: added warning when MSRP is loaded in a configuration without TLS.  TLS is mandatory for MSRP relays.
 
-commit 942229d809e715ae330894b20d099f38b616c044
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Sep 18 20:42:55 2012 +0200
+commit b220a571d010851ee72c6bf6263a958335283b62
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sun May 12 13:55:46 2013 +0100
 
-    Minor bug-fix: Need to update length.
+    modules/websocket: added warning when websocket module is loaded in a configuration without either the nathelper or outbound modules
 
-commit 84563257d6c174c7ef3c7ee9b931e64a0b5a95c2
+commit 2bb07b9d2df567e24f86b291bee7748db104252b
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 18 19:29:36 2012 +0100
+Date:   Sun May 12 13:54:59 2013 +0100
 
-    modules/websocket: Updated example kamailio.cfg
-    
-    - Now using corex and alias_subdomains.
-    
-      It is quite likely that a WebSocket server will be running on a host within
-      the domain it is authoritative for and that the WebSocket client will
-      address that host directly.  This means that the alias_subdomains modparam
-      is a good way to get a domain and all of its sub-domains to match "myself".
-    
-      This is very useful for checking the Host: header in the WebSocket
-      handshake.
-    
-    - Added handling of OPTIONS pings.
-    
-    - Fixed a problem with the Host: header check.
-    
-      When you connect to a WS or WSS socket in Google Chrome on the default ports
-      (80 and 443 respectively) the Host: header will contain just a hostname
-      (for example, "proxy.example.com") which works with is_myself().
-    
-      When you connect to a WS or WSS socket in Google Chrome on a non-default port
-      (for example, 8080 or 8443 respectively) the Host: header will contain a
-      hostname and port (for example, "proxy.example.com:8080") whoch does not work
-      with is_myself().
-    
-      However, both "sip:proxy.example.com" and "sip:proxy.example.com:8080" will
-      work, so simply adding "sip:" to the start of the contents of the Host:
-      header before checking fixes the problem.
-    
-    - Tidied up response reason texts.
-    
-    - Tidied up some of the TLS specific checks in event_route[xhttp:request].
-    
-    - Removed some DBG level log messages.
-    
-    - Added a (commented out) example for checking the Origin: header in the
-      WebSocket handshake.
+    modules/outbound: added warning message when outbound module is loaded in a configuraiton that does not load the stun module
 
-commit 566ac92dc07d9928808a319d774a0e3cdb49d021
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 18 09:58:54 2012 -0400
+commit 9af456f292e25be2c5689212ed097177a5a16338
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri May 10 20:04:02 2013 +0100
 
-    Remove update_flag for now.
+    modules/websocket: Added ws_close() exported function
     
-    Using UPDATE to correct URIs on both ends of the call caused the Polycom
-    handsets to report loops. This in spite of them returning 200 OK to the
-    UPDATEs and logging that the URIs were being updated successfully.
-
-commit aa15ad5a0ee35f6676012a84c1e2501b1533ba6c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 18 14:50:33 2012 +0200
-
-    corex: fixed typos in documentation example
+    - Enables immediate closure of a WebSocket connection from the configuration
+      file.
 
-commit ca2454106d869dacccda6bd5564037a83edd89bc
+commit 399dd84d28da82d751e40488cda604a4e03fcbf3
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 18 11:53:02 2012 +0100
+Date:   Fri May 10 20:02:51 2013 +0100
 
-    pkg/kamailio/(centos|fedora): Fixed some issues with boxgrinder builds
+    modules/pv: added new $conid PV
     
-    - Fixed typo in README
-    - New version of BoxGrinder limits appliance name to 35 characters
-      (so had to shorten these)
+    - Returns the TCP connection ID that the current message arrived on (for
+      TCP/TLS/WS/WSS) or $null (for UDP/SCTP)
 
-commit 9430ee8d313ece9c97384868ee7623c0979028f5
+commit 81d3eebd51089686949ab22da60166d4f3a460a7
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 18 09:27:38 2012 +0200
+Date:   Tue May 7 19:15:36 2013 +0200
 
-    pkg/kamailio/rpm: fixed copy&paste error for PKG_MEMORY size
+    core: get rid of deferencing type-punned warning in deb wheezy
+    
+    - reported by Victor Seva
 
-commit 9430290ad91ca775bb18f54e70308917ce1e790a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 18 09:18:52 2012 +0200
+commit acf033559f728e9967eb32f5340b0508a232172b
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Tue May 7 22:31:34 2013 +0800
 
-    pkg/kamailio/rpm: added option to set pkg memory size for init.d script
-    
-    - split of MEMORY parameter to SHM_MEMORY and PKG_MEMORY
-    - EXTRA_OPTIONS variable to add other command line parameters
+    Remove "ignore_failed_auth" Parameter from example config - otherwise you may register without correct password.
+    (the parameter was added for loadtesting only)
 
-commit 0b09c36e4251ee292a48d2fd83bca2fd0ff4c268
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 18 00:32:48 2012 -0400
+commit 994155161263dab7a7f7c01105ea474702cf7fee
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Mon May 6 11:03:07 2013 -0400
 
-    Reconcile mismatched Contact and To/From URIs early.
-    
-    Fixes dropped state for caller URI (and stuck state for callee if callee
-    is SCA) on second pickup on different handset after hold. Depending on
-    the values in the To/From headers won't work, since the SCA reINVITE to
-    seize a held call uses the SCA group's AoR in RURI, To and From, leading
-    to problems in SCA-to-SCA calls.
+    path: support SPVE in add_path*() and add second parameter
     
-    This does not yet resolve the display URI problem.
+    This includes a major rewrite and code cleanup of prepend_path(), which
+    doesn't perform any other functional changes.
 
-commit 75143735af38a921f8d8f1bcafdba14de4a3e39a
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 18 00:26:50 2012 -0400
+commit fa9b8664a3b7c7a035c738a37b8ef0ef44190cb8
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri May 3 19:53:12 2013 +0300
 
-    Add sca_aor_create_from_info.
+    modules/rls: added support for escaped chars in rls-services document
 
-commit b19767513663acd96776cc454fe42ea11c50431f
-Merge: 2750e03 cccdaea
+commit 86d706bd4a1e31160883a4f094f3e04f9380de04
 Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Mon Sep 17 17:29:48 2012 +0200
+Date:   Fri May 3 18:45:07 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    Make XML-RCP configurable in example scripts
+    - Improvement: Automatically enable TCP, if XML-RPC is requested
+    - Improvement: Allow the configuration of TCP-Children (especially for XML-RPC)
+    - Improvement: Add missing configuration information
 
-commit 2750e03d4977d4a8f59ca0d2d0f59e1caec96b2d
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Mon Sep 17 17:25:38 2012 +0200
+commit 141808e9c0789e56f29297e2d2c185e091ebb66a
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Thu May 2 23:41:28 2013 +0200
 
-    New Option: "x" for automatic bridging between IPv4 and IPv6.
-    Based on the following assumption: "i" is the IPv4 interface
-    and "e" is the IPv6 interface on the RTPProxy (tested with both
-    RTPProxy and Sipwise's ngcp-mediaproxy-ng).
-    
-    Mechanism is as follows:
-    - IP in SDP is IPv4: Do bridging "ie"
-    - IP in SDP is IPv6: Do bridging "ei"
+    memcached: port to more recent memory manager callback structure
     
-    Not a big deal, but makes the configuration much more easier.
+    * port to more recent memory manager callback structure
+    * add small wrapper for calloc, implemented not optimal at the moment
+      because the pkg_calloc from core/mem is not exported yet
+    * add initial code to check for server connection during startup, not
+      enabled yet as its work in progress
+    * reorder structure a bit to allow for clean shutdown because of internal mm
 
-commit cccdaead04411175c46dd660c91c037c45f80c33
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Mon Sep 17 17:34:57 2012 +0300
+commit 0332acbc4cf2339f3b6b068f460d00e92221a8ef
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Thu May 2 21:36:17 2013 +0200
 
-    core:parser fix possible bug in msg_parser
-    
-    If buffer was NULL, tmp was returned uninitialized, thus possible to cause problems
+    memcache: fix "maybe used uninitialized" warning from gcc
 
-commit a6c250c091e29c1f4fd53782dfb723fa194fe03e
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Mon Sep 17 17:21:37 2012 +0300
+commit 003d87edc23f62de98a1a22db03b12ea58abcbc6
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Thu May 2 21:17:57 2013 +0200
 
-    core: fixed some bening (-Wunused-var) warnings displayed by clang
-    
-    Core builds with no errors/warning
+    mangler: fix double definition of contact_flds_separator, reported from ld
 
-commit 5273948a6eeb6f6fe878696dce54880cabb0ef7c
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Mon Sep 17 17:21:02 2012 +0300
+commit d6dba0e1b649bcfacaac2dd3496b497e944ebaba
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu May 2 13:43:58 2013 +0200
 
-    Makefiles.defs: clang compiles to O9
+    Makefile: fixed path to kamailio.default in deb specs dir
 
-commit 2d6a8e0ae7eb9bbf839227ae370ede7bf7d89ab1
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Mon Sep 17 14:36:00 2012 +0200
+commit 50e9baf2131befa2243a221566b6505a55216208
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed May 1 18:04:47 2013 +0300
 
-    Revert "Do not perform a lookup for IPv4 addresses, if only listening on IPv6 sockets."
-    Can be done by configuration.
-    
-    This reverts commit e1b3961b16b76b02ae7ad5f52b2e9db126f81ff9.
+    modules/registrar: added regid_mode module param
+    - Tells if REGISTER contact regid (if present) is used when REGISTER request
+      is saved even if request does not indicate support for outbound.
 
-commit 97e03b52f1e15d7f22416274cf696fb5c6a94758
-Merge: e1b3961 d9b009e
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Mon Sep 17 14:35:12 2012 +0200
+commit cc00df26d2e3298751541cc0d4ad35bf0ac361f4
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed May 1 12:34:25 2013 +0300
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/htable: added htable.reload rpc command
 
-commit d9b009ef3c430f6ea064b4a72d5b94ce842ede1d
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Mon Sep 17 10:55:48 2012 +0200
+commit 0ff087e9715298abf3187c52a9d1ac70031f1499
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed May 1 11:54:20 2013 +0300
 
-    benchmark: fixed bug/typo in calculating time diff ;)
+    modules/mtree: added mtree.reload rcp command
 
-commit 9d5ef9925da0257a46afa7e8d8dfa1ce8920364a
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Mon Sep 17 11:42:01 2012 +0300
+commit c57575c5b289c3468eb5c651c1e56699f554298a
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed May 1 09:43:51 2013 +0300
 
-    cfg.y : improved printing of error messages to stderr
-    
-    The -E was ignored during the yyparse() stage, if log_stderr=no parameter in the cfg was set (default config)
-    This caused problems debugging certain lodmodule errors.
+    modules/usrloc: added missing rpc commands
+    - added missing rpc commands ul.rm, ul.rm_contact, ul.flush, and ul.add
+      by patch provided by Víctor Seva
 
-commit 2e5145ecdd8368c947ea93b98449ebd997824ce2
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Mon Sep 17 10:17:41 2012 +0300
+commit 878b343f374a62d7ea5ebe5e85b00c391956b623
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Tue Apr 30 12:01:00 2013 +0200
 
-    Provide inline linkage for non-gcc compilers(like clang)
-    
-    Inline method in headers should be declared extern.
+    data_lump return a comment back to it's owner
 
-commit 92d6ed40ca4aeb36d5d07a9048145779febba062
+commit 8f74c57605fdd1d31c7808a3b8afc79cc981b370
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Sep 17 00:03:58 2012 +0100
+Date:   Mon Apr 29 20:54:52 2013 +0100
 
-    pkg/kamailio/fedora/16: Updated .spec for Fedora and CentOS builds
+    modules/websocket: fixed mandatory headers check
 
-commit bde7e9465db9e7c9ecb485c57edabbd032f3b770
+commit a2e7f65ee8b86d37a6772619ae10087a05219192
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Sep 16 23:47:20 2012 +0100
+Date:   Mon Apr 29 20:38:06 2013 +0100
 
-    modules_k/rls: Fixed segmentation fault in RLS when a resource-list is updated
-    
-    - Found and fixed by Hugh Waite @ Crocodile RCS
+    modules/websocket: doubled the size of the buffer for adding headers to WebSocket handshake responses
 
-commit 67df57c984e040a948d01d2c6bf1a9461d271f8e
+commit 3d5c66997e77ae4f4c181e5a77c943156a7db00a
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Sep 16 23:46:07 2012 +0100
+Date:   Mon Apr 29 20:34:36 2013 +0100
 
-    modules_k/rls: Fixed race-condition on multi-server systems that can cause different NOTIFYs with the same CSeq
-    
-    - Found by Hugh Waite @ Crocodile RCS and fixed by Peter Dunkley @ Crocodile RCS
+    websocket: added "cors_mode" parameter to enable "Cross-origin resource sharing" on WebSocket handshakes
+    - I don't know of any WebSocket clients that require this (yet).  But having it
+      in there won't break anything.
+
+commit 14d4ea782a9a24da9755963ea12807f255cebce5
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Mon Apr 29 11:26:18 2013 -0400
+
+    db_mysql: add cast to remove compile warning
 
-commit 424d2cabbe2e20c7ed134f6c9bd463811f2de63f
+commit 218a83c50a217c420502d484738b6b3401c89b8c
+Merge: edebc03 aefea54
 Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sun Sep 16 17:20:38 2012 +0300
+Date:   Sat Apr 27 18:10:28 2013 +0300
 
-    modules_k/usrloc: modified syslog messages on bad and non-local sockets
-    - Changed syslog message on non-local socket from warning to debug,
-      because non-local socket is ok when nathelper obtains the contacts and
-      overrides the socket.
-    - Corrected syslog messages on bad and non-local sockets.
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    - Forgot to pull before push.
 
-commit 279fe72dbe9009aa9e73d7609460d4dc613bfa6d
+commit edebc03f65445f968accb58b5a761817aaee55e8
 Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sun Sep 16 17:14:18 2012 +0300
+Date:   Sat Apr 27 18:07:21 2013 +0300
 
-    lib/srdb1/schema: added expires_idx on location table
+    modules/usrloc: fixed typo in db_ops_ruid param name
 
-commit a46c8859c4f9451764a92cd329f4225a5b43a986
+commit aefea5477dc7878d5e818628e04ddcb088fd2858
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Sep 14 13:45:14 2012 +0200
+Date:   Fri Apr 26 19:55:43 2013 +0200
 
-    Makefile.defs: version set to 3.4.0-dev4
+    tm: wrap around expression adjusting length for To/From headers
+    
+    - applies for local requests
 
-commit 5b3d0d2837823a4879e493f04d4e995c3e29d37b
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Fri Sep 14 13:53:00 2012 +0300
+commit ff890a4eee1888ed3e1e080a18bd72124ab99690
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Apr 26 19:00:36 2013 +0200
 
-    lib/kcore: other inline linker fixes
+    tm: fixed name of the target uri used for From header
     
-    use of 'static inline' where appliable
+    - effect of previous commit
 
-commit 452c543de61d413351a5ac0816adc137d150824b
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Fri Sep 14 13:17:24 2012 +0300
+commit f22dcd559c739dd99275cd2444cf481d458d2fab
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Apr 26 18:32:55 2013 +0200
 
-    core: Added support for the clang compiler
+    dispatcher: proper localization of To uri for keepalives
     
-    Support for clang, a C compiler from the LLVM suite has been added.
-    Install clang and run 'make cfg CC=clang && make' for building. GCC Inline assembly is supported.
-    TODO: clean warning caused by clang (-Wunused-variable, etc)
+    - it was affected by introduction of <> around the URI in To header
+    - reported by Peter Dunkley
 
-commit d5a8649a2059466a1a8b9e2adbef139d0300a599
-Author: Marius Zbihlei <marius.zbihlei at 1and1.ro>
-Date:   Fri Sep 14 13:15:47 2012 +0300
+commit 57ed79b9d45c29d37c405c3fa582c1d1011a2315
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Apr 26 18:24:01 2013 +0200
 
-    core: Fixed inline function declaration for non-gcc linkers
+    tm: adjust size of the hooks to From/To headers for local genrated requests
     
-    usage of either 'extern inline' or 'static inline' depending on function scope is recommended
+    - take in cosideration <> if it is the case
 
-commit e1b2e0bdb0b2bbd41fbe4e2a1cedb0fb4a682a5f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Sep 12 13:08:56 2012 -0400
+commit 2e1ade7c66217280455136fb85aeb3a8e8e6917d
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Apr 26 15:29:47 2013 +0100
+
+    modules/siptrace: Support for ws: and wss: (fake protocols as per tls:)
 
-    Initial attempt to use a flag & exported function to send UPDATEs.
+commit 5b96c7e6ec3cfd8354a6a257a87144196d57fec3
+Author: Marius Zbihlei <mariuszbi at gmail.com>
+Date:   Fri Apr 26 09:56:26 2013 +0100
+
+    core: fixed compilation on Solaris, due to missing gethostbyname2
     
-    Additional fixes:
-        * only attempt to unlink appearances on CANCEL if AoRs are SCA.
-        * remove TMCB_DESTROY callback stuff.
+    TODO: provide a wrapper over dnssec for getipnode...() for Solaris
 
-commit 571212688fbe0dd56c4e18d0ae611f8c4b5df59c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Sep 12 01:29:38 2012 -0400
+commit 5e96920289cbf448ac684d8cb1333d75f65a729a
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 25 14:50:41 2013 -0400
 
-    Remove misleading comment.
+    snmpstats: fix cross-compilation
 
-commit 798b1324e42071d04f5d71cbef6ef97ca576d6f3
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Sep 12 01:06:51 2012 -0400
+commit ad11cdca0941cd114e17bb80337a7557818220d5
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Apr 25 18:16:28 2013 +0100
 
-    Register TMCB_E2EACK_IN on INVITE if either caller or callee are SCA.
-    
-    Fixes NOTIFYs on call answer if caller is non-SCA and callee is SCA.
-    Appearance state of SCA callee was getting updated in this case, but
-    the ACK callback wasn't getting registered, so no NOTIFYs to group.
-    
-    Additional small changes:
-    	* Put quotes around appearance-uri value in Call-Info header.
-    	* Only try to update appearance state on 18x reply if caller
-    	is SCA.
-    	* Temporarily disable TMCB_DESTROY callback registration.
+    modules/msrp: Use "msrps://" instead of "msrp://" in headers when the transport is WSS
 
-commit 06853f5569a9215d0774ca92c7eda673a04b238d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 11 23:47:00 2012 -0400
+commit 4c7195915b38ba343484833532b82b42879d7138
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Apr 25 16:13:48 2013 +0100
 
-    Clarify certain pro/con points re: UPDATE handling.
+    modules/websocket: fixed segmentation fault relating to recent counter changes
 
-commit cc03c65d108c0a3f9df1dd076ee24f0f70c4b6e7
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 11 23:15:45 2012 -0400
+commit 4e4b1339bfd3a832f5feeb1d2a2380c7455ec82b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Thu Apr 25 14:50:40 2013 +0200
 
-    Fix core on shutdown: param passed to usrloc cb must be separate shm_malloc'd.
+    tm: add angle brackets around From/To URI for local generated requests
     
-    Passing the module struct (sca_mod) as the callback param causes a core dump
-    on shutdown because the usrloc callback destructor will shm_free any param
-    if non-NULL, and the module is already disposed by that point. The callback
-    isn't currently using any param, so for now pass NULL params when registering
-    for usrloc event callbacks.
+    - safer for special cases of URI format
 
-commit 91f575b4baf34a8bff16022e807fb086a051414a
-Merge: b6477c2 8fed32c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 11 17:35:32 2012 -0400
+commit 744a8d317b894a1360e3441a9e69ac9190a1745b
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Thu Apr 25 14:12:21 2013 +0300
 
-    Merge branch 'master' of git+ssh://repo.net.isc.upenn.edu/git/pnp/sip-router-sca-module
+    modules/outbound: added force_no_outbound flag
 
-commit b6477c2f2329f3c07b5c4ef31dba92e5d49105d6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 11 17:34:36 2012 -0400
+commit 81f622b9ef7d32434659f1e6d9a21c8013cefec7
+Author: Klaus Darilion <klaus.mailinglists at pernau.at>
+Date:   Thu Apr 25 08:12:07 2013 +0000
 
-    Add notes about how to send UPDATEs to call legs after hold/pickup
+    sipcapture/siptrace: set default db_url to read-write URL
 
-commit 95581558c230054b082200f10509b8c61e036131
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 22:02:21 2012 +0200
+commit c923dec79e20b77f0b42f0ef286eb396bb06f29c
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Apr 22 17:09:19 2013 +0200
 
-    corex: documented the new parameter alias_subdomains
+    app_lua: Added sr.xavp.get function in order to get a table with all the values of a xavp.
 
-commit eaed27161e36b0bec9bef2660d2fae80092a2e42
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 21:52:01 2012 +0200
+commit 0c866d07dd2124b92329106c1cea19bef6ccca9a
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Apr 22 10:48:08 2013 +0200
+
+    app_lua: Added sr.xavp.get_keys function.
+
+commit 288e2739da28251e12086b52358c3a0d18e91fa5
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Mon Apr 22 10:46:17 2013 +0200
+
+    core[xavp]: Added helper function to get a list of keys from a xavp variable.
+
+commit ac99219b0a850e0305eaf661b028536cfc28e2cb
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 24 22:01:59 2013 +0100
 
-    corex: new parameter alias_subdomains
+    modules/presence_xml: fixed issue with parsing some pres-rules documents
     
-    - adds domain and all its subdomains to myself condition, registering a
-      callback for check self event
+    - pres-rules that contain external links in a <conditions /> node don't
+      have to have <identity /> nodes in the <conditions /> node.
+    - Kamailio returns an error when it finds a <conditions /> node with
+      no <identity /> node inside it.
+    - Kamailio doesn't support external links, but it should skip over
+      the <conditions /> nodes that contain them rather than return
+      an error as later <conditions /> nodes may contain entries it can
+      work with.
 
-commit e1b3961b16b76b02ae7ad5f52b2e9db126f81ff9
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Sep 11 19:39:32 2012 +0200
+commit 96a1af2f261085db695d8a3b23c1a16f39b393fa
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 24 21:07:07 2013 +0100
 
-    Do not perform a lookup for IPv4 addresses, if only listening on IPv6 sockets.
+    examples: added WebSocket edge proxy example using outbound for NAT traversal
 
-commit 8fed32ca2984a5e8eeb92656d7c1bb4c7355ce4a
-Author: Jorj Bauer <jorj at jorj.org>
-Date:   Tue Sep 11 11:25:38 2012 -0400
+commit 4f68c5626530a1bfe2c7ce72eb3de24b3e7e73dc
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 24 21:06:36 2013 +0100
 
-    reduce dependency on copy-and-paste string literals
+    examples: added outbound edge proxy and registrar example configurations
 
-commit 750ec99e6d65b00f0e203f4cd508a2435812491d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 11 10:40:26 2012 -0400
+commit a0c85d1187dd75a8ab6db9604baee93a5d4f478f
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 24 21:04:56 2013 +0100
 
-    Improvements to hold/pickup when caller & callee are in SCA groups.
-    
-    UPDATEs ifdef'd out for now. Will set flag or AVP for script to trigger
-    UPDATEs to both call legs after relaying ACK.
+    examples: updated basic websocket example
 
-commit 78dae896127ce6762e3fa7c2541e1b5f9b8a9023
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Tue Sep 11 15:13:39 2012 +0200
+commit cf908dc57b4f62e8daf28c7a0199284bd0b4dc69
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 24 21:04:24 2013 +0100
 
-    db scheme: add missing usrloc and aliases version increase, reported from Juha
+    modules/outbound: Updated examples (edge proxy and registrar) in documentation
 
-commit ca551f7cb3770a08832758e543587415b3c6d80d
-Merge: 2b62b73 5ac76c5
+commit e8cf4ef94d8759641ce682b50bad303baa58a2e8
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 14:01:16 2012 +0100
+Date:   Wed Apr 24 16:34:29 2013 +0100
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/rr: Fixes relating to outbound and record-routing
+
+commit 9b1f607ccd3575a2c3a4aba7f6c36e637f9d7022
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 24 14:28:36 2013 +0100
+
+    pkg/kamailio/(centos|fedora): Updated rel in .spec file
+
+commit 0b8cbbd8359a3c049b0da7a743de3b996412ab35
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 24 14:26:09 2013 +0100
+
+    core: Fixed error where ";transport=wss" parameter was sometimes added to URIs
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      registrar(k): set found if lookup for uri branch is successful
+    - It should always be ";transport=ws" with WebSocket
 
-commit 2b62b73f8d966d2418c765839ab43b3dbc57545f
+commit 1e84948d120ef2b1206f90458d47486239cfd81b
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:59:55 2012 +0100
+Date:   Wed Apr 24 14:24:45 2013 +0100
 
-    lib/srdb1/schema: Updated indices for presence tables based on results of latest performance testing
+    modules/rr: Double-route and outbound support in loose.c
     
-    - By Hugh Waite @ Crocodile RCS Ltd and Peter Dunkley @ Crocodile RCS Ltd
+    - Have removed outbound support from strict routing for now as it was incorrect
+      and I don't have a system to test with.
 
-commit 5ac76c501c87da24443ec56b7cf4ac93b8318f49
+commit 0125cdf0e75271a8478a3eadacc54ea1c1eb4da0
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 14:46:03 2012 +0200
+Date:   Wed Apr 24 17:26:15 2013 +0200
 
-    registrar(k): set found if lookup for uri branch is successful
-    
-    - the additional branches can hit all not found, but still a found on
-      r-uri can happen
+    usrloc: update call-id value in db when matching record by ruid
 
-commit b0d642016cca83c519ea9aa0e04aa9bf353e07e4
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:23:23 2012 +0100
+commit ef0a17f0e4c9426f64168eb24568ba906e554315
+Author: Jon Bonilla <jbonilla at sipwise.com>
+Date:   Wed Apr 24 16:46:55 2013 +0200
 
-    modules_k/pua: Adjusted locking for dialog insertion.  Candidate fix for "temporary dialog" error reported by Juha
+    pkg/deb: Deprecate lenny
+    
+    Lenny is not a supported version of debian any more.
+    At sip-router squeeze and wheezy are being mantained at the moment.
+    Let's deprecate lenny for future releases.
 
-commit 6924912be955b9f7ba47fd57b22ffe0c01eb68b2
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:10:08 2012 +0100
+commit d9b7cfcd63b5432bc956f0be3a9b4d5eea026786
+Author: Jon Bonilla <jbonilla at sipwise.com>
+Date:   Wed Apr 24 16:42:59 2013 +0200
 
-    modules_k/rls: Fixed segmentation fault when uploading new contact lists for a logged in subscriber
+    pkg/deb: Change memcache module dependencies
     
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    libmemcached-dev is the new dependency deprecating libmemcache
 
-commit af8230b1ac6a88dfb10d567e784a3c39a8f1b863
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:09:22 2012 +0100
+commit 9106eca16924dd6dc797295ba2d74ee16865acaf
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Apr 24 16:27:13 2013 +0200
 
-    modules_k/rls: Improved check for expired subscriptions in DB only mode
+    usrloc: regenerated the readme for db_ops_ruid parameter
 
-commit 7b64e538b350ebd520b80f668045b9f3c7d68fb9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:08:38 2012 +0100
+commit e66842c2fc34d8dc8980efa821f7039685edef87
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Apr 24 15:41:34 2013 +0200
+
+    usrloc: documented db_ops_ruid parameter
+
+commit 61e08282c905c2ee03a2be618b1e700fc0acbdeb
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Apr 24 15:34:16 2013 +0200
+
+    usrloc: option to do db update/delete ops using ruid
+    
+    - new parameter db_obs_ruid - if set to 1, db update/delete operations
+      are done using ruid value
+    - if paramter set to 0 (default) the old style using aor, contact and
+      call-id is done
+
+commit 52d339408f499c867548f2531be1cac119b31e3b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Apr 24 13:38:32 2013 +0200
 
-    modules_k/rls: Fixed issues with for() loops in DB only mode
+    core: new global parameter - modinit_delay
     
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    - sepecify microseconds to sleep after initializing a module in order to
+      cope with systems having rate limits on new connections to db or other
+      servers
 
-commit 5235a1d6218e0bb16f6c9998789864635f54d03e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:06:54 2012 +0100
+commit 735f83d6346c97d6f7b1da26a2fee1b6270872b1
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Apr 24 13:36:08 2013 +0200
 
-    modules_k/rls: core_hash() not used correctly to distribute notifier traffic
+    registrar: added debug message to print generated ruid for contact
     
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    - formatted condition to fit 80 char long line
 
-commit 6eccc8b61e848977012d6efa1fb5aae61f8d441e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:05:15 2012 +0100
+commit a74980270b655124c276279e54b8f82965f3f4b8
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Apr 24 10:26:49 2013 +0200
 
-    modules_k/rls: Fixed issues to do with expiry and rls_expires_offset
+    sqlops: use one char buf for empty strings in db results
     
-    - These cause particular problems on multi-server systems.
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    - safe for the parts of code that want to access it even for write
 
-commit 725020f91493d33c5fa86828a421ed465731658e
+commit 0e09fba67dc5d75d5e73bb7d35deecf721b37cfc
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 13:03:32 2012 +0100
+Date:   Wed Apr 24 11:49:21 2013 +0100
 
-    modules_k/rls: Added missing lock_release()
+    modules/rr: refactored process_outbound()
     
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    - Still need to update loose.c to properly handle double-RRs with flow-tokens
 
-commit 20475258957cbf3183e5e771e9fd41dc69336096
+commit c38c0ba0ab3244aa387de706a4555fab28c67ad7
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 12:59:08 2012 +0100
+Date:   Wed Apr 24 11:48:21 2013 +0100
 
-    modules_k/pua_db: If PUA finds more than one matching dialog (when there should only be one) delete them all
+    modules/rr: add double record-routes when outbound is enabled
     
-    - A timing difference on multiple-servers can sometimes cause this,
-      and (if it happens, it doesn't when the clocks are synced) you can
-      end up with the same error coming out lots because the DB is not
-      cleaned up.
+    - Note: loose.c does not yet handle these properly
 
-commit ef7d43fc614276b75c560660c7e4368fd18d574d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 12:58:13 2012 +0100
+commit fdb6c8cbafec7849367f16f5dc56ffa20885bef4
+Author: Klaus Darilion <klaus.mailinglists at pernau.at>
+Date:   Wed Apr 24 09:09:25 2013 +0000
 
-    modules_k/pua: Fixed incorrect check/use of update_period modparam
+    core: fix default read-only DB URL
 
-commit d9087dbbf411f71486a4ce765aa5d6dfeb531f9c
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 12:56:52 2012 +0100
+commit 53319656247a2aa685f4d9b6f667192f945bc62a
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Tue Apr 23 14:04:39 2013 +0200
 
-    modules_k/presence: Improved check for expired dialogs in DB only mode with notifier tasks
+    modules/sipt add value tables to docs, add section ids to pvars
 
-commit cd6415240ff243842b4e11b095103f00fd64d0d9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 12:55:49 2012 +0100
+commit 20646b530baa1a2807e52048a8d99d31d2171bb6
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Apr 23 13:02:49 2013 +0200
 
-    modules_k/presence: Fixed some problems with for() loops in DB only mode
+    usrloc: re-init sruid struct for each child
     
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    - avoid overapping values for xmlrpc handling
 
-commit 3635a0d920f0d03e85b8b97a44d878f0f8d13931
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 12:54:51 2012 +0100
+commit 6835b9bc1c80035a603016cf8149afefbf535929
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Apr 23 11:59:09 2013 +0200
 
-    modules_k/presence: Fixed level of a diagnostic message
+    uac: regenerated readme with new wiki link
 
-commit 4b9aa7f144b8cf3e6da775563528913ed79e0553
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 12:53:58 2012 +0100
+commit 2b97e81b281802283ebc665da6f9190f0a9705ab
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Apr 23 11:58:17 2013 +0200
 
-    modules_k/presence: core_hash not used correctly to distribute notifier traffic
-    
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    docbook: uptdated wiki link in entities file
 
-commit a29a2a81bc541af020955dbda0d352445fef5788
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Sep 11 12:51:33 2012 +0100
+commit b89c747bc717c0f9053e53c53a74f9744c1b8606
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Apr 23 11:52:13 2013 +0200
 
-    modules_k/presence: Fixed inconsistencies in use of expires_offset for removing subcriptions
+    uac: added possibility to authenticate generated requests
     
-    - These caused particular problems on mulit-server, DB only, systems
-    - Found and fixed by Hugh Waite @ Crocodile RCS Ltd.
+    - $uac_req(auser) - specify the authentication username
+    - $uac_req(apasswd) - specify the authentication password
+    - if both attributes above are set and the request is challenged with
+      401/407, then the request is resent with auth header
 
-commit bb7bc779da5910a3d22cb5631b532ac3a3eb6b1a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 13:01:13 2012 +0200
+commit b57d14afeed443bd3ff847a455c1f07bdca7dd09
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Tue Apr 23 10:39:01 2013 +0200
 
-    registrar(k): documented lookup_branches(...) function
+    modules/sipt forgot to stage the documentation (pvars added)
 
-commit 2ac602d3de1330705ecfdede660d43c02e4b4334
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 12:52:45 2012 +0200
+commit d02ebb2584d2e4f676a9f8c4e0f6095045de86db
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Tue Apr 23 10:37:09 2013 +0200
 
-    registrar(k): new function lookup_branches(domain)
-    
-    - lookup the contacts for r-uri and additional branches
-    - only branches that are clean (i.e., have only r-uri set) are used
-    - useful for group dialing, to lookup all AoR in the group, without a
-      need to loop back
+    modules/sipt regenerate README with new api
 
-commit 0724528964f8ea74049cd2d2e08082025b5c5377
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 12:45:25 2012 +0200
+commit 781b0a68cbf3a9b93bda0ebafb9ae64257c202d3
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Tue Apr 23 10:30:11 2013 +0200
 
-    core: whitespace identation fixes
+    modules/sipt refactor get functions into pvars
+    
+    return value of 0 in a function causes the script to exit, so
+    pvars are used instead to safely get the values
+    
+    also getting screening and presentation information added
 
-commit f252606e41e00595cdaace7491af3d8daa138272
+commit ee928f8229dffdcb2d980e6ca192a9a7778e893b
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 09:02:51 2012 +0200
+Date:   Mon Apr 22 18:10:38 2013 +0200
 
-    kamctl: regenerated the db creation scripts
+    core: include <netinet/in.h> in new dns_func.c file to fix compilation of freebsd
     
-    - there were changes in presence tables not propagated to scripts
-    - it includes the updates for location tables
+    - patch by Victor V. Kustov
 
-commit fd911bbfdc82fc41312e2b4466e71ccd24bc5ee2
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 09:02:34 2012 +0200
+commit 717cd63e7f52f9298e6ba6f55f12129ab5e61ccd
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Mon Apr 22 10:11:17 2013 +0200
 
-    lib/srdb1: added unique constraint on ruid for aliases table
+    modules/sipt added new method sipt_set_calling
 
-commit 2c1a857f08512e7008cbd15c23716e149204a06d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 09:00:10 2012 +0200
+commit 066011935c7a2636ea976923e46d33ae5fb4c793
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Sun Apr 21 21:56:28 2013 +0200
 
-    lib/srdb1: added unique constraint on ruid for location table
+    memcached: port module to use the newer libmemcached library
+    * based on a patch from Charles Chance, sipcentric.com
+    * He added new functionality to set the expiry directly in the key
+    * Added memory manager wrapping functions and some more logging,
+    * smaller cleanups in the code structure
+    * This is work in progress, the memory management stuff is not yet
+    * finished, as this needs different logic for client lib version
+    * before and after 0.32. It will not work at the moment correctly.
 
-commit 6b7a27e81cc838de6af9a1c55edb937d1094ce98
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Sep 11 08:52:53 2012 +0200
+commit dedede1cc7d384be3b4436a474b53d03f91a966a
+Author: Marius Zbihlei <mariuszbi at gmail.com>
+Date:   Sun Apr 21 20:28:21 2013 +0100
 
-    kex: documented mi statistics commands
-    
-    - reported by David at lublink
+    modules/dnssec added cleanup of context
 
-commit 59cc9a44ef0c603503eac70d4b3367b47a610176
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 11 00:10:32 2012 -0400
+commit e206fdf4bfb398f5175726d75bfa5f9b8f5a9b70
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Apr 21 21:17:29 2013 +0200
 
-    Re-enabled usrloc bindings so deleting subscriptions on unREGISTER works.
+    Makefile.defs: version set to 4.1.0-dev3
 
-commit e82a63d6874fa609d7588323500e5560b3ebe963
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 11 00:09:05 2012 -0400
+commit 7ec7231a86bc895b22a8ae5b617764b6171ac6d4
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Apr 21 21:16:49 2013 +0200
 
-    Add sca_update.c & sca_update.h to send UPDATEs to both legs after pickup.
+    Makefile: added target to install init.d script on debian
 
-commit bedb7fdc6d02e92fbf52ad4acb6dfcbb49f0bc49
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Fri Sep 7 19:16:37 2012 +0300
+commit be4b94efde40180d642af0e87f15f4c9bdc4ce7b
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Sun Apr 21 19:51:34 2013 +0200
 
-    db schema: removed unique requirement from pua expires_idx
-    
-    - TODO: change also other than mysql table structures
+    tests: fix test sipp scenario
 
-commit 08cb1ca64b7259b6cb82751eaedda238fd902ac2
-Merge: 9717357 9329c7d
+commit 731f1b2a72a04901b11e34de91bc1c276e47fce1
 Author: Henning Westerholt <hw at kamailio.org>
-Date:   Fri Sep 7 13:52:36 2012 +0200
+Date:   Sun Apr 21 19:25:51 2013 +0200
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
-    
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      Use &long_hf_len; instead of &uri_len; for path column in location table.
+    tests: fix module paths
 
-commit 97173572a81b67dd5165de2948562d5db91168d5
+commit 65d2823cd6236cfebc26f4a1d5b6e5ee2a3d2156
 Author: Henning Westerholt <hw at kamailio.org>
-Date:   Fri Sep 7 12:57:30 2012 +0200
+Date:   Sun Apr 21 18:54:48 2013 +0200
 
-    db scheme: move usrloc and alias expire time 10 years to the future, to 2030
+    tests: remove some unnecessary directory changes
 
-commit 9329c7d1522f9692f46210aa72e9e932b97a0178
-Author: Iñaki Baz Castillo <ibc at aliax.net>
-Date:   Fri Sep 7 12:53:48 2012 +0200
+commit cd46c51dd12e85ba1508ce5752762269686eeded
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Sun Apr 21 18:49:19 2013 +0200
 
-    Use &long_hf_len; instead of &uri_len; for path column in location table.
+    tests: fix some old paths
 
-commit 976f801ae2df9597be0fccff89496bde34b22e62
+commit 59117e598386d013d9c9f62282aa434dc5806c03
 Author: Henning Westerholt <hw at kamailio.org>
-Date:   Fri Sep 7 12:44:33 2012 +0200
+Date:   Sun Apr 21 18:30:21 2013 +0200
 
-    dialog: use long_hf_len instead of hardcoded value in table defs, no actual schema change
+    tests: use bash compliant return values
 
-commit 61254d70442144277981f2d866de379413634a4f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Sep 5 15:14:18 2012 -0400
+commit b3682521361ce0cdbaf50f843a2d80bcb1b8b41d
+Author: Marius Zbihlei <mariuszbi at gmail.com>
+Date:   Sun Apr 21 15:26:05 2013 +0100
 
-    [SIPR-699]: delete subscription when endpoint's registration ends
+    modules/dnssec: added support for libval query parameter flags
     
-    Detect registration deletion or expiration, and delete endpoint's
-    call-info subscription.
+    Documentation in the README
 
-commit d1d2494c966d65828d1920296056da840a11efd9
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Wed Sep 5 06:44:39 2012 -0400
+commit ebeb18ffed8e81ae472b4c07097b58fbea115b5b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Apr 21 16:07:34 2013 +0200
 
-    sdpops: Fix memory leakage in w_get_sdp function.
+    pv: updated link to wiki site
 
-commit 163f860ef7c0ed9a720207499d054e7f68b139df
+commit f0c467f64c044de0b0f37addccb97d3ccff78706
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Sep 5 08:58:18 2012 +0200
+Date:   Sun Apr 21 16:06:56 2013 +0200
 
-    dialog(k): fixed the name of event route
-    
-    - it is 'dialog:failed' instead of 'dialog:failure'
-    - reported by Uri Shacked
+    acc: updated link to pseudo-variables cookbook
 
-commit 52f501388c99e992d371d17a78dd36ff373d354c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Sep 4 10:25:14 2012 -0400
+commit a5a7d62271bf1674015d8ab1d928c0325224b77e
+Author: Marius Zbihlei <mariuszbi at gmail.com>
+Date:   Sun Apr 21 13:32:26 2013 +0100
+
+    modules/dnssec: removed unused variable
+
+commit 61519687d5cca6e77ba2ba456f845c140a66ccc1
+Author: Marius Zbihlei <mariuszbi at gmail.com>
+Date:   Sun Apr 21 13:30:16 2013 +0100
 
-    [SIPR-700]: module should drop subscriber if NOTIFY delivery fails.
+    modules/dnssec: removed bogus param
+
+commit 325aa35f76f7727abe010b03a0dd03b5f487e26a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Apr 21 13:38:30 2013 +0200
+
+    Makefile.groups: proper fixing of all modules list
     
-    Module unlinks & deletes subscription if call-info NOTIFY to subscriber fails.
-    Also fix memory leak in the expired purge tick, which was unlinking but not
-    deleting.
+    - reported by Vicente Hernando
 
-commit 18c5f3fec6b5e4d2e8ad86b13c5b4e62c6c5513c
-Author: Boudewyn Ligthart <bligthart at btlnet.co.uk>
-Date:   Tue Sep 4 16:16:38 2012 +0300
+commit fc80791c65fa46389168bd5e16af6b33c1bbc36c
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Apr 21 13:09:43 2013 +0200
 
-    modules/db_cassandra: Added raw query support
+    Makefile.groups: fixed another type of double parenthesis
     
-    The raw queries can be performed through avpops module and have to have
-    the CQL syntax.
+    - reported by Vicente Hernando
 
-commit 15f5c9f2f7323c5192a7eb550cc7e7c53b20782a
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Mon Sep 3 21:31:58 2012 +0200
+commit edd7f8ed5b8b893276c86bb054e6f7523ad69f33
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Apr 19 22:50:26 2013 +0200
 
-    b/f: In case of IPv6 Option in the RTP-Command, the pointers and the length need to be updated.
+    Makefile.groups: fixed typo
 
-commit a6a37ad2ae7dd99deae3ec9d83ab38ab54e2f2af
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Mon Sep 3 13:01:05 2012 +0200
+commit ea964748dc638af82d2363317ca2eade98a279ac
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri Apr 19 17:39:05 2013 +0300
 
-    kamdbctl: add some explanation to the variables section and fix path
+    modules/outbound: downgraded one INFO to DGB
 
-commit a5a58239efb00f25cd51753c984ee4469fd97754
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Mon Sep 3 08:53:47 2012 +0200
+commit 7a96d912032939b8eb108e0e84b70bbf0642e2ab
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri Apr 19 17:36:27 2013 +0300
 
-    xlog: new module parameters log_colors
+    modules/outbound: for non-reg requests, check if outbound is supported
     
-    - update the colorscheme for log levels
+       4.3.  Sending Non-REGISTER Requests
+       ...
+       UAs that support this specification SHOULD include the outbound
+       option tag in a Supported header field in a request that is not a
+       REGISTER request.
 
-commit 1c1bdda16c7643b882a437583368d97e33c21e56
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Mon Sep 3 08:52:26 2012 +0200
+commit 752de05cc567c7502b1e723a09e350ce8d447664
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri Apr 19 13:24:52 2013 +0300
 
-    core: added function to update log level color scheme
+    modules/rr: if outbound request is outgoing, do nothing outbound
+      specific in loose_route()
 
-commit e09b5bc8f7d17d8d9d9754152d78b0c835e94a9f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Sep 2 13:36:55 2012 +0200
+commit e3c0a3abb6045e841fbb4b1b61a518b2b87a217d
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 16:03:50 2013 -0400
 
-    kamctl: regenerated db creation scripts
+    seas: fix warning [-Wunused-result]
+     - ignoring return value of write, declared with attribute warn_unused_result [-Wunused-result]
 
-commit dfc98801110554f92aeaa80594e01cad16c9dcd1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Sep 2 13:29:18 2012 +0200
+commit c0f4b6cf664ac552d0c994e99adb13991a37ef28
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 16:01:16 2013 -0400
 
-    prefix_route: new parameter to control the exit from config
-    
-    - 'exit' controls if prefix_route() triggers cfg exit or returns true
-      upon matching a prefix. Default is 1 (on) for backward compatibility
-    - prefix_route() takes an optional parameter that can be used to match
-      the prefix instead of r-uri username
+    seas: fix compiler warning [-Wunused-but-set-variable]
 
-commit 886a0659449bc03bd7c5e852fe6ba29a17ad923d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Sep 2 13:08:53 2012 +0200
+commit 12cd241d95b8d38cea6e60676b752f8ef8a2ed8c
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 15:54:14 2013 -0400
 
-    srdb1: table_name set to unique constraint in version table
+    seas: fix compiler warning [-Wunused-but-set-variable]
 
-commit ca57c8631511943e835e8b030dad638f92aff884
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Sep 2 11:59:38 2012 +0200
+commit 21e51107a5a08b182abc7bffbac1fec1be27950b
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 15:51:50 2013 -0400
 
-    tm: new config parameter - remap_503_500
-    
-    - option to disable remapping of 503 response code to 500
+    seas: fix compiler warning [-Wunused-but-set-variable]
 
-commit fe00a3346a2276b25ae26160ce76bf658b5b826e
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Sat Sep 1 16:24:02 2012 +0200
+commit 2abf2d4a42c05004319e682d2ad07d69bf2fc89e
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 15:50:25 2013 -0400
 
-    core: log_color - new global parameter to enable colorful log messages
-    
-    - enabled only when log_stderr=1
-    - equivalent of -e command parameter
-    - it can be: 0 - disabled (no colors, default); 1 - enabled
+    seas: fix compiler warning:
+     - warning: variable flags set but not used [-Wunused-but-set-variable]
 
-commit 6bda9c0b7aac195902d2c42123bdde007a9a687f
-Author: Elena-Ramona Modroiu <ramona at asipto.com>
-Date:   Sat Sep 1 16:16:21 2012 +0200
+commit 21386829d819c06c42871cf5b68d0d3a63ef0222
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 15:48:03 2013 -0400
 
-    core: -e - new cli parameter to enable colorful log messages
-    
-    - used only when log messages are printed to stderr
-    - each log level is printed in different color, using term colors (like
-      $C(xy) variable)
+    seas: fix compiler warning:
+     - warning: variable flags set but not used [-Wunused-but-set-variable]
 
-commit 28a7300cd83e135b1c0d5488cb289fc7415fbd8c
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sat Sep 1 13:32:18 2012 +0300
+commit 200eddad28abd6bc51da3285dd52d5f8c88c4e56
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 15:45:50 2013 -0400
 
-    modules/dialplan: always set type of attrs pvar value
-    
-    - Type of attrs pvar value was not set when dp_translate didn't result
-      in any change.
+    seas: fix compiler warning
+     - warning: variable flags2 set but not used [-Wunused-but-set-variable]
+
+commit 63736be1e4d2d6e82a0f7be6a85a96ee66c10146
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 15:42:40 2013 -0400
 
-commit 494b383edde7a2d193c220f3117506e4cc95932f
+    seas: fix compiler warning:
+     - warning: variable falgs set but not used [-Wunused-but-set-variable]
+
+commit 8393ccdc1558f56ba819a442d0c50d25f51a934d
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Aug 31 10:29:45 2012 +0200
+Date:   Thu Apr 18 21:28:54 2013 +0200
 
-    auth: print return code in log when nonce is invalid
-    
-    - it will give a clue about why nonce is considered invalid
+    dnssec: added reference to wikipedia's DNSSEC article
 
-commit e4ecf49add0e62330e1db071106806e35e9b078a
+commit 343379957ab783a32c48822de479a9d8c2dafdf3
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 30 22:38:11 2012 +0200
+Date:   Thu Apr 18 21:22:47 2013 +0200
 
-    corex: a new module to collect reimplemented core cfg functions
-    
-    - old core functions for cofiguration file do not take variables in the
-      parameters, working only with static strings or integers
-    - some of them will be reimplemented in corex moduel to add support for
-      variables, making the parameters to be dynamic at runtime
-    - append_branch(...) was reimplemented at this moment, allowing URI and
-      Q parameters to contain variables
-    - there are also brand new features - two RPC commands, one to list the
-      listen sockets and the other to list the hostname aliases
-    - name of the module comes from CORE eXtensions
+    xlog: link to wiki updated
 
-commit 41918bca6d6a99f6773a72ab132e75c940ecd79a
+commit e2f9e909a2abd02cebb292cc8cb3500aa4c07036
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 30 22:36:10 2012 +0200
+Date:   Thu Apr 18 21:22:01 2013 +0200
 
-    core: removed append_branch() from cfg language structure
-    
-    - cfg append_branch() is no longer implemented by core, being moved to
-      corex module in order to allow variables in the parameters
+    dnssec: make web links clickable for html version
 
-commit eb73f14958ede24928f312fa0e44d171fa7bf373
+commit b3c8f92fe48ac90802c989c74c3a34cfea065861
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Apr 18 14:09:09 2013 -0400
+
+    dns_cache.c: fix compiler warnings
+     - warningâsr_sums[*].r_sum may be used uninitialized in this function [-Wuninitialized]
+     - warningâsr_sums[*].rr may be used uninitialized in this function [-Wuninitialized]
+
+commit 38a4b85dc327e18af7e22e585f02413d7f08c56c
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 30 22:34:40 2012 +0200
+Date:   Thu Apr 18 18:01:35 2013 +0200
 
-    kex: removed km_append_branch() cfg funtion
+    Makefile.groups: dnssec module added to dedicated compile group
     
-    - functionalty being replaced by append_branch() from corex module which
-      can take also Q as parameter
+    - it depends on libval and other external libs
 
-commit 132df8d61eefcc2dbea08ae70db82393803d9488
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 30 10:16:04 2012 +0200
+commit be3819d410bf5a9f11c3744d9978e60103746041
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Apr 17 17:10:21 2013 +0200
 
-    core: exported get_valid_proto_name() via headers
+    modules/dialog_ng: fixed incorrect log level
 
-commit 21583d47751fc7f684dac41a3bfbfc3b2c0bf3a3
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 30 10:15:26 2012 +0200
+commit ee2cdfdaf8e2dc177fed64c6f4ab05a85f9fb0c6
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Apr 17 16:49:21 2013 +0200
 
-    db_cluster: safety check for existence of several DB API members
+    modules/cdp: Initial framework for Credit Control Application
+    	- inital support for RFC 4006
+    	- this will be used to build IMS Ro charging interface TS32.299
 
-commit 82bb7a8b67e488e7089d194fa5f96e9ae61dfb03
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Thu Aug 30 17:39:47 2012 +0300
+commit e237f9573435a8a11672b155c1cf9a64638b87d2
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Wed Apr 17 16:40:32 2013 +0200
 
-    modules/db_cassandra Updated in doc location table schema
+    modules/dialog_ng: API added function to get current dialog from msg
 
-commit 0f8f21e390e8442cf1f527d3654dedc5a40bfcea
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Thu Aug 30 17:21:29 2012 +0300
+commit 2190c572cd1bc4b57a3c2dd5241e556b834c728c
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Tue Apr 16 14:28:59 2013 +0300
 
-    modules/db_cassandra: Fixed segmentation fault in case of bad table schema
-    
-    Reported by Boudewyn Ligthart.
+    modules/usrloc: init _ul_sruid also in mi_child_init
 
-commit 8d70484116e48b15681589f70c650a082614396c
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Thu Aug 30 05:20:25 2012 -0400
+commit 2a77ed2bdc9341ecf7d7200e420a1f49e4e9b6ab
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Apr 14 10:11:29 2013 +0200
 
-    ndb_redis: argument checking in redisc_free_reply
+    auth: skip processing of PRACK in consume_credentials()
+    
+    - report and patch suggestions by Jorj Bauer
 
-commit 512013f324dd6faa37e26302a267afb07252812a
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Thu Aug 30 12:24:24 2012 +0300
+commit 56f7a8b98778f9c9b71f613a5df5eaa1705a7a00
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Sat Apr 13 15:37:18 2013 -0400
 
-    modules/db_cassandra: Updated replace function to the new signature
+    tls: fix compiler warning
+     - tls_config.c:61:19: warning: ât.val.sâ is used uninitialized in this function [-Wuninitialized]
 
-commit 978ec2fb51751529953eadec653772edd5dc1ccd
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Wed Aug 29 15:47:10 2012 -0400
+commit d992d3b223a3319a360f033d1d904873160f706e
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Sat Apr 13 17:44:15 2013 +0300
 
-    modules_k/nathelper: fix a= lines inserted out of order
+    siputils:  added new function is_supported(option)
     
-    RFC 4566 dictates a particular order of fields in the SDP body, in particular
-    media-specific a= lines must be last fields within an m= block. Inserting
-    them right after the m= lines violates this order if other fields (such as
-    c=) are present, causing parse errors in some clients. So instead, insert
-    them at the end of each m= block.
+    - Checks if given option is listed in any of the Supported: headers of
+      the request.
 
-commit b7a1ba89ce9d8a310b9b0151f6535d612dbc9057
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Wed Aug 29 12:45:40 2012 -0400
+commit 2d27dd1080cd490e93646b38d3912dcbe3761ca5
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Apr 13 11:26:48 2013 +0200
 
-    ndb_redis: redisc_exec_argv function
+    xcap_server: init etag variable for PUT operations
+    
+    - the function xcaps_get_db_etag() may not found a record to db and will
+      not initialize it, resulting in bogus value passed to
+      check_preconditions()
+    - reported by Juha Heinanen, FS#283
 
-commit ae7047e05a7ff05a1707446286e2837fa49671dc
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Wed Aug 29 19:33:51 2012 +0300
+commit 22019e51e1e561a46eb9490c684b979f02be4e48
+Merge: 3c54420 f88dd6d
+Author: Marius Zbihlei <mariuszbi at gmai.com>
+Date:   Sat Apr 13 08:44:43 2013 +0100
 
-    kamctl/dbcassandra: Updated schema for cassandra location table
+    Merge branch 'dnssec'
+    
+    Added support for DNSSEC as module
 
-commit 4b60f510b3fe4ac8ff8fa2721cc40b18b93ed5d1
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Mon Aug 27 16:22:35 2012 -0400
+commit 3c54420914c011bdd874a97c4c40ee9dacb59788
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Apr 12 00:50:24 2013 +0200
 
-    ndb_redis: add some error checks in redisc_exec function.
+    core: safety check for content-lenght size in tcp read
+    
+    - avoid getting negative
+    - upon a report by Kevin Wojtysiak
 
-commit 57b5efa329ee50cfee361fe10204b37ca8a8e039
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Mon Aug 27 07:01:18 2012 -0400
+commit 1a22767e39d50af450a49256b4425503a2d0d388
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Thu Apr 11 09:31:37 2013 +0300
 
-    ndb_redis: add goto error_exec instead of return
+    modules/path: unescaped received param value also in path rr callback
 
-commit 2bd8309a9e1af15dc3b5dafdfc84b97fc8338c98
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Mon Aug 27 12:49:07 2012 +0200
+commit 2003bc3b1cc73caa36e9b4892d8d25f810d6c458
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Thu Apr 11 08:11:35 2013 +0300
 
-    pkg/deb Set Standards version to 3.9.3
+    modules/registrar: unescape received value using kcore function
+    
+    - Now that unescaped received value goes into separate buffer, it is
+      possible to use kcore unescape function.
 
-commit e8c7708bed7081e74ee43370ab63031daac6fb8b
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Mon Aug 27 11:35:50 2012 +0200
+commit 262b5880616d8b58cf9b012b460793f9879087b3
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Apr 10 22:42:43 2013 +0300
 
-    pkg/deb: Don't conflict with -dbg any more
+    modules/registrar: fixed bug in un-escaping of path/received
 
-commit b53ca97379e1b4aeae80b794f23e25e9150a0e58
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Aug 27 10:37:50 2012 +0200
+commit d9c0024033278975a38c010b768e8f95c2dbb144
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Apr 10 18:04:03 2013 +0300
 
-    db_cluster: more verbosity when building cluster structures
+    modules/path: b/f generate valid received param value
 
-commit 11bc9210cd6665087ef79f7b6af9e9e478ea7923
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 24 23:12:19 2012 -0400
+commit c01b97dd39a418acd0db7b4515d155c45d4092e6
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Apr 10 18:00:04 2013 +0300
 
-    Display owner and dialog in sca.all_appearances output.
+    modules/registrar: unescape path header received param value
 
-commit 205c18d3697367fcbc0d93cc243fcb9f751e83df
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 24 23:10:56 2012 -0400
+commit ff2b0751b7a7925769afd14eae8c01b3af063568
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Apr 10 15:01:52 2013 +0100
 
-    Add routine to update callee. Add two convenience lock-if-SCA routines.
+    pkg/kamailio/(centos|fedora): Updated .spec
     
-    Extend appearance struct to store previous owner, callee & dialog.
+    - Added sipt module
+    - Increased rel to dev2
 
-commit 94cf6005b264fecd888c8141ebf4247b2a02855f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 24 15:20:23 2012 -0400
+commit 94ce2b1de63432baaaecd9285608380a40a70550
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Wed Apr 10 09:34:49 2013 -0400
 
-    Notes on use of To-URI during pickup of held call.
+    db_mysql: fix segfault when recursive queries are made
+    
+    The MySQL result object (MYSQL_RES) should not be stored within the
+    srdb1 connection object, but rather within the srdb1 result object.
+    Otherwise recursive queries overwrite each other's result sets, which
+    results in segfault.
 
-commit 75b304538f4094340ab7471487cac687fbd1c769
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 24 13:38:31 2012 -0400
+commit 8366a26fb8e3c6d5815cd4cd5bde48575e9f6b71
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Wed Apr 10 09:33:53 2013 -0400
 
-    Add sca_uri_build_aor().
+    srdb1: add new db-private generic pointer to struct db1_res
 
-commit fbc6ce9c0792408877166a3e35b1c6cc2dc645e3
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Fri Aug 24 09:51:06 2012 +0200
+commit d17b02ed5014b4e32bd0060f32cabd750956779c
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Wed Apr 10 13:55:57 2013 +0200
 
-    xmlrpc: more correct re XMLRPC spec re. no type specified, defaults to string
-    - This will allow you to receive docs like <value>mystringvalue</value>
-    - instead of only allowing <value><string>mystringvalue</string></value>
-    - according to spec if no type specified, assume string
-    - allows kamailio to receive messages from apache ws-xmlrpc which doesnt specify string type
+    modules/pipelimit: check correctly for all arguments in mi_set_pipe
 
-commit 881ee61c85f66767e0e8988e0a98205abbc7f9e9
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Fri Aug 24 09:48:46 2012 +0200
+commit d20439c0398f6821f9e0e861a597d1dee62f6c91
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 10 12:31:41 2013 +0100
 
-    Revert "xmlrpc: more correct re XMLRPC spec re. no type specified, defaults to string"
+    modules/tm: documentation: Updated branch_failure route name format
     
-    This reverts commit 35e5e50c8f624ab70ef095bdbc729861b4a0a749.
+    - Updated event_route[tm:branch-failure:name] documentation
+    - Updated t_next_contact_flow function
 
-commit 35e5e50c8f624ab70ef095bdbc729861b4a0a749
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Fri Aug 24 09:21:40 2012 +0200
+commit 6e28b187ab4d9cb100e58cb7667c0ee64e8b6deb
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 10 11:33:15 2013 +0100
 
-    xmlrpc: more correct re XMLRPC spec re. no type specified, defaults to string
-    - This will allow you to receive docs like <value>mystringvalue</value>
-    - instead of only allowing <value><string>mystringvalue</string></value>
-    - according to spec if no type specified, assume string
-    - allows kamailio to receive messages from apache ws-xmlrpc which doesnt specify string type
+    modules/tm: Enable named branch_failure routes
+    
+    - branch failure routes must be named with the format:
+    -- "tm:branch-failure:myroute"
+    - and enabled with the function:
+    -- t_on_branch_failure("myroute")
 
-commit 4d15ba97bab58108cfedc45158d90583f67cdadf
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Aug 24 09:14:28 2012 +0200
+commit fb4d9dae890705388275abe1fa06358187917d01
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 10 11:27:59 2013 +0100
 
-    db_cluster: use connection from write structure for db updates
+    core: Allow colon separated tokens in event_route names
     
-    - could be related to an issue reported by Øyvind Kolbu
+    - Event routes can have named routes following the format:
+    -- <module>:<event>:<name>
+    -
 
-commit 10327c61d35e034f31c49a27f11f81ec82c22055
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:41:27 2012 +0100
+commit a1edd20adff116ce78083ca9744e7072e0305728
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 10 11:10:27 2013 +0100
 
-    modules_k/rls: Use database row/table locking where supported in DB only mode
+    modules/registrar: Remove unnecessary BRANCH_FAILURE flags
     
-    - Under load there are lots of DB deadlocks when using
-      (start|end)_transaction() with multiple presence processes and/or
-      servers.
-    - Without using (start|end)_transaction() multiple processes/servers
-      overwrite each others changes.
-    - Using row locking (where possible) and table locking (where
-      required) fixes these problems.
-    - IMPORTANT NOTE: DB only, multi-process/multi-server, presence will
-      only work properly under high-load when using a database driver that
-      supports transactions and locking (currently just db_postgres).
+    Functions that run in an event route require the EVENT_ROUTE / REQUEST_ROUTE
+    flag set, not the BRANCH_FAILURE_ROUTE flag
 
-commit 92aedbb83f5d6cbfc7c4b5e68f260f7ecccc992e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:40:56 2012 +0100
+commit 200357577d70f13ad1f01d8f831eca274ca2e669
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Apr 10 09:17:58 2013 +0300
 
-    modules_k/pua: Use database row/table locking where supported in DB only mode
-    
-    - Under load there are lots of DB deadlocks when using
-      (start|end)_transaction() with multiple presence processes and/or
-      servers.
-    - Without using (start|end)_transaction() multiple processes/servers
-      overwrite each others changes.
-    - Using row locking (where possible) and table locking (where
-      required) fixes these problems.
-    - IMPORTANT NOTE: DB only, multi-process/multi-server, presence will
-      only work properly under high-load when using a database driver that
-      supports transactions and locking (currently just db_postgres).
+    modules/tm: updated README on t_branch_timeout and t_branch_replied usage
 
-commit 34cd2acb5370f36238f8765765cee6d97fd18209
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:36:34 2012 +0100
+commit 2be84576fb5bc7d973b84b7a9f6a61b28ce2cead
+Merge: 3b785c2 12f441f
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Apr 10 09:11:55 2013 +0300
 
-    modules_k/presence: Use database row/table locking where supported in DB only mode
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
     
-    - Under load there are lots of DB deadlocks when using
-      (start|end)_transaction() with multiple presence processes and/or
-      servers.
-    - Without using (start|end)_transaction() multiple processes/servers
-      overwrite each others changes.
-    - Using row locking (where possible) and table locking (where
-      required) fixes these problems.
-    - IMPORTANT NOTE: DB only, multi-process/multi-server, presence will
-      only work properly under high-load when using a database driver that
-      supports transactions and locking (currently just db_postgres).
+    modules/tm: allow calling of t_branch_timeout and t_branch_replied from
+        tm:branch-failure event route
 
-commit f1f39db4f8a73f16497c4cc2658e9b4e68bac0fc
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:27:29 2012 +0100
+commit 3b785c288916269664bf77d916572945ce93e489
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Wed Apr 10 09:09:54 2013 +0300
 
-    modules/db_postgres: Added support for database row and table locking to PostgreSQL database module
-    
-    - start_transaction() now takes an argument allowing the type of locking
-      (none, read, or full) to be specified.
-    - new query_lock() API will use a SELECT ... FOR UPDATE query instead of
-      just a SELECT ...
+    modules/tm: allow calling of t_branch_timeout() and t_branch_replied()
+        from tm:branch-failure event route
 
-commit 6c39a678a5b1bf00e0a138daa90ac6401b017d94
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:26:44 2012 +0100
+commit 12f441f4b75f15ab25fc42889bfce65940d0c0d0
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Tue Apr 9 16:38:22 2013 -0400
 
-    lib/srdb1: Added support for database row and table locking to SRDB1
-    
-    - Requires support within the database module
+    pv: implement pv transformation {en,de}code.base64
 
-commit 9b77e69de0953f9f6f48d4c1cf06f7e593469912
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:21:54 2012 +0100
+commit dbb01573bc30eb59e712536d43c0caad357d90fa
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Apr 7 20:32:02 2013 +0200
 
-    modules_k/rls: Some incorrect pkg_free() calls in DB only code
-    
-    - Found and fixed by Hugh Waite @ Crocodile RCS
+    snmpstats Update dev note
 
-commit b9e77beaee850303ffa736cb4043d21a1806fa4f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:21:03 2012 +0100
+commit 5886fa623776eae7a33ff8777e68d29a170f0fac
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Apr 7 10:17:16 2013 +0200
 
-    modules_k/pua: transaction not ended before calling send_publish() from TM call-back
+    lib/kcore Make sure that the bytes waiting stats also report IPv6 sockets
+
+commit 2a895f5dcfd5b7ce003e37b2b1db6690852e3ff5
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Tue Apr 9 18:28:01 2013 +0300
+
+    modules/tm: load_contacts() now prefers contacts whose path is empty
     
-    - Found by Hugh Waite @ Crocodile RCS and fixed by Peter Dunkley
-      @ Crocodile RCS
+    - For contacts with the same q, order contacts so that contacts that
+      have empty path are preferred over ones that have path defined.  In
+      practice, this affects only contacts with the same ua instance id.
 
-commit f20713462410211370e762abb463f0ceafd36d8d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 21 15:19:51 2012 +0100
+commit 34290a9be20cd5986a569caeba3a2fd0efbeeb1f
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Tue Apr 9 17:25:59 2013 +0300
+
+    modules/rr: loose_route() return code 2 documentation
+
+commit fd5a1d772cc08af05e669ee00e926ee488f734f8
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Tue Apr 9 17:08:43 2013 +0300
 
-    modules/db_postgres: libpq requires null terminated string, but Kamailio internal str type is not (necessarily) null-terminated
+    modules/rr: new loose_route() result code
     
-    - Found and fixed by Paul Pankhurst @ Crocodile RCS
+    - Introduced new loose_route() result code 2 that is returned if
+      route calculation based on flow-token has been successful.
 
-commit 0b247dbdea53bf46fbe222bbf2dea66b030fdd35
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 20 22:22:44 2012 -0400
+commit 1dde1f64524db71b374ee81943fc259e8c818892
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Apr 9 11:32:17 2013 +0100
 
-    Fix [SIPR-688]: deadlock on BYE.
+    modules/tm: Fix uninitialised instance and ruid values
+    
+    In t_next_contacts:
+    - Ensure instance was initialised to null when not present
+    - Extract ruid value before storing a subsequent flow
 
-commit 79f7cbf4d301f90e750d94cceebba6a3a87a293f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 20 17:21:41 2012 -0400
+commit 0d41a8d0a251b351104b3feba8fde5373e928d92
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Tue Apr 9 01:03:49 2013 +0200
 
-    Use new sca_appearance owner and dialog update routines.
+    modules/ndb_redis: b/f redisc_exec returns false if redis server is down.
 
-commit 8ec690991cd04bd8e2a343e16cd951e19ed60eac
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 20 17:17:49 2012 -0400
+commit a177a33b9938a36cfaedbce61734a1525e5b1665
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Apr 9 00:21:44 2013 +0200
 
-    Add sca_appearance_update_owner_unsafe & sca_appearance_update_dialog_unsafe
+    .gitignore: added protoshoot binary the ignore list of git
 
-commit a03b6671398707c0f1f8fe4c0b187109b8a4b1bd
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 20 17:13:17 2012 -0400
+commit 13fd48f89555f5421e8285669e303bcefe44f149
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Apr 9 00:18:35 2013 +0200
 
-    Replace dialog in appearance on held call pickup.
+    parser: safety check for max port length in URI
     
-    Known bugs: [SIPR-689]
+    - can't be longer than 5, a port being 16b value
+    - reported by Kevin Wojtysiak
 
-commit c7f7971fca82f2267cfff732c3d525af1af15938
+commit 28a8b87885e373bee8cc81985277ae718973fdfd
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Aug 20 09:30:53 2012 +0200
+Date:   Tue Apr 9 00:15:47 2013 +0200
 
-    nathelper(k): documented keepalive_timeout parameter
+    rr: use port.len to check for buffer overflow instead of max port len
+    
+    - reported by Kevin Wojtysiak
 
-commit 962fbef66a67c8c4ddf815e492b1f192a50339e7
-Merge: af16e04 ac45478
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Aug 19 22:38:13 2012 +0100
+commit a9e555e6e41271e015c47d29ba85276673d3b7b6
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Apr 8 15:01:41 2013 -0400
 
-    Merge branch 'master' into outbound
+    modules/sca: reduce verbosity of RPC sca.all_subscriptions output
     
-    Conflicts:
-    	pkg/kamailio/fedora/16/kamailio.spec
+    - accommodate more subscriptions without hitting kamcmd buffer limits.
 
-commit ac45478f8bc32a806edb80874bf8c5e3d5342707
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Aug 19 22:30:49 2012 +0100
+commit 7eaaf7ec7a3727ea38a330d51771b0446c58d8d6
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Mon Apr 8 12:13:54 2013 +0200
 
-    pkg/kamailio/fedora: Updated rel in .spec to dev3
+    modules/ndb_redis: avoid warning unused next_rpl variable.
 
-commit af16e04d837008e5158f3f0bc9f175b0fc02a08a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Aug 19 22:15:58 2012 +0100
+commit a43f2ebd4c952be55b2844f94d3a8b587a9e5202
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Mon Apr 8 11:47:51 2013 +0200
 
-    modules_k/outbound: Renamed nat_uac_test() in this module to ob_nat_uac_test()
-    
-    - That way it shouldn't conflict with nathelper:nat_uac_test() if both modules
-      are loaded.
+    modules/ndb_redis: b/f restore correctly last char in argument strings.
 
-commit 61674b59c6b14aded58fcd9801370b3648f9d21c
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Aug 19 20:47:43 2012 +0100
+commit 4924d136c7fd1886e411436c8005945b41c08f74
+Author: Vicente Hernando <vhernando at systemonenoc.com>
+Date:   Mon Apr 8 11:32:40 2013 +0200
 
-    modules_k/outbound: Started to fill in function that determines whether Outbound is required
+    modules/ndb_redis: follow section id guidelines.
 
-commit 8bc7114c6a915985ca2f4e9ab50ea608437c7256
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Aug 19 21:29:06 2012 +0200
+commit f4e4c3f8741868a310a59ec165a82e0353b7f161
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Mon Apr 8 11:18:44 2013 +0200
 
-    core: rephrased debug message about no 2nd via in reply
+    modules/sipt: adapt module to use SUBTYPE_ISUP
 
-commit 23e3258e3cb3c025c79570bcfe8395e92645fb16
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Aug 19 20:20:54 2012 +0100
+commit 25135d4deb54281bffdf372ad948ef0fa38b2d7b
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Mon Apr 8 11:17:04 2013 +0200
 
-    modules_k/outbound: Added nat_uac_outbound and tidied up module stub
+    parser/parse_content: add support for the ISUP subtype
 
-commit 7376222d183d8122ef64467eae2d8d8dfdc6bc47
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Aug 19 20:18:51 2012 +0100
+commit b7829454810379c46ed74ff78dd3e8099ac05fb4
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Sun Apr 7 20:07:23 2013 +0300
 
-    modules_k/nathelper: Moved code for nat_uac_test into header files
-    
-    - This is to enable the code to be directly included into other modules and
-      used without requiring nathelper to be loaded.
-    - Specifically, this will be used with Outbound where the nat_uac_test()
-      will be helpful for Outbound-based NAT traversal, but there should be no
-      need to load nathelper too.
+    modules/textops: free spve params of in_list function
 
-commit 36845cc575f36a62d88b0e10826c04d63edbd536
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Aug 19 13:01:36 2012 +0200
+commit 87da891388c3e76c80ac677e7b2342ce9f86a3f1
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Sun Apr 7 18:01:19 2013 +0300
 
-    usrloc(k): keep time of the last keepalive for natted UDP contacts
-    
-    - new field in the contact structure to keep the timestamp when that
-      conctact was refreshed by keepalive or registration update
-    - it is taken in cosideration to remove contacts that don't reply to nat
-      ping requests, so it works only together with nathelper module
-    - when an UDP contact is not resposive for an interval of time, the
-      contact is set to expire is 10 seconds. This process takes place in
-      the function that fetches the list of contacts for nat pinging
-    - last_modified and last_keepalive are exported to mi and rpc list
-      commands
+    modules/registrar: b/f route param was passed uninitialized to parse_rr_body
 
-commit a308226ced8b9807ee91f8e24c72d778e5a62e86
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Aug 19 12:56:24 2012 +0200
+commit 75dfe341aba8bdc6f0ead4f060f05c34c69e267e
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Apr 7 10:03:12 2013 +0200
 
-    nathelper(k): hanlde sip ping replies
+    snmpstats Avoid compiler warnings with older versions of net-snmp
     
-    - new parameter 'keepalive_timeout' to detect if a contact does not
-      reply to sip ping requests
-    - default is 0 (feature disabled) - it should be few times more than
-      natping_interval
+    Centos has an older version of net-snmp that has slightly different
+    structure definitions than the current one.
 
-commit c8421620772184d28fd5b08d09b1e64cf0a8866a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Aug 19 12:52:51 2012 +0200
+commit f2c17f4325d5b03697e76bd4b4ee8050d5e4d6c8
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Apr 7 09:53:24 2013 +0200
 
-    core: added q_memrchr(...)
-    
-    - reverse search for char in a buffer
+    snmpstats Final fixes for IPv6 support.
 
-commit 98301c7e11d4bef786abbd3329287144df02184f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Sun Aug 19 09:48:42 2012 +0200
+commit 0fd0906680ce0f022820fd15819486eb4acfe24a
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Apr 7 09:45:21 2013 +0200
 
-    core: typedef'ed enum request_method to request_method_t
+    snmpstats minor typo fixes
 
-commit a2b8e55aa3f5d939d396270d47c3182bc840070d
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 16 16:27:57 2012 -0400
+commit dbde9b609c2a3538fca1e7db72e518f97b3f018a
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Apr 6 22:06:47 2013 +0200
 
-    Fix [SIPR-683]: append appearance-uri to call-info NOTIFYs
+    snmpstats Add IPv6 support in list of active interfaces
+    
+    Output from SNMPwalk after this patch:
+    KAMAILIO-SIP-COMMON-MIB::kamailioSIPTransportRcv.ipv6."20:01:DB:80:21:2e:00:00:00:00:00:00:00:00:00:22".5080 = BITS: 40 udp(1)
 
-commit dbc44c00534b8c34dc8a39dd2d9d931a2cd2d4ff
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 16 22:26:17 2012 +0200
+commit bddf66407ef7521f3d1f1e941b4c1e104e59d1ef
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Apr 6 22:04:51 2013 +0200
 
-    tm: removed inexistent function from docs
-    
-    - append_branch()/t_fork() does not exist in tm anymore
+    snmpstats fix typo in Makefile.
 
-commit e159eb090c9355431aa1e69a9d1dc622eb94cd89
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 16 20:24:28 2012 +0200
+commit 7bbf8fece2cc93c5b1ddd2c3dcc12e8a920dd54d
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Apr 6 22:02:48 2013 +0200
 
-    pv: new pv class $version(key)
+    snmpstats Add disabled section in Makefile for compilation on Centos systems
     
-    - return attributes of the software version
-    - key can be:
-    	- num - return version number
-    	- full - return all version string
-    	- hash - return git hash code and status
+    Net-SNMP and snmpd can be built with embedded perl and libwrap support. If that's
+    the case on your system you need to enable the EMBEDDED_PERL section in the
+    Makefile. Maybe this could be enabled automatically.
 
-commit 5a9340a2309e7689da4d34eeeef12b0bed2f6e09
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 16 20:24:02 2012 +0200
+commit e28a06a7a8f5558bb81cfc09d5cb70b9c6938328
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Apr 6 21:56:59 2013 +0200
 
-    core: added pv_get_strzval(...) helper function for pv
+    lib/kcore Fix IPv6 support in interface list
+    
+    Added a new function that takes family as an argument. In order to list both
+    IPv4 and IPv6 you need to call that function once per address family.
+    Keep the old IPv4-only function for backwards compatibility.
 
-commit e5b1b1ec11406cb91eb809d618b132bf8a5f808a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 16 18:18:04 2012 +0200
+commit a56a0e32a329ec05a6bb33713b120a949a0cf04b
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Apr 6 14:59:19 2013 +0200
 
-    Makefile.defs: version set to 3.4.0-dev3
+    pipelimit Add section IDs to xml documentation
 
-commit 8a7a06f4d9c78f6da0558806d988c817fd6d0018
-Author: Iñaki Baz Castillo <ibc at aliax.net>
-Date:   Thu Aug 16 16:17:51 2012 +0200
+commit 0f4168e0e6b53c8993121f7a751cabecc2d3e1f3
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Apr 6 14:51:59 2013 +0200
 
-    Process CANCEL before in-dialog requests. This prevents issues with some devices sending buggy CANCEL with To-tag when cancelling an initial INVITE.
+    ipops Add section IDs to README xml files
 
-commit d661028060369e702f5882b6492040bd71fb900a
-Author: Iñaki Baz Castillo <ibc at aliax.net>
-Date:   Thu Aug 16 16:13:50 2012 +0200
+commit 1eeae38650ce70ade73f7e03fd3be78f1d97e0e5
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Sat Apr 6 11:59:55 2013 +0200
 
-    Add Record-Route for in-dialog NOTIFY as per RFC 6665.
+    modules/sipt/doc: add section headers & fix README file
 
-commit 776dcfd081910b9fabbee7cbe0c483e25d1dcfc8
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 16 01:37:13 2012 -0400
+commit 0ecde91fe6e911997b1f5ee33eb50fa6778b7a89
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Apr 5 21:30:06 2013 +0200
 
-    Call hold + pickup from another handset is now working.
+    rr: added missing s in sips for record route
     
-    A bunch of changes (with a lot of redundancy) for this:
-        sca_call_info_is_line_seize_reinvite()
-        sca_call_info_seize_held_call()
-        sca_call_info_header_remove() now working
-        RURI rewrite, drop branches
-        lots of debugging messages that can be removed later
+    - reported by Sander van Grieken
 
-commit 80f5d1e048363a4a2d05bb561fdd5c9706135c47
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 16 01:29:13 2012 -0400
+commit 6433c3b1c2d84d6a6168e7bdccf9c4f13dc50586
+Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
+Date:   Fri Apr 5 21:21:33 2013 +0200
 
-    Add dset.h for branch manipulation and ruri_mark_new()
+    modules/sipcapture: added customization for X-CID header.
+    		thanks for the patch goes to Markus Monka <mmonka at gmail.com>
 
-commit 4a0acc450620fefad49e679131790339e4ffbea7
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 16 01:28:21 2012 -0400
+commit 19c8f0eaac2b77f06f2842d3a7d481268afa096a
+Author: Alexandr Dubovikov <alexandr.dubovikov at gmail.com>
+Date:   Fri Apr 5 21:10:57 2013 +0200
 
-    Add sca_dialog_create_replaces_header.
+    modules/sipcapture: fixed ERR message for HEPv3,
+    		added table param for sip_capture() function
 
-commit 22fd70a90607d90ebdabab65e6da3d5d7e0f5aeb
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 16 01:27:09 2012 -0400
+commit d992e4dc8742807f71645f385d68d60b90746fb3
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Fri Apr 5 18:43:06 2013 +0200
 
-    sca_appearance_update_unsafe now updates index owner and callee.
-    
-    Add missing check for failed pkg_malloc, too.
+    modules/sipt: updated README
 
-commit e1149b05868b918d0bc52b2d46bb02f7799358db
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Aug 15 13:01:43 2012 +0200
+commit 59b9208700e578df5000f8ad732c2e444712b0fa
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Fri Apr 5 18:38:36 2013 +0200
 
-    dispatcher(k): corrected setid_pvname parameter name
+    modules/sipt: added some additional getter methods
     
-    - readme listed it as setid_pvar, the source code expected setid_pvname
-    - reported by Dan B.
+    new functions: sipt_get_cpc() sipt_get_calling_party_nai() sipt_get_called_party_nai()
 
-commit be05dfc0f4af62f9c368960fe75a810548be8b87
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Aug 15 12:48:32 2012 +0200
+commit 38053da7b5951b13be413aac61f89ad418aba99e
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Apr 5 14:12:22 2013 +0100
 
-    dispatcher(k): corrected the variable which is set by ds_is_from_list()
-    
-    - setid_pvar is used instead of grp_avp
-    - reported by Dan B.
+    modules/websocket: Update README xml with section IDs
 
-commit 91d6d3c8a1484b23ff74f0cfd6356447985455a5
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Aug 14 22:18:50 2012 +0200
+commit b38d9c93207a219bbcbc4ad40886b983a391c90b
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Apr 5 14:07:18 2013 +0100
 
-    acc(k): added notes about dynamic table name for db acc to docs
+    modules/tm: Added branch_failure event route to tm documentation
 
-commit 95ee0a3ee75556a25f3a9286837a57decf6c3c91
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Oct 12 14:52:07 2010 +0200
+commit 8def957134e6068c14d2180d8497c6eb1f2a6cc5
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Apr 5 13:35:51 2013 +0100
 
-    acc(k): table name for db acc can be dynamic
+    modules/websocket: re-added declaration of ws_keepalive_mechanism to ws_frame.c
     
-    - you can include variables in table name and will be evaluated at
-      runtime:
-        modparam("acc", "db_table_acc", "acc_$time(year)_$time(mon)")
-      will write now to table acc_2010_10
-    - same can be done for missed_calls table name
-    - second parameter of acc_db_request() supports as well config variables
-    (cherry picked from commit e8f6a95d43b6a4340cf7e97213af5c71fa2a69e9)
+    - Accidentally removed when configuration framework stuff was added.
 
-commit cff481736a3d62cd633077653ba52c00112b2333
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 14 13:07:30 2012 -0400
+commit 52741b4c709713b0cd0a3b9b81701ce2cf95b731
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Apr 5 13:33:19 2013 +0100
 
-    Add sca_get_msg_method.
+    Revert "modules/websocket: b/f defined missing ws_keepalive_mechanism variable"
     
-    Simplify method checks for requests/responses.
+    This reverts commit caf4769ec0f243df71e79ee3c0781afbe5884bac.
 
-commit e22e5f83115d9f1e33c27ae437d93d7701330a8c
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 14 15:53:07 2012 +0100
+commit caf4769ec0f243df71e79ee3c0781afbe5884bac
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri Apr 5 15:17:07 2013 +0300
 
-    modules_k/rls: Fixed incorrect table version check
-    
-    - Found by Hugh Waite @ Crocodile RCS
+    modules/websocket: b/f defined missing ws_keepalive_mechanism variable
 
-commit de8b241ea39284cce4c7e1850fcf3cef4c4c4a0a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 14 15:52:37 2012 +0100
+commit 2168999d8f198268526404946b0def97b87fd8f5
+Merge: 98d76f9 6a9048a
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Apr 5 09:33:38 2013 +0100
+
+    Merge remote branch 'origin/hpw/branch_failure_route'
+    
+    * origin/hpw/branch_failure_route:
+      modules/tm: Fix t_next_contact_flow return value
+      modules/tmx: Add $T_reply_ruid pv to return ruid for a branch reply
+      modules/tm: Make ruid available in uac structure
+      modules/registrar: Allow unregister for ruids in branch_failure_route
+      modules/usrloc: Fix get_urecord_by_ruid to return static aor
+      modules/tm: Fix setting instance in uac branches
+      modules/tm: Enable retrieving of branch instance id from uac structure
+      modules/xprint: Updated to use the new get_branch()/next_branch() functions
+      modules/pv: Updated to use the new get_branch()/next_branch() functions
+      modules/permissions: Updated to use the new get_branch()/next_branch() functions
+      modules/domain: Updated to use the new get_branch()/next_branch() functions
+      core: Update get_branch() to return instance from appended branches
+      modules/tm: Update t_next_contact_flows for use in branch_failure event_route
+      core: Add defines required for a new branch_failure_route type
+      modules/tm: Create branch-failure event route
+      Revert "core: Initial revision of branch_failure_route"
+      core: Initial revision of branch_failure_route
+      modules/tm: Initial revision of branch_failure_route
+
+commit 98d76f94f2a4587b7a93e8e9982ff8017cabd9a3
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Fri Apr 5 09:09:00 2013 +0200
 
-    modules_k/rls: Fixed memory leak in rls under some error conditions
-    
-    - Found and fixed by Hugh Waite @ Crocodile RCS
+    lib/ims: Added cscf_get_p_charging_vector to retrieve icid,term_ioi,orig_ioi
 
-commit f9c5c389b2412d23f1fdd35c6e97dfe7dbe44811
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Aug 14 11:19:08 2012 +0200
+commit 0964bc96b1e3cd3bb7478388f6df3cb69fffce64
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Thu Apr 4 22:27:02 2013 +0200
 
-    pkg/kamailio/rpm: execute 'success' for start operation
+    snmpstats Add support for the new transports as well as new roles
     
-    - reported by Andre
+    The edgeproxyServer is a SIP Outbound edge proxy that manages flows to NATted clients.
+    The sipcaptureServer collects SIP messages for Homer SIP capture
 
-commit b215201ca00712ef3cf1af9e2d46111ac39cd671
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 14 09:19:49 2012 +0100
+commit ac19c57490f2d7758fb0d66e5fc473dcd464d325
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Thu Apr 4 21:57:31 2013 +0200
 
-    pkg/kamailio/(centos|fedora): updated CentOS/Fedora build to add Outbound module stub
+    snmpstats Align transports to RFC 4780
 
-commit c9b45176a1e3a55820c98f4907927ee217007e2e
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 14 09:17:16 2012 +0100
+commit 53579abc49fcb61ba7358d64e2d25bdabfe42afd
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 22:17:27 2013 +0200
 
-    Makefile: added Outbound stub module
+    group Update README xml with section ID's
 
-commit 82de81e6becd747f84f67b360c510e3edbeeedf3
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 14 09:15:51 2012 +0100
+commit 0f7821b1ab454e0b0a7ec49f76f1f63c65f12a90
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Thu Apr 4 17:08:39 2013 +0200
 
-    modules_k/outbound: added stub module for Outbound
+    modules/sipt: regenerate README
 
-commit 7d80fd2b6f4eb5b5edff2a6c580010760cc07747
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 14 00:26:50 2012 -0400
+commit 6cff96362ef9c2a675ff170f804cad08db2a1f87
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Thu Apr 4 17:06:31 2013 +0200
 
-    Fix [SIPR-677]: NOTIFYs go to answering SCA group too early.
-    
-    Register a callback for ACKs following 200 OK replies to INVITE (TMCB_E2EACK_IN).
-    Check to see if the To-URI is a shared appearance AoR, and NOTIFY if it is.
+    modules/sipt/doc: fix typo in method name
 
-commit bf6addd45db22b038fd698ab538416b0b18b16cb
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 14 00:19:15 2012 -0400
+commit e09e20ad7524e2d1469187812b8920723481014f
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Thu Apr 4 15:43:29 2013 +0200
 
-    Add tm_load.h for tm module API.
+    modules/sipt: resolve a compiler warning on osx
 
-commit cf6f490058a24f228dc72b82166cdda52d36488b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 14 00:18:26 2012 -0400
+commit 9dde9cb53367b75643c4f95f5aea2b7ce1d1f859
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Thu Apr 4 12:06:37 2013 +0200
 
-    Invoke sca_appearance_register when saving a subscription.
-    
-    Ensures an sca_appearance_list for the subscribing AoR exists in the
-    appearances hash table.
+    ims_auth: Log, which AVP could not be found.
 
-commit e6cbeaf209fec63a6b677e192547710825c5f964
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 14 00:17:40 2012 -0400
+commit b523c774721afaa34f36dc278805736e04b3d27c
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Thu Apr 4 11:56:03 2013 +0200
 
-    Added sca_appearance_register.
-    
-    Ensures an sca_appearance_list for SUBSCRIBE-ing AoRs exists in the
-    appearances table.
+    modules/sipt: Update README in separate commit per best practices
 
-commit f43e4c36cf67635c697af88ef510d26454298951
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 14 00:17:09 2012 -0400
+commit 8cdbaddbf8ec9bfedc32732a6fed6753fab424ec
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Thu Apr 4 11:40:26 2013 +0200
 
-    Moved tm_load.h header to sca_common.h
+    modules/sipt/doc: corrected documentation typos
 
-commit 4f243623e1c379f3ea5d0aa76396cd7b8c3610a9
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 14 00:16:23 2012 -0400
+commit a45583716671406f6a76cfdf8778517a28cbf2e3
+Author: Torrey Searle <tsearle at gmail.com>
+Date:   Thu Apr 4 10:20:08 2013 +0200
 
-    Notes on moving entirely to using tm module callbacks.
+    modules/sipt: initial import of module
 
-commit dfbb0af56aec99e3c76476bba16c54cf0d7d928f
+commit 6a547b27a6e4715f2ccc3094018ed564066f7834
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Aug 13 22:46:49 2012 +0100
+Date:   Thu Apr 4 00:38:56 2013 +0100
 
-    modules/websocket: removed another magic number
+    doc/cfg_list: added stun to cfg docbook Makefile
 
-commit 8d3eec4f8fbfb2d037e09b80c5d45b5fc400f729
+commit 91b357872f06e988fd09003cffc02742d2731ce3
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Aug 13 21:55:37 2012 +0100
+Date:   Thu Apr 4 00:38:25 2013 +0100
 
-    modules/websocket: Replaced magic number
+    modules/stun: added read-only stun_active cfg value
 
-commit d7fc85a606d4d2ab79f0afce99e30eff1144f9f1
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 13 14:57:25 2012 -0400
+commit 0c49defdd27567e522c0555a9a40b0c76f5ef865
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Apr 4 00:38:01 2013 +0100
 
-    Notes regarding use of tm module callbacks to handle ACKs
+    modules/websocket: removed some unnecessary includes
 
-commit 8ae135a34433054a3871cdebaeb79c5c62290761
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 13 14:26:00 2012 -0400
+commit fc1f1b750f911f7fa2d453f6ce61f011844536a9
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Apr 4 00:37:22 2013 +0100
 
-    Split INVITE handler into dedicated functions, myriad other changes.
-    
-    Implement SLCB_REPLY_READY callback function to catch proxy-generated
-    errors from e.g. sl_reply, which doesn't hit the onreply_route.
-    
-    Fixes for [SIPR-665], [SIPR-668], [SIPR-669], [SIPR-670] and [SIPR-673].
+    modules/outbound: a bit of tidying up
 
-commit 57905957db810e6b2a2cdb6279d0840c1ab9363c
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 13 14:24:35 2012 -0400
+commit 124a40aa8c2de6831bc801899aeaa9ec05bebf77
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Apr 4 00:23:54 2013 +0100
 
-    Hook sl module's SLCB_REPLY_READY to detect proxy-generated errors.
+    doc/cfg_list: added outbound and websocket to cfg doc generation
 
-commit 9f1d0920e7f370f655007818e9fc8d97a2505849
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 13 14:22:46 2012 -0400
+commit a33d556fc5c6c11d6364daed01bf91dbf552784b
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Apr 4 00:23:16 2013 +0100
 
-    Extend sca_subscription_terminate to take options.
+    modules/websocket: updated copyright year
     
-    Allows caller to unsubscribe, or unsubscribe and drop released line.
+    - also remove configuration framework stuff in preparation for putting it
+      in separate files.
 
-commit 87742f9cd82a7da2da2cab59ea4e6338c76fa3c0
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Mon Aug 13 13:10:37 2012 -0400
+commit fe912bc27e41906902f5d25838eac95304c332eb
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Apr 4 00:22:49 2013 +0100
 
-    modules/lcr, modules_k/regex: Fix stack overflow from pcre_fullinfo(PCRE_INFO_SIZE)
+    modules/websocket: moved config framework stuff to separate files
     
-    Fix instances where pcre_fullinfo(PCRE_INFO_SIZE) was given only an "int"
-    argument, which results in stack overflow on some 64-bit platforms where
-    an "int" is only 32 bits long. It expects a "size_t" argument, which is
-    64 bits long.
+    - To facilitate docbook
 
-commit 65dcb2d0e72757d51b0ee51c457c5440278444bc
+commit f85976ec461fc8325c9fa55e2b38ffef132098e1
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Aug 13 15:50:05 2012 +0100
+Date:   Thu Apr 4 00:22:15 2013 +0100
 
-    modules_k/rls: Added DB transaction code around rls_presentity insert/replace
+    modules/outbound: updated year in copyright statement
 
-commit c9628aa038ad7099a72af67f9284e5d0a9b78173
+commit cf5a4dcc3454f3c0e08228d0824f57db8aa2e192
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Aug 13 15:49:09 2012 +0100
+Date:   Thu Apr 4 00:21:47 2013 +0100
 
-    modules_k/rls: Fixed memory leak in rls
-    
-    - Issue fixed by Paul Pankhurst and Peter Dunkley @ Crocodile RCS
+    modules/outbound: fixed typo
 
-commit 5387288eac896a0710fb1c55cc4837e973e04946
+commit 5dc7bf64ede0d41cead968ac52677df022f262a8
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Aug 13 15:48:18 2012 +0100
+Date:   Thu Apr 4 00:20:55 2013 +0100
 
-    modules_k/pua: Fixed double-free in pua
+    modules/outbound: Removed extern for ds_ping_reply_codes_update
 
-commit b5132f217f521872fb0a6a4ab215443a700bab6f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Aug 13 15:45:20 2012 +0100
+commit 7fffcebb7ec85bfdffd3712b8f7d8ee91575fe22
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 21:55:47 2013 +0200
 
-    modules_k/usrloc: Downgraded a WARN to INFO
-    
-    - When Kamailio loads a contact binding whose socket is not local a
-      warning is printed.  Unfortunately, this happens a lot on multi-server
-      systems and it is not something to worry about.
-    - The end result is a huge number of warnings that swamps log messages
-      relating to real problems.
-    - So downgrading to INFO.
+    pike Add counter for blocked IP addresses
 
-commit f3123f3a567d16ed84635bf1bb3cb7df900e4a66
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 10 01:56:24 2012 -0400
+commit ddfadf58f4a99fb160554e81e43fca5ddf0c38ad
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 21:27:45 2013 +0200
 
-    Removed sca_unsubscribe_line_seize export.
+    pike Update README with section ID's
 
-commit ed1c6f28cfddcebb2afe7dc983afaffe401ab6b6
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 10 01:55:46 2012 -0400
+commit ba074d8a9ad0c415237e9c604a3adb432c51b754
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 21:22:47 2013 +0200
 
-    Removed unusued exported sca_unsubscribe_line_seize function.
+    sst Update documentation and add reference to dialog_ng module
 
-commit 1eb761515c6abb5cda4771c297401e62b81c5d12
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 10 01:39:37 2012 -0400
+commit 530e1e9e3f5100c4e6fc8ecb1f2005c07e7b860a
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 21:11:08 2013 +0200
 
-    sca_subscription_terminate doesn't care if a subscription exists.
-    
-    It now returns early if there's no subscription to terminate.
-    Increment NOTIFY Cseq for line-seize subscription before sending
-    terminating packet.
+    snmpstats Documentation updates
 
-commit b36730323a3f8d7c7973fb9438abe29508597233
+commit 43cc6015e8604e309672da4d754b5022d1e256c9
 Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 10 01:35:36 2012 -0400
+Date:   Wed Apr 3 14:54:36 2013 -0400
 
-    Add sca_appearance_seize_next_available_unsafe.
+    modules/sca: ensure line-seize sub update uses index from request
     
-    Used in INVITE 200 reply handler to seize and make active the SCA
-    callee's appearance-state.
+    - lazy removal of line-seize subscriptions that were not used for a
+      call could lead to failure to release expired seized appearance.
+      Client must have a lingering, expired line-seize subscription that
+      hasn't yet been purged by the timer, and indices must not match.
+      Fix ensures that the appearance-index from the new line-seize
+      subscription overwrites the index left over from the expired one.
 
-commit 2a840c67a35c4e06bc5c362e2e28cb42de216552
+commit 3339e7a5bd205599fed63f82536626732b3f23d9
 Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Fri Aug 10 01:30:44 2012 -0400
+Date:   Wed Apr 3 14:46:27 2013 -0400
 
-    Fix [SIPR-663]: handle Contact-less BYEs. Add sca_uri_extract_aor.
+    modules/sca: fix SCA_CALL_INFO_EMPTY macro
     
-    The raw URI from the To header body frequently contains a parameter
-    list. We only use AoRs to do lookups.
+    - test should be a logical OR, not AND.
 
-commit e32fdffcdeedf1e0d0399d883e2029e4ef093844
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 9 16:37:16 2012 -0400
+commit 348876e0097f70b6e155e1afe58030d5bd6077fc
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 20:56:49 2013 +0200
 
-    Updated NOTES re: seizing held line from another handset.
+    timer Documentation update (section IDs)
 
-commit f61295a91bb92645ea46dea5f6101232afeb720d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 9 16:14:43 2012 +0200
+commit 7670fafb184f0f16bf5903b4c75c3d327891756f
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 20:53:49 2013 +0200
 
-    usrloc(k): safety check for raw_query
-    
-    - db get all contacts functions requires raw_query, but not all db
-      modules implement it
+    sipcapture Update to README xml files (section IDs)
 
-commit e154b2fb9f02d56d9c6a4b2d285791151ae0c8a3
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 9 08:50:20 2012 +0200
+commit 244bfd5004804b20d983afd6e9caccfd9f70fde4
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 20:20:47 2013 +0200
 
-    rr(k): fixed offset in building new route header
+    snmpstats Add transport indications to the mib
     
-    - related to the previous fix done to strict routing intermediary hop
+    This commit adds support for the config framework to the snmpstats module.
 
-commit e009f06789c73860428a42c92ee3d8e1f3079831
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Aug 8 23:22:10 2012 -0400
+commit 7bc2efb300dcce267984cd3804349295ec8d2ed5
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 20:01:35 2013 +0200
 
-    Add sca_uri_is_shared_appearance.
-    
-    Remove a few debugging lines.
+    core Make sure Kamailio doesn't crash if TCP is disabled and RPC core.tcp_list RPC command is issued
 
-commit 94534adda00e8c47a45f01ba824b9bd238293274
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Thu Aug 9 00:20:57 2012 +0200
+commit d7959e5e63130889b6b589096388eaa6b76216d1
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 09:22:49 2013 +0200
 
-    pkg/deb wrap and sort debian control
-    
-    This makes it easier to track the dependency
-    changes for version control systems and diff logs
-    
-    Credits to Michael Prokop mprokop at sipwise.com
+    kex Update README XML with section id's
 
-commit ae8f15dcdea73156dbc704bc46908b76ba174393
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Aug 8 20:27:17 2012 +0200
+commit 3814b0ef258fb904aa3571058a9e76dc990bd252
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Wed Apr 3 09:14:41 2013 +0200
 
-    nathelper(k): use usrloc ruid and aorhash to build from tag of SIP keepalives
-    
-    - update due to last change in usrloc get all records API function
-    - these values can be used to identify the usrloc records (e.g., upon
-      handling the SIP keepalive reply)
+    tls Reformat section IDs
 
-commit 7b863271880a643d72b506975faa0669d2ca268a
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Aug 8 20:24:09 2012 +0200
+commit 6a9048a14bae1fd9a66239533a9af23ad390ab20
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 3 16:18:14 2013 +0100
 
-    usrloc(k): return ruid and aor hash in get all contacts API functions
+    modules/tm: Fix t_next_contact_flow return value
     
-    - these records are used to send NAT keepalives
-    - aor hash is set to 0 if db_mode is DB_ONLY, it is not stored in
-      database
+    - Return 1 if a new flow was found
+    - Return -1 if not found
 
-commit c1240aa21a534f1c1a5bdaaebd9c29fe4984a4bb
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Aug 8 12:05:44 2012 +0100
+commit 4ae14b095cb0a24f743a6c90db2f273dcfb163aa
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Apr 3 16:57:44 2013 +0200
 
-    modules_k/rls: Fixed memory leak in RLS
-    
-    - Leak only happens when there is more than one Record-Route: header
-    - Fixed by Hugh Waite @ Crocodile RCS
+    b/f: Initialize rtpp_set_list properly (set it to 0), this can otherwise cause errors.
 
-commit 58b22e62ea360c38574ad5ef2a031bb9413807fa
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Aug 8 10:14:57 2012 +0100
+commit 6759d6bbdd5ff918759789bde00b8e74235b4051
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 3 15:55:47 2013 +0100
 
-    modules_k/snmpstats: Added defines for WebSocket transport
+    modules/tmx: Add $T_reply_ruid pv to return ruid for a branch reply
     
-    - There are no specific stats for WebSocket connections here (just
-      as there are none for SCTP), but the defines are there as place-
-      holders.
+    - Can be run from a failure_route or branch_failure_route
 
-commit 6eb7414bc7e6f2027d49d5b01462e565ae4a93a1
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Aug 8 10:10:42 2012 +0100
+commit ef9115b65fc21f8d64687b2787a50aa025d188c7
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 3 15:18:22 2013 +0100
 
-    modules_k/seas: Added WebSocket transport support
+    modules/tm: Make ruid available in uac structure
     
-    - Note: seas doesn't seem to compile at the moment, but I think the
-      four lines added for WebSockets are OK...
+    - ruid is stored per uac
+    - ruid can be retrieved when a response to the branch is received
 
-commit e1848d9c7fcaa04e785fe39365abd90b3c075f2f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Aug 8 10:08:33 2012 +0100
+commit 4cdd9f7502a11bc48d0413811606444b24b984e2
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 3 15:06:35 2013 +0100
 
-    modules_k/nat_traversal: Added WebSocket transport support
+    modules/registrar: Allow unregister for ruids in branch_failure_route
+    
+    - unregister(domain, uri, ruid) is accepted in branch_failure_route
+    - unregister(domain) is not.
 
-commit f96e6005eb5a071ec25c9ab3174c4150223448cd
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Aug 8 09:59:59 2012 +0100
+commit 445e23e221d54e105f256e54c06c6e5a28ba848c
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Apr 3 15:04:38 2013 +0100
 
-    modules/lcr: Added WebSocket transport to lcr
+    modules/usrloc: Fix get_urecord_by_ruid to return static aor
     
-    - LCR won't use a WebSocket gateway (this doesn't make sense), but
-      PROTO_(WS|WSS) has been added to some switch statements to catch
-      misconfiguration and get rid of compiler warnings.
+    - Fixed a bug which returned a pointer to a stack variable
+    - Fixed some potential (?) infinite loops
 
-commit c7a9b1ed48631952f286d312721e8c45dde05ca1
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Aug 8 09:49:13 2012 +0100
+commit befb822c7548c063c9643e8e6b27b1a6e9ff1631
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Apr 3 12:55:01 2013 +0200
 
-    modules_k/path: Added WebSocket transport support to Path module
+    b/f: an error would be nice, if the module fails to load ;-)
 
-commit 6f928a54d137e2e08ccc1a278afb04b40e34307f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Aug 7 23:38:18 2012 +0100
+commit 3b76b3bb674420ffcee1cb400ee812bf9e7db418
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Apr 2 20:35:44 2013 +0200
 
-    modules/websocket: Added new event_route[websocket:closed] which is run when a WebSocket connection is closed
-    
-    - Also changed ws_handle_handshake() to return 1 on success (still 0 on all
-      errors as they are handled - and the correct responses sent - within the
-      function).
+    utils Add section ID's to README xml
 
-commit eaf81de37baac269135cac55ab4fd42d3b72e045
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 7 16:46:52 2012 -0400
+commit 43d59fe1093e7319848794a7c266d3605f764d1a
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Apr 2 20:31:07 2013 +0200
 
-    Detect call hold INVITEs & update state. Handle Call-Info in BYE replies.
-    
-    Blinking lights on hold! Consultative & blind xfers work!
+    db_cluster Add section IDs to XML file and update some text
 
-commit 68a3cbd66187460aafa84c8ce6a1f2190aa27a62
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 7 16:26:33 2012 -0400
+commit 68a8ef2ed9e616f563a28d87d591f5deebd23085
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Apr 2 20:29:50 2013 +0200
 
-    Add sca_appearance_state_for_index.
-    
-    Convenient for looking up appearance based on line-seize subscription info.
+    modules/dialog_ng: fixed bad append bug and added null sentinel
+    	- thanks Hugh
 
-commit 9347715a2f5ac4f847e45d1412bab48cacbf0b17
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 7 16:25:43 2012 -0400
+commit f0f31127878ecde2dac854598030f0d7d5374f18
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Apr 2 20:08:43 2013 +0200
 
-    Only NOTIFY on line-seize subscription expiration if state is "seized"
+    acc Update documentation with section IDs
 
-commit d8bcf925501f883ebab79d45e75aee5ef9042cca
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Aug 7 16:23:28 2012 -0400
+commit 70c5705a6cfd9ba8fc8f5519145eb5d4b13770da
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Apr 2 19:26:35 2013 +0200
 
-    Add sca_call_is_held to detect whether call is on hold.
-    
-    Uses parser/sdp/sdp.h; very similar to modules_k/textops's is_audio_on_hold.
+    db_mysql Correct e-mail address that had a typo.
+
+commit 9e7f627c5e9a4c34193e4662fbe341b70fa308bf
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Apr 2 19:44:46 2013 +0200
+
+    modules/dialog_ng: bug fix for concurrent dialog did generation
+    	- spotted by Camille @ Orange - tks!
 
-commit aacd6d6cc854d995c26080687d2e97e17ea04d10
-Author: Victor <linuxmaniac at torreviejawireless.org>
-Date:   Mon Aug 6 09:25:32 2012 +0200
+commit b961a960581394913dc79240fe983723a57e5b26
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Tue Apr 2 13:23:27 2013 +0100
 
-    fix typo errors on binaries.
+    modules/stun: fixed typo
 
-commit b9d082fbbaf16faadccb45dcf89f05c910d93b61
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 6 16:27:35 2012 -0400
+commit fe977dfcb940b1c48dd26fe5fe61a25aed23b96a
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Apr 2 14:13:01 2013 +0200
 
-    Fix reply handling, add CANCEL handler, handle BYEs from non-SCA lines
+    db_mysql Add transaction support
     
-    Add some debugging messages.
+    Patch contributed via Google+ by Håkon Nassjöen <haakon.nassjoen at gmail.com>
 
-commit f728283da3473a80e65a9d32c36d0a5dc580a3cb
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 6 16:26:06 2012 -0400
+commit e9267d7e6a0c6a1715f70916a6879f4288f14a57
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Apr 2 11:09:27 2013 +0200
 
-    Fix implementation by pointing dialog members to correct offsets.
+    cfgutils Adding ID's to xml sections for alfabetic indexes
 
-commit e94074a009c275dacb5d9c0aee03ae04ce4c7d25
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Aug 6 16:24:14 2012 -0400
+commit 399ab478349f320a44180abbb1546c93981b566a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Apr 1 22:40:21 2013 +0200
 
-    Add sca_appearance_unlink_by_tags.
-    
-    Allow unlinking from appearance list by dialog. Useful when handling
-    requests/responses from non-SCA lines to SCA lines. sca_appearance
-    struct is now aware of its appearance list to make this possible.
+    app_lua: readme regenerated to be in sync with xml docbook file
 
-commit a66be990168739acfa9dd7e2b99f22fed61fc2ec
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Aug 5 16:45:04 2012 +0100
+commit 1262b4401954661028e10bfb3b54d0ed00876711
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Mon Apr 1 20:41:48 2013 +0200
 
-    pkg/kamailio/fedora/17: Fixed problem with appliances
+    snmpstats add entry for outbound module
 
-commit 9fc34aad6328a92b7572ae077d9ff4d2699dbb48
-Author: Alex Balashov <abalashov at evaristesys.com>
-Date:   Sun Aug 5 08:22:12 2012 -0400
+commit 7d272f893c3e0f260db1af5fc07dccd7d93690df
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Mon Apr 1 10:06:33 2013 +0200
 
-    core: Added null pointer check to parser/msg_parser.c:get_hdr_field().
-    
-    Encountered crash bug in which 'buf' pointer passed to get_hdr_field()
-    was null.  There is no null check, so attempts to dereference it lead to
-    a crash:
-    
-    Core was generated by `/usr/local/sbin/kamailio -P /var/run/kamailio.pid -m 1024 -u root -g root -f /r'.
-    Program terminated with signal 11, Segmentation fault.
-        at parser/msg_parser.c:102
-    102		if ((*buf)=='\n' || (*buf)=='\r'){
-    
-    Fixed by adding a check for buf == NULL to top of function.
+    snmpstats Documentation updates
 
-commit 49f25c402871a619404b61e29ff496c71daad8be
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Aug 3 14:39:49 2012 +0100
+commit 5397c6c4d9a9b3f50561893855d7469cfbf58858
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Mon Apr 1 09:12:01 2013 +0200
 
-    modules_k/rls: Fixed segmentation fault in RLS
-    
-    - Fix by Paul Pankhurst @ Crocodile RCS
+    outbound add config framework variable to indicate active module
 
-commit 5c83492470e8d1a706933915fcfbf6cfe2e0fd55
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Aug 3 14:38:49 2012 +0100
+commit 709acbb709c43d1b9d391bebf8a99b3bfe3c3e28
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 30 19:01:52 2013 +0100
 
-    modules_k/dispatcher: Dispatcher reload MI command not returning errors correctly
-    
-    - Fix by Hugh Waite @ Crocodile RCS
+    cfg.h - config framework - doxygenify documentation
 
-commit 19aafcfc262c16f98793ef135900cd65fca44522
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Aug 3 14:37:20 2012 +0100
+commit 2df6f560bcc54d2966732d397713a9cf3233d5fe
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 31 21:49:10 2013 +0200
 
-    modules/tm: Enhanced t_replicate so that if a NULL string is used it replicates to $du
+    dialog: SDP can be passed to MI/RPC dlg_bridge
     
-    - Added by Hugh Waite @ Crocodile RCS
+    - rework from a patch of Patrick E.
 
-commit 79a614ced2283264e3746cfcfd32fe4245f6496b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Aug 3 11:32:28 2012 +0100
+commit aa6154afcf3e2d59ad09659d7e60bf3691f1d2e3
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Mar 30 22:31:31 2013 +0100
 
-    pkg/kamailio/fedora/17: Fixed typo in appliance files
+    doc/rpc_list: updated the docs with lists of rpc commands
 
-commit 090be2532da73f51043f9ba5f4b221fe338d60fa
+commit 11bc294a9d64e31014ccb836290467984c28ce65
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Aug 3 09:20:03 2012 +0200
+Date:   Sat Mar 30 20:59:24 2013 +0100
 
-    rr(k): add missing '<' in Route header for strict routing
+    dialog_ng: set kamailio mod interface always
     
-    - if next hop is strict router after loose routing, moving the r-uri to
-      last Route header was missing '<' in front of the address
-    - reported by Varsha Venkatraramani
+    - it breaks rpc list generation otherwise
 
-commit 0f0e2f0092beca6dc1e8eddaf5aaf85ebe839f3b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 2 15:59:54 2012 -0400
+commit 688f2902977ee52d0c3d89a1f6459ca0d8c624f9
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat Mar 30 20:28:03 2013 +0000
 
-    Add sca_get_msg_cseq_method
+    modules/websocket: moved some configuration across to the cfg framework
+    
+    - As suggested by @oej
 
-commit b483b96c9b5519e20720a08132ead94dd56ee47e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 2 15:09:28 2012 -0400
+commit 21fa34f61ba4d9778e6b79d978818b47d0928639
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat Mar 30 12:21:02 2013 +0000
 
-    Make Call-Info header detection case-insensitive.
+    modules/websocket: added lots more SIP/MSRP specific statistics
     
-    Net::SIP lowercases's initial character after hyphen in headers.
+    - also updated output of dump MI command to include sub-protocol information
 
-commit 7a5c91b8b79c7599d8e81fe3a50a3c778f88592b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 2 12:18:15 2012 -0400
+commit 63b50d3b0e3a2250effd9a1aa92b7776854364a6
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Sat Mar 30 11:36:41 2013 +0000
 
-    Update sca_appearance_update_unsafe call to match new prototype.
+    modules/websocket: added some sub-protocol related statistics
 
-commit baf11d677e14317385e7a63072d16d14efb04406
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 2 12:16:16 2012 -0400
+commit f88dd6d7197af1e4bf5a9e24cdf9ac8975ae2345
+Author: Marius Zbihlei <mariuszbi at gmai.com>
+Date:   Sat Mar 30 11:19:24 2013 +0000
 
-    Initial (unsafe) non-locking appearance update routine.
+    modules/dnssec Added copyright notices
     
-    Only updates index, state, uri & dialog. TODO: owner, callee.
+    Also forgot a memset..
 
-commit ee464091c3506c6c977cba49fe5a310656d7e310
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Thu Aug 2 12:03:40 2012 -0400
+commit 75ade496d319ac16df0b00ca578c1cc9b866010a
+Author: Marius Zbihlei <mariuszbi at gmai.com>
+Date:   Sat Mar 30 10:56:18 2013 +0000
 
-    Initial work looking up SCA appearance by dialog, not Call-Info header.
+    modules/dnssec New dnssec resolver module based on libval
     
-    Required to process responses/requests from non-SCA lines.
+    To use, simply load the module
+    It will overide the system resolvers (i.e. gethostbyname, res_search) with libval's provided wrappers that support
+    DNSSEC.
+    Further functionality will be added.
 
-commit bcff862df5b937e3a6ff87e4415e0039fd989908
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 2 10:16:31 2012 +0200
+commit 243da7b8a96db33090fd6e2e5d84f4dcd47652b5
+Author: Jon Bonilla <jbonilla at sipwise.com>
+Date:   Sat Mar 30 11:46:00 2013 +0100
 
-    core: added md5 wrapper functions to build with Colin Plumb's md5 code
+    Set lucid version to 4.0.0
+
+commit 0d279eb512ac6740fe1da6e96f7580303f09c025
+Author: Marius Zbihlei <mariuszbi at gmai.com>
+Date:   Sat Mar 30 10:44:39 2013 +0000
+
+    core: refactored DNS primitives and removed DNSSEC support from core
     
-    Author: Tzafrir Cohen <tzafrir at debian.org>
+    The library functions can now be easily overwritten by modules(dnssec) to allow enhanced resolving capabilities
 
-commit e6d912ad036aa92604ba3f2bf65cc4c4ba3e4d2f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Aug 2 10:13:00 2012 +0200
+commit f139948421f2232efae6c2bdd6ea95547b6de533
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 30 09:49:16 2013 +0100
 
-    core: Use Colin Plumb's MD5 implementation
+    snmpstats Add support for the Websocket module statistics
+    
+    Hint to developers: If you add statistics and selects in your module, you
+    make it very easy to add SNMP support for your module. Then SNMPstats
+    can just use generic APIs to find your data. Please also add a generic
+    way of finding out if a module is configured and used too, if possible.
+    Sometimes modules are just loaded, but not used anywhere. Better to
+    reflect real data in SNMP if possible.
     
-    Origin: http://anonscm.debian.org/gitweb/?p=dpkg/dpkg.git;a=summary
-    Author: Tzafrir Cohen <tzafrir at debian.org>
+    Using the old "SER" way of using selects for config data that
+    is allowed to change at runtime opens up for SNMP writes to manage
+    your module as well.
     
-    Borrowed the md5 code from dpkg instead of the existing md5.[ch]
+    And of course, using selects and counters/statistics variables also
+    helps the RPC interface, so it's both cool and the Right Thing To Do (TM).
     
-    This makes the code compatible with Debian packing rules and
-    restrictions regarding license for distribution
+    Yes, commit messages can be informative as well. :-)
 
-commit efa3099252ca5d200bef6ce71df33f33b55f9941
+commit b9476db0c1e1ce869c1da2f87dfaf411edf69277
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jul 30 12:57:09 2012 +0200
+Date:   Sat Mar 30 09:24:19 2013 +0100
 
-    register(k): pack contact info based on header for searching existing ul records
-    
-    - not using the contact header resulted in omitting instance and reg-id
-      parameters, not following gruu/ob extensions, ending in duplicate
-      records for same +sip.instance
-    - reported by José Luis Millán
+    core: set TOS for tcp IPv6 sockets
 
-commit a7cad776a514b0ec73a5c40b7971af8e0f0da92b
+commit b57f64533dbc538f3d5282d0196598062f0b4652
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jul 30 12:55:36 2012 +0200
+Date:   Sat Mar 30 09:15:00 2013 +0100
 
-    usrloc(k): on ul update, re-clone uri and callid if instance is set
-    
-    - changes can happen when gruu/ob is enabled as the UA can get different
-      address for same instance
+    core: set TOS for IPv6 sctp sockets
 
-commit 72942d8441e04c6f92c8072a373e1f0a9dcc0e61
+commit 222066ba16ec4b2064c4fc50e533e27f4c4fb74d
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jul 30 11:18:28 2012 +0200
+Date:   Fri Mar 29 12:19:36 2013 +0100
 
-    db_sqlite: added notes about usage in readme
+    app_lua: clean local reload array and shut down
+
+commit e2bd2192b5ddc33d0e8fd486467842d9cceda131
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 30 09:10:02 2013 +0100
+
+    stun	Add clarification to the README
     
-    - based on content by Meftah Tayeb
+    And a big thank you to Peter Dunkley and Crocodile RCS for doing the
+    work involved in making this a module, instead of a compile time
+    options. Modules are cool. And easier to handle by pre-compiled
+    distributions/packages.
 
-commit a4e2c43cd66a86bef2d8bda1b0ca0c6f93517a8d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jul 27 13:14:53 2012 +0200
+commit ce0c420ba30388256e958a0bdf6d8f37138c3f97
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 23:35:39 2013 +0000
 
-    rtpproxy: allow pv as parameter to set_rtpproxy_set() function
+    modules/outbound: changed some INFO level output to DBG
 
-commit 9a1450d99accef8e473cf2324412fdfc09a7cd11
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Fri Jul 27 13:08:21 2012 +0300
+commit bce42abfd19f5beb26fc27ab77fed5f679a378ee
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 23:31:54 2013 +0000
 
-    modules/lcr:  improved documentation of lcr_count module param
+    modules/rr: fixed outbound related segmentation fault
 
-commit 1c2cb66a8c9a4482ac278604f32bd772973a787f
-Author: Richard Fuchs <rfuchs at sipwise.com>
-Date:   Thu Jul 26 09:41:26 2012 -0400
+commit 7dfdcfed55916cce7541d28251cb4c82a0823829
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 23:31:39 2013 +0000
 
-    modules/lcr: Fix printing of IPv4 addresses in lcr.dump_gws
-    
-    IPv4 addresses were printed incorrectly. Also add special handling for
-    null gw addresses and print them as 0.0.0.0 for backwards compatibility.
+    modules/outbound: fixed segmentation fault
 
-commit 4a61c692e69fad0e6788725a1e0b2c844607ed7e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 14:47:48 2012 -0400
+commit 56be9d6100c22333a14f18f0a506bd8652240e9d
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 23:12:58 2013 +0000
 
-    Implement sca_call_info_update and handler functions.
+    core: added structure to hold cached decoded flow-token to sip_msg structure
 
-commit e278397916e0b31d7510a3ef324631fd0c0d7d97
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:47:13 2012 -0400
+commit dc1e11b5d03ec033ba7fee421f57d56fa223fddb
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 23:12:18 2013 +0000
 
-    Improve subscription termination handling. Track appearance indexes.
-    
-    Release seized lines on subscription termination. Use updated constant.
+    modules/rr: updated because outbound:decode_flow_token() arguments changed
 
-commit a2f99b96bebf7def0c9bc65f1d635679671c1798
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:33:22 2012 -0400
+commit 2bff7566a0506ea06ab2de735db30af3e4c9c110
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 23:11:24 2013 +0000
 
-    Add unsafe (i.e., use only when locked) find and unlink functions.
+    modules/outbound: cache decoded flow-token in sip_msg structure
     
-    Reduce amount of locking done oer operation by acquiring lock once,
-    then using "unsafe" hash table functions.
+    - Saves multiple OpenSSL calls if the same flow-token is needed in more
+      than one place
 
-commit 1c0166538f51c94ee357df82a5c7b24f7a34fca5
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:28:42 2012 -0400
+commit 030d591a1e80b32d88b606bf0bc0d8ed80ad3b31
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 22:32:13 2013 +0000
 
-    Add sca_appearance_for_index_unsafe, sca_appearance_for_dialog.
-    
-    sca_appearance_update_index now updates dialog, too.
+    modules/outbound: updated edge proxy example to use STUN module
 
-commit 6d96f924f9888b7f432ba3f3e1cc5b6b294f0f9b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:22:42 2012 -0400
+commit 2857eb4b2de20c18ac31212c5336092f08184309
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 22:28:00 2013 +0000
 
-    Use updated sca_appearance_update_index, constant name.
+    modules/stun: removed unnecessary include
 
-commit 7adbb3bb212f20426ccdf8cfd10ef91359fbc87f
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:20:24 2012 -0400
+commit c264ea399e17a87a59282b654bdbdebea2841e34
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 21:49:56 2013 +0000
 
-    Export sca_call_info_update.
+    pkg/kamailio/(centos|fedora): Updated .spec to build new stun module
     
-    Temporarily export sca_unsubscribe_line_seize.
+    - Also updated rel to dev1
 
-commit f8ca7820635567052d9c5b202fac11134ab0db3e
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:07:52 2012 -0400
+commit e090a714728950b40cf09956137db4ce93d08960
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 21:49:29 2013 +0000
 
-    Use updated constants, add comment about hooking failed replies.
+    modules/outbound: updated to reflect STUN being in a module now
 
-commit 058b0aa803d66f0fb9b3ae87435a6cd3924e3043
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:05:23 2012 -0400
+commit c22230bddf3aeebdae9062d3c5c4c37ce59f8a96
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 21:49:07 2013 +0000
 
-    Add prototype for sca_dialog_build_from_headers, SCA_DIALOG_EMPTY
+    core: Updated modules list in Makefile.groups to include stun
 
-commit 4cdfefd8a47a2bea10d279ad20579b056c4e49d1
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:03:44 2012 -0400
+commit c573aa70bba657ba58202c4125d354439478adb2
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 21:47:57 2013 +0000
 
-    include data_lump.h for del_lump Call-Info header removal.
+    core: removed STUN from core
+    
+    - Added hooks so that STUN messages can be passed to a module
+    - Removed STUN configuration file parameters
 
-commit a0b59cd0c5d4d86e0d553d81d70fb2adb0d8b643
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 11:01:53 2012 -0400
+commit 55510ba22e248ea774e7c04b0132c9c5af858d15
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 21:46:20 2013 +0000
 
-    New notes on dialog tracking, removing header, sdp parsing
+    core: removed ser_stun.[ch] from core
+    
+    - STUN now in a module
 
-commit b9e5fb0de5757551866738db3892c1b9adce4a58
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Wed Jul 25 10:59:57 2012 -0400
+commit 02718defd1785fe5b94255077a9945354ee6cc19
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 21:45:45 2013 +0000
 
-    Add util functions, sca_dialog_build_from_tags.
+    modules/stun: Module documentation for STUN
 
-commit f492b41bd12904e3132260562073e79d76a003a5
-Author: Alex Balashov <abalashov at evaristesys.com>
-Date:   Mon Jul 23 22:23:36 2012 -0400
+commit 4afa7a1f9dfc61679db11a5e76e3d3de10be1391
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 21:44:48 2013 +0000
 
-    mqueue: Added mq_size() function to get runtime size of mqueue in script.
+    modules/stun: STUN module
+    
+    - Based on ser_stun.[ch]
+    - No longer a compile time option in Kamailio core
 
-commit 41f77159c5851bb36ad12abecc2faf58602d6935
-Author: Alex Balashov <abalashov at evaristesys.com>
-Date:   Mon Jul 23 19:53:41 2012 -0400
+commit 84ad1a93976a0f8251ab0d86319d91d48a3a4d91
+Merge: 45b4d0b 33108f4
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Mar 29 14:55:58 2013 +0000
 
-    mqueue: Added MI command to get current size of mqueue.
-    
-    There is currently no runtime visibility into the size of a given mqueue.
-    To address this, added an MI command 'mq_get_size' that can return the size
-    of an mqueue by name.  Example:
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
     
-       diminuendo-1:~/sip-router/modules/mqueue# kamctl fifo mq_get_size r_write
-       mqueue::  name=r_write size=1
+    * 'master' of ssh://git.sip-router.org/sip-router:
+      modules/registrar: changed instance related INFO to DBG
 
-commit b26f862322ad311e3c42d899f72eaa1fb665b755
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Fri Jul 20 16:59:52 2012 +0300
+commit 45b4d0b480ca0c0c02327bcbd925865a7571fcf5
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Mar 29 14:54:52 2013 +0000
 
-    modules/matrix Fixed MI command not exported
-    
-    Added missing register_mi_mod() call in mod_init.
+    lib/srdb1, kamctl: Add new rtpproxy db table to schema
 
-commit 9a4b9061387ac88c9c0db7945b41c8a24986b7bc
-Author: Dragos Dinu <dragos.dinu at 1and1.ro>
-Date:   Fri Jul 20 10:48:48 2012 +0300
+commit 33108f4843fdef6d45773849089446b0c408ecf3
+Author: Juha Heinanen <jh at tutpro.com>
+Date:   Fri Mar 29 16:30:51 2013 +0200
 
-    modules/sipcapture: Extended sipcapture to support multiple tables
-    
-    The sipcapture module can support storing the information to multiple sql tables.
-    Tests have shown that a major bottleneck against scalability on multi core CPU of
-    the capture node instance was caused by using a single MySQL Table.
-    The frontend (HOMER) will be soon patched to support retrieval of data from multiple
-    sources.
-    
-    The decision to select witch table is written to, can be configured from random,
-    round robin or hashing via username or callid.
+    modules/registrar: changed instance related INFO to DBG
 
-commit 0f702f6e236eb0cbb238bf83a0c4ae94d7b3cad8
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Thu Jul 19 17:49:13 2012 +0300
+commit 9a0e58667f705197b8e5291b54909fd370b2b7ab
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Mar 29 14:07:59 2013 +0000
 
-    modules_k/uac: uac_replace_from/to AUTO mode with dialog module
+    modules/rtpproxy: Add database support to rtpproxy
     
-    Added a implementation for uac_replace_from/to() that uses the dialog
-    module for AUTO mode. In this mode the URIs are stored as dialog
-    variables.
+    - If db_url modparam is set rtpproxy sets will be loaded from database
+    - If the instance is marked as disabled in database it will be loaded as disabled
     
-    The change in tm module fixes a bug: if uac_replace_to() was called, the
-    URI was not changed accordingly in Cancel.
+    - Currently no persistence (enable/disable MI command does not affect DB)
+    - Loaded during mod_init - cannot be reloaded at runtime (as before)
 
-commit 04041593c08959a640b23d16ba944300f2c320c8
+commit f9a7a9476f3d925fbfbde706ff7690423e96e7c8
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jul 19 10:28:13 2012 +0200
+Date:   Fri Mar 29 12:05:17 2013 +0100
 
-    permissions(k): added new cfg function allow_address_group(addr, port)
+    app_lua: moved local array for reload as global variable
     
-    - return group of matching address and port record in address table
+    - avoid runtime allocation/free for each execution when reload is
+      enabled
+    - renamed sr_reload to _app_lua_sr_reload for better namespacing
+      conflict resolution
 
-commit 21fe4ed3496de3094d12f941310df605e492a713
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jul 19 10:23:20 2012 +0200
+commit c9082cb51b204d5001b0bb819d72669fdcdf3d98
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Fri Mar 29 10:21:42 2013 +0100
 
-    core: fixup helper function for spve - igp parameters
+    modules/app_lua: Fix not C standard initialization
 
-commit 0615826fe602c5183fbc7be7c51de5eb5eb7223c
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 18 19:00:38 2012 +0200
+commit 9d908f1d24df8c1644c3fbed3d99f5011106cae6
+Author: Victor Seva <linuxmaniac at torreviejawireless.org>
+Date:   Thu Mar 28 10:18:10 2013 +0100
 
-    tls: set function to return the id
-    
-    - starting with v1.0.0 openssl does not use anymore getpid(), but address
-      of errno which can point to same virtual address in a multi-process
-      application
-    - for refrence http://www.openssl.org/docs/crypto/threads.html
-    - credits to Jijo on sr-dev mailing list
+    modules/app_lua: Added reload parameter to deactivate the reload check
 
-commit e35e16efbbc6c746a7a4dfeddfc241c2c78d30bc
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 18 18:51:54 2012 +0200
+commit db397f15b9d2faacda9a8175398e1df524fd1875
+Author: Víctor <linuxmaniac at torreviejawireless.org>
+Date:   Wed Mar 27 21:30:40 2013 +0100
 
-    kamdbctl: mtree tables were not in the list for db creation
+    modules/app_lua: add app_lua.list and app_lua.reload rpc commands
 
-commit 3bcff044593687f7f0e71cb7f084b071dd09bff0
+commit 50b116cf4c9c33c4f23c1d5b66fd313a7f40c572
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 18 08:54:56 2012 +0200
+Date:   Fri Mar 29 11:02:31 2013 +0100
 
-    kamctl: stats command can print a single group of statistics
+    usrloc: use NULL domain for updating ul attributes for use_domain=0
     
-    - groupid can be given as command parameter
+    - use counter var for db matching keys
 
-commit bb4925540d241eb91cc8b68712bec20f1970b086
+commit afc8b3e7ae13198c7bca42f7f7fc5499418cfa59
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jul 18 08:27:52 2012 +0200
+Date:   Fri Mar 29 09:25:09 2013 +0100
 
-    kamailio.cfg: removed sample db_mode parameter for domain module
-    
-    - no longer exists since 3.3 domain update
+    Makefile.defs: version set to 4.1.0-dev2
 
-commit 58502f3fa92b6ea2dd50c8b2274b17fc0b5bc083
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Jul 17 16:49:40 2012 -0400
+commit c77ec4ed4cc756373b0f20885d4f04d2276c00c1
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Mar 29 09:23:43 2013 +0100
 
-    Fixes for line-seize reSUBSCRIBEs, line-seize expire time.
+    Makefile: pure target associated to maintainer-clean
 
-commit 7062904cba4c36e2f296b782fd9175914cc9b348
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Jul 17 16:47:46 2012 -0400
+commit c26d6bb13fb699ec2cb9e916d8a562d3ee4c8f0d
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Fri Mar 29 09:38:29 2013 +0100
 
-    Fix sca_call_info_header_append_appearances.
+    snmpstats Adding more memory data variables
     
-    Loop wasn't incrementing buffer pointer.
-
-commit 342d4cee957ef3944419197a58f28354dec0945b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Jul 17 10:44:53 2012 -0400
+    Also, remove dependency of the kex module by interfacing directly
+    with the core the same way as the kex module does get memory information.
 
-    Add parser/hf.h. Required for Call-Info header parsing.
+commit 60953cd884af7d070ce44844a874f2bd75833998
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 29 01:08:02 2013 +0000
 
-commit a93b2c5c007e05c6027643e2b9f09a6775bbce4b
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Jul 17 10:44:12 2012 -0400
+    modules/outbound: updated edge proxy example in README
 
-    Release seized appearances when line-seize subscriber hangs up.
+commit f6b72765da5cf12f8dc1e4157a3e526d5d0aa956
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Thu Mar 28 22:50:59 2013 +0100
 
-commit eecb3b1830903c3e42c80ceb1e458cc631c3a495
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Jul 17 10:43:22 2012 -0400
+    snmpstats Adding another list of TCP settings
+    
+    Just a few more to go, then TLS
 
-    Fix leak: Call sca_appearance_free after unlinking appearance.
+commit 57bb2450a5b0db4c18dd139ae3ae28f480b379c7
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Thu Mar 28 21:30:57 2013 +0100
 
-commit 7e4aa668d1fa5c6cc34d6e5350c64649a005c641
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Jul 17 10:42:16 2012 -0400
+    snmpstats Add a few more TCP connection settings
 
-    Implement sca_call_info_header_find and sca_call_info_body_parse.
+commit 464ce5d71d738f706f0d4a26573444809496068e
+Merge: 1d8597f 084be45
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Thu Mar 28 10:00:05 2013 +0000
+
+    Merge branch 'master' into hpw/branch_failure_route
+    
+    * master: (33 commits)
+      core: set TOS for IPv6 UDP sockets
+      rtpproxy: add missing wrapper function for unforce_rtp_proxy
+      modules/outbound: further improvement to the use_outbound() check
+      rtpproxy: support pvars in function parameters
+      modules/rr: copy the flow-token for "incoming" messages when using outbound
+      modules/outbound: improved check for outbound
+      modules/rr: only use flow-token for routing if it doesn't point to the source of the request
+      pkg/kamailio/(centos|fedora): Updated .spec after addition of cnxcc module
+      Makefile.groups: cnxcc module added to extra list
+      core: auto-define cfg directive MOD_modname for each loaded module
+      snmpstats Add tcpasync and tcpmaxconns
+      snmpstats Add IDs to sections in documentation
+      cnxcc: added new module for credit control
+      snmpstats activate new parts of the KAMAILIO-MIB
+      snmpstats Add information about version and tcp connections
+      usrloc: new option for db_mode - DB_READONLY (4)
+      enum: define the max size for numbers
+      db_mysql: new module parameter - insert_delayed
+      Makefile: exclude debian sym link when generating tarball
+      msrp: fix compile warning of argument type in dbg message
+      ...
 
-commit da5a8008460bc03c6cb6d32740cf09425c0ed067
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Tue Jul 17 10:39:30 2012 -0400
+commit 1d8597f99b43154c1a078ade47984e6faf9f149c
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Thu Mar 28 09:48:04 2013 +0000
 
-    Implement sca_appearance_release_index.
-    
-    Correct sca_appearance_free prototype.
+    modules/tm: Fix setting instance in uac branches
 
-commit 31d651479c210e4b1d181fc34b10aae67e716bb7
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Tue Jul 17 10:15:46 2012 -0400
+commit 084be456bc0fab015cf9964ac85651fa60ea77c9
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Wed Mar 27 20:53:00 2013 +0100
 
-    Remove duplicate entry of "default_domain" in docs.
-    Remove double occurance of the CSeq Attribute in the XML.
-    (closes FS#246 - pua_reginfo adds duplicate cseq field in XML body on the Bugtracker)
+    core: set TOS for IPv6 UDP sockets
     
-    Thanks to Andrew Pogrebennyk (apogrebennyk at sipwise.com) for pointing this out.
+    - reported by Klaus Feichtinger, FS#179
 
-commit d694cebab5b2e2849059fb0376a38e074646c703
-Author: Andrew Mortensen <admorten at isc.upenn.edu>
-Date:   Mon Jul 16 09:25:00 2012 -0400
+commit 9e6af79d0cf1b0e10694880147a28966313fb5a4
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Wed Mar 27 13:30:05 2013 -0400
 
-    Shared Call Appearance module for sip-router.
-    
-    Move to repo.net.isc.upenn.edu.
+    rtpproxy: add missing wrapper function for unforce_rtp_proxy
 
-commit f003344fce108600c966dd3b79c5c89cb364afe5
+commit a5f8f4cd4da60168fd73d7999c09181582ec5943
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jul 14 22:15:00 2012 +0100
+Date:   Wed Mar 27 16:51:52 2013 +0000
 
-    pkg/kamailio/fedora/17: Updated appliances
+    modules/outbound: further improvement to the use_outbound() check
 
-commit 60f0665348e80f056f2a0de5263de95f898e4583
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jul 13 18:03:46 2012 +0200
+commit cd3358dd935781489e2b7122fe20a19310f97546
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Wed Mar 27 12:46:28 2013 -0400
 
-    cdp_avp: fixed small typo in readme
+    rtpproxy: support pvars in function parameters
 
-commit f3ff581dbd0a53c4c5eafdf829bef0c25e8e8f28
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Fri Jul 13 16:50:07 2012 +0300
+commit 0c1725c8ccb08280a9c161e34fa9e43347cae7b0
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Mar 27 16:33:17 2013 +0000
 
-    lib/srdb1 : put pooling constans into separate header file to reduce
-    include dependancy
+    modules/rr: copy the flow-token for "incoming" messages when using outbound
 
-commit 1f6bfa0b3ba15201c2ca3e2387a9f9e81e989643
-Author: Pawel Kuzak <pawel.kuzak at 1und1.de>
-Date:   Fri Jul 13 16:06:48 2012 +0300
+commit b2fb355fe5c9c64727d873cbe8d6fd883ebd2537
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Mar 27 16:32:59 2013 +0000
 
-    Ported gruu and outbound changes to p_usrloc module
+    modules/outbound: improved check for outbound
 
-commit e570709eeb0bf874f8a825efe982bdff794c22b3
-Merge: 2b77f22 8328637
+commit 874669f483e1efba032bd695eb6cee4275673874
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jul 13 10:37:08 2012 +0100
+Date:   Wed Mar 27 15:43:02 2013 +0000
 
-    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    modules/rr: only use flow-token for routing if it doesn't point to the source of the request
+
+commit 2f85ac8828b2d336069c618ef4d209d61809c19f
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Mar 27 14:36:59 2013 +0000
+
+    modules/tm: Enable retrieving of branch instance id from uac structure
     
-    * 'master' of ssh://git.sip-router.org/sip-router:
-      Makefile.defs: version set 3.4.0-dev2
-      parser/sdp: more suggestive debug message
-      parser/sdp: prevent manipulation with freed structure
-      core: Removed unused enum (crept in during WebSocket implementation)
-      modules/ipops: Corrected is_in_subnet() exported function and added is_ip to module C API
-      modules/sl: Fixed segmentation fault and corrected log messages
-      modules_k/registrar: Fixed some errors in module documentation
-      core: update printing of socket lists to show the advertised address if set for the socket
-      modules_k/presence: Added missing use_table() call
+    - Add instance to uac structure and populate when uac created
+    - Add get_this_branch_instance function to retrieve instance in a branch failure route
 
-commit 2b77f22f159bf14a9e08d339bd69f8d1c35f541d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jul 13 10:36:31 2012 +0100
+commit 5d1a3b87fde83455f63075d8fdf39b7b99d4053c
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Mar 27 14:25:32 2013 +0000
 
-    pkg/kamailio/fedora/16: Updated rel in .spec to dev2
+    modules/xprint: Updated to use the new get_branch()/next_branch() functions
 
-commit 832863723365ffd6f071a31415cca6b0f4cde391
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jul 13 09:49:40 2012 +0200
+commit 800d56979226ad80e045fb316e19fb3b77ce7f57
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Mar 27 13:59:44 2013 +0000
 
-    Makefile.defs: version set 3.4.0-dev2
+    pkg/kamailio/(centos|fedora): Updated .spec after addition of cnxcc module
 
-commit faf7806b7488143f0637b9db896d849249eb059a
+commit 94272bdb6ce2a15ba2e165eef59561c2d2992a5f
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jul 13 09:49:16 2012 +0200
+Date:   Wed Mar 27 13:39:28 2013 +0100
 
-    parser/sdp: more suggestive debug message
+    Makefile.groups: cnxcc module added to extra list
 
-commit f529cdb8b818017c20b73ba5be89309745ea95c5
-Author: Michal Karas <largon at largon.net>
-Date:   Thu Jul 12 17:38:15 2012 +0200
+commit a1e0c05e953140b026325117c3d8ace5a2ccf900
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Mar 27 11:53:18 2013 +0000
 
-    parser/sdp: prevent manipulation with freed structure
+    modules/pv: Updated to use the new get_branch()/next_branch() functions
     
-    - FS#244
+    - New instance parameter is currently not used
 
-commit e3cadfd261d2d4b88e288e893a1e6171b14f4218
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 12 22:45:32 2012 +0100
+commit 691ebf0178aa25b5ef19eb6a220d335be3900a3b
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Mar 27 11:52:15 2013 +0000
 
-    core: Removed unused enum (crept in during WebSocket implementation)
+    modules/permissions: Updated to use the new get_branch()/next_branch() functions
 
-commit 8ab4daa7f13a70f1fb77d7a98f11f7290a42c321
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 12 21:50:00 2012 +0100
+commit 58c9ba973415caf2a39c0c6fefbd66986d475a89
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Mar 27 11:46:45 2013 +0000
 
-    modules/ipops: Corrected is_in_subnet() exported function and added is_ip to module C API
-    
-    - Fixes and enhancements by Hugh Waite @ Crocodile RCS
+    modules/domain: Updated to use the new get_branch()/next_branch() functions
 
-commit e78ff34f1ecfe9a60a52996126032ea04fb490ab
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 12 21:48:08 2012 +0100
+commit 42a1548a57ec8e3a8779f1644347340c25aa1bdd
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Wed Mar 27 11:44:08 2013 +0000
 
-    modules/sl: Fixed segmentation fault and corrected log messages
+    core: Update get_branch() to return instance from appended branches
     
-    - Fixes by Hugh Waite @ Crocodile RCS
+    - get_branch() and next_branch() updated
+    - modified select_core.c to use new function definition
 
-commit 6d040935f31be0098a09f4621874268164f3926a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 12 21:46:58 2012 +0100
+commit 14525efb68380b759347e64441cb90f97c1e3595
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Mar 26 23:45:50 2013 +0100
 
-    modules_k/registrar: Fixed some errors in module documentation
+    core: auto-define cfg directive MOD_modname for each loaded module
     
-    - Fix by Hugh Waite @ Crocodile RCS
+    - example: if acc module is loaded, MOD_acc is defined in cfg
+    - suggestion by Olle E. Johansson
 
-commit 274969bcca2301c96dbbcc17c5b1d411073c8277
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 12 21:44:45 2012 +0100
+commit e1dc02d523867fc9934e862397e6da6b256c7b1b
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Mar 26 22:16:03 2013 +0100
 
-    core: update printing of socket lists to show the advertised address if set for the socket
+    snmpstats Add tcpasync and tcpmaxconns
+    
+    This is to test if I can reach core configuration settings for TCP. Tests prove that it's
+    possible. Will go ahead and add other settings as well.
     
-    - useful for diagnosing what is going on with advertised address
-    - Enhancement added by Hugh Waite @ Crocodile RCS
+    One question is if we should allow changing these variables in SNMP, like we do
+    over the RPC interface or selects. Let's think about that.
 
-commit 0de5e17770cd5dcfcdd64174eb24f0bcaccef021
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 12 21:20:49 2012 +0100
+commit 63a72893c84aad1edd7b139dbe36e3c337d4e9ae
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Mar 26 21:29:48 2013 +0100
 
-    modules_k/presence: Added missing use_table() call
+    snmpstats Add IDs to sections in documentation
 
-commit f2f8ff72137a39702d284dfe6deb9ef4442e4e78
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 12 16:26:38 2012 +0100
+commit 76a967f1db16540257fe8a54fe85e3993060b304
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Mar 26 12:10:11 2013 +0000
 
-    Makefile: SCTP library check doesn't look in /usr/lib64
+    modules/tm: Update t_next_contact_flows for use in branch_failure event_route
     
-    - This means you can't build Kamailio for a 64-bit OS like CentOS or
-      Fedora.
+    - Rename to t_next_contact_flow as only one flow will be used
+    - Selects and uses the next flow with the same instance_id as the failed branch
 
-commit 3bf1b0472df3be94f6ec1d5ce7573d96dbd88a7a
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Thu Jul 12 09:27:56 2012 +0200
+commit 0b79baecf4a36a47522fd222614e370c5d044e8f
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Mar 26 11:43:35 2013 +0000
 
-    Revert 008c92bece290aed3b8e6439be71c2c37526901d
-    
-    We'll readd the dependency once the websocket
-     module is enabled for build
+    core: Add defines required for a new branch_failure_route type
 
-commit 699526ddb3b02cb5766bc7ad6f1c7a1861006d4c
-Author: Klaus Darilion <klaus.mailinglists at pernau.at>
-Date:   Wed Jul 11 12:30:51 2012 +0000
+commit 54a98bc741daba4d0c14c587d22dddf3c01a2e30
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Mar 26 11:40:38 2013 +0000
 
-    kamdbctl: add domain_attrs table to standard tables
+    modules/tm: Create branch-failure event route
 
-commit 40b37899aaadd1518d812c4a32aeab330b864cb4
-Author: Andreas Granig <agranig at sipwise.com>
-Date:   Wed Jul 11 12:52:38 2012 +0200
+commit 054af083489cba1d7072768734abdc5cf8ef916b
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Mar 26 11:22:31 2013 +0000
 
-    modules_k/uac: fix handling of empty display-part.
+    Revert "core: Initial revision of branch_failure_route"
+    
+    Remove new branch_failure_route in favour of an event_route
     
-    This re-enables the feature to strip the display name by setting
-    an empty string, like uac_replace_from("", "$var(from)");
+    This reverts commit a5946574cb9917f0a9a90ea547c9357f3f6477bd.
 
-commit 9485cfac5e1e6f4bb53407d3382f7dc725598f8a
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Tue Jul 10 12:05:02 2012 +0200
+commit 96596e282af0a967c93e162169c6729d183557b9
+Author: Carlos Ruiz Díaz <carlos.ruizdiaz at gmail.com>
+Date:   Tue Mar 26 00:58:28 2013 -0300
 
-    ndb_redis: README file update. redis_cmd variadic function.
+    cnxcc: added new module for credit control
 
-commit 1010594cf1d7df4753a61142dc86d7d04f6c4be3
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Tue Jul 10 05:54:00 2012 -0400
+commit d269473c935ccd1b867ba215c8b4701f8cf24027
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Mar 24 21:52:41 2013 +0100
 
-    ndb_redis: redis_cmd variadic function documentation.
+    snmpstats activate new parts of the KAMAILIO-MIB
 
-commit ca5e3d93e3f117651d2152dccdfd4c299bf7f508
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Tue Jul 10 05:48:45 2012 -0400
+commit 90c51c7b0f85494bc95afc4b976c142051cb7792
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Mar 24 21:49:02 2013 +0100
 
-    ndb_redis: redis_cmd changed into a variadic function.
+    snmpstats Add information about version and tcp connections
+    
+    Output from SNMPwalk with the new additions:
     
-    - command string can be split into several strings.
+    KAMAILIO-MIB::kamailioNetTcpConnEstablished.0 = Counter32: 0
+    KAMAILIO-MIB::kamailioNetTcpConnFailed.0 = Counter32: 0
+    KAMAILIO-MIB::kamailioNetTcpConnReset.0 = Counter32: 0
+    KAMAILIO-MIB::kamailioNetTcpConnSuccess.0 = Counter32: 0
+    KAMAILIO-MIB::kamailioNetTcpConnOpened.0 = Gauge32: 0
+    KAMAILIO-MIB::kamailioNetTcpConnPassiveOpen.0 = Counter32: 0
+    KAMAILIO-MIB::kamailioNetTcpConnReject.0 = Counter32: 0
+    KAMAILIO-MIB::kamailioNetTcpEnabled.0 = INTEGER: true(1)
+    
+    KAMAILIO-MIB::kamailioSrvMaxMemory.0 = Gauge32: 33554432
+    KAMAILIO-MIB::kamailioSrvFreeMemory.0 = Gauge32: 31709088
+    
+    KAMAILIO-MIB::kamailioSrvCnfFullVersion.0 = STRING: kamailio 4.5.0 (i386/linux) 50af49
+    KAMAILIO-MIB::kamailioSrvCnfVerName.0 = STRING: kamailio
+    KAMAILIO-MIB::kamailioSrvCnfVerVersion.0 = STRING: 4.5.0
+    KAMAILIO-MIB::kamailioSrvCnfVerArch.0 = STRING: i386
+    KAMAILIO-MIB::kamailioSrvCnfVerOs.0 = STRING: linux
+    KAMAILIO-MIB::kamailioSrvCnfVerId.0 = STRING: 50af49
+    KAMAILIO-MIB::kamailioSrvCnfVerCompTime.0 = STRING: 12:12:27 Mar 24 2023
+    KAMAILIO-MIB::kamailioSrvCnfVerCompiler.0 = STRING: gcc 4.1.2
+    KAMAILIO-MIB::kamailioSrvCnfVerFlags.0 = STRING: STATS: Off, USE_IPV6, USE_TCP, USE_TLS, TLS_HOOKS, USE_RAW_SOCKS, DISABLE_NAGLE, USE_MCAST, DNS_IP_HACK, SHM_MEM, SHM_MMAP, PKG_MALLOC, USE_FUTEX, FAST_LOCK-ADAPTIVE_WAIT, USE_DNS_CACHE, USE_DNS_FAILOVER, USE_NAPTR, USE_DST_BLACKLIST, HAVE_RESOLV_RES
 
-commit 008c92bece290aed3b8e6439be71c2c37526901d
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Sun Jul 8 21:20:35 2012 +0300
+commit d80ea02f5d96477e1c6deca581500cfa4a24380e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 24 13:53:50 2013 +0100
 
-    pkg/kamailio/deb/wheezy: Added build dependency on libunistring-dev.
+    usrloc: new option for db_mode - DB_READONLY (4)
+    
+    - location records are loaded only at startup
+    - no write back to database, not even at shutdown
+    - useful when registrations are replicated to another node that does the
+      db storage at runtime
+    - started from a patch by Marcus Hunger
 
-commit b705c4c8bbbd36dce28b8d9e2344e7544f4e5fdc
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jul 8 02:06:05 2012 +0100
+commit ef8fae0e21ca09725c7f9c06384e0a4ce37c4c6e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 24 13:24:58 2013 +0100
 
-    pkg/kamailio/fedora/17: Added @Base group to BoxGrinder appliances
+    enum: define the max size for numbers
     
-    - This groups is required to get the network to come up automatically for
-      Fedora 17 (it wasn't needed for Fedora 16 or CentOS 6).
+    - set it to 22 (previously hardcoded value was 17)
+    - easier to adjust and check for overlenght
+    - patch by Marcus Hunger
 
-commit 7a3ce731e73d4b47646f2562e588886137cc8e85
-Merge: f64fda6 acb0ae8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jul 7 17:52:20 2012 +0100
+commit 61c706ef813520ce0ac6767e6be7ef6e52bd6b3a
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 24 13:07:39 2013 +0100
 
-    Merge branch 'master' into websocket
+    db_mysql: new module parameter - insert_delayed
+    
+    - if set to 1, then all INSERT API queries will be converted in INSERT
+      DELAYED (only DB API insert, not for raw queries)
 
-commit acb0ae899ca7341f06fa4418c88f3b42d3460f49
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Fri Jul 6 18:23:09 2012 +0200
+commit 9cbe03b3b42826c656b73a8793a8c2db9e7c3d29
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 24 12:50:50 2013 +0100
 
-    ndb_redis: update README file
+    Makefile: exclude debian sym link when generating tarball
 
-commit b237db588f4de8eb3e1f8bf321e010ce5f9cded3
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Fri Jul 6 12:12:36 2012 -0400
+commit 7339d847adfd098c58426e96e5e3730ad580d543
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 24 12:38:45 2013 +0100
 
-    ndb_redis: redisc_free_reply only frees redisReply structure.
+    msrp: fix compile warning of argument type in dbg message
     
-    - freeing whole redisc_reply_t structure causes a bug, so better remove only inner data.
+    - reported by Olle E. Johansson
 
-commit f64fda60da151e2672e5eade99eee636ace25695
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 22:58:24 2012 +0100
+commit bb76415ba7b623242a84b295728e61d307ab48fb
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Mar 24 11:45:43 2013 +0100
 
-    pkg/kamailio/fedora/16: tidied up kamailio.spec
+    snmpstats Clear upp method-supported logic a bit and add "dialog-ng" for call statefullness
 
-commit 380ab4c742c4060d7601e4b0491ebdb9eb0bb157
-Merge: a4db0a0 ef6da28
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 22:55:44 2012 +0100
+commit 3580d7fbc3318a2eefaa62e60fcad363e953cccb
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sun Mar 24 11:38:27 2013 +0100
 
-    Merge branch 'master' into websocket
+    snmpstats Add SNMP support for shared memory
     
-    Conflicts:
-    	pkg/kamailio/fedora/16/kamailio.spec
+    This is just the first proof-of-concept addition, will add more of the
+    core variables for memory and TCP connections
 
-commit ef6da283105197eda608cc3571cfc6772c343aa6
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 23:39:51 2012 +0200
+commit 1826a5f4e3a981e30956da61e11ea551aae0b714
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sat Mar 23 10:44:31 2013 +0100
 
-    parser: remove old $Id$ docs header from subversion times, not usable anymore
+    rr: use sips to build RR headers of R-URI has sips
+    
+    - reported by Hugh James, FS#277
 
-commit fa441a9cdb28fb6336805f45aa65de13c9bcc139
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 23:35:27 2012 +0200
+commit 4baf0389c57a7e705c5b01dd95da0e8978dc784a
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Mar 20 13:23:49 2013 -0400
 
-    parser: add missing copyright statement to files, this part was contributed
-    in commit 3c736126b097137ec943b5931f867bc7e9d82e76 Author: Jamey Hicks,
-    jamey dot hicks at hp dot com, Date: Fri Dec 3 13:37:57 2004 +0000
+    p_usrloc: commenting out unused db_timer_udomain() to get rid of compiler warnings
 
-commit f358aa1b6983a7e1a17745658c4c7f8efa08966c
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 23:30:15 2012 +0200
+commit 67609608aa4306de9a34a28a3a31880ad0d17e8e
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Mar 20 13:16:27 2013 -0400
 
-    parser: add missing copyright statement to files, this part was contributed from
-    Vaclav Kubart, vaclav dot kubart at iptel dot org in commit
-    488624056c4651fd57fdffd1cbfdd2a07928fdab, Date: Wed Jun 21 13:33:01 2006 +0000
+    kamailio/utils/sercmd: remove unused but set variable
 
-commit 8361d5921557630576d6f542603f769bff420887
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 23:26:45 2012 +0200
+commit b7a41ef47ad5d7fa90e577673cc2f38ab5ef2237
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Mar 20 13:15:08 2013 -0400
 
-    parser: add missing copyright statement to files, this part was contributed
-    in commit 3c736126b097137ec943b5931f867bc7e9d82e76
-    Author: Jamey Hicks, jamey dot hicks at hp dot com, Date: Fri Dec 3 13:37:57 2004 +0000
+    kamailio/utils/sercmd: remove unused but set variable
 
-commit 6742b34bb385742aa80cd23d9dedbd366a243650
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 23:14:42 2012 +0200
+commit ff94115921a08ba4da29baf2761db47bd0b7f8f5
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Mar 20 13:13:27 2013 -0400
 
-    parser: const-correctness for some module utility functions
+    kamailio/utils/sercmd: remove unused but set variable
 
-commit a8e108ec68f6117c33669e35bccaf9b779858e25
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 23:04:43 2012 +0200
+commit 387adace552c22eaf15a049b23694bcd79cea3a8
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Mar 20 13:02:16 2013 -0400
 
-    parser: some more const-correctness for the other functions in msg_parser.[c,h]
+    auth_diameter: remove unused but set variable
 
-commit 8f0f3fb39695ba52938c42ea58519485299f2fa4
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 22:40:45 2012 +0200
+commit 941c48ae6909994ae090c9d52766cd4dd5d4f938
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Wed Mar 20 13:00:27 2013 -0400
 
-    parser: remove two blocks of old code, commented some years ago
+    auth_diameter: remove unused but set variable
 
-commit f7b97e8a8329f23aef74be87f9ff18c3206e811a
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Thu Jul 5 22:35:22 2012 +0200
+commit 94e7ae77a6674d5e6a6d025a8e85f7b1c8733057
+Author: Carsten Bock <carsten at ng-voice.com>
+Date:   Wed Mar 20 17:31:34 2013 +0100
 
-    parser: make get_hdr_field(..) and necessary called functions const-correct
+    Updated example config for S-CSCF
 
-commit 1c4e782f33f3c12747a4e8d9b9f67bf035007658
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 21:16:43 2012 +0100
+commit 0d8cec6b6cd9027ef7313608db7e27667643fdf6
+Author: Anca Vamanu <anca.vamanu at 1and1.ro>
+Date:   Wed Mar 20 15:39:12 2013 +0200
 
-    pkg/kamailio/fedora/16: fixed typo in .spec
+    modules/drouting Improvement for do_routing in failure route
+    
+    Improvement for sort_order 2 : if the failure groups have repeating
+    gateways the module will take care internally not to try again a gateway
+    that was already tried.
 
-commit a4db0a0f9577477a15f90e3e4674a941aa306730
-Merge: 6af91d1 2b392e4
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 21:15:22 2012 +0100
+commit 6bb98ddd9ee4913c7a56ca5ffa57d9f74e7bc1b3
+Author: Lucian Balaceanu <lucian.balaceanu at 1and1.ro>
+Date:   Wed Mar 20 14:27:30 2013 +0200
 
-    Merge branch 'master' into websocket
+    modules/carrierroute Improvement for cr_route in failure route
     
-    Conflicts:
-    	Makefile
-    	pkg/kamailio/centos/6/kamailio-build.appl
-    	pkg/kamailio/centos/6/kamailio.appl
-    	pkg/kamailio/fedora/16/kamailio-build.appl
-    	pkg/kamailio/fedora/16/kamailio.appl
-    	pkg/kamailio/fedora/16/kamailio.spec
-    	pkg/kamailio/fedora/17/kamailio-build.appl
-    	pkg/kamailio/fedora/17/kamailio.appl
+    Small improvement in cr_route() function - when it is called from
+    failure_route it will take care not choose a previously choosen gateway.
+    
+    Added cr_reload sercmd.
 
-commit 2b392e46054bfe5f6ab475a53ba3212d548f2c7f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 20:41:36 2012 +0100
+commit a5946574cb9917f0a9a90ea547c9357f3f6477bd
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Mar 19 15:43:46 2013 +0000
 
-    pkg/kamailio/(centos|fedora): Updated .spec and .appl files to build RPM for cdp and cdp_avp modules
+    core: Initial revision of branch_failure_route
+    
+    - New branch_failure_route defined
+    - cfg route is called but xlog() causes segfault
 
-commit 6af91d1fb3839fd02cd2739d9c8c784497e1d6e9
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 15:23:19 2012 +0100
+commit 4e0cf550f75835b3f97bda9bb7934389a54b1f18
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Mar 19 15:41:55 2013 +0000
 
-    modules/websocket: More tidy-up of example configuration file
+    modules/tm: Initial revision of branch_failure_route
+    
+    - New branch_failure_route defined
+    - cfg route is called but xlog() causes segfault
 
-commit ac40abf75710281049ec424061d94cdc5f45aa10
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 12:16:31 2012 +0100
+commit a0b01f77de163cf7ea9d71d5293a1bfa20d31fa6
+Author: Henning Westerholt <hw at kamailio.org>
+Date:   Tue Mar 19 15:32:25 2013 +0100
 
-    pkg/kamailio/(centos|fedora): Added git to the build appliances
+    rtpproxy: fix spelling error in docs, reported from Victor V. Kustov, coyote at bks dot tv
 
-commit 324e8f36443f15af0ee5e7d96323c7e394202ea8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jul 5 12:08:40 2012 +0100
+commit c218ae122d5de9757bacc114a4bf4a374b7ea9c7
+Merge: ea3a03d 92bbfd0
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Tue Mar 19 09:38:17 2013 +0000
 
-    modules/websocket: Tidied up example kamailio.cfg
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    
+    * 'master' of ssh://git.sip-router.org/sip-router:
+      modules/sca: seize appearance for SCA callee answering w/o Call-Info
 
-commit 840d829149961d79fe9c84e59c14b8f72de4c44d
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Jul 4 23:46:46 2012 +0100
+commit 92bbfd0b04306dd53e8eae444f46de768239875b
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Mar 18 15:03:24 2013 -0400
 
-    pkg/kamailio/(centos|fedora): Added instructions on using BoxGrinder appliances to build Kamailio RPMs
+    modules/sca: seize appearance for SCA callee answering w/o Call-Info
+    
+    - Yealink firmware 7.70.0.130 doesn't include a Call-Info header with
+      200 OK response to INVITE.
 
-commit 2685b26f7587172ad95f0e1e21114ebd483e6e5f
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Wed Jul 4 22:24:33 2012 +0200
+commit ea3a03de4f1a3ba163302ab2d5ee140bab49a85c
+Merge: 3a45d92 fac2d49
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Mon Mar 18 17:24:03 2013 +0000
 
-    remove one redundant inclusion of casandra module in excluded modules
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    
+    * 'master' of ssh://git.sip-router.org/sip-router:
+      modules/sca: cast logging of time_t to long int to quiet warnings.
 
-commit 754853be86112f52f2b7f1d4ea0a0317d6c1e324
-Author: Henning Westerholt <hw at kamailio.org>
-Date:   Wed Jul 4 22:22:26 2012 +0200
+commit fac2d49b667c5c18fce01387d9c02afcce8ec55f
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Mar 18 10:32:45 2013 -0400
 
-    add cdp module to excluded modules, as its depends on libxml
+    modules/sca: cast logging of time_t to long int to quiet warnings.
+    
+    - Report from Olle Johansson. Latent Y2K38 problem, but that needs a
+      project-wide solution.
 
-commit 1792586578d9680d45d52af37ddf2786b8b30ca8
-Merge: 86362e5 1382c30
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Jul 4 18:08:02 2012 +0100
+commit 3a45d925c7f06072aef9edba3b0ef8c17e12c6e2
+Merge: dd0b43e 07ddc78
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Mon Mar 18 11:57:17 2013 +0000
 
-    Merge branch 'master' into websocket
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
     
-    * master:
-      modules/lcr: Fixed to/from_gw tests when proto parameter is 0 (ANY)
-      cdp_avp: added README file
-      CDP: Fixed README
-      CDP: A few fixes to docs and location of image files - cleaner organisation
-      new modules: CDP (C Diameter Peer) and CDP_AVP 	- These modules were originally written by Fraunhofer and have been 	  ported to Kamailio, with some minor additions and improvements. Examples 	  on using the modules to come shortly - diameter_rx, diameter_ro, etc
+    * 'master' of ssh://git.sip-router.org/sip-router:
+      modules/app_java: refactoring, changed parameter 'force_kam_cmd_exec' to 'force_cmd_exec', updated docs     - moved ThrowNewException from utils to java_support     - removed macro FORCE_CAST_O2P     - removed get_struct_sip_msg     - renamed parameter 'force_kam_cmd_exec' to 'force_cmd_exec'     - updated docs caused parameter change
+      modules/app_java: README to README-draft, added actual README
+      modules/app_java: moved README, removed other formats except xml from doc directory.
+      modules/app_java: added documentation, removed *.class,*.jar
+      modules/sca: fix -Waddress warnings caused by static strs in SCA_STR_EMPTY
+      modules/sca: process BYE without Call-Info from shared line.
+      modules/outbound: Warn during mod_init() if STUN is not built or enabled
+      modules/outbound: free shared memory for flow-token key during shutdown
+      sca: reduce log level to DBG when replacing RURI when retrieving held call.
+      modules/outbound: Fixed bug in outbound mod_init
+      modules/outbound: The flow-token key is now automatically generated
+
+commit 07ddc78df819edff18cc339cb234c22d140bd3a4
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Mon Mar 18 02:04:17 2013 +0200
 
-commit 86362e52c17858bfb81bda33cc6ae46e0f75517f
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Jul 4 16:15:29 2012 +0100
+    modules/app_java: refactoring, changed parameter 'force_kam_cmd_exec' to 'force_cmd_exec', updated docs
+        - moved ThrowNewException from utils to java_support
+        - removed macro FORCE_CAST_O2P
+        - removed get_struct_sip_msg
+        - renamed parameter 'force_kam_cmd_exec' to 'force_cmd_exec'
+        - updated docs caused parameter change
+
+commit 87a21516e1c75d11513df901567183b0146337ab
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Mon Mar 18 01:45:49 2013 +0200
 
-    modules/websocket: Fixes to WS and WSS message sending
+    modules/app_java: README to README-draft, added actual README
 
-commit d1d9d63984fed14fc2912c31e7abc30e0500bbb8
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Jul 4 16:13:40 2012 +0100
+commit a01d84bf61ade1b0362c16a41acec262a41b919a
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Mon Mar 18 01:20:29 2013 +0200
 
-    modules_k/pv: Added missing break;s
+    modules/app_java: moved README, removed other formats except xml from doc directory.
 
-commit 1ccd1f68cff759a2a54b8f441ca8c53647f845a4
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Jul 4 16:12:53 2012 +0100
+commit fc425b1c36a335af1ee5ca183cca72b6a472843f
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Sun Mar 17 01:16:20 2013 +0200
 
-    core: Fixes for WSS (secure WebSocket) transport and Via:s
+    modules/app_java: added documentation, removed *.class,*.jar
 
-commit 1382c30da7ffd8831479affafde4d8e038a41240
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Jul 4 17:15:43 2012 +0300
+commit d80b4afc7d0dddebd9ffe06e0174a79871daf822
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Sat Mar 16 16:35:29 2013 -0400
+
+    modules/sca: fix -Waddress warnings caused by static strs in SCA_STR_EMPTY
+    
+    - Tested on Ubunut 12.04 LTS. Report from Konstantin Mosesov.
+
+commit 287cccf2af17e5f2f8fe09c41025b4d27bb4fda9
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Fri Mar 15 17:01:23 2013 -0400
 
-    modules/lcr: Fixed to/from_gw tests when proto parameter is 0 (ANY)
+    modules/sca: process BYE without Call-Info from shared line.
     
-    - Also, updated README regarding handling of NULL value in lcr_gw
-      transport column.
+    - Ciscos & Aastras don't seem include Call-Info header in BYE. Look up
+      dialog by tags and release associated appearance-index.
 
-commit c39580925bebdb6506e106295119fb72f861e76f
+commit 85b26219f9e4c3c8c7c990a4897d40645b4ad6e7
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jul 3 23:59:22 2012 +0100
+Date:   Fri Mar 15 15:04:07 2013 +0000
 
-    modules/websocket and pkg/kamailio/fedora: Added websocket module documentation
+    modules/outbound: Warn during mod_init() if STUN is not built or enabled
+    
+    - STUN is required for outbound with UDP.  Don't want to stop Kamailio starting
+      when the outbound module is loaded and STUN is not available - but a warning
+      seems appropriate.
 
-commit 6d751215160cddb96dd16b33bd668d573a61b3d8
+commit 9d9d51438acd1d534f14ecbc8eb0030b45333177
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jul 3 16:57:50 2012 +0100
+Date:   Fri Mar 15 14:54:41 2013 +0000
+
+    modules/outbound: free shared memory for flow-token key during shutdown
+
+commit a51bc822f70f4185b55455456dc147205cbbbdc7
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Fri Mar 15 10:22:26 2013 -0400
 
-    pkg/kamailio/(centos|fedora): Tweaked .spec and .appl files to add WebSocket support
+    sca: reduce log level to DBG when replacing RURI when retrieving held call.
 
-commit b7e7535289dfab413cbc1333ac545f31f3c992c2
+commit c924645fcfb706fc20ed715a00531d785f99cbde
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jul 3 16:57:00 2012 +0100
+Date:   Fri Mar 15 14:07:04 2013 +0000
 
-    core: Added websocket module to Makefile
+    modules/outbound: Fixed bug in outbound mod_init
 
-commit eff18c9ce6de48e6a2f821148cbce586a088512c
+commit f474e85616f6f98a6ac193c7425f6c85af8efa20
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jul 3 16:56:11 2012 +0100
+Date:   Fri Mar 15 12:14:31 2013 +0000
+
+    modules/outbound: The flow-token key is now automatically generated
+    
+    - Uses OpenSSL RAND_bytes() to select 20 cryptographically strong pseudo-random
+      bytes for the key.
+    - Flow-token key can no longer be manually set.
 
-    modules/websocket: Updated example kamailio.cfg
+commit dd0b43e2ac06ed901f959d9e5a90312d865dedfd
+Merge: 1c27645 3445718
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Fri Mar 15 12:08:16 2013 +0000
 
-commit 12d1977f97023a279d8f72c02c80e0f9dc902047
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Tue Jul 3 12:50:10 2012 +0200
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
+    
+    * 'master' of ssh://git.sip-router.org/sip-router: (40 commits)
+      modules/registrar: fixed lock usage in unregister()
+      modules/pv: can only retrieve $ruid for a request
+      ims_icscf: fix include list for BSD
+      modules/pv: added new $ruid and $branch(ruid) PVs
+      modules/xprint: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/tm: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/pv: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/permissions: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/domain: updated use of get_branch() and next_branch() to cope with additional argument
+      core: updated use of get_branch() and next_branch() to cope with additional argument
+      core: updated get_branch() and next_branch() to return ruid (if set)
+      modules/tm: updated t_serial to store/retrieve ruid
+      modules/registrar: tidied up unregister() function
+      modules/ims_isc: updated to include new argument to append_branch()
+      modules/ims_icscf: updated to include new argument to append_branch()
+      modules/exec: updated to include new argument to append_branch()
+      modules/enum: updated to include new argument to append_branch()
+      modules/dialplan: updated to include new argument to append_branch()
+      modules/cpl-c: updated to include new argument to append_branch()
+      modules/corex: updated to include new argument to append_branch()
+      ...
 
-    cdp_avp: added README file
+commit 3445718155b324c3c9e4eac0d6137b6d8dca8cbf
+Merge: e930f94 d6eac37
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 15 11:28:25 2013 +0000
+
+    Merge branch 'outbound'
+    
+    * outbound: (46 commits)
+      modules/registrar: fixed lock usage in unregister()
+      modules/pv: can only retrieve $ruid for a request
+      modules/pv: added new $ruid and $branch(ruid) PVs
+      modules/xprint: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/tm: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/pv: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/permissions: updated use of get_branch() and next_branch() to cope with additional argument
+      modules/domain: updated use of get_branch() and next_branch() to cope with additional argument
+      core: updated use of get_branch() and next_branch() to cope with additional argument
+      core: updated get_branch() and next_branch() to return ruid (if set)
+      modules/tm: updated t_serial to store/retrieve ruid
+      modules/registrar: tidied up unregister() function
+      modules/ims_isc: updated to include new argument to append_branch()
+      modules/ims_icscf: updated to include new argument to append_branch()
+      modules/exec: updated to include new argument to append_branch()
+      modules/enum: updated to include new argument to append_branch()
+      modules/dialplan: updated to include new argument to append_branch()
+      modules/cpl-c: updated to include new argument to append_branch()
+      modules/corex: updated to include new argument to append_branch()
+      modules/avpops: updated to include new argument to append_branch()
+      ...
 
-commit 85cd6662b7f5e0fee477550088cc4ca546193b36
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Tue Jul 3 12:40:43 2012 +0200
+commit d6eac37fb61a79e7d99b749aa20ff903523ff2d0
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 15 11:15:16 2013 +0000
 
-    CDP: Fixed README
+    modules/registrar: fixed lock usage in unregister()
 
-commit a4a1e5d6b0f5aab70d0395adfc5e10ee8a277b1e
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Tue Jul 3 12:14:21 2012 +0200
+commit 86440c81639e1aff66e7449a121ac8ae6d43197a
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 15 11:14:06 2013 +0000
 
-    CDP: A few fixes to docs and location of image files - cleaner organisation
+    modules/pv: can only retrieve $ruid for a request
+    
+    - cache it in an avp for the request if you need it later
 
-commit 3c085d120d49abec97019103f4c210ebdcaf1ed6
-Author: Jason Penton <jason.penton at smilecoms.com>
-Date:   Tue Jul 3 11:24:36 2012 +0200
+commit e930f94b71d2e5c40fa44d78738ce5efb747c5b1
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Fri Mar 15 09:03:26 2013 +0100
 
-    new modules: CDP (C Diameter Peer) and CDP_AVP
-    	- These modules were originally written by Fraunhofer and have been
-    	  ported to Kamailio, with some minor additions and improvements. Examples
-    	  on using the modules to come shortly - diameter_rx, diameter_ro, etc
+    ims_icscf: fix include list for BSD
+    
+    - patch by Victor V. Kustov
 
-commit b66cd6508d9bff106a88fbbd1c649e492b6d742c
+commit 44e43d541baf52a327485d8627de3b95961bdaf9
+Merge: b53624e 81b5473
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jul 1 22:21:38 2012 +0100
+Date:   Fri Mar 15 00:02:38 2013 +0000
 
-    modules/websockets: Added some extra debug/diagnostics
+    Merge branch 'master' into outbound
+    
+    * master:
+      sca: fix private hold handling
+      xhttp_pi: escape special characters
 
-commit ba0ff3123a223365c07a0d2ffa85d2d150f86bce
+commit b53624e388c283ae1294bf595af123c3b77f6b93
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jul 1 22:20:36 2012 +0100
+Date:   Thu Mar 14 23:55:14 2013 +0000
 
-    core: Updated Via and Record-Route generation for WebSockets
+    modules/pv: added new $ruid and $branch(ruid) PVs
 
-commit 3d4a77d86a879d55f8b39bc2a86bc2f51d0258f9
+commit 0137a2a91d29cbd80829b79dcb4cfd9659b7e9be
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 22:53:00 2012 +0100
+Date:   Thu Mar 14 23:35:02 2013 +0000
 
-    core: Added more PROTO_WS and PROTO_WSS checks
+    modules/xprint: updated use of get_branch() and next_branch() to cope with additional argument
 
-commit 56767ad8cb445f8475c6372c964c4d57fb40a500
+commit 0860555382575943b5f704b53a48e63db90754d8
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 22:52:26 2012 +0100
+Date:   Thu Mar 14 23:34:48 2013 +0000
 
-    modules/websocket: Removed SIPp script and HTML file from example directory
+    modules/tm: updated use of get_branch() and next_branch() to cope with additional argument
 
-commit fd2a237fbac519ad709c5f169cbc3f29b125409f
-Merge: b66e815 8c789cd
+commit a16fb22d12696f707839f7b97da471d02121e228
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 21:13:58 2012 +0100
+Date:   Thu Mar 14 23:34:34 2013 +0000
 
-    Merge branch 'master' into websocket
-    
-    Conflicts:
-    	pkg/kamailio/fedora/16/kamailio.spec
+    modules/pv: updated use of get_branch() and next_branch() to cope with additional argument
 
-commit 8c789cdeb969af921e74a4ece194ccda5c297e6a
+commit cb68cab9ce13142592590042283ca1aa3f85ac84
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 21:05:40 2012 +0100
+Date:   Thu Mar 14 23:34:18 2013 +0000
 
-    pkg/kamailio/fedora: Updated some packaging related stuff
-    
-    - Updated the rel in the .spec to dev1
-    - Replaced local %{_sharedir} macro in .spec with standard %{_datadir} macro
-    - Tweak/update to Fedora 16 test appliance
-    - Added BoxGrinder appliances for Fedora 17
+    modules/permissions: updated use of get_branch() and next_branch() to cope with additional argument
 
-commit b66e815ebe9ee9a5035abaf08c6e97a9c3281dcc
+commit f63b55b96e9a2900cf73183fdaa41992c3c31dc5
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 20:36:00 2012 +0100
+Date:   Thu Mar 14 23:34:01 2013 +0000
 
-    modules/websocket: Corrected output of ws.dump MI command
+    modules/domain: updated use of get_branch() and next_branch() to cope with additional argument
 
-commit 6fe3e10b4a17c166f642500748392a9bcb72cabd
+commit 55e069d5c169d9022582c51a9bce82adc136c29c
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 20:35:10 2012 +0100
+Date:   Thu Mar 14 23:33:23 2013 +0000
 
-    core: Fixed segmentation fault
-    
-    - Tiny window for this...  but I hit it when Google Chrome crashed during
-      a WebSocket session
+    core: updated use of get_branch() and next_branch() to cope with additional argument
 
-commit 5456e4e90c6330877e0d25d14fba143f2f98f8c6
+commit 8e6c690ea3cdfd9dd1349f2ce144d7dfd432b50d
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 00:46:20 2012 +0100
+Date:   Thu Mar 14 23:32:42 2013 +0000
 
-    modules/websocket: Updated connection reuse and closing flags for WebSocket handshake.
-    
-    - Updated the sample kamailio.cfg to match too.
+    core: updated get_branch() and next_branch() to return ruid (if set)
 
-commit dc7fa93f2e60efd2f7d428762590fa313e3fe91f
+commit 87e624ffe1e66104b04d34bd2102f458f5785bf0
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 00:02:29 2012 +0100
+Date:   Thu Mar 14 23:16:27 2013 +0000
 
-    modules/websocket: improved sample kamailio.cfg for WebSockets
+    modules/tm: updated t_serial to store/retrieve ruid
 
-commit 1e2f18da2f2c8791f804b33e96dea043f18642bf
+commit dd90d9685cb66843ff48c55b0100de9f98bfdf52
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 30 00:01:07 2012 +0100
+Date:   Thu Mar 14 23:05:32 2013 +0000
 
-    everything: shotgun attempt to put PROTO_WS and PROTO_WSS across core and in modules I use
-    
-    - Bound to have missed something and lots of testing required.
+    modules/registrar: tidied up unregister() function
 
-commit 9349870abc5eb0688cf0fd50c0fa54098158fa79
+commit b49ea76814d2933bb9bc58f82230c4569be171af
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 23:11:15 2012 +0100
+Date:   Thu Mar 14 22:58:44 2013 +0000
 
-    core: rolled back changes to receive.c
-    
-    - Not actually needed because the recent change to ws_frame.c covers it all
-      (I think)
+    modules/ims_isc: updated to include new argument to append_branch()
 
-commit 636a6dabd14e08f2255e52a58353822642deda10
+commit 01f4a316eeb2ed9b7110cb5ee8c96c4923b9acaa
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 23:08:19 2012 +0100
+Date:   Thu Mar 14 22:58:24 2013 +0000
 
-    modules/websocket: Make sure that all WebSocket messages are sent on connections that already exist
-    
-    - This is the same as using set_forward_no_connect() and
-      set_reply_no_connect() in kamailio.cfg.  But this means it will
-      always happen automatically for WebSocket messages.
-    - This is important as a WebSocket server cannot create connections -
-      so we always have to use one that already exists.
+    modules/ims_icscf: updated to include new argument to append_branch()
 
-commit 242920ec30af3a954f8a193d417c671a29d383b4
+commit 4ed5c06088fc87a32ecb59a291f83e947aee7070
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 23:05:48 2012 +0100
+Date:   Thu Mar 14 22:58:04 2013 +0000
 
-    core: Make sure that responses to requests received on a WebSocket are sent on existing connections
-    
-    - WebSocket servers cannot create connections to WebSocket clients - so
-      this setting is essential.
-    - It does exactly the same thing as using set_reply_no_connect() in
-      kamailio.cfg - but this way it is always on (as it must be) for
-      WebSockets.
+    modules/exec: updated to include new argument to append_branch()
 
-commit 915894b15d9096388a0136d2d2bdf48ef65b4c4a
+commit 08b7df7556f6677ed6049825cf20155162269fd4
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 23:03:15 2012 +0100
+Date:   Thu Mar 14 22:57:49 2013 +0000
 
-    modules_k/nathelper: Added nat_uac_test() check for WebSockets
-    
-    - At the moment (and until Kamailio and _all_ WebSocket clients support
-      outbound) we want to treat WebSocket UAs as behind NATs (even when they
-      are not).
-    - This is so that the aliasing (which is good for TCP/TLS connection reuse
-      as well as NAT traversal) can be used to make sure messages to WebSocket
-      UAs are routed correctly.
+    modules/enum: updated to include new argument to append_branch()
 
-commit 353ad95af22d7a4c7d20aebbed291fef085867ba
+commit dab406ed0301bfea5a9e6234119082e445dd5806
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 17:47:22 2012 +0100
+Date:   Thu Mar 14 22:57:30 2013 +0000
 
-    modules/websockets: Changes WS to be a protocol in its own right instead of a flag on TCP/TLS connections
+    modules/dialplan: updated to include new argument to append_branch()
 
-commit 8c4d2e7379e783ac22b63266c3a63a2579100d87
+commit cb10662ae458b799d9746948aba59fb513af318d
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 17:47:06 2012 +0100
+Date:   Thu Mar 14 22:57:06 2013 +0000
 
-    modules_k/nathelper: Added PROTO_WS support
+    modules/cpl-c: updated to include new argument to append_branch()
 
-commit d08c4dc3341d2f2ac497a81fed9aef522ce16ed9
+commit 4d3639a674af7ae8102e3ae3e94e84674d9848ae
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 17:46:36 2012 +0100
+Date:   Thu Mar 14 22:56:51 2013 +0000
 
-    modules/tm: Added PROTO_WS support
+    modules/corex: updated to include new argument to append_branch()
 
-commit 8393efff31843b04b45e6bf728469b32625e86b0
+commit bc8fd8b3b458bf088a83e6c6f17bd21743aaf8e9
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 29 17:44:15 2012 +0100
+Date:   Thu Mar 14 22:56:27 2013 +0000
 
-    core: Changed WS from being a flag on a TCP/TLS connection to a protocol in its own right
-    
-    - Also added ;transport=ws parameter parsing for URIs
+    modules/avpops: updated to include new argument to append_branch()
 
-commit 9d720b83c9dd27e927627132ec052b15efeba518
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jun 29 16:06:42 2012 +0200
+commit 821d92298d22c6fa2d17e85b3c0f021cd0dbeb8e
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 22:55:46 2013 +0000
 
-    kamailio.cfg: use add_contact_alias()/handle_uri_alias() for NATed calls
+    modules/alias_db: updated to include new argument to append_branch()
 
-commit 6cfc7ccda69803e8767cfd125a263e9fcafb895d
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jun 29 12:34:08 2012 +0200
+commit 4fb8d035a952e1f719e60470e7bea2e3877331d5
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 22:46:51 2013 +0000
 
-    Makefile.defs: version set to 3.4.0-dev1
+    core: updated to include new argument for append_branch()
 
-commit bd346c4d541a87b2fed17261eaf6f10b29443574
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jun 29 12:28:07 2012 +0200
+commit ac7b94dbd991ba5c25d9afece2b6172b829f514b
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 22:46:08 2013 +0000
 
-    kamailio.cfg: set version to 3.4 in the top comments
+    modules/registrar: fill in ruid in msg and branch structures during lookup()
 
-commit 6da3e961d7f0d302b8f275aec07abfd411bcf875
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jun 29 12:25:24 2012 +0200
+commit e3ba8f38f7bd008f72705fb6acd082e65b5a140e
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 22:42:16 2013 +0000
 
-    tm: added t_is_set("target") function
-    
-    - returns true if the attribute specified by the target parameter is set
-      for current transaction (e.g., failure_route, branch_route,
-      onreply_route)
-    - on_negative was replaced with on_failure internally to be consistent
-      with config file naming
+    core: added ruid to msg and branch structures
 
-commit 8c6f700b4213552789fa97c4edf0ff4bb4b61f90
+commit 0e634d5828ec7e2c9418089007cdac0318e4aced
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 28 17:57:44 2012 +0100
+Date:   Thu Mar 14 22:00:54 2013 +0000
 
-    core: added support for WS keyword for use in conditionals with proto and snd_proto
+    modules/registrar: fixed typo
 
-commit d07a57f6849e94764302939541157c71d73eae6a
+commit f892c3c87b181c4b3d32b080f2dbb8ba0b88807f
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 28 17:55:53 2012 +0100
+Date:   Thu Mar 14 21:57:59 2013 +0000
 
-    core: fixed an issue where big websocket requests (single WS frame but across multiple packets) weren't handled
+    parser: fixed typo
 
-commit 3269116331b5161cd08aba390a0e3804dafdf668
+commit 98c0aa3930031e681f0211bc7f07e208c2288703
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 28 17:54:45 2012 +0100
+Date:   Thu Mar 14 21:55:34 2013 +0000
 
-    core: Fix to msg_send() so that requests destined for a WebSocket connection go through the websocket module
-    
-    - responses already worked
+    parser: updated path for some of the includes in files moved from lib/kcore
 
-commit d6f89300f70a8b511a1454eb1742561547b69a52
+commit 19ff7249507118ddfcf34e8dd02407ae3663314f
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 28 17:53:55 2012 +0100
+Date:   Thu Mar 14 21:52:33 2013 +0000
 
-    modules/websockets: tidied up a bit of the code
+    modules/sst: updated path to parse_supported.h
 
-commit f030b2f274b69526f256e66098de72a074000ed1
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jun 28 16:24:47 2012 +0200
+commit 59189c400f807deb92b5ee897ea2e19cc086c500
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 21:52:18 2013 +0000
 
-    p_usrloc: added missing usrloc API members
-    
-    - they are set to NULL to get a clean crash, they have to be implemented
-    - the missing API members are the functions introduced in 3.3 for
-      handling SIP GRUU and Outbound extensions
-    - a proper fix to follow
-    - reported by Dan Bogos
+    modules/rls: updated path to parse_supported.h
 
-commit ccfc9a41d453b05d25396a42aee641a2558e478c
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Thu Jun 28 02:13:54 2012 +0200
+commit 1a920fc0a69916670ad2cd04e85926546e69a2d5
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 21:51:44 2013 +0000
 
-    pkg/deb Fix lsb init file
-    
-    We depend on $remote_fs as required_[start|stop]
+    modules/registrar: updated path to parse_(require|supported).h
 
-commit 79e99ae5cbe7016f22454faf4f9e9f5a463a4f7d
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Thu Jun 28 02:01:11 2012 +0200
+commit 0497e50dfe195e3b633741f2fcb476ff234285f4
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 21:51:11 2013 +0000
 
-    pkg/deb Build kamailio-dbg package
+    modules/ims_registrar_scscf: updated path to parse_supported.h
 
-commit 8d649d042d43c4dc29b2cb747ba87c1f75590713
-Author: Anca Vamanu <anca.vamanu at 1and1.ro>
-Date:   Wed Jun 27 18:34:55 2012 +0300
+commit 96347fb3b2d747712c52579abec081b8eec545d1
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Thu Mar 14 21:50:20 2013 +0000
 
-    modules_k/presence_xml Xcap auth reason when user deleted from list
-    
-    The reason in Subscription-Status header in Notify when a user is
-    deleted from the contact list can be decided by the admin by setting
-    presence_xml module parameter xcapauth_usedel_reason. Default value is
-    "probation".
-    (cherry picked from commit 3abf967f61a1bd95c28d4e8a929a8bd5df00671d)
+    lib/kcore, parser: moved parse_(options_tags|require|supported) to parser
 
-commit 3a2e929c63c656fe2db78e746546af05c66740ea
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jun 25 18:36:18 2012 +0200
+commit 81b5473f5a191a5aa81295acf0d96a22160f7f31
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Fri Mar 1 16:33:59 2013 -0500
 
-    dialog(k): proper unlock of profile for mi list command
+    sca: fix private hold handling
     
-    - the profile was unlocked in a wrong place, before finishing listing
-      the its content and could cause a race in accessing it
-    - reported by Ricardo Martinez
+    - private hold call-info was being ignored in hold reINVITEs, causing
+      inaccurate "active" notifications to go to subscribers.
 
-commit 2664cb9aa8ffd5d26ef6a0841318ccbcdefbf69b
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jun 25 10:36:31 2012 +0200
+commit a00662049f2f245f53dfb23a07da9229e2ebe159
+Author: Ovidiu Sas <osas at voipembedded.com>
+Date:   Thu Mar 14 12:16:32 2013 -0400
 
-    dispatcher(k): allow set id 0 for OPTIONS callback
-    
-    - set id is provided in param pointer address, 0 being equivalent to
-      NULL
-    - reported by Avi Brender
+    xhttp_pi: escape special characters
 
-commit c270ac0e54ada9cc2599b21f8c87b5a0704093af
+commit 6b4d87a4321f8edefbf93b1323502d4bab965290
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jun 24 00:40:24 2012 +0100
+Date:   Thu Mar 14 14:19:31 2013 +0000
 
-    modules/websocket: improvements to ws.dump MI command
+    modules/registrar: Updated documentation for outbound related modparams
 
-commit 6dfd1476bee55dd6287652b1f9ee9a8cf4d809f0
+commit 2a4300284364c4be42b1e4262966d17e5a546799
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 22:13:35 2012 +0100
+Date:   Thu Mar 14 14:19:05 2013 +0000
 
-    pkg/kamailio/fedora: added WebSocket module to .spec file
+    modules/register: Fixed mod init check of flow_timer modparam
 
-commit 4611d052b9e73f9b301a043da632e28b7ec65bf4
+commit c9f8bfdf7a124c9136b28cf78936ac14cec511b9
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 21:57:37 2012 +0100
+Date:   Thu Mar 14 12:25:52 2013 +0000
 
-    modules/websocket: now using libunistring:u8_check() to work out whether to send text or binary websocket frames
-    
-    - There is no straight-forward (or practical) way to be sure that a SIP request
-      only contains UTF-8 characters and therefore should be sent as text instead
-      of binary.  However, you can sometimes tell whether the request definitely
-      isn't UTF-8 by checking for invalid byte sequences - and when it is definitely
-      not UTF-8 frames _MUST_ be sent as binary.
+    modules/registrar: fixes to checking of Require: and Supported: headers for outbound
 
-commit 7cd27114725b49864b6be812658aa00003c54e99
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 21:57:09 2012 +0100
+commit 1c276452b2880cc47994f17460403c58e0ef5c87
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Thu Mar 14 11:57:55 2013 +0000
 
-    parser: Update Via parsing state-machine to support WS and WSS
+    documentation: Fix Content-Length typos
+    
+    - Fix typos in textops/textopsx documenation
+    - Regenerate cfg list documentation
 
-commit 64406b209d8b4fd9ed127a6b4b965e3c1863c3d2
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 21:55:34 2012 +0100
+commit 90cbe54c01fe9513a0041f19e8a73f3ff7dccaf6
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Thu Mar 14 10:41:24 2013 +0000
 
-    modules/websocket: updated example configuration and test scripts
+    core: Fix Content-Length typos
     
-    - Added options_rx.xml SIPp script
-    - kamailio.cfg routes OPTIONS to SIPp
-    - websocket_test.html now using WSS (WS over TLS)
+    One typo in the HTTP11CONTINUE response headers
+    One in the tcp option help string for 'accept_no_cl'
+    Two in code comments
 
-commit 11a2ad18ea0b263316fe8728aa44b892d7c4fe86
+commit 9e3c6550c02efc1181aba85fc6b7e871fb632da5
+Merge: 9a4afee 289bc23
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 21:52:15 2012 +0100
+Date:   Thu Mar 14 10:10:49 2013 +0000
 
-    core: fixed segmentation fault I had added to forward.h
+    Merge branch 'master' into outbound
+    
+    * master:
+      Makefile.groups: Updated package group for app_java.
 
-commit 1f139814262a4c5979c5301812f81304d885e92c
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 19:10:03 2012 +0100
+commit 289bc2399c09f5f449fd835f9a046597e4f2b38f
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Wed Mar 13 22:29:20 2013 +0200
 
-    core: added events and data-structures so that Kamailio core can transmit through the WebSocket module
+    Makefile.groups: Updated package group for app_java.
 
-commit 50d20ecde5503d11358b86cbd23456e2a302c9be
+commit 9a4afeecf8d1166533fefd4df2afc850a44c9ec3
+Merge: 71c197d 7d46ff0e
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 19:08:38 2012 +0100
+Date:   Wed Mar 13 16:57:11 2013 +0000
 
-    modules/websocket: added generic transmit functions to WebSocket module so Kamailio core can send WebSocket frames
+    Merge branch 'master' into outbound
+    
+    * master: (68 commits)
+      modules/permissions: DNS domain names in address table
+      modules/app_java  - New module app_java: Java Native Interface support.
+      nathelper: Decrease ambiguity by renaming sipping_disable_bflag to natping_disable_bflag
+      registrar: New set_q_override function
+      parser,modules/pv,modules/sipcapture: Improved parsing of P-Asserted/Preferred-Identity headers
+      Makefile.dirs: updated the list with module directories
+      NEWS Update with reference to Wiki
+      INSTALL update for release
+      README - last minute small edits
+      tm: set proper buffer len when Max-Forward header is not added
+      core: try to detect ipv6 addresses only when USE_IPV6 is used
+      pkg: deb specs updated for v4.0.0
+      INSTALL: updates for v4.0.0
+      ChangeLog_k: removed obsolete file
+      ChangeLog: updated content to prepare for v4.0.0
+      sca: fix regression dropping Expires header from SUBSCRIBE replies.
+      sca: move SUBSCRIBE response handling to sca_subscription_reply
+      sca: reject out-of-dialog attempts to seize privately held call.
+      sca: make sca_reply a generic reply function.
+      pkg/kamailio/(centos|fedora): added docbook2X build requirement
+      ...
+    
+    Conflicts:
+    	modules/registrar/save.h
 
-commit 5c4133c2ba036776a1ea3c1f73c51a7d9d518fbe
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 17:37:25 2012 +0100
+commit 7d46ff0e5487d9e925c78a57fd7ee036858f0c15
+Author: avamanu <avamanu at avamanu.(none)>
+Date:   Wed Mar 13 17:49:21 2013 +0200
 
-    modules/websocket: Fixed a couple of connection issues and now dropping received SIP requests into receive_msg()
+    modules/permissions: DNS domain names in address table
     
-    - SIP parser not updated for WS and WSS yet
+    Added the possibility to check also against DNS domain names with
+    allow_address() function.
+    Now in the address table one group can have exact IPs, subnet IPs
+    and DNS domain names.
 
-commit ad7ea60ff5e8e2a8d5b9ddeaca99a2bab7941e70
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 16:07:12 2012 +0100
+commit c5f47af145e19f11fafc3ca570e994185f33542d
+Author: Konstantin Mosesov <ez at voipgroup.org.ua>
+Date:   Wed Mar 13 17:53:54 2013 +0200
 
-    modules/websocket: updated example/test kamailio.cfg to support TLS
-    
-    - Basic WebSocket working over TLS
+    modules/app_java  - New module app_java: Java Native Interface support.
 
-commit 5d8239f5da2176938e0c789b9b2caa493725daa1
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 15:03:48 2012 +0100
+commit 93b2b3ba7951bc84a208fb296b3c7b4e52516389
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Tue Mar 12 09:43:57 2013 -0400
 
-    modules/websocket: finished off WebSocket connection management
+    nathelper: Decrease ambiguity by renaming sipping_disable_bflag to natping_disable_bflag
 
-commit 3a64dffb99cfe098f90fdd5c79adc938ac230bf6
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 23 11:31:50 2012 +0100
+commit 857d35f827e0113d1e24caee1b137e91c3e30b42
+Merge: e84eedf 29f0779
+Author: Jason Penton <jason.penton at smilecoms.com>
+Date:   Tue Mar 12 13:05:19 2013 +0200
 
-    modules/websocket: tidied up some of the WS connection code
+    Merge branch 'master' of ssh://git.sip-router.org/sip-router
 
-commit 2f30521ea903b1805c728d60cccda6b2636cacde
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 22 00:34:24 2012 +0100
+commit 29f0779226712f631eff5664f08cdada96f4eef0
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Mon Mar 11 17:37:12 2013 +0000
 
-    modules/websocket: Closing handshake now working
+    registrar: New set_q_override function
     
-    - Also completed MI commands which allowed me to test Ping and Pong
+    The set_q_override function will override the value of the q parameter
+    from the Contact header in subsequent calls to the save() function for
+    the current request.
+    Currently exported as a C-API function
 
-commit 76f15b97d60b0e1c2c22fabc6c7310b33ad80742
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 21 17:37:08 2012 +0100
+commit 09441e89d3bb10d7a4b8c0192e429a8ca1827461
+Author: Hugh Waite <hugh.waite at crocodile-rcs.com>
+Date:   Mon Mar 11 16:55:23 2013 +0000
+
+    parser,modules/pv,modules/sipcapture: Improved parsing of
+    P-Asserted/Preferred-Identity headers
+    
+    parser:
+    - Abstracted addr-spec parsing from parse_to.c into new file.
+    (parse_addr_spec.c)
+    - Added support for comma separated addr-spec values.
+    - Created new P-Asserted-Identity and P-Preferred-Identity header parsers
+    that parse all instances and allows comma separated values.
+    modules/pv:
+    - Added PV index to $ai, $pu, $pU, $pd and $pn variables to retreive the
+    n'th URI instance. E.g. $(ai[1])
+    modules/sipcapture:
+    - Updated to use the new structure
+    - Maintains previous behaviour - only uses the first URI
+
+commit c72aabf37beb308f99b46f764ee9c01b0d875da3
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 11 15:57:31 2013 +0100
 
-    modules/websocket: More tidying up
+    Makefile.dirs: updated the list with module directories
 
-commit 2af2b3277a8b9fb46c5fa9a5ce38eea072a22663
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 21 16:58:05 2012 +0100
+commit 697a272672e434b017cd7e3c6782c5cefa0f2de8
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Mon Mar 11 11:43:49 2013 +0100
 
-    modules/websocket: fixed typo
+    NEWS Update with reference to Wiki
 
-commit 857b117c5058200b57501868d5d29dab778fbd94
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 21 16:28:57 2012 +0100
+commit 220b782018c3158a05f695eac5b1bff0f7ad239f
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Mon Mar 11 11:36:54 2013 +0100
 
-    modules/websockets: started adding WebSocket connection management to WebSocket module
+    INSTALL update for release
 
-commit 7d35945ec66caa286db66cd55ef56c78f29c434c
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 21 13:50:53 2012 +0100
+commit 0bdc78ffb5e4a2f4d77df39372dad66cdf3c141d
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Mon Mar 11 11:16:09 2013 +0100
 
-    modules/websocket: Added connection close code and tidied up MI commands
+    README - last minute small edits
 
-commit a2f9844c01eb19d42d2a2864213c301c53f9b4ec
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Wed Jun 20 21:08:19 2012 +0200
+commit 2d38b046b6202a35c0adf4c8b61f0d665432dd4f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 11 09:38:37 2013 +0100
 
-    ndb_redis: README file update for unix domain socket support.
+    tm: set proper buffer len when Max-Forward header is not added
+    
+    - reported by Juha Heinanen
 
-commit b20f81a4efc43faed2656170f8b4108f897dffee
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Wed Jun 20 14:59:47 2012 -0400
+commit b035aa9f2cc19d387b1b8f33a7888ffee27a4138
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 10 23:53:26 2013 +0100
 
-    ndb_redis: able to connect to redis server via unix domain socket.
+    core: try to detect ipv6 addresses only when USE_IPV6 is used
     
-    - added unix atribute in server modparam
-    - unix attribute has higher precedence over address and port
+    - reported by Juha Heinanen
 
-commit b260b0ad1bb6c687ef00eb084357d337549ae2ec
-Author: Carsten Bock <carsten at ng-voice.com>
-Date:   Wed Jun 20 15:41:02 2012 +0200
+commit a349d9aab2d95b9b1cbc58870ead9a7294bcdcaa
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 10 22:46:50 2013 +0100
 
-    Disable keeping alive of dialog, if the dialog-api does not provide a dlg_flag.
+    pkg: deb specs updated for v4.0.0
 
-commit 1835cd92f2475ce12a79d972ca6548fbbb857ce4
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Tue Jun 19 13:31:42 2012 -0400
+commit b4ebc4a8164cfee995fb3ed0570702ae0547c0ce
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 10 22:07:11 2013 +0100
 
-    ndb_redis: remove warning: implicit declaration of function redisc_free_reply
+    INSTALL: updates for v4.0.0
 
-commit 06982365e6d361d8fb78e1ece579eb1de87db643
+commit ff04edd6ee7ddc213b346afffeec04a995bf16fa
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jun 19 15:06:03 2012 +0200
+Date:   Fri Mar 8 23:22:06 2013 +0100
 
-    pv: new variable $cnt(...) to count the number of other array variables
-    
-    - for now it supports counting AVPS - $cnt($avp(x) - returns the number
-      of how many AVPs with name x exist
-    - future plans - count headers with same name, xavps ...
+    ChangeLog_k: removed obsolete file
 
-commit b5af0f6622d592f52f53b8c8572fcfe73fab867f
+commit 28111e7943f209ed936a6e9f1d5278d6235cedbb
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Tue Jun 19 15:05:33 2012 +0200
+Date:   Fri Mar 8 23:20:06 2013 +0100
 
-    core: typedefed avp search state structure
+    ChangeLog: updated content to prepare for v4.0.0
 
-commit 95ca295c7db108c688d7f9278d089dcd6660d712
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Tue Jun 19 12:18:30 2012 +0200
+commit 3b557293a33f6f3003fdd62a45e02cf8736b534e
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Mon Mar 4 23:13:53 2013 -0500
 
-    ndb_redis: README file update for redis_free function.
+    sca: fix regression dropping Expires header from SUBSCRIBE replies.
+    
+    - extra_headers.len lacked Expires header length after snprintf.
 
-commit 13bbe5ef4575cb9018bea5b1d6871214ab7287d1
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Tue Jun 19 05:56:24 2012 -0400
+commit d528c27b6fa69530bfde4a6ce83c5d4dcc6499a5
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Sun Mar 3 17:01:53 2013 -0500
 
-    ndb_redis: redis_free function.
+    sca: move SUBSCRIBE response handling to sca_subscription_reply
     
-    - Free an unused ndb_redis reply, including also its inner rplRedis
-    structure.
+    - create necessary headers, pass to newly generic sca_reply function.
 
-commit f457ec98c2208d181bb94ace50b82faed6d707e0
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jun 17 21:31:29 2012 +0100
+commit e565748048d7a6b6fda0a28959e092380c5bc26a
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Sun Mar 3 17:00:44 2013 -0500
 
-    modules/websocket: Filled in MI commands to dump WebSocket connection details and Close a WebSocket
+    sca: reject out-of-dialog attempts to seize privately held call.
+    
+    - per spec, reject with 403 Forbidden.
 
-commit 69c264b19f8b42e4700f9f8523912cf29eeadde5
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jun 17 21:30:33 2012 +0100
+commit d6d71b0e217226fe43491a0e9ba75ec0a6649cd5
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Sun Mar 3 16:59:23 2013 -0500
 
-    core: Fixed a problem with receiving WebSocket frames
+    sca: make sca_reply a generic reply function.
     
-    - If two frames were pulled from the buffer at the same time the second
-      wasn't being processed.
+    - take a pre-filled extra_headers parameter instead, add with add_lump_rpl.
 
-commit d3e770533b908acf73b359ba556a972c1330a118
+commit dd2ef87af7dac6fb1411d58a0dd2e6125b99da80
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jun 17 14:29:44 2012 +0100
+Date:   Thu Mar 7 02:11:35 2013 +0000
 
-    modules/websocket: more work on WebSocket framing and base-protocol
+    pkg/kamailio/(centos|fedora): added docbook2X build requirement
 
-commit c04689c5f5017456a9a5c0f6b617e13ee6f7a1d6
+commit df1af285d60e2d066c2753e8f3815a7dc4f97684
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jun 17 14:28:20 2012 +0100
+Date:   Wed Mar 6 11:08:32 2013 +0000
 
-    core: added clone buf support for WebSocket connections
+    pkg/kamailio/(centos|fedora): re-added perl files
 
-commit d096e24b900856396332ebd61ae854fc044c8971
-Author: Vicente Hernando <vhernando at systemonenoc.com>
-Date:   Sun Jun 17 15:02:43 2012 +0200
+commit f4a4ad8effe41a30705a49da3097818c83d3be6e
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Mar 5 18:35:08 2013 +0100
 
-    ndb_redis: free _redisc_rpl_list.
+    Makefile.groups: fixed typo in the name of perl mods list
     
-    - Free pending redis data to close ndb_redis module in a cleaner way.
+    - reported by Peter Dunkley
 
-commit 68c60fd4156bda792463bd202b82afb2c967dcdd
+commit 3262a99d41a16b478f7186be6334dce901ddc25c
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jun 17 00:44:14 2012 +0100
+Date:   Tue Mar 5 17:08:54 2013 +0000
 
-    modules/websocket: received frame decoding
+    pkg/kamailio/(centos|fedora): updated .spec to match latest changes
 
-commit 62691a52ffd48e4dc674027cfe9b984620a55b88
+commit 76aa97c074ddbdd82217633ff4fb0c6401d1666f
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sun Jun 17 00:43:44 2012 +0100
+Date:   Tue Mar 5 15:53:46 2013 +0000
 
-    core: tidied up websocket frame length code
+    pkg/kamailio/(centos|fedora): updated rel and ver in .spec
 
-commit 1718093cfad0ea8085d20a7b5fd995f93c91a48a
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 16 22:58:36 2012 +0100
+commit 49251e62da99bf05f257e12306cafec614feb408
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Tue Mar 5 17:11:51 2013 +0100
+
+    Makefile.groups: mi_xmlrpc has a dedicated pkg grpup depending on xmlrpc-c library
+
+commit 98be8f70d4df6011991d04b5c0d86a1aac6a0737
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Tue Mar 5 12:09:42 2013 +0100
 
-    core: improved de-buffering for websockets
+    db_sqlite Make sure module compiles on BSD systems too
     
-    - This should handle the case that the full TCP packet hasn't been received
-      when the read function is called.  Not sure how to explicitly test this
-      though.
+    Copied from db_unixodbc/Makefile
 
-commit 74a32e90a9c86c40d9497a9543eedba63556e865
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 16 22:58:00 2012 +0100
+commit 6375044137494f1203f26580e16f63c92225c596
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 4 23:41:31 2013 +0100
 
-    core: make it possible to retrieve TCP connection without updating connection liifetime
+    Makefile.groups: restored outbound as packaging group
 
-commit 68686612a5775e6d677becffa0873028b1c766bb
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 16 22:57:34 2012 +0100
+commit 068e6e5903801ca7cb7d1ca304d35bca70a34b58
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 4 19:56:54 2013 +0100
 
-    modules/websocket: small tidy up to handshake code
+    usrloc: added missing state from AoR contact dump
 
-commit 3ec469611f9f6c57d593c000614f461488b760a3
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 16 17:06:33 2012 +0100
+commit d83b9aefd5afa25b2d18a8bf92357fbd33d627bf
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 4 16:30:34 2013 +0100
 
-    core: Added WS support/events to Kamailio core
+    dispatcher: release lock instead of destroy when cleaning active calls hash table
+    
+    - this could happen when dispatcher list was reloaded
+    - reported and fix by Dmitry, closes FS#275
 
-commit 6d93ce1b8a752e2b3fdb0ff7a3cbef0c7bc44787
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 16 17:05:54 2012 +0100
+commit 1d0e8dd793b3bab7f42ad8e956a704c6f287a6e1
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 4 16:20:13 2013 +0100
 
-    modules/websocket: WS module registering for WS messages and basic handler implementation
+    Makefile.defs: version set to 4.1.0-dev1
 
-commit 48e7ee701571c127effa3b0ddd06468154ddf139
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Sat Jun 16 14:38:22 2012 +0100
+commit 3cf821d9983418d68ca33edc35ff5eb2e592d16f
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 4 16:19:20 2013 +0100
 
-    modules/websocket: more work on module boiler-plate and handshake
-    
-    - Handshake now works with Google Chrome
+    Makefile.groups: refer to pkg groups instead of K
 
-commit 80c4f4b1d9ff31e79c999b82db35c3b9abc56e22
+commit 09c7b67beee9529d6a7c06e600c7f294bf453eda
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Fri Jun 15 17:17:07 2012 +0200
+Date:   Mon Mar 4 16:14:42 2013 +0100
 
-    dialog(k): proper local linking of profile before dlg is created
+    db_postgres: handle prepare statements in DB APIv2
     
-    - reported by Nick R.
+    - patch by  Markus Bucher, closes FS#272
 
-commit 407130579cb10620480e8800558375094aaf07be
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 15 10:17:06 2012 +0100
+commit b5024f320b578c831d3ee13b077bb87954bc61b0
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 4 16:09:36 2013 +0100
 
-    modules/websocket: Improvements to handshake handler
+    Makefile: updated the groups of modules
+    
+    - they are kept in Makefile.groups to keep main Makefile cleaner
+    - most of modules are in lists groupped mostly by dependency
+    - compilation and packaging groups are build using the lists
+    - exclude_modules list is automatically built from all modules without
+      those part of lists with external dependencies
 
-commit 48ba74772c398396e54a3cbb2d6cee9f4065d599
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Fri Jun 15 00:40:28 2012 +0100
+commit 01cbe8bf98d6ad1ef8cf7e0b9f646fde81831fc6
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Mon Mar 4 10:46:01 2013 +0100
 
-    modules/websocket: First attempt a module for websocket support
+    Makefile.defs: -DWITH_AS_SUPPORT is on by default
     
-    - So far this is:
-      - Module boiler-plate
-      - WebSocket handshake
-      - Example/test kamailio.cfg
+    - it was for kamailio flavour only
+    - can be disabled with WITHAS=0 and exclude_modules+=seas
 
-commit 5ed96d257f2d402597a678e4451fd9011786f4a2
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 14 17:43:54 2012 +0100
+commit 23a22e2c8d73843798d66ec1bebe22cf7702213b
+Author: Daniel-Constantin Mierla <miconda at gmail.com>
+Date:   Sun Mar 3 23:53:14 2013 +0100
 
-    modules_k/presence: partial NOTIFYs for presence.winfo not correctly formed when using notifier processes
+    Makefile: split module groups definitions in Makefile.groups
     
-    - I seem to have broken things when I did a pre-merge re-order/clean-up
-      of the code
-    - Issue found by Hugh Waite @ Crocodile RCS and fixed by Hugh Waite and
-      Peter Dunkley @ Crocodile RCS
+    - the part was quite big and it is more config related than build rules
+    - it has to be updated with the current list of modules
 
-commit 78da4d35dfceaa3d167d2b5ad66f1a27bc0f4628
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 14 17:41:49 2012 +0100
+commit 522d06e75bf3c549af007701332f7db53a1b5ab6
+Author: Andrew Mortensen <admorten at isc.upenn.edu>
+Date:   Thu Feb 14 16:55:36 2013 -0500
 
-    modules_k/pua: send_publish() doesn't work correctly in DB only mode with certain DBs
+    sca: fix race condition when two endpoints seize same index simultaneously
     
-    - The pua record wasn't getting inserted in some cases
-    - Looks like I removed a couple of lines I shouldn't have when merging
-      from Crocodile's internal SVN repository to git
-    - Issue found by Hugh Waite @ Crocodile RCS and fixed by Hugh Waite and
-      Peter Dunkley @ Crocodile RCS
+    - return 480 Temporarily Unavailable to loser of race.
 
-commit 9dbe8f9fdff1eb5718698cdcdf2357ee1fabd42b
-Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Thu Jun 14 12:10:35 2012 +0100
+commit 7c940fa74dd0d39d798b5ed63edf8079f24f2bde
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 2 16:25:24 2013 +0100
 
-    modules_k/presence: Fixed segmentation fault when uploading pres-rules documents
-    
-    - Found and fixed by Hugh Waite @ Crocodile RCS
+    pv Minor doc update
 
-commit 1d89d7bea854c2e2c646b5d13ba215795325b50f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Thu Jun 14 12:24:36 2012 +0200
+commit ab1d5bf573b43daf204eb1572083c8f12791a3e1
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 2 15:53:08 2013 +0100
 
-    pua: remove wrong free of TM callback param in send_publish()
+    pv Add RPC commands shvGet and shvSet to manipulate and list shared variables
+
+commit 68094dd3639d1f4cc497e4affb1a89909947c7b3
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 2 09:41:18 2013 +0100
+
+    presence Add RPC command presence.cleanup
+
+commit c2c4c393a3c68ed3fb6fd53a71febdd93398f77c
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 2 07:56:48 2013 +0100
+
+    cfgutils  Add functions for checking if a route exists
     
-    - reported by Charles Chance and Juha Heinanen
+    Adding check_route_exists() and route_if_exists() functions.
 
-commit 748b79fdeba12736b109dfbd77a3e9bb04c80b97
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 13 17:29:51 2012 +0200
+commit 0d69ffe84069e9cd9e41de194cbeff002e3d31b9
+Author: Olle E. Johansson <oej at edvina.net>
+Date:   Sat Mar 2 07:56:21 2013 +0100
 
-    usrloc(k): better safety check for null record access
+    cfgutils documentation
 
-commit 31f404a98b09b5a6270e860574b16c9f9112c305
+commit b23510e0adb6060a257c8662700450ed7faef080
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 13 16:33:17 2012 +0200
+Date:   Fri Mar 1 18:12:23 2013 +0100
 
-    usrloc(k): safety check for first record in udomain slot
+    rtpproxy: proper fixup function for rtpproxy_manage(...)
     
-    - reported by David Kovarik, FS#234
+    - second parameter was resolved as spve type, although fixed as str
+    - reported by  Markus Bucher, FS#273
 
-commit b8201c6dbff5967d1277363d119cbf33590d4112
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Wed Jun 13 15:38:20 2012 +0200
+commit 71c197dfe0b787a2abeadb730fda5241f294237c
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 1 11:41:18 2013 +0000
 
-    Makefile: Add db_cluster
+    modules/registrar: updated module documentation
     
-    Added to standard group as it has no dependencies
+    - Added ruid parameter to unregister
+    - Added missing attributes to $ulc() description
 
-commit 9a310fe940e4b93e13539ccfbd6137ba76dcce87
-Author: Juha Heinanen <jh at tutpro.com>
-Date:   Wed Jun 13 16:25:12 2012 +0300
+commit 0a919692b299e2eb819f7c97fa218189849d4566
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Fri Mar 1 11:19:42 2013 +0000
 
-    modules_k/presence_[dialoginfo|mwi|reginfo]: fixed test of wrong variable
+    modules/registrar: added additional unregister() exported function to allow the removal of a specific contact
+    
+    - Contact is removed by using the ruid (unique ID for the location record)
+    - Getting the ruid to use here is a problem still to be solved.
 
-commit b13434ff7f8e8b1b88434e888c26a77874eceeb0
+commit 65dc9c8cf35fc3e631380d65e8c99e8f84d465cc
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Wed Jun 13 11:47:07 2012 +0100
+Date:   Thu Feb 28 14:40:41 2013 +0000
 
-    modules_k/usrloc: Only run timer when timer_interval > 0
+    modules/registrar: RFC 5626 section 6 support
     
-    - This is useful on DB only multi-server systems when the database is
-      cleaned up outside of Kamailio.
-    - This is a re-instatement of something that worked before the
-      addition of GRUU.
+    - Behaviour when outbound in use but first edge proxy does not
+      support it.
 
-commit c737ff95bb2e742981d81088169baa60d4605b85
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Wed Jun 13 11:51:57 2012 +0200
+commit abc1e61dea4e96235ca54955f664effc66568d6d
+Author: Richard Fuchs <rfuchs at sipwise.com>
+Date:   Wed Feb 27 11:17:03 2013 -0500
 
-    drouting: reset the content of routing tree if root pointer is not freed
+    nathelper: add new option sipping_disable_bflag
     
-    - reported by Yufei Tao
+    sipping_disable_bflag can be set on a per-registration basis
+    to disable NAT pings completely
 
-commit 9fda39db41328a47180a7591713323ca00a140a6
-Author: Jon Bonilla <manwe at aholab.ehu.es>
-Date:   Wed Jun 13 03:16:37 2012 +0200
+commit aabb7adb933185f4bc12dcd82cdee357246c8c2f
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Feb 27 15:29:35 2013 +0000
 
-    pkg/deb Update debian version to 3.4.0~dev0
+    modules/registrar: add Require: outbound to 200 OK when required by client and supported by server
+    
+    - Reported by @oej
 
-commit e037e9ed2b6f3d840c6e8bf18a3caeaa3274f004
+commit 936b6892a8a0ff25b108635e48a146b7cbc3a7ff
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jun 12 14:24:48 2012 +0100
+Date:   Wed Feb 27 14:03:27 2013 +0000
 
-    modules_k/registrar: Fixed merge error in api.c
-    
-    - Issue found and fixed by Hugh Waite @ Crocodile RCS Ltd
+    lib/kcore: added parser for Require: header
 
-commit 76d2424a798a1381f51003a9aa4f174ba243ecc0
+commit be95ad30bf92cce4611f41e7d52d7a12f557e863
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jun 12 02:25:24 2012 +0100
+Date:   Wed Feb 27 14:03:13 2013 +0000
 
-    modules/ipops: Added new exported function is_in_subnet()
-    
-    - Feature added by Hugh Waite @ Crocodile RCS Ltd
+    parser: updated for parse_supported refactoring
 
-commit 0aae547c7f18186372f01b07144b64a646b37971
+commit 167283826a4b534bc68d96e5e8eb6bc686a6d293
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jun 12 02:10:30 2012 +0100
+Date:   Wed Feb 27 14:02:47 2013 +0000
 
-    modules/app_lua: Added registrar:save_uri support
-    
-    - Feature by Hugh Waite @ Crocodile RCS Ltd
+    modules/sst: updated for parse_supported refactoring
 
-commit b4f3aea40c9588d60fb6643c52860a40b9ed994e
+commit 35e981d6c22bf4a5326cad34c2f2aa0d45d77e08
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jun 12 02:07:42 2012 +0100
+Date:   Wed Feb 27 14:02:28 2013 +0000
 
-    modules_k/registrar: Exported save_uri
-    
-    - Feature added by Hugh Waite @ Crocodile RCS Ltd
+    modules/rls: updated for parse_supported refactoring
 
-commit 3d3b1daf319fe87b880671cd5de9a2a6ace6c64b
+commit 6c24a8dfa84d1e92fdd53e4c8c2bd7bc1715ceb5
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Tue Jun 12 02:01:10 2012 +0100
+Date:   Wed Feb 27 14:02:05 2013 +0000
 
-    modules/tls: Fixed log level and diagnostic typo
-    
-    - Fix by Hugh Waite @ Crocodile RCS Ltd
+    modules/registrar: updated for parse_supported refactoring
 
-commit 74641106779c13fa2f6bf2384293e35dc21f3b5a
+commit 2855d20641d171ffcf3e711292cc8648d74ce5b0
 Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
-Date:   Mon Jun 11 22:39:10 2012 +0100
+Date:   Wed Feb 27 14:01:18 2013 +0000
 
-    pkg/kamailio/fedora/16: Updated ver and rel in .spec to 3.4.0 and dev0
+    modules/ims_registrar_scscf: updated for parse_supported refactoring
 
-commit 0c7b9304efd5954cf53ba13a065b05a277efc91f
-Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jun 11 14:32:44 2012 +0200
+commit af75f69a581e19f8008c326f882aae0f65f86ea8
+Author: Peter Dunkley <peter.dunkley at crocodile-rcs.com>
+Date:   Wed Feb 27 13:59:56 2013 +0000
 
-    registrar(k): don't access realm_prefix.s if len is <=0
+    lib/kcore: abstracted the option-tag parsing code out of parse_supported.[ch]
     
-    - solaris is not happy accessing .s struct field if set to 0
+    - This is to make it easier to add parsers for other similar headers
+      (for example, Require:)
 
-commit d42379da90f2ec87cb5dbb00ebb563c7528ec910
+commit 9f9b56088e706970bab2ab644a51d267fabcae6c
 Author: Daniel-Constantin Mierla <miconda at gmail.com>
-Date:   Mon Jun 11 12:32:05 2012 +0200
+Date:   Wed Feb 27 09:22:14 2013 +0100
 
-    Makefile: version set to 3.4.0-dev0
+    Makefile.defs: version set to 4.1.0-dev0
     
-    - development for future major version 3.4.0 is open
+    - master branch is open for adding new features to be part of v4.1.x
 
-
-===================== 2012-06-18 Version 3.3.0 Released =====================
+===================== 2013-03-11 Version 4.0.0 Released =====================
diff --git a/Makefile b/Makefile
index 5351a38..d0e00b9 100644
--- a/Makefile
+++ b/Makefile
@@ -622,6 +622,7 @@ tar: makefile_vars $(auto_gen_keep)
 	$(TAR) -C .. \
 		--exclude=$(notdir $(CURDIR))/test* \
 		--exclude=$(notdir $(CURDIR))/tmp* \
+		--exclude=$(notdir $(CURDIR))/debian \
 		--exclude=$(notdir $(CURDIR))/debian/$(MAIN_NAME) \
 		--exclude=$(notdir $(CURDIR))/debian/$(MAIN_NAME)-* \
 		--exclude=$(notdir $(CURDIR))/$(MAIN_NAME)_tls* \
@@ -1013,6 +1014,50 @@ clean_modules_cfg clean-modules-cfg:
 .PHONY: clean_makefile_vars clean-makefile-vars
 	rm -f Makefile.vars
 
+# clean everything generated - shortcut on maintainer-clean
+.PHONY: pure
+pure: maintainer-clean
+
+.PHONY: install_initd_debian install-initd-debian
+install_initd_debian install-initd-debian:
+	sed -e "s#DAEMON=/usr/sbin/kamailio#DAEMON=$(bin_prefix)/$(bin_dir)$(NAME)#g" \
+		-e "s#NAME=kamailio#NAME=$(NAME)#g" \
+		-e "s#DESC=Kamailio#DESC=$(NAME)#g" \
+		-e "s#HOMEDIR=/var/run/kamailio#HOMEDIR=/var/run/$(NAME)#g" \
+		-e "s#DEFAULTS=/etc/default/kamailio#DEFAULTS=/etc/default/$(NAME)#g" \
+		-e "s#CFGFILE=/etc/kamailio/kamailio.cfg#CFGFILE=$(cfg_prefix)/$(cfg_dir)$(NAME).cfg#g" \
+		< pkg/kamailio/deb/debian/kamailio.init \
+		> /etc/init.d/$(NAME)
+	chmod +x /etc/init.d/$(NAME)
+	sed -e "s#RUN_KAMAILIO=no#RUN_KAMAILIO=yes#g" \
+		< pkg/kamailio/deb/debian/kamailio.default \
+		> /etc/default/$(NAME)
+	mkdir -p /var/run/$(NAME)
+	adduser --quiet --system --group --disabled-password \
+        --shell /bin/false --gecos "$(NAME)" \
+        --home /var/run/$(NAME) $(NAME)
+	chown $(NAME):$(NAME) /var/run/$(NAME)
+
+.PHONY: install_initd_centos install-initd-centos
+install_initd_centos install-initd-centos:
+	sed -e "s#KAM=/usr/sbin/kamailio#KAM=$(bin_prefix)/$(bin_dir)$(NAME)#g" \
+		-e "s#PROG=kamailio#PROG=$(NAME)#g" \
+		-e "s#DEFAULTS=/etc/default/kamailio#DEFAULTS=/etc/default/$(NAME)#g" \
+		-e "s#PID_FILE=/var/run/kamailio.pid#PID_FILE=/var/run/$(NAME).pid#g" \
+		-e "s#LOCK_FILE=/var/lock/subsys/kamailio#LOCK_FILE=/var/lock/subsys/$(NAME)#g" \
+		-e "s#KAMCFG=/etc/kamailio/kamailio.cfg#KAMCFG=$(cfg_prefix)/$(cfg_dir)$(NAME).cfg#g" \
+		< pkg/kamailio/rpm/kamailio.init \
+		> /etc/init.d/$(NAME)
+	chmod +x /etc/init.d/$(NAME)
+	sed -e "s#RUN_KAMAILIO=no#RUN_KAMAILIO=yes#g" \
+		-e "s#USER=kamailio#USER=$(NAME)#g" \
+		-e "s#GROUP=kamailio#GROUP=$(NAME)#g" \
+		< pkg/kamailio/rpm/kamailio.default \
+		> /etc/default/$(NAME)
+	/usr/sbin/groupadd -r $(NAME)
+	/usr/sbin/useradd -r -g $(NAME) -s /bin/false -c "Kamailio Daemon" \
+                  -d ${lib_prefix}/${lib_dir} $(NAME)
+
 .PHONY: dbschema
 dbschema:
 	- at echo "Build database schemas"
diff --git a/Makefile.defs b/Makefile.defs
index ee9f231..480a3f8 100644
--- a/Makefile.defs
+++ b/Makefile.defs
@@ -155,15 +155,17 @@ endif
 
 # application server support on
 WITHAS ?= 1
+# enable core hooks for SCTP
+SCTP ?= 1
 
 # what to install
 INSTALL_FLAVOUR=$(FLAVOUR)
 
-#version number
+# version number
 VERSION = 4
-PATCHLEVEL = 0
-SUBLEVEL = 4
-EXTRAVERSION = 
+PATCHLEVEL = 1
+SUBLEVEL =  0
+EXTRAVERSION =
 
 # memory manager switcher
 # 0 - f_malloc (fast malloc)
@@ -172,7 +174,7 @@ MEMMNG ?= 1
 # memory debugger switcher
 # 0 - off (no-debug mode)
 # 1 - on (debug mode)
-MEMDBG ?= 0
+MEMDBG ?= 1
 
 SER_VER = $(shell expr $(VERSION) \* 1000000 + $(PATCHLEVEL) \* 1000 + \
 			$(SUBLEVEL) )
@@ -647,8 +649,6 @@ data_target = $(prefix)/$(data_dir)
 # -DPROFILING
 #		if enabled profiling will be enabled for child processes
 #		Don't forget to set PROFILE (see below)
-# -DUSE_STUN
-#		compiles in stun support
 # -DNO_SIG_DEBUG
 #        turns off debugging messages in signal handlers (which might be 
 #         unsafe)
@@ -682,7 +682,6 @@ C_DEFS= $(extra_defs) \
 	 -DPKG_MALLOC \
 	 -DSHM_MEM  -DSHM_MMAP \
 	 -DDNS_IP_HACK \
-	 -DUSE_IPV6 \
 	 -DUSE_MCAST \
 	 -DUSE_TCP \
 	 -DDISABLE_NAGLE \
@@ -752,10 +751,6 @@ ifeq ($(WITHAS), 1)
 	C_DEFS+= -DWITH_AS_SUPPORT
 endif
 
-ifneq ($(STUN),)
-	C_DEFS+= -DUSE_STUN
-endif
-
 ifeq ($(mode),)
 	mode = release
 endif
@@ -843,6 +838,7 @@ endif
 
 ifeq ($(ARCH), arm6)
 	use_fast_lock=yes
+	C_DEFS+=-DNOSMP # very unlikely to have an smp arm
 endif
 
 ifeq ($(ARCH), ppc)
@@ -1765,10 +1761,6 @@ ifeq ($(OS), linux)
 			LIBS+=-lpthread
 		endif
 	endif
-	ifneq (,$(findstring -DUSE_DNSSEC, $(C_DEFS)))
-		LIBS+=-lval-threads -lcrypto -lsres -lpthread
-$(info "using libval for DNSSEC validation")
-	endif
         # check for >= 2.5.44
 
 	ifeq ($(shell [ $(OSREL_N) -ge 2005044 ] && echo has_epoll), has_epoll)
@@ -1794,31 +1786,6 @@ $(info "using libval for DNSSEC validation")
 	ifeq ($(NO_SELECT),)
 		C_DEFS+=-DHAVE_SELECT
 	endif
-	# sctp support
-	ifeq ($(SCTP),1)
-		# test to see if the devfiles and lib are installed
-		sctp_dev_locations := /usr/include/netinet/sctp.h \
-								$(LOCALBASE)/include/netinet/sctp.h
-		sctp_lib_locations := /usr/lib/libsctp.so \
-								/usr/lib64/libsctp.so \
-								$(LOCALBASE)/usr/local/lib/libsctp.so
-		sctp_dev_path := $(wildcard $(sctp_dev_locations))
-		sctp_lib_path := $(wildcard $(sctp_lib_locations))
-		ifeq ($(sctp_dev_path),)
-$(info "sctp development files not installed -- sctp disabled")
-			override SCTP := 
-		endif
-		ifeq ($(sctp_lib_path),)
-$(info "sctp libraries not installed -- sctp disabled")
-			override SCTP := 
-		endif
-		
-		ifeq ($(SCTP),1)
-			# use lksctp
-			C_DEFS+=-DUSE_SCTP
-			LIBS+=-lsctp
-		endif
-	endif # SCTP
 endif
 
 ifeq  ($(OS), solaris)
@@ -1893,26 +1860,6 @@ ifeq ($(OS), freebsd)
 		C_DEFS+=-DHAVE_SELECT
 	endif
 	YACC=yacc
-	# sctp support
-	ifeq ($(SCTP),1)
-		# test to see if the devfiles and lib are installed
-		sctp_dev_locations := /usr/include/netinet/sctp.h \
-								$(LOCALBASE)/include/netinet/sctp.h
-		sctp_dev_path := $(wildcard $(sctp_dev_locations))
-		ifeq ($(sctp_dev_path),)
-$(info "sctp development files not installed -- sctp disabled")
-			override SCTP := 
-		endif
-		ifeq ($(shell [ $(OSREL_N) -lt 7000 ] && echo sctp), sctp)
-$(info "old freebsd version (>= 7.0 needed) -- sctp disabled")
-			override SCTP := 
-		endif
-		
-		ifeq ($(SCTP),1)
-			C_DEFS+=-DUSE_SCTP
-			LIBS+=  # no extra libs needed on freebsd
-		endif
-	endif # SCTP
 endif
 
 ifeq ($(OS), dragonfly)
@@ -1935,29 +1882,6 @@ ifeq ($(OS), dragonfly)
 		C_DEFS+=-DHAVE_SELECT
 	endif
 	YACC=yacc
-	# sctp support
-	ifeq ($(SCTP),1)
-		# test to see if the devfiles and lib are installed
-		sctp_dev_locations := /usr/include/netinet/sctp.h \
-								$(LOCALBASE)/include/netinet/sctp.h
-		sctp_dev_path := $(wildcard $(sctp_dev_locations))
-		ifeq ($(sctp_dev_path),)
-$(info "sctp development files not installed -- sctp disabled")
-			override SCTP :=
-		endif
-		# FIXME: don't know what's the status of SCTP on dragonfly
-		#        (we suppose the 2.6 version is >= the version in
-		#         in freebsd 7.0)
-		ifeq ($(shell [ $(OSREL_N) -lt 2006 ] && echo sctp), sctp)
-$(info "old dragonfly version (>= 2.6 needed) -- sctp disabled")
-			override SCTP :=
-		endif
-		
-		ifeq ($(SCTP),1)
-			C_DEFS+=-DUSE_SCTP
-			LIBS+=  # no extra libs needed on freebsd
-		endif
-	endif # SCTP
 endif
 
 ifeq ($(OS), openbsd)
@@ -2064,9 +1988,9 @@ ifeq ($(OS), darwin)
 endif
 
 ifneq (,$(findstring cygwin, $(OS)))
-	# cygwin doesn't support IPV6 and doesn't support fd passing so no TCP
-	#C_DEFS:=$(filter-out -DUSE_IPV6 -DUSE_TCP, $(C_DEFS))
-	DEFS_RM+=-DUSE_IPV6 -DUSE_TCP
+	# cygwin does support IPV6 starting from version 1.7, but (still?) doesn't support fd passing so no TCP
+	#C_DEFS:=$(filter-out -DUSE_TCP, $(C_DEFS))
+	DEFS_RM+=-DUSE_TCP
 	C_DEFS+=-DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
 			-DHAVE_MSG_NOSIGNAL -DHAVE_MSGHDR_MSG_CONTROL -DHAVE_ALLOCA_H \
 			-DHAVE_TIMEGM -DHAVE_SCHED_SETSCHEDULER
@@ -2100,11 +2024,6 @@ LIBS+= -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib -lssl -lcrypto \
 #       E.g.: make CORE_TLS=1 EXTRA_TLS_LIBS="-lz -lkrb5"
 endif
 
-ifneq ($(STUN),)
-C_INCLUDES+= -I$(LOCALBASE)/ssl/include
-LIBS+= -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib -lcrypto
-endif
-
 ifneq ($(found_lock_method), yes)
 $(warning	No locking method found so far, trying SYS V sems)
 		C_DEFS+= -DUSE_SYSV_SEM  # try sys v sems
diff --git a/Makefile.groups b/Makefile.groups
index aa41e71..d1cad86 100644
--- a/Makefile.groups
+++ b/Makefile.groups
@@ -13,12 +13,12 @@ mod_list_basic=async auth benchmark blst cfg_rpc cfgutils corex counters \
 				   mediaproxy mi_datagram mi_fifo mi_rpc mqueue \
 				   nat_traversal nathelper path pike pv ratelimit rr rtimer \
 				   rtpproxy sanity sdpops siputils sl statistics textops \
-				   textopsx tm tmx topoh xlog
+				   textopsx tm tmx topoh xlog rtpproxy-ng stun
 
 # - extra used modules, with no extra dependency
-mod_list_extra=avp auth_diameter call_control dmq domainpolicy msrp pdb qos \
-				 sca seas sms sst timer tmrec uac_redirect xhttp xhttp_rpc \
-				 xprint
+mod_list_extra=avp auth_diameter call_control cnxcc dmq domainpolicy msrp pdb \
+			     qos sca seas sms sst timer tmrec uac_redirect xhttp \
+				 xhttp_rpc xprint
 
 # - common modules depending on database
 mod_list_db=acc alias_db auth_db avpops cfg_db db_text db_flatstore \
@@ -92,9 +92,18 @@ mod_list_tlsdeps=auth_identity tls
 # - modules depending on openssl library
 mod_list_outbound=outbound
 
-# - modules depending on unistring library
+# - modules depending on openssl and unistring library
 mod_list_websocket=websocket
 
+# - modules depending on libval-threads libcrypto libsres libpthread
+mod_list_dnssec=dnssec
+
+# - modules depending on libsctp
+mod_list_sctp=sctp
+
+# - modules depending on openssl library
+mod_list_autheph=auth_ephemeral
+
 # - modules related to SIMPLE presence extensions
 mod_list_presence=presence presence_conference presence_dialoginfo \
 					   presence_mwi presence_profile presence_reginfo \
@@ -134,11 +143,14 @@ mod_list_mono=app_mono
 # - modules related to IMS extensions
 mod_list_ims=cdp cdp_avp dialog_ng ims_auth ims_isc ims_icscf ims_qos \
 			   ims_registrar_pcscf ims_registrar_scscf ims_usrloc_pcscf \
-			   ims_usrloc_scscf
+			   ims_usrloc_scscf ims_charging
 
 # - modules depending on osp toolkit library
 mod_list_osp=osp
 
+# - modules depending on java library
+mod_list_java=app_java
+
 # - modules depending on iptables library
 mod_list_iptrtpproxy=iptrtpproxy
 
@@ -161,7 +173,9 @@ mod_list_all=$(sort $(mod_list_basic) $(mod_list_extra) \
 			   $(mod_list_mono) $(mod_list_ims) \
 			   $(mod_list_cassandra) $(mod_list_oracle) \
 			   $(mod_list_iptrtpproxy) $(mod_list_mi_xmlrpc) \
-			   $(mod_list_outbound) $(mod_list_osp) )
+			   $(mod_list_outbound) $(mod_list_osp) \
+			   $(mod_list_java) $(mod_list_dnssec) \
+			   $(mod_list_sctp) $(mod_list_autheph))
 
 
 
@@ -307,6 +321,17 @@ module_group_kims=$(mod_list_ims)
 # pkg outbound module
 module_group_koutbound=$(mod_list_outbound)
 
+# pkg java module
+module_group_kjava=$(mod_list_java)
+
+# pkg dnssec module
+module_group_kdnssec=$(mod_list_dnssec)
+
+# pkg sctp module
+module_group_ksctp=$(mod_list_sctp)
+
+# pkg auth_ephemeral module
+module_group_kautheph=$(mod_list_autheph)
 
 # list of static modules
 #
diff --git a/README b/README
index e0eae66..cf5fff4 100644
--- a/README
+++ b/README
@@ -1,18 +1,21 @@
-$Id$
 
 
-                Welcome to Kamailio v4.0!
+Kamailio v4.1
+=============
 
-                http://www.kamailio.org/
-                ==========================
+http://www.kamailio.org
+
+Table of contents
+  I.   About Kamailio
+  II.  Feature List
+  III. Getting started
+  IV.  About the project
+  V.   Obtaining Help
+  VI.  More Information
 
-I.   About Kamailio
-II.  Feature List
-III. Getting started
-IV.  About the project
-V.   Obtaining Help
-VI.  More Information
 
+I. About Kamailio
+=================
 
 Kamailio is an industrial-strength, free server for realtime communication,
 based on the Session Initiation Protocol (SIP RFC3261). 
diff --git a/action.c b/action.c
index e64cf81..5fa50ee 100644
--- a/action.c
+++ b/action.c
@@ -89,7 +89,7 @@
 #include "tcp_server.h"
 #endif
 #ifdef USE_SCTP
-#include "sctp_server.h"
+#include "sctp_core.h"
 #endif
 #include "switch.h"
 #include "events.h"
@@ -111,7 +111,30 @@
 int _last_returned_code  = 0;
 struct onsend_info* p_onsend=0; /* onsend route send info */
 
+/* current action executed from config file */
+static cfg_action_t *_cfg_crt_action = 0;
 
+/* return current action executed from config file */
+cfg_action_t *get_cfg_crt_action(void)
+{
+	return _cfg_crt_action;
+}
+
+/* return line in config for current executed action */
+int get_cfg_crt_line(void)
+{
+	if(_cfg_crt_action==0)
+		return 0;
+	return _cfg_crt_action->cline;
+}
+
+/* return name of config for current executed action */
+char *get_cfg_crt_name(void)
+{
+	if(_cfg_crt_action==0)
+		return 0;
+	return _cfg_crt_action->cfile;
+}
 
 /* handle the exit code of a module function call.
  * (used internally in do_action())
@@ -423,9 +446,11 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 						case PROTO_UDP:
 #ifdef USE_TCP
 						case PROTO_TCP:
+						case PROTO_WS:
 #endif
 #ifdef USE_TLS
 						case PROTO_TLS:
+						case PROTO_WSS:
 #endif
 #ifdef USE_SCTP
 						case PROTO_SCTP:
@@ -509,7 +534,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 			ret=append_branch(msg, &a->val[0].u.str, &msg->dst_uri,
 					  &msg->path_vec, a->val[1].u.number,
 					  (flag_t)flags, msg->force_send_socket,
-					  0, 0);
+					  0, 0, 0, 0);
 			/* if the uri is the ruri and q was also not changed, mark
 			   ruri as consumed, to avoid having an identical branch */
 			if ((a->val[0].u.str.s == 0 || a->val[0].u.str.len == 0) &&
@@ -1570,7 +1595,9 @@ int run_actions(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 	for (t=a; t!=0; t=t->next){
 		if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0))
 			ms = TICKS_TO_MS(get_ticks_raw());
+		_cfg_crt_action = t;
 		ret=do_action(h, t, msg);
+		_cfg_crt_action = 0;
 		if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)) {
 			ms = TICKS_TO_MS(get_ticks_raw()) - ms;
 			if(ms >= cfg_get(core, core_cfg, latency_limit_action)) {
diff --git a/action.h b/action.h
index a2a5395..2ef00f7 100644
--- a/action.h
+++ b/action.h
@@ -68,6 +68,9 @@ int run_actions(struct run_act_ctx* c, struct action* a, struct sip_msg* msg);
 
 int run_top_route(struct action* a, sip_msg_t* msg, struct run_act_ctx* c);
 
+cfg_action_t *get_cfg_crt_action(void);
+int get_cfg_crt_line(void);
+char *get_cfg_crt_name(void);
 
 #ifdef USE_LONGJMP
 int run_actions_safe(struct run_act_ctx* c, struct action* a,
diff --git a/autover.h b/autover.h
index 3624852..3314601 100644
--- a/autover.h
+++ b/autover.h
@@ -2,6 +2,6 @@
  * DO NOT EDIT IT
  */
 
-#define REPO_VER "cabe58"
-#define REPO_HASH "cabe58"
+#define REPO_VER "350d2e"
+#define REPO_HASH "350d2e"
 #define REPO_STATE ""
diff --git a/cfg.lex b/cfg.lex
index 5a7ce8a..8e60c1e 100644
--- a/cfg.lex
+++ b/cfg.lex
@@ -337,6 +337,7 @@ AVP_PREF	(([ft][rud]?)|g)\.
 DEBUG	debug
 FORK	fork
 FORK_DELAY	fork_delay
+MODINIT_DELAY	modinit_delay
 LOGSTDERROR	log_stderror
 LOGFACILITY	log_facility
 LOGNAME		log_name
@@ -359,6 +360,7 @@ DNS_RETR_NO		dns_retr_no
 DNS_SERVERS_NO	dns_servers_no
 DNS_USE_SEARCH	dns_use_search_list
 DNS_SEARCH_FMATCH	dns_search_full_match
+DNS_NAPTR_IGNORE_RFC	dns_naptr_ignore_rfc
 /* dns cache */
 DNS_CACHE_INIT	dns_cache_init
 DNS_USE_CACHE	use_dns_cache
@@ -392,7 +394,6 @@ CHILDREN children
 SOCKET_WORKERS socket_workers
 CHECK_VIA	check_via
 PHONE2TEL	phone2tel
-SYN_BRANCH syn_branch
 MEMLOG		"memlog"|"mem_log"
 MEMDBG		"memdbg"|"mem_dbg"
 MEMSUM		"mem_summary"
@@ -453,25 +454,6 @@ TLS_SEND_TIMEOUT	"tls_send_timeout"
 DISABLE_SCTP	"disable_sctp"
 ENABLE_SCTP	"enable_sctp"
 SCTP_CHILDREN	"sctp_children"
-SCTP_SOCKET_RCVBUF	"sctp_socket_rcvbuf"|"sctp_socket_receive_buffer"
-SCTP_SOCKET_SNDBUF	"sctp_socket_sndbuf"|"sctp_socket_send_buffer"
-SCTP_AUTOCLOSE	"sctp_autoclose"
-SCTP_SEND_TTL	"sctp_send_ttl"
-SCTP_SEND_RETRIES	"sctp_send_retries"
-SCTP_ASSOC_TRACKING	"sctp_assoc_tracking"
-SCTP_ASSOC_REUSE	"sctp_assoc_reuse"
-SCTP_MAX_ASSOCS		"sctp_max_assocs"
-SCTP_SRTO_INITIAL	"sctp_srto_initial"
-SCTP_SRTO_MAX		"sctp_srto_max"
-SCTP_SRTO_MIN		"sctp_srto_min"
-SCTP_ASOCMAXRXT		"sctp_asocmaxrxt"
-SCTP_INIT_MAX_ATTEMPTS		"sctp_init_max_attempts"
-SCTP_INIT_MAX_TIMEO			"sctp_init_max_timeo"
-SCTP_HBINTERVAL				"sctp_hbinterval"
-SCTP_PATHMAXRXT				"sctp_pathmaxrxt"
-SCTP_SACK_DELAY				"sctp_sack_delay"
-SCTP_SACK_FREQ				"sctp_sack_freq"
-SCTP_MAX_BURST				"sctp_max_burst"
 
 ADVERTISED_ADDRESS	"advertised_address"
 ADVERTISED_PORT		"advertised_port"
@@ -495,14 +477,9 @@ KILL_TIMEOUT	"exit_timeout"|"ser_kill_timeout"
 MAX_WLOOPS		"max_while_loops"
 PVBUFSIZE		"pv_buffer_size"
 PVBUFSLOTS		"pv_buffer_slots"
-HTTP_REPLY_HACK		"http_reply_hack"
+HTTP_REPLY_PARSE		"http_reply_hack"|"http_reply_parse"
 VERSION_TABLE_CFG		"version_table"
 
-/* stun config variables */
-STUN_REFRESH_INTERVAL "stun_refresh_interval"
-STUN_ALLOW_STUN "stun_allow_stun"
-STUN_ALLOW_FP "stun_allow_fp"
-
 SERVER_ID     "server_id"
 
 LATENCY_LOG				latency_log
@@ -561,10 +538,10 @@ COLON		":"
 STAR		\*
 DOT			\.
 CR			\n
-EVENT_RT_NAME [a-zA-Z][0-9a-zA-Z-]*":"[a-zA-Z][0-9a-zA-Z-]*
+EVENT_RT_NAME [a-zA-Z][0-9a-zA-Z-]*(":"[a-zA-Z][0-9a-zA-Z-]*)+
 
 
-COM_LINE	#
+COM_LINE	"#"|"//"
 COM_START	"/\*"
 COM_END		"\*/"
 
@@ -712,6 +689,7 @@ IMPORTFILE      "import_file"
 <INITIAL>{DEBUG}	{ count(); yylval.strval=yytext; return DEBUG_V; }
 <INITIAL>{FORK}		{ count(); yylval.strval=yytext; return FORK; }
 <INITIAL>{FORK_DELAY}	{ count(); yylval.strval=yytext; return FORK_DELAY; }
+<INITIAL>{MODINIT_DELAY}	{ count(); yylval.strval=yytext; return MODINIT_DELAY; }
 <INITIAL>{LOGSTDERROR}	{ yylval.strval=yytext; return LOGSTDERROR; }
 <INITIAL>{LOGFACILITY}	{ yylval.strval=yytext; return LOGFACILITY; }
 <INITIAL>{LOGNAME}	{ yylval.strval=yytext; return LOGNAME; }
@@ -747,6 +725,8 @@ IMPORTFILE      "import_file"
 								return DNS_USE_SEARCH; }
 <INITIAL>{DNS_SEARCH_FMATCH}	{ count(); yylval.strval=yytext;
 								return DNS_SEARCH_FMATCH; }
+<INITIAL>{DNS_NAPTR_IGNORE_RFC}	{ count(); yylval.strval=yytext;
+								return DNS_NAPTR_IGNORE_RFC; }
 <INITIAL>{DNS_CACHE_INIT}	{ count(); yylval.strval=yytext;
 								return DNS_CACHE_INIT; }
 <INITIAL>{DNS_USE_CACHE}	{ count(); yylval.strval=yytext;
@@ -795,7 +775,6 @@ IMPORTFILE      "import_file"
 <INITIAL>{SOCKET_WORKERS}	{ count(); yylval.strval=yytext; return SOCKET_WORKERS; }
 <INITIAL>{CHECK_VIA}	{ count(); yylval.strval=yytext; return CHECK_VIA; }
 <INITIAL>{PHONE2TEL}	{ count(); yylval.strval=yytext; return PHONE2TEL; }
-<INITIAL>{SYN_BRANCH}	{ count(); yylval.strval=yytext; return SYN_BRANCH; }
 <INITIAL>{MEMLOG}	{ count(); yylval.strval=yytext; return MEMLOG; }
 <INITIAL>{MEMDBG}	{ count(); yylval.strval=yytext; return MEMDBG; }
 <INITIAL>{MEMSUM}	{ count(); yylval.strval=yytext; return MEMSUM; }
@@ -886,44 +865,6 @@ IMPORTFILE      "import_file"
 <INITIAL>{ENABLE_SCTP}	{ count(); yylval.strval=yytext; return ENABLE_SCTP;}
 <INITIAL>{SCTP_CHILDREN}	{ count(); yylval.strval=yytext;
 										return SCTP_CHILDREN; }
-<INITIAL>{SCTP_SOCKET_RCVBUF}	{ count(); yylval.strval=yytext;
-										return SCTP_SOCKET_RCVBUF; }
-<INITIAL>{SCTP_SOCKET_SNDBUF}	{ count(); yylval.strval=yytext;
-										return SCTP_SOCKET_SNDBUF; }
-<INITIAL>{SCTP_AUTOCLOSE}	{ count(); yylval.strval=yytext;
-										return SCTP_AUTOCLOSE; }
-<INITIAL>{SCTP_SEND_TTL}	{ count(); yylval.strval=yytext;
-										return SCTP_SEND_TTL; }
-<INITIAL>{SCTP_SEND_RETRIES}	{ count(); yylval.strval=yytext;
-										return SCTP_SEND_RETRIES; }
-<INITIAL>{SCTP_ASSOC_TRACKING}	{ count(); yylval.strval=yytext;
-										return SCTP_ASSOC_TRACKING; }
-<INITIAL>{SCTP_ASSOC_REUSE}		{ count(); yylval.strval=yytext;
-										return SCTP_ASSOC_REUSE; }
-<INITIAL>{SCTP_MAX_ASSOCS}		{ count(); yylval.strval=yytext;
-										return SCTP_MAX_ASSOCS; }
-<INITIAL>{SCTP_SRTO_INITIAL}	{ count(); yylval.strval=yytext;
-										return SCTP_SRTO_INITIAL; }
-<INITIAL>{SCTP_SRTO_MAX}	{ count(); yylval.strval=yytext;
-										return SCTP_SRTO_MAX; }
-<INITIAL>{SCTP_SRTO_MIN}	{ count(); yylval.strval=yytext;
-										return SCTP_SRTO_MIN; }
-<INITIAL>{SCTP_ASOCMAXRXT}	{ count(); yylval.strval=yytext;
-										return SCTP_ASOCMAXRXT; }
-<INITIAL>{SCTP_INIT_MAX_ATTEMPTS}	{ count(); yylval.strval=yytext;
-										return SCTP_INIT_MAX_ATTEMPTS; }
-<INITIAL>{SCTP_INIT_MAX_TIMEO}	{ count(); yylval.strval=yytext;
-										return SCTP_INIT_MAX_TIMEO; }
-<INITIAL>{SCTP_HBINTERVAL}	{ count(); yylval.strval=yytext;
-										return SCTP_HBINTERVAL; }
-<INITIAL>{SCTP_PATHMAXRXT}	{ count(); yylval.strval=yytext;
-										return SCTP_PATHMAXRXT; }
-<INITIAL>{SCTP_SACK_DELAY}	{ count(); yylval.strval=yytext;
-										return SCTP_SACK_DELAY; }
-<INITIAL>{SCTP_SACK_FREQ}	{ count(); yylval.strval=yytext;
-										return SCTP_SACK_FREQ; }
-<INITIAL>{SCTP_MAX_BURST}	{ count(); yylval.strval=yytext;
-										return SCTP_MAX_BURST; }
 <INITIAL>{SERVER_SIGNATURE}	{ count(); yylval.strval=yytext; return SERVER_SIGNATURE; }
 <INITIAL>{SERVER_HEADER}	{ count(); yylval.strval=yytext; return SERVER_HEADER; }
 <INITIAL>{USER_AGENT_HEADER}	{ count(); yylval.strval=yytext; return USER_AGENT_HEADER; }
@@ -972,8 +913,8 @@ IMPORTFILE      "import_file"
 									return PVBUFSIZE; }
 <INITIAL>{PVBUFSLOTS}			{	count(); yylval.strval=yytext;
 									return PVBUFSLOTS; }
-<INITIAL>{HTTP_REPLY_HACK}		{	count(); yylval.strval=yytext;
-									return HTTP_REPLY_HACK; }
+<INITIAL>{HTTP_REPLY_PARSE}		{	count(); yylval.strval=yytext;
+									return HTTP_REPLY_PARSE; }
 <INITIAL>{VERSION_TABLE_CFG}  { count(); yylval.strval=yytext; return VERSION_TABLE_CFG;}
 <INITIAL>{SERVER_ID}  { count(); yylval.strval=yytext; return SERVER_ID;}
 <INITIAL>{LATENCY_LOG}  { count(); yylval.strval=yytext; return LATENCY_LOG;}
@@ -985,10 +926,6 @@ IMPORTFILE      "import_file"
 <INITIAL>{LOADPATH}		{ count(); yylval.strval=yytext; return LOADPATH; }
 <INITIAL>{MODPARAM}     { count(); yylval.strval=yytext; return MODPARAM; }
 
-<INITIAL>{STUN_REFRESH_INTERVAL} { count(); yylval.strval=yytext; return STUN_REFRESH_INTERVAL;}
-<INITIAL>{STUN_ALLOW_STUN} { count(); yylval.strval=yytext; return STUN_ALLOW_STUN;}
-<INITIAL>{STUN_ALLOW_FP} { count(); yylval.strval=yytext; return STUN_ALLOW_FP;}
-
 <INITIAL>{EQUAL}	{ count(); return EQUAL; }
 <INITIAL>{ADDEQ}          { count(); return ADDEQ; }
 <INITIAL>{EQUAL_T}	{ count(); return EQUAL_T; }
@@ -1167,11 +1104,7 @@ IMPORTFILE      "import_file"
 <INITIAL>{INET}			{ count(); yylval.intval=AF_INET;
 							yy_number_str=yytext; return NUMBER; }
 <INITIAL>{INET6}		{ count();
-						#ifdef USE_IPV6
-						  yylval.intval=AF_INET6;
-						#else
-						  yylval.intval=-1; /* no match*/
-						#endif
+						yylval.intval=AF_INET6;
 						yy_number_str=yytext;
 						return NUMBER; }
 <INITIAL>{SSLv23}		{ count(); yylval.strval=yytext; return SSLv23; }
diff --git a/cfg.y b/cfg.y
index 0c4fb5d..195593b 100644
--- a/cfg.y
+++ b/cfg.y
@@ -135,7 +135,7 @@
 #include "flags.h"
 #include "tcp_init.h"
 #include "tcp_options.h"
-#include "sctp_options.h"
+#include "sctp_core.h"
 #include "pvar.h"
 #include "lvalue.h"
 #include "rvalue.h"
@@ -165,11 +165,7 @@
 		if (rt!=ONSEND_ROUTE) yyerror( s " allowed only in onsend_routes");\
 	}while(0)
 
-#ifdef USE_IPV6
 	#define IF_AUTO_BIND_IPV6(x) x
-#else
-	#define IF_AUTO_BIND_IPV6(x) warn("IPV6 support not compiled");
-#endif
 
 #ifdef USE_DNS_CACHE
 	#define IF_DNS_CACHE(x) x
@@ -195,12 +191,6 @@
 	#define IF_DST_BLACKLIST(x) warn("dst blacklist support not compiled in")
 #endif
 
-#ifdef USE_STUN
-	#define IF_STUN(x) x
-#else 
-	#define IF_STUN(x) warn("stun support not compiled in")
-#endif
-
 #ifdef USE_SCTP
 	#define IF_SCTP(x) x
 #else
@@ -396,6 +386,7 @@ extern char *finame;
 %token DEBUG_V
 %token FORK
 %token FORK_DELAY
+%token MODINIT_DELAY
 %token LOGSTDERROR
 %token LOGFACILITY
 %token LOGNAME
@@ -418,6 +409,7 @@ extern char *finame;
 %token DNS_SERVERS_NO
 %token DNS_USE_SEARCH
 %token DNS_SEARCH_FMATCH
+%token DNS_NAPTR_IGNORE_RFC
 %token DNS_CACHE_INIT
 %token DNS_USE_CACHE
 %token DNS_USE_FAILOVER
@@ -449,7 +441,6 @@ extern char *finame;
 %token SOCKET_WORKERS
 %token CHECK_VIA
 %token PHONE2TEL
-%token SYN_BRANCH
 %token MEMLOG
 %token MEMDBG
 %token MEMSUM
@@ -519,25 +510,6 @@ extern char *finame;
 %token DISABLE_SCTP
 %token ENABLE_SCTP
 %token SCTP_CHILDREN
-%token SCTP_SOCKET_RCVBUF
-%token SCTP_SOCKET_SNDBUF
-%token SCTP_AUTOCLOSE
-%token SCTP_SEND_TTL
-%token SCTP_SEND_RETRIES
-%token SCTP_ASSOC_TRACKING
-%token SCTP_ASSOC_REUSE
-%token SCTP_MAX_ASSOCS
-%token SCTP_SRTO_INITIAL
-%token SCTP_SRTO_MAX
-%token SCTP_SRTO_MIN
-%token SCTP_ASOCMAXRXT
-%token SCTP_INIT_MAX_ATTEMPTS
-%token SCTP_INIT_MAX_TIMEO
-%token SCTP_HBINTERVAL
-%token SCTP_PATHMAXRXT
-%token SCTP_SACK_DELAY
-%token SCTP_SACK_FREQ
-%token SCTP_MAX_BURST
 %token ADVERTISED_ADDRESS
 %token ADVERTISED_PORT
 %token DISABLE_CORE
@@ -560,7 +532,7 @@ extern char *finame;
 %token MAX_WLOOPS
 %token PVBUFSIZE
 %token PVBUFSLOTS
-%token HTTP_REPLY_HACK
+%token HTTP_REPLY_PARSE
 %token VERSION_TABLE_CFG
 %token CFG_DESCRIPTION
 %token SERVER_ID
@@ -586,10 +558,6 @@ extern char *finame;
 %token ADDEQ
 
 
-%token STUN_REFRESH_INTERVAL
-%token STUN_ALLOW_STUN
-%token STUN_ALLOW_FP
-
 /*pre-processor*/
 %token SUBST
 %token SUBSTDEF
@@ -852,6 +820,8 @@ assign_stm:
 	| FORK  EQUAL error  { yyerror("boolean value expected"); }
 	| FORK_DELAY  EQUAL NUMBER { set_fork_delay($3); }
 	| FORK_DELAY  EQUAL error  { yyerror("number expected"); }
+	| MODINIT_DELAY  EQUAL NUMBER { set_modinit_delay($3); }
+	| MODINIT_DELAY  EQUAL error  { yyerror("number expected"); }
 	| LOGSTDERROR EQUAL NUMBER { if (!config_check)  /* if set from cmd line, don't overwrite from yyparse()*/ 
 					if(log_stderr == 0) log_stderr=$3; 
 				   }
@@ -896,6 +866,8 @@ assign_stm:
 	| DNS_USE_SEARCH error { yyerror("boolean value expected"); }
 	| DNS_SEARCH_FMATCH EQUAL NUMBER   { default_core_cfg.dns_search_fmatch=$3; }
 	| DNS_SEARCH_FMATCH error { yyerror("boolean value expected"); }
+	| DNS_NAPTR_IGNORE_RFC EQUAL NUMBER   { default_core_cfg.dns_naptr_ignore_rfc=$3; }
+	| DNS_NAPTR_IGNORE_RFC error { yyerror("boolean value expected"); }
 	| DNS_CACHE_INIT EQUAL NUMBER   { IF_DNS_CACHE(dns_cache_init=$3); }
 	| DNS_CACHE_INIT error { yyerror("boolean value expected"); }
 	| DNS_USE_CACHE EQUAL NUMBER   { IF_DNS_CACHE(default_core_cfg.use_dns_cache=$3); }
@@ -969,8 +941,6 @@ assign_stm:
 	| CHECK_VIA EQUAL error { yyerror("boolean value expected"); }
 	| PHONE2TEL EQUAL NUMBER { phone2tel=$3; }
 	| PHONE2TEL EQUAL error { yyerror("boolean value expected"); }
-	| SYN_BRANCH EQUAL NUMBER { syn_branch=$3; }
-	| SYN_BRANCH EQUAL error { yyerror("boolean value expected"); }
 	| MEMLOG EQUAL intno { default_core_cfg.memlog=$3; }
 	| MEMLOG EQUAL error { yyerror("int value expected"); }
 	| MEMDBG EQUAL intno { default_core_cfg.memdbg=$3; }
@@ -1131,12 +1101,8 @@ assign_stm:
 	| TCP_SOURCE_IPV4 EQUAL error { yyerror("IPv4 address expected"); }
 	| TCP_SOURCE_IPV6 EQUAL ipv6 {
 		#ifdef USE_TCP
-			#ifdef USE_IPV6
 				if (tcp_set_src_addr($3)<0)
 					warn("tcp_source_ipv6 failed");
-			#else
-				warn("IPv6 support not compiled in");
-			#endif
 		#else
 			warn("tcp support not compiled in");
 		#endif
@@ -1426,122 +1392,6 @@ assign_stm:
 		#endif
 	}
 	| SCTP_CHILDREN EQUAL error { yyerror("number expected"); }
-	| SCTP_SOCKET_RCVBUF EQUAL NUMBER {
-		#ifdef USE_SCTP
-			sctp_default_cfg.so_rcvbuf=$3;
-		#else
-			warn("sctp support not compiled in");
-		#endif
-	}
-	| SCTP_SOCKET_RCVBUF EQUAL error { yyerror("number expected"); }
-	| SCTP_SOCKET_SNDBUF EQUAL NUMBER {
-		#ifdef USE_SCTP
-			sctp_default_cfg.so_sndbuf=$3;
-		#else
-			warn("sctp support not compiled in");
-		#endif
-	}
-	| SCTP_SOCKET_SNDBUF EQUAL error { yyerror("number expected"); }
-	| SCTP_AUTOCLOSE EQUAL NUMBER {
-		#ifdef USE_SCTP
-			sctp_default_cfg.autoclose=$3;
-		#else
-			warn("sctp support not compiled in");
-		#endif
-	}
-	| SCTP_AUTOCLOSE EQUAL error { yyerror("number expected"); }
-	| SCTP_SEND_TTL EQUAL NUMBER {
-		#ifdef USE_SCTP
-			sctp_default_cfg.send_ttl=$3;
-		#else
-			warn("sctp support not compiled in");
-		#endif
-	}
-	| SCTP_SEND_TTL EQUAL error { yyerror("number expected"); }
-	| SCTP_SEND_RETRIES EQUAL NUMBER {
-		#ifdef USE_SCTP
-			sctp_default_cfg.send_retries=$3;
-		#else
-			warn("sctp support not compiled in");
-		#endif
-	}
-	| SCTP_SEND_RETRIES EQUAL error { yyerror("number expected"); }
-	| SCTP_ASSOC_TRACKING EQUAL NUMBER {
-		#ifdef USE_SCTP
-			#ifdef SCTP_CONN_REUSE
-				sctp_default_cfg.assoc_tracking=$3;
-			#else
-				if ($3)
-					warn("sctp association tracking/reuse (SCTP_CONN_REUSE) "
-							"support not compiled in");
-			#endif /* SCTP_CONN_REUSE */
-		#else
-			warn("sctp support not compiled in");
-		#endif /* USE_SCTP */
-	}
-	| SCTP_ASSOC_TRACKING EQUAL error { yyerror("number expected"); }
-	| SCTP_ASSOC_REUSE EQUAL NUMBER {
-		#ifdef USE_SCTP
-			#ifdef SCTP_CONN_REUSE
-				sctp_default_cfg.assoc_reuse=$3;
-			#else
-				if ($3)
-					warn("sctp association reuse (SCTP_CONN_REUSE) support"
-							" not compiled in");
-			#endif /* SCTP_CONN_REUSE */
-		#else
-			warn("sctp support not compiled in");
-		#endif /* USE_SCTP */
-	}
-	| SCTP_ASSOC_REUSE EQUAL error { yyerror("number expected"); }
-	| SCTP_MAX_ASSOCS EQUAL intno {
-			IF_SCTP(sctp_default_cfg.max_assocs=$3);
-	}
-	| SCTP_MAX_ASSOCS EQUAL error { yyerror("number expected"); }
-	| SCTP_SRTO_INITIAL EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.srto_initial=$3);
-	}
-	| SCTP_SRTO_INITIAL EQUAL error { yyerror("number expected"); }
-	| SCTP_SRTO_MAX EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.srto_max=$3);
-	}
-	| SCTP_SRTO_MAX EQUAL error { yyerror("number expected"); }
-	| SCTP_SRTO_MIN EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.srto_min=$3);
-	}
-	| SCTP_SRTO_MIN EQUAL error { yyerror("number expected"); }
-	| SCTP_ASOCMAXRXT EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.asocmaxrxt=$3);
-	}
-	| SCTP_ASOCMAXRXT EQUAL error { yyerror("number expected"); }
-	| SCTP_INIT_MAX_ATTEMPTS EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.init_max_attempts=$3);
-	}
-	| SCTP_INIT_MAX_ATTEMPTS EQUAL error { yyerror("number expected"); }
-	| SCTP_INIT_MAX_TIMEO EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.init_max_timeo=$3);
-	}
-	| SCTP_INIT_MAX_TIMEO EQUAL error { yyerror("number expected"); }
-	| SCTP_HBINTERVAL EQUAL intno {
-			IF_SCTP(sctp_default_cfg.hbinterval=$3);
-	}
-	| SCTP_HBINTERVAL EQUAL error { yyerror("number expected"); }
-	| SCTP_PATHMAXRXT EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.pathmaxrxt=$3);
-	}
-	| SCTP_PATHMAXRXT EQUAL error { yyerror("number expected"); }
-	| SCTP_SACK_DELAY EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.sack_delay=$3);
-	}
-	| SCTP_SACK_DELAY EQUAL error { yyerror("number expected"); }
-	| SCTP_SACK_FREQ EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.sack_freq=$3);
-	}
-	| SCTP_SACK_FREQ EQUAL error { yyerror("number expected"); }
-	| SCTP_MAX_BURST EQUAL NUMBER {
-			IF_SCTP(sctp_default_cfg.max_burst=$3);
-	}
-	| SCTP_MAX_BURST EQUAL error { yyerror("number expected"); }
 	| SERVER_SIGNATURE EQUAL NUMBER { server_signature=$3; }
 	| SERVER_SIGNATURE EQUAL error { yyerror("boolean value expected"); }
 	| SERVER_HEADER EQUAL STRING { server_hdr.s=$3;
@@ -1706,14 +1556,8 @@ assign_stm:
 	| PVBUFSIZE EQUAL error { yyerror("number expected"); }
 	| PVBUFSLOTS EQUAL NUMBER { pv_set_buffer_slots($3); }
 	| PVBUFSLOTS EQUAL error { yyerror("number expected"); }
-	| HTTP_REPLY_HACK EQUAL NUMBER { http_reply_hack=$3; }
-	| HTTP_REPLY_HACK EQUAL error { yyerror("boolean value expected"); }
-	| STUN_REFRESH_INTERVAL EQUAL NUMBER { IF_STUN(stun_refresh_interval=$3); }
-	| STUN_REFRESH_INTERVAL EQUAL error{ yyerror("number expected"); }
-	| STUN_ALLOW_STUN EQUAL NUMBER { IF_STUN(stun_allow_stun=$3); }
-	| STUN_ALLOW_STUN EQUAL error{ yyerror("number expected"); }
-	| STUN_ALLOW_FP EQUAL NUMBER { IF_STUN(stun_allow_fp=$3) ; }
-	| STUN_ALLOW_FP EQUAL error{ yyerror("number expected"); }
+	| HTTP_REPLY_PARSE EQUAL NUMBER { http_reply_parse=$3; }
+	| HTTP_REPLY_PARSE EQUAL error { yyerror("boolean value expected"); }
     | SERVER_ID EQUAL NUMBER { server_id=$3; }
     | LATENCY_LOG EQUAL NUMBER { default_core_cfg.latency_log=$3; }
 	| LATENCY_LOG EQUAL error  { yyerror("number  expected"); }
@@ -1869,17 +1713,12 @@ ipv6addr:
 		if ($$==0) {
 			LOG(L_CRIT, "ERROR: cfg. parser: out of memory.\n");
 		} else {
-		#ifdef USE_IPV6
 			memset($$, 0, sizeof(struct ip_addr));
 			$$->af=AF_INET6;
 			$$->len=16;
 			if (inet_pton(AF_INET6, $1, $$->u.addr)<=0) {
 				yyerror("bad ipv6 address");
 			}
-		#else
-			yyerror("ipv6 address & no ipv6 support compiled in");
-			YYABORT;
-		#endif
 		}
 	}
 	;
@@ -2256,10 +2095,8 @@ exp_elem:
 			}
 			if (s_tmp.s){
 				ip_tmp=str2ip(&s_tmp);
-			#ifdef USE_IPV6
 				if (ip_tmp==0)
 					ip_tmp=str2ip6(&s_tmp);
-			#endif
 				pkg_free(s_tmp.s);
 				if (ip_tmp) {
 					$$=mk_elem($2, $1, 0, NET_ST, 
@@ -2777,17 +2614,10 @@ attr_id_any_str:
 	;
 
 pvar:	PVAR {
-			pv_spec=pkg_malloc(sizeof(*pv_spec));
-			if (!pv_spec) {
-				yyerror("Not enough memory");
-				YYABORT;
-			}
-			memset(pv_spec, 0, sizeof(*pv_spec));
 			s_tmp.s=$1; s_tmp.len=strlen($1);
-			if (pv_parse_spec(&s_tmp, pv_spec)==0){
-				yyerror("unknown script pseudo variable %s", $1 );
-				pkg_free(pv_spec);
-				pv_spec=0;
+			pv_spec=pv_cache_get(&s_tmp);
+			if (!pv_spec) {
+				yyerror("Can't get from cache: %s", $1);
 				YYABORT;
 			}
 			$$=pv_spec;
@@ -2802,12 +2632,8 @@ avp_pvar:	AVP_OR_PVAR {
 				}
 				memset(lval_tmp, 0, sizeof(*lval_tmp));
 				s_tmp.s=$1; s_tmp.len=strlen(s_tmp.s);
-				if (pv_parse_spec2(&s_tmp, &lval_tmp->lv.pvs, 1)==0){
-					/* not a pvar, try avps */
-					/* lval_tmp might be partially filled by the failed
-					   pv_parse_spec2() (especially if the avp name is the
-					   same as a pv class) => clean it again */
-					memset(lval_tmp, 0, sizeof(*lval_tmp));
+				lval_tmp->lv.pvs = pv_cache_get(&s_tmp);
+				if (lval_tmp->lv.pvs==NULL){
 					lval_tmp->lv.avps.type|= AVP_NAME_STR;
 					lval_tmp->lv.avps.name.s.s = s_tmp.s+1;
 					lval_tmp->lv.avps.name.s.len = s_tmp.len-1;
@@ -2854,15 +2680,14 @@ lval: attr_id_ass {
 						yyerror("Not enough memory");
 						YYABORT;
 					}
-					lval_tmp->type=LV_PVAR; lval_tmp->lv.pvs=*($1);
-					pkg_free($1); /* free the pvar spec we just copied */
+					lval_tmp->type=LV_PVAR; lval_tmp->lv.pvs=$1;
 					$$=lval_tmp;
 				}
 	| avp_pvar    {
 					if (($1)->type==LV_PVAR){
-						if (!pv_is_w(&($1)->lv.pvs))
+						if (!pv_is_w($1->lv.pvs))
 							yyerror("read only pvar in assignment left side");
-						if ($1->lv.pvs.trans!=0)
+						if ($1->lv.pvs->trans!=0)
 							yyerror("pvar with transformations in assignment"
 									" left side");
 					}
@@ -2874,14 +2699,14 @@ rval: intno			{$$=mk_rve_rval(RV_INT, (void*)$1); }
 	| STRING			{	s_tmp.s=$1; s_tmp.len=strlen($1);
 							$$=mk_rve_rval(RV_STR, &s_tmp); }
 	| attr_id_any		{$$=mk_rve_rval(RV_AVP, $1); pkg_free($1); }
-	| pvar				{$$=mk_rve_rval(RV_PVAR, $1); pkg_free($1); }
+	| pvar				{$$=mk_rve_rval(RV_PVAR, $1); }
 	| avp_pvar			{
 							switch($1->type){
 								case LV_AVP:
 									$$=mk_rve_rval(RV_AVP, &$1->lv.avps);
 									break;
 								case LV_PVAR:
-									$$=mk_rve_rval(RV_PVAR, &$1->lv.pvs);
+									$$=mk_rve_rval(RV_PVAR, $1->lv.pvs);
 									break;
 								default:
 									yyerror("BUG: invalid lvalue type ");
@@ -2934,8 +2759,24 @@ rval_expr: rval						{ $$=$1;
 		| rval_expr BIN_LSHIFT rval_expr {$$=mk_rve2(RVE_BLSHIFT_OP, $1,  $3);}
 		| rval_expr BIN_RSHIFT rval_expr {$$=mk_rve2(RVE_BRSHIFT_OP, $1,  $3);}
 		| rval_expr rve_cmpop rval_expr %prec GT { $$=mk_rve2( $2, $1, $3);}
-		| rval_expr rve_equalop rval_expr %prec EQUAL_T
-			{ $$=mk_rve2( $2, $1, $3);}
+		| rval_expr rve_equalop rval_expr %prec EQUAL_T {
+			/* comparing with $null => treat as defined or !defined */
+			if($3->op==RVE_RVAL_OP && $3->left.rval.type==RV_PVAR
+					&& $3->left.rval.v.pvs.type==PVT_NULL) {
+				if($2==RVE_DIFF_OP || $2==RVE_IDIFF_OP
+						|| $2==RVE_STRDIFF_OP) {
+					DBG("comparison with $null switched to notdefined operator\n");
+					$$=mk_rve1(RVE_DEFINED_OP, $1);
+				} else {
+					DBG("comparison with $null switched to defined operator\n");
+					$$=mk_rve1(RVE_NOTDEFINED_OP, $1);
+				}
+				/* free rve struct for $null */
+				rve_destroy($3);
+			} else {
+				$$=mk_rve2($2, $1, $3);
+			}
+		}
 		| rval_expr LOG_AND rval_expr	{ $$=mk_rve2(RVE_LAND_OP, $1, $3);}
 		| rval_expr LOG_OR rval_expr	{ $$=mk_rve2(RVE_LOR_OP, $1, $3);}
 		| LPAREN rval_expr RPAREN		{ $$=$2;}
@@ -3173,7 +3014,7 @@ cmd:
 	}
 	| FORWARD_SCTP error { $$=0; yyerror("missing '(' or ')' ?"); }
 	| FORWARD_SCTP LPAREN error RPAREN { $$=0; 
-									yyerror("bad forward_tls argument"); }
+									yyerror("bad forward_sctp argument"); }
 	| LOG_TOK LPAREN STRING RPAREN	{$$=mk_action(LOG_T, 2, NUMBER_ST,
 										(void*)(L_DBG+1), STRING_ST, $3);
 									set_cfg_pos($$); }
diff --git a/cfg/cfg.h b/cfg/cfg.h
index b85e44e..478d540 100644
--- a/cfg/cfg.h
+++ b/cfg/cfg.h
@@ -36,10 +36,10 @@
 #define CFG_VAR_STR		3U
 #define CFG_VAR_POINTER		4U
 
-/* number of bits required for the variable type */
+/*! \brief number of bits required for the variable type */
 #define CFG_INPUT_SHIFT		3
 
-/* input type */
+/*! \brief input types */
 #define CFG_INPUT_INT		(CFG_VAR_INT << CFG_INPUT_SHIFT)
 #define CFG_INPUT_STRING	(CFG_VAR_STRING << CFG_INPUT_SHIFT)
 #define CFG_INPUT_STR		(CFG_VAR_STR << CFG_INPUT_SHIFT)
@@ -47,28 +47,25 @@
 #define CFG_VAR_MASK(x)		((x)&((1U<<CFG_INPUT_SHIFT)-1))
 #define CFG_INPUT_MASK(x)	((x)&((1U<<(2*CFG_INPUT_SHIFT))-(1U<<CFG_INPUT_SHIFT)))
 
-/* atomic change is allowed */
-#define CFG_ATOMIC		(1U<<(2*CFG_INPUT_SHIFT))
-/* variable is read-only */
-#define CFG_READONLY		(1U<<(2*CFG_INPUT_SHIFT+1))
-/* per-child process callback needs to be called only once */
-#define CFG_CB_ONLY_ONCE	(1U<<(2*CFG_INPUT_SHIFT+2))
+#define CFG_ATOMIC		(1U<<(2*CFG_INPUT_SHIFT))	/*!< atomic change is allowed */
+#define CFG_READONLY		(1U<<(2*CFG_INPUT_SHIFT+1))	/*!< variable is read-only */
+#define CFG_CB_ONLY_ONCE	(1U<<(2*CFG_INPUT_SHIFT+2))	/*!< per-child process callback needs to be called only once */
 
 typedef int (*cfg_on_change)(void *, str *, str *, void **);
 typedef void (*cfg_on_set_child)(str *, str *);
 
-/* strutrure to be used by the module interface */
+/*! \brief structrure to be used by the module interface */
 typedef struct _cfg_def {
 	char	*name;
 	unsigned int	type;
 	int	min;
 	int	max;
-	cfg_on_change	on_change_cb;
+	cfg_on_change		on_change_cb;
 	cfg_on_set_child	on_set_child_cb;
 	char	*descr;
 } cfg_def_t;
 
-/* declares a new cfg group
+/*! \brief declares a new cfg group
  * handler is set to the memory area where the variables are stored
  * return value is -1 on error
  */
@@ -81,33 +78,33 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
 #define cfg_get(gname, handle, var) \
 	((struct cfg_group_##gname *)handle)->var
 
-/* declares a single variable with integer type */
+/*! \brief declares a single variable with integer type */
 int cfg_declare_int(char *group_name, char *var_name,
 		int val, int min, int max, char *descr);
 
-/* declares a single variable with str type */
+/*! \brief declares a single variable with str type */
 int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr);
 
-/* Add a varibale to a group instance with integer type.
+/*! \brief Add a variable to a group instance with integer type.
  * The group instance is created if it does not exist.
  * wrapper function for new_add_var()
  */
 int cfg_ginst_var_int(char *group_name, unsigned int group_id, char *var_name,
 			int val);
 
-/* Add a varibale to a group instance with string type.
+/*! \brief Add a variable to a group instance with string type.
  * The group instance is created if it does not exist.
  * wrapper function for new_add_var()
  */
 int cfg_ginst_var_string(char *group_name, unsigned int group_id, char *var_name,
 			char *val);
 
-/* Create a new group instance.
+/*! \brief Create a new group instance.
  * wrapper function for new_add_var()
  */
 int cfg_new_ginst(char *group_name, unsigned int group_id);
 
-/* returns the handle of a cfg group */
+/*! \brief returns the handle of a cfg group */
 void **cfg_get_handle(char *gname);
 
 #endif /* _CFG_H */
diff --git a/cfg_core.c b/cfg_core.c
index 55a5638..06edb86 100644
--- a/cfg_core.c
+++ b/cfg_core.c
@@ -76,11 +76,7 @@ struct cfg_group_core default_core_cfg = {
 	0, /* blst_sctp_imask */
 #endif
 	/* resolver */
-#ifdef USE_IPV6
 	1,  /*!< dns_try_ipv6 -- on by default */
-#else
-	0,  /*!< dns_try_ipv6 -- off, if no ipv6 support */
-#endif
 	0,  /*!< dns_try_naptr -- off by default */
 	30,  /*!< udp transport preference (for naptr) */
 	20,  /*!< tcp transport preference (for naptr) */
@@ -92,6 +88,7 @@ struct cfg_group_core default_core_cfg = {
 	1,  /*!< dns_search_list */
 	1,  /*!< dns_search_fmatch */
 	0,  /*!< dns_reinit */
+	1,  /*!< dns_naptr_ignore_rfc */
 	/* DNS cache */
 #ifdef USE_DNS_CACHE
 	1,  /*!< use_dns_cache -- on by default */
@@ -220,13 +217,13 @@ cfg_def_t core_cfg_def[] = {
 	{"dns_try_naptr",	CFG_VAR_INT,	0, 1, 0, 0,
 #endif
 		"enable/disable NAPTR DNS lookups"},
-	{"dns_udp_pref",	CFG_VAR_INT,	0, 0, 0, reinit_naptr_proto_prefs,
+	{"dns_udp_pref",	CFG_VAR_INT,	0, 0, 0, reinit_proto_prefs,
 		"udp protocol preference when doing NAPTR lookups"},
-	{"dns_tcp_pref",	CFG_VAR_INT,	0, 0, 0, reinit_naptr_proto_prefs,
+	{"dns_tcp_pref",	CFG_VAR_INT,	0, 0, 0, reinit_proto_prefs,
 		"tcp protocol preference when doing NAPTR lookups"},
-	{"dns_tls_pref",	CFG_VAR_INT,	0, 0, 0, reinit_naptr_proto_prefs,
+	{"dns_tls_pref",	CFG_VAR_INT,	0, 0, 0, reinit_proto_prefs,
 		"tls protocol preference when doing NAPTR lookups"},
-	{"dns_sctp_pref",	CFG_VAR_INT,	0, 0, 0, reinit_naptr_proto_prefs,
+	{"dns_sctp_pref",	CFG_VAR_INT,	0, 0, 0, reinit_proto_prefs,
 		"sctp protocol preference when doing NAPTR lookups"},
 	{"dns_retr_time",	CFG_VAR_INT,	0, 0, 0, resolv_reinit,
 		"time in s before retrying a dns request"},
@@ -243,6 +240,8 @@ cfg_def_t core_cfg_def[] = {
 	{"dns_reinit",		CFG_VAR_INT|CFG_INPUT_INT,	1, 1, dns_reinit_fixup,
 		resolv_reinit,
 		"set to 1 in order to reinitialize the DNS resolver"},
+	{"dns_naptr_ignore_rfc",	CFG_VAR_INT,	0, 0, 0, reinit_proto_prefs,
+		"ignore the Order field required by RFC 2915"},
 	/* DNS cache */
 #ifdef USE_DNS_CACHE
 	{"use_dns_cache",	CFG_VAR_INT,	0, 1, use_dns_cache_fixup, 0,
diff --git a/cfg_core.h b/cfg_core.h
index 4bfbfbb..3739acb 100644
--- a/cfg_core.h
+++ b/cfg_core.h
@@ -80,6 +80,7 @@ struct cfg_group_core {
 	int dns_search_list;
 	int dns_search_fmatch;
 	int dns_reinit;
+	int dns_naptr_ignore_rfc;
 	/* DNS cache */
 #ifdef USE_DNS_CACHE
 	int use_dns_cache;
diff --git a/config.h b/config.h
index fce4c22..32cd55c 100644
--- a/config.h
+++ b/config.h
@@ -75,6 +75,10 @@
 
 #define MAX_INSTANCE_SIZE 256 		/*!< Maximum length of +sip.instance contact header param value buffer */
 
+#define MAX_RUID_SIZE 65		/*!< Maximum length of ruid for location records */
+
+#define MAX_UA_SIZE 255			/*!< Maximum length of user-agent for location records */
+
 #define MY_VIA "Via: SIP/2.0/UDP "
 #define MY_VIA_LEN (sizeof(MY_VIA) - 1)
 
diff --git a/core_cmd.c b/core_cmd.c
index a31d124..304c49d 100644
--- a/core_cmd.c
+++ b/core_cmd.c
@@ -47,10 +47,6 @@
 #include "tcp_options.h"
 #include "core_cmd.h"
 #include "cfg_core.h"
-#ifdef USE_SCTP
-#include "sctp_options.h"
-#include "sctp_server.h"
-#endif
 
 #ifdef USE_DNS_CACHE
 void dns_cache_debug(rpc_t* rpc, void* ctx);
@@ -765,6 +761,11 @@ static void core_tcp_list(rpc_t* rpc, void* c)
 	struct tcp_connection* con;
 	int i, len, timeout;
 
+	if (tcp_disable) {
+		rpc->fault(c, 500, "tcp support disabled");
+		return;
+	}
+
 	TCPCONN_LOCK;
 	for(i = 0; i < TCP_ID_HASH_SIZE; i++) {
 		for (con = tcpconn_id_hash[i]; con; con = con->id_next) {
@@ -834,133 +835,6 @@ static void core_tcp_list(rpc_t* rpc, void* c)
 }
 
 
-
-static const char* core_sctp_options_doc[] = {
-	"Returns active sctp options. With one parameter"
-	" it returns the sctp options set in the kernel for a specific socket"
-	"(debugging), with 0 filled in for non-kernel related options."
-	" The parameter can be: \"default\" | \"first\" | address[:port] ."
-	" With no parameters it returns ser's idea of the current sctp options"
-	 " (intended non-debugging use).",
-	/* Documentation string */
-	0                                 /* Method signature(s) */
-};
-
-static void core_sctp_options(rpc_t* rpc, void* c)
-{
-#ifdef USE_SCTP
-	void *handle;
-	struct cfg_group_sctp t;
-	char* param;
-	struct socket_info* si;
-	char* host;
-	str hs;
-	int hlen;
-	int port;
-	int proto;
-
-	param=0;
-	if (!sctp_disable){
-		/* look for optional socket parameter */
-		if (rpc->scan(c, "*s", &param)>0){
-			si=0;
-			if (strcasecmp(param, "default")==0){
-				si=sendipv4_sctp?sendipv4_sctp:sendipv6_sctp;
-			}else if (strcasecmp(param, "first")==0){
-				si=sctp_listen;
-			}else{
-				if (parse_phostport(param, &host, &hlen, &port, &proto)!=0){
-					rpc->fault(c, 500, "bad param (use address, address:port,"
-										" default or first)");
-					return;
-				}
-				if (proto && proto!=PROTO_SCTP){
-					rpc->fault(c, 500, "bad protocol in param (only SCTP"
-										" allowed)");
-					return;
-				}
-				hs.s=host;
-				hs.len=hlen;
-				si=grep_sock_info(&hs, port, PROTO_SCTP);
-				if (si==0){
-					rpc->fault(c, 500, "not listening on sctp %s", param);
-					return;
-				}
-			}
-			if (si==0 || si->socket==-1){
-				rpc->fault(c, 500, "could not find a sctp socket");
-				return;
-			}
-			memset(&t, 0, sizeof(t));
-			if (sctp_get_cfg_from_sock(si->socket, &t)!=0){
-				rpc->fault(c, 500, "failed to get socket options");
-				return;
-			}
-		}else{
-			sctp_options_get(&t);
-		}
-		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "ddddddddddddddddddd",
-			"sctp_socket_rcvbuf",	t.so_rcvbuf,
-			"sctp_socket_sndbuf",	t.so_sndbuf,
-			"sctp_autoclose",		t.autoclose,
-			"sctp_send_ttl",	t.send_ttl,
-			"sctp_send_retries",	t.send_retries,
-			"sctp_assoc_tracking",	t.assoc_tracking,
-			"sctp_assoc_reuse",	t.assoc_reuse,
-			"sctp_max_assocs", t.max_assocs,
-			"sctp_srto_initial",	t.srto_initial,
-			"sctp_srto_max",		t.srto_max,
-			"sctp_srto_min",		t.srto_min,
-			"sctp_asocmaxrxt",	t.asocmaxrxt,
-			"sctp_init_max_attempts",	t.init_max_attempts,
-			"sctp_init_max_timeo",t.init_max_timeo,
-			"sctp_hbinterval",	t.hbinterval,
-			"sctp_pathmaxrxt",	t.pathmaxrxt,
-			"sctp_sack_delay",	t.sack_delay,
-			"sctp_sack_freq",	t.sack_freq,
-			"sctp_max_burst",	t.max_burst
-		);
-	}else{
-		rpc->fault(c, 500, "sctp support disabled");
-	}
-#else
-	rpc->fault(c, 500, "sctp support not compiled");
-#endif
-}
-
-
-
-static const char* core_sctpinfo_doc[] = {
-	"Returns sctp related info.",    /* Documentation string */
-	0                               /* Method signature(s) */
-};
-
-static void core_sctpinfo(rpc_t* rpc, void* c)
-{
-#ifdef USE_SCTP
-	void *handle;
-	struct sctp_gen_info i;
-
-	if (!sctp_disable){
-		sctp_get_info(&i);
-		rpc->add(c, "{", &handle);
-		rpc->struct_add(handle, "ddd",
-			"opened_connections", i.sctp_connections_no,
-			"tracked_connections", i.sctp_tracked_no,
-			"total_connections", i.sctp_total_connections
-		);
-	}else{
-		rpc->fault(c, 500, "sctp support disabled");
-	}
-#else
-	rpc->fault(c, 500, "sctp support not compiled");
-#endif
-}
-
-
-
-
 static const char* core_udp4rawinfo_doc[] = {
 	"Returns udp4_raw related info.",    /* Documentation string */
 	0                                     /* Method signature(s) */
@@ -1106,9 +980,6 @@ static rpc_export_t core_rpc_methods[] = {
 	{"core.tcp_info",          core_tcpinfo,           core_tcpinfo_doc,    0},
 	{"core.tcp_options",       core_tcp_options,       core_tcp_options_doc,0},
 	{"core.tcp_list",          core_tcp_list,          core_tcp_list_doc,0},
-	{"core.sctp_options",      core_sctp_options,      core_sctp_options_doc,
-		0},
-	{"core.sctp_info",         core_sctpinfo,          core_sctpinfo_doc,   0},
 	{"core.udp4_raw_info",     core_udp4rawinfo,       core_udp4rawinfo_doc,
 		0},
 	{"core.aliases_list",      core_aliases_list,      core_aliases_list_doc,   0},
diff --git a/counters.c b/counters.c
index 6e5ffbb..3bfe542 100644
--- a/counters.c
+++ b/counters.c
@@ -89,12 +89,20 @@ static int grp_no; /* number of groups */
 
 /** counters array. a[proc_no][counter_id] =>
   _cnst_vals[proc_no*cnts_no+counter_id] */
-counter_array_t* _cnts_vals;
+counter_array_t* _cnts_vals = 0;
 int _cnts_row_len; /* number of elements per row */
 static int cnts_no; /* number of registered counters */
 static int cnts_max_rows; /* set to 0 if not yet fully init */
 
 
+int counters_initialized(void)
+{
+	if (unlikely(_cnts_vals == 0)) {
+		/* not init yet */
+		return 0;
+	}
+	return 1;
+}
 
 /** init the coutner hash table(s).
  * @return 0 on success, -1 on error.
diff --git a/counters.h b/counters.h
index ea16e28..9fd7c32 100644
--- a/counters.h
+++ b/counters.h
@@ -87,6 +87,7 @@ extern int _cnts_row_len; /* number of elements per row */
 
 
 
+int counters_initialized(void);
 int init_counters(void);
 void destroy_counters(void);
 int counters_prefork_init(int max_process_no);
diff --git a/data_lump.h b/data_lump.h
index 88a1f0d..d4b24f0 100644
--- a/data_lump.h
+++ b/data_lump.h
@@ -75,11 +75,11 @@ struct lump* insert_cond_lump_after(struct lump* after, enum lump_conditions c,
 struct lump* insert_cond_lump_before(struct lump* after, enum lump_conditions c,
 									enum _hdr_types_t type);
 
-/*! \brief removes an already existing header */
 /* set an anchor if there is no existing one at the given offset,
  * otherwise return the existing anchor */
 struct lump* anchor_lump2(struct sip_msg* msg, int offset, int len, enum _hdr_types_t type,
 								int *is_ref);
+/*! \brief removes an already existing header */
 struct lump* del_lump(struct sip_msg* msg, int offset, int len, enum _hdr_types_t type);
 /*! \brief set an anchor */
 struct lump* anchor_lump(struct sip_msg* msg, int offset, int len, enum _hdr_types_t type);
diff --git a/dns_cache.c b/dns_cache.c
index 5690cb6..41c93d8 100644
--- a/dns_cache.c
+++ b/dns_cache.c
@@ -1891,10 +1891,8 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
 #endif /* USE_DNS_CACHE_STATS */
 
 	if (type==T_A){
-#ifdef USE_IPV6
 		if (str2ip6(name)!=0)
 			goto end;
-#endif /* USE_IPV6 */
 		if ((ip=str2ip(name))!=0){
 				e=dns_cache_mk_ip_entry(name, ip);
 				if (likely(e))
@@ -1902,7 +1900,6 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
 				goto end; /* we do not cache obvious stuff */
 		}
 	}
-#ifdef USE_IPV6
 	else if (type==T_AAAA){
 		if (str2ip(name)!=0)
 			goto end;
@@ -1913,7 +1910,6 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
 				goto end;/* we do not cache obvious stuff */
 		}
 	}
-#endif /* USE_IPV6 */
 #ifdef DNS_WATCHDOG_SUPPORT
 	if (atomic_get(dns_servers_up)==0)
 		goto end; /* the servers are down, needless to perform the query */
@@ -2412,16 +2408,9 @@ inline static struct hostent* dns_entry2he(struct dns_hash_entry* e)
 			len=4;
 			break;
 		case T_AAAA:
-#ifdef USE_IPV6
 			af=AF_INET6;
 			len=16;
 			break;
-#else /* USE_IPV6 */
-			LOG(L_ERR, "ERROR: dns_entry2he: IPv6 dns cache entry, but "
-						"IPv6 support disabled at compile time"
-						" (recompile with -DUSE_IPV6)\n");
-			return 0;
-#endif /* USE_IPV6 */
 		default:
 			LOG(L_CRIT, "BUG: dns_entry2he: wrong entry type %d for %.*s\n",
 					e->type, e->name_len, e->name);
@@ -2472,10 +2461,8 @@ inline static struct hostent* dns_a_get_he(str* name)
 	struct hostent* he;
 
 	e=0;
-#ifdef	USE_IPV6
 	if (str2ip6(name)!=0)
 		return 0;
-#endif
 	if ((ip=str2ip(name))!=0){
 		return ip_addr2he(name, ip);
 	}
@@ -2488,7 +2475,6 @@ inline static struct hostent* dns_a_get_he(str* name)
 }
 
 
-#ifdef USE_IPV6
 /* gethostbyname compatibility: performs an aaaa_lookup and returns a pointer
  * to a statical internal hostent structure
  * returns 0 on success, <0 on error (see the error codes)
@@ -2512,7 +2498,6 @@ inline static struct hostent* dns_aaaa_get_he(str* name)
 	dns_hash_put(e);
 	return he;
 }
-#endif
 
 
 
@@ -2527,16 +2512,10 @@ inline static int dns_rr2ip(int type, struct dns_rr* rr, struct ip_addr* ip)
 			return 0;
 			break;
 		case T_AAAA:
-#ifdef USE_IPV6
 			ip->af=AF_INET6;
 			ip->len=16;
 			memcpy(ip->u.addr, ((struct aaaa_rdata*)rr->rdata)->ip6, 16);
 			return 0;
-#else /* USE_IPV6 */
-			LOG(L_ERR, "ERROR: dns_rr2ip: IPv6 dns rr, but IPv6 support"
-					   "disabled at compile time (recompile with "
-					   "-DUSE_IPV6)\n" );
-#endif /*USE_IPV6 */
 			break;
 	}
 	return -1;
@@ -2554,7 +2533,6 @@ inline static int dns_rr2ip(int type, struct dns_rr* rr, struct ip_addr* ip)
  */
 struct hostent* dns_get_he(str* name, int flags)
 {
-#ifdef USE_IPV6
 	struct hostent* he;
 
 	if ((flags&(DNS_IPV6_FIRST|DNS_IPV6_ONLY))){
@@ -2570,9 +2548,6 @@ struct hostent* dns_get_he(str* name, int flags)
 		he=dns_aaaa_get_he(name);
 	}
 	return he;
-#else /* USE_IPV6 */
-	return dns_a_get_he(name);
-#endif /* USE_IPV6 */
 }
 
 
@@ -2624,7 +2599,8 @@ struct hostent* dns_resolvehost(char* name)
 		ret =  _resolvehost(name);
 		if(unlikely(!ret)){
 			/* increment dns error counter */
-			counter_inc(dns_cnts_h.failed_dns_req);
+			if(counters_initialized())
+				counter_inc(dns_cnts_h.failed_dns_req);
 		}
 		return ret;
 	}
@@ -2705,42 +2681,23 @@ struct hostent* dns_srv_sip_resolvehost(str* name, unsigned short* port,
 		}else{
 			/* check if it's an ip address */
 			if ( ((ip=str2ip(name))!=0)
-#ifdef	USE_IPV6
 				  || ((ip=str2ip6(name))!=0)
-#endif
 				){
 				/* we are lucky, this is an ip address */
 				return ip_addr2he(name,ip);
 			}
 
+			if(srv_proto==PROTO_WS || srv_proto==PROTO_WS) {
+				/* no srv records for web sockets */
+				return 0;
+			}
+
 			switch(srv_proto){
-				case PROTO_NONE: /* no proto specified, use udp */
-					if (proto)
-						*proto=PROTO_UDP;
-					/* no break */
 				case PROTO_UDP:
-					memcpy(tmp, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
-					memcpy(tmp+SRV_UDP_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_UDP_PREFIX_LEN + name->len] = '\0';
-					len=SRV_UDP_PREFIX_LEN + name->len;
-					break;
 				case PROTO_TCP:
-					memcpy(tmp, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
-					memcpy(tmp+SRV_TCP_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_TCP_PREFIX_LEN + name->len] = '\0';
-					len=SRV_TCP_PREFIX_LEN + name->len;
-					break;
 				case PROTO_TLS:
-					memcpy(tmp, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
-					memcpy(tmp+SRV_TLS_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_TLS_PREFIX_LEN + name->len] = '\0';
-					len=SRV_TLS_PREFIX_LEN + name->len;
-					break;
 				case PROTO_SCTP:
-					memcpy(tmp, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN);
-					memcpy(tmp+SRV_SCTP_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_SCTP_PREFIX_LEN + name->len] = '\0';
-					len=SRV_SCTP_PREFIX_LEN + name->len;
+					create_srv_name(srv_proto, name, tmp);
 					break;
 				default:
 					LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n",
@@ -2871,17 +2828,13 @@ struct hostent* dns_naptr_sip_resolvehost(str* name, unsigned short* port,
 		*proto=PROTO_UDP; /* just in case we don't find another */
 		/* check if it's an ip address */
 		if ( ((tmp_ip=str2ip(name))!=0)
-#ifdef	USE_IPV6
 			  || ((tmp_ip=str2ip6(name))!=0)
-#endif
 			){
 			/* we are lucky, this is an ip address */
-#ifdef	USE_IPV6
 			if (((dns_flags&DNS_IPV4_ONLY) && (tmp_ip->af==AF_INET6))||
 				((dns_flags&DNS_IPV6_ONLY) && (tmp_ip->af==AF_INET))){
 				return 0;
 			}
-#endif
 			*port=SIP_PORT;
 			return ip_addr2he(name, tmp_ip);
 		}
@@ -2984,10 +2937,8 @@ inline static int dns_a_resolve( struct dns_hash_entry** e,
 	ret=-E_DNS_NO_IP;
 	if (*e==0){ /* do lookup */
 		/* if ip don't set *e */
-#ifdef	USE_IPV6
 		if (str2ip6(name)!=0)
 			goto error;
-#endif
 		if ((tmp=str2ip(name))!=0){
 			*ip=*tmp;
 			*rr_no=0;
@@ -3017,7 +2968,6 @@ error:
 }
 
 
-#ifdef USE_IPV6
 /* lookup, fills the dns_entry pointer and the ip addr.
  *  (with the first good ip). if *e ==0 does the a lookup, and changes it
  *   to the result, if not it uses the current value and tries to use
@@ -3064,7 +3014,6 @@ inline static int dns_aaaa_resolve( struct dns_hash_entry** e,
 error:
 	return ret;
 }
-#endif /* USE_IPV6 */
 
 
 
@@ -3089,7 +3038,6 @@ inline static int dns_ip_resolve(	struct dns_hash_entry** e,
 
 	ret=-E_DNS_NO_IP;
 	if (*e==0){ /* first call */
-#ifdef USE_IPV6
 		if ((flags&(DNS_IPV6_FIRST|DNS_IPV6_ONLY))){
 			ret=dns_aaaa_resolve(e, rr_no, name, ip);
 			if (ret>=0) return ret;
@@ -3102,9 +3050,6 @@ inline static int dns_ip_resolve(	struct dns_hash_entry** e,
 		}else if (!(flags&(DNS_IPV6_ONLY|DNS_IPV4_ONLY))){
 			ret=dns_aaaa_resolve(e, rr_no, name, ip);
 		}
-#else /* USE_IPV6 */
-		ret=dns_a_resolve(e, rr_no, name, ip);
-#endif /* USE_IPV6 */
 	}else if ((*e)->type==T_A){
 		/* continue A resolving */
 		/* retrieve host name from the hash entry  (ignore name which might
@@ -3112,7 +3057,6 @@ inline static int dns_ip_resolve(	struct dns_hash_entry** e,
 		host.s=(*e)->name;
 		host.len=(*e)->name_len;
 		ret=dns_a_resolve(e, rr_no, &host, ip);
-#ifdef USE_IPV6
 		if (ret>=0) return ret;
 		if (!(flags&(DNS_IPV6_ONLY|DNS_IPV6_FIRST|DNS_IPV4_ONLY))){
 			/* not found, try with AAAA */
@@ -3123,13 +3067,11 @@ inline static int dns_ip_resolve(	struct dns_hash_entry** e,
 			/* delay original record release until we're finished with host*/
 			dns_hash_put(orig);
 		}
-#endif /* USE_IPV6 */
 	}else if ((*e)->type==T_AAAA){
 		/* retrieve host name from the hash entry  (ignore name which might
 		  be null when continuing a srv lookup) */
 		host.s=(*e)->name;
 		host.len=(*e)->name_len;
-#ifdef USE_IPV6
 		/* continue AAAA resolving */
 		ret=dns_aaaa_resolve(e, rr_no, &host, ip);
 		if (ret>=0) return ret;
@@ -3142,15 +3084,6 @@ inline static int dns_ip_resolve(	struct dns_hash_entry** e,
 			/* delay original record release until we're finished with host*/
 			dns_hash_put(orig);
 		}
-#else /* USE_IPV6 */
-		/* ipv6 disabled, try with A */
-		orig=*e;
-		*e=0;
-		*rr_no=0;
-		ret=dns_a_resolve(e, rr_no, &host, ip);
-		/* delay original record release until we're finished with host*/
-		dns_hash_put(orig);
-#endif /* USE_IPV6 */
 	}else{
 		LOG(L_CRIT, "BUG: dns_ip_resolve: invalid record type %d\n",
 					(*e)->type);
@@ -3282,23 +3215,24 @@ error:
  * h must be initialized prior to  calling this function and can be used to
  * get the subsequent ips
  * returns:  <0 on error
- *            0 on success and it fills *ip, *port, dns_sip_resolve_h
- * WARNING: when finished, dns_sip_resolve_put(h) must be called!
+ *            0 on success and it fills *ip, *port, *h
  */
 inline static int dns_srv_sip_resolve(struct dns_srv_handle* h,  str* name,
 						struct ip_addr* ip, unsigned short* port, char* proto,
 						int flags)
 {
+	struct dns_srv_proto srv_proto_list[PROTO_LAST];
 	static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */
-	int len;
 	str srv_name;
 	struct ip_addr* tmp_ip;
 	int ret;
 	struct hostent* he;
-	char srv_proto;
+	size_t i,list_len;
+	char origproto;
 
+	origproto = *proto;
 	if (dns_hash==0){ /* not init => use normal, non-cached version */
-		LOG(L_WARN, "WARNING: dns_sip_resolve: called before dns cache"
+		LOG(L_WARN, "WARNING: dns_srv_sip_resolve: called before dns cache"
 					" initialization\n");
 		h->srv=h->a=0;
 		he=_sip_resolvehost(name, port, proto);
@@ -3308,92 +3242,63 @@ inline static int dns_srv_sip_resolve(struct dns_srv_handle* h,  str* name,
 		}
 		return -E_DNS_NO_SRV;
 	}
-	len=0;
 	if ((h->srv==0) && (h->a==0)){ /* first call */
-		if (proto){ /* makes sure we have a protocol set*/
-			if (*proto==0)
-				*proto=srv_proto=PROTO_UDP; /* default */
-			else
-				srv_proto=*proto;
-		}else{
-			srv_proto=PROTO_UDP;
+		if (proto && *proto==0){ /* makes sure we have a protocol set*/
+			*proto=PROTO_UDP; /* default */
 		}
-		h->port=(srv_proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we
+		h->port=(*proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we
 														don't find another */
-		h->proto=srv_proto; /* store initial protocol */
+		h->proto=*proto; /* store initial protocol */
 		if (port){
 			if (*port==0){
 				/* try SRV if initial call & no port specified
 				 * (draft-ietf-sip-srv-06) */
 				if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){
-					LOG(L_WARN, "WARNING: dns_sip_resolvehost: domain name too"
+					LOG(L_WARN, "WARNING: dns_srv_sip_resolve: domain name too"
 								" long (%d), unable to perform SRV lookup\n",
 								name->len);
 				}else{
 					/* check if it's an ip address */
 					if ( ((tmp_ip=str2ip(name))!=0)
-#ifdef	USE_IPV6
 						  || ((tmp_ip=str2ip6(name))!=0)
-#endif
 						){
 						/* we are lucky, this is an ip address */
-#ifdef	USE_IPV6
 						if (((flags&DNS_IPV4_ONLY) && (tmp_ip->af==AF_INET6))||
 							((flags&DNS_IPV6_ONLY) && (tmp_ip->af==AF_INET))){
 							return -E_DNS_AF_MISMATCH;
 						}
-#endif
 						*ip=*tmp_ip;
 						*port=h->port;
 						/* proto already set */
 						return 0;
 					}
 
-					switch(srv_proto){
-						case PROTO_NONE: /* no proto specified, use udp */
-							if (proto)
-								*proto=PROTO_UDP;
-							/* no break */
-						case PROTO_UDP:
-							memcpy(tmp, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
-							memcpy(tmp+SRV_UDP_PREFIX_LEN, name->s, name->len);
-							tmp[SRV_UDP_PREFIX_LEN + name->len] = '\0';
-							len=SRV_UDP_PREFIX_LEN + name->len;
-							break;
-						case PROTO_TCP:
-							memcpy(tmp, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
-							memcpy(tmp+SRV_TCP_PREFIX_LEN, name->s, name->len);
-							tmp[SRV_TCP_PREFIX_LEN + name->len] = '\0';
-							len=SRV_TCP_PREFIX_LEN + name->len;
-							break;
-						case PROTO_TLS:
-							memcpy(tmp, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
-							memcpy(tmp+SRV_TLS_PREFIX_LEN, name->s, name->len);
-							tmp[SRV_TLS_PREFIX_LEN + name->len] = '\0';
-							len=SRV_TLS_PREFIX_LEN + name->len;
-							break;
-						case PROTO_SCTP:
-							memcpy(tmp, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN);
-							memcpy(tmp+SRV_SCTP_PREFIX_LEN, name->s, name->len);
-							tmp[SRV_SCTP_PREFIX_LEN + name->len] = '\0';
-							len=SRV_SCTP_PREFIX_LEN + name->len;
-							break;
-						default:
-							LOG(L_CRIT, "BUG: sip_resolvehost: "
-									"unknown proto %d\n", (int)srv_proto);
-							return -E_DNS_CRITICAL;
-					}
-					srv_name.s=tmp;
-					srv_name.len=len;
-					if ((ret=dns_srv_resolve_ip(h, &srv_name, ip,
-															port, flags))>=0)
-					{
+					/* looping on the ordered list until we found a protocol what has srv record */
+					list_len = create_srv_pref_list(&origproto, srv_proto_list);
+					for (i=0; i<list_len;i++) {
+						switch (srv_proto_list[i].proto) {
+							case PROTO_UDP:
+							case PROTO_TCP:
+							case PROTO_TLS:
+							case PROTO_SCTP:
+								create_srv_name(srv_proto_list[i].proto, name, tmp);
+								break;
+							default:
+								LOG(L_CRIT, "BUG: dns_srv_sip_resolve: "
+										"unknown proto %d\n", (int)srv_proto_list[i].proto);
+								return -E_DNS_CRITICAL;
+						}
+						srv_name.s=tmp;
+						srv_name.len=strlen(tmp);
+						if ((ret=dns_srv_resolve_ip(h, &srv_name, ip, port, flags))>=0)
+						{
+							h->proto = *proto = srv_proto_list[i].proto;
 #ifdef DNS_CACHE_DEBUG
-						DBG("dns_sip_resolve(%.*s, %d, %d), srv0, ret=%d\n",
-							name->len, name->s, h->srv_no, h->ip_no, ret);
+							DBG("dns_srv_sip_resolve(%.*s, %d, %d), srv0, ret=%d\n",
+								name->len, name->s, h->srv_no, h->ip_no, ret);
 #endif
-						/* proto already set */
-						return ret;
+							return ret;
+						}
 					}
 				}
 			}else{ /* if (*port==0) */
@@ -3408,13 +3313,12 @@ inline static int dns_srv_sip_resolve(struct dns_srv_handle* h,  str* name,
 			ret=dns_srv_resolve_ip(h, &srv_name, ip, port, flags);
 			if (proto)
 				*proto=h->proto;
-			DBG("dns_sip_resolve(%.*s, %d, %d), srv, ret=%d\n",
+			DBG("dns_srv_sip_resolve(%.*s, %d, %d), srv, ret=%d\n",
 					name->len, name->s, h->srv_no, h->ip_no, ret);
 			return ret;
 	}
-/*skip_srv:*/
 	if (name->len >= MAX_DNS_NAME) {
-		LOG(L_ERR, "dns_sip_resolve: domain name too long\n");
+		LOG(L_ERR, "dns_srv_sip_resolve: domain name too long\n");
 		return -E_DNS_NAME_TOO_LONG;
 	}
 	ret=dns_ip_resolve(&h->a, &h->ip_no, name, ip, flags);
@@ -3423,7 +3327,7 @@ inline static int dns_srv_sip_resolve(struct dns_srv_handle* h,  str* name,
 	if (proto)
 		*proto=h->proto;
 #ifdef DNS_CACHE_DEBUG
-	DBG("dns_sip_resolve(%.*s, %d, %d), ip, ret=%d\n",
+	DBG("dns_srv_sip_resolve(%.*s, %d, %d), ip, ret=%d\n",
 			name->len, name->s, h->srv_no, h->ip_no, ret);
 #endif
 	return ret;
@@ -3453,11 +3357,12 @@ inline static int dns_naptr_sip_resolve(struct dns_srv_handle* h,  str* name,
 	struct ip_addr* tmp_ip;
 	naptr_bmp_t tried_bmp;
 	struct dns_hash_entry* e;
-	char n_proto;
+	char n_proto, origproto;
 	str srv_name;
 	int ret;
 
 	ret=-E_DNS_NO_NAPTR;
+	origproto=*proto;
 	if (dns_hash==0){ /* not init => use normal, non-cached version */
 		LOG(L_WARN, "WARNING: dns_sip_resolve: called before dns cache"
 					" initialization\n");
@@ -3475,17 +3380,13 @@ inline static int dns_naptr_sip_resolve(struct dns_srv_handle* h,  str* name,
 
 		/* check if it's an ip address */
 		if ( ((tmp_ip=str2ip(name))!=0)
-#ifdef	USE_IPV6
 			  || ((tmp_ip=str2ip6(name))!=0)
-#endif
 			){
 			/* we are lucky, this is an ip address */
-#ifdef	USE_IPV6
 			if (((flags&DNS_IPV4_ONLY) && (tmp_ip->af==AF_INET6))||
 				((flags&DNS_IPV6_ONLY) && (tmp_ip->af==AF_INET))){
 				return -E_DNS_AF_MISMATCH;
 			}
-#endif
 			*ip=*tmp_ip;
 			h->port=SIP_PORT;
 			h->proto=*proto;
@@ -3517,6 +3418,7 @@ inline static int dns_naptr_sip_resolve(struct dns_srv_handle* h,  str* name,
 								from previous dns_srv_sip_resolve calls */
 	}
 naptr_not_found:
+	*proto=origproto;
 	return dns_srv_sip_resolve(h, name, ip, port, proto, flags);
 }
 #endif /* USE_NAPTR */
@@ -3534,7 +3436,6 @@ naptr_not_found:
  * get the subsequent ips
  * returns:  <0 on error
  *            0 on success and it fills *ip, *port, dns_sip_resolve_h
- * WARNING: when finished, dns_sip_resolve_put(h) must be called!
  */
 int dns_sip_resolve(struct dns_srv_handle* h,  str* name,
 						struct ip_addr* ip, unsigned short* port, char* proto,
@@ -3564,7 +3465,6 @@ inline static int dns_a_get_ip(str* name, struct ip_addr* ip)
 }
 
 
-#ifdef USE_IPV6
 inline static int dns_aaaa_get_ip(str* name, struct ip_addr* ip)
 {
 	struct dns_hash_entry* e;
@@ -3577,7 +3477,6 @@ inline static int dns_aaaa_get_ip(str* name, struct ip_addr* ip)
 	if (e) dns_hash_put(e);
 	return ret;
 }
-#endif /* USE_IPV6 */
 
 
 
@@ -4288,7 +4187,6 @@ int dns_cache_add_record(unsigned short type,
 			}
 			break;
 		case T_AAAA:
-#ifdef USE_IPV6
 			ip_addr = str2ip6(value);
 			if (!ip_addr) {
 				LOG(L_ERR, "ERROR: Malformed ip address: %.*s\n",
@@ -4296,10 +4194,6 @@ int dns_cache_add_record(unsigned short type,
 				return -1;
 			}
 			break;
-#else /* USE_IPV6 */
-			LOG(L_ERR, "ERROR: IPv6 support is disabled\n");
-			return -1;
-#endif /* USE_IPV6 */
 		case T_SRV:
 			rr_name = *value;
 			break;
@@ -4596,7 +4490,6 @@ int dns_cache_delete_single_record(unsigned short type,
 			}
 			break;
 		case T_AAAA:
-#ifdef USE_IPV6
 			ip_addr = str2ip6(value);
 			if (!ip_addr) {
 				LOG(L_ERR, "ERROR: Malformed ip address: %.*s\n",
@@ -4604,10 +4497,6 @@ int dns_cache_delete_single_record(unsigned short type,
 				return -1;
 			}
 			break;
-#else /* USE_IPV6 */
-			LOG(L_ERR, "ERROR: IPv6 support is disabled\n");
-			return -1;
-#endif /* USE_IPV6 */
 		case T_SRV:
 			rr_name = *value;
 			break;
diff --git a/dns_func.c b/dns_func.c
new file mode 100644
index 0000000..da2ce7b
--- /dev/null
+++ b/dns_func.c
@@ -0,0 +1,55 @@
+
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2013  mariuszbi at gmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * DNS wrappers
+ */
+/*
+ * History:
+ * --------
+ *  2013-03 initial version (marius)
+*/
+
+#include "dns_func.h"
+
+#include <netinet/in.h>
+#include <resolv.h>
+#include <sys/types.h>
+#include <netdb.h>
+
+struct hostent;
+
+struct dns_func_t dns_func = {
+	res_init,
+	res_search,
+	gethostbyname,
+#ifdef HAVE_GETHOSTBYNAME2
+	gethostbyname2
+#else
+	NULL
+#endif
+};
+
+ 
+void load_dnsfunc(struct dns_func_t *d) {
+	dns_func.sr_res_init = d->sr_res_init;
+	dns_func.sr_res_search = d->sr_res_search;
+	dns_func.sr_gethostbyname = d->sr_gethostbyname;
+	dns_func.sr_gethostbyname2 = d->sr_gethostbyname2;
+} 
+
diff --git a/dns_func.h b/dns_func.h
new file mode 100644
index 0000000..623c3b8
--- /dev/null
+++ b/dns_func.h
@@ -0,0 +1,55 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2013 mariuszbi at gmail.com
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * DNS Wrapper functions 
+ */
+/*
+ * History:
+ * --------
+ *  2013-03  initial version (marius)
+*/
+
+#ifndef DNS_FUNC_H
+#define DNS_FUNC_H
+
+#include <sys/socket.h>
+
+struct hostent;
+
+typedef int (*res_init_t)(void);
+typedef int (*res_search_t)(const char*, int, int, unsigned char*, int);
+typedef struct hostent* (*gethostbyname_t)(const char*);
+typedef struct hostent* (*gethostbyname2_t)(const char*, int);
+
+struct dns_func_t {
+	res_init_t sr_res_init;
+	res_search_t sr_res_search;
+	gethostbyname_t sr_gethostbyname;
+	gethostbyname2_t sr_gethostbyname2;
+};
+
+/* 
+ * initiate structure with system values
+ */
+//extern struct dns_func_t dns_func;
+
+extern 
+void load_dnsfunc(struct dns_func_t *d);
+
+
+#endif
diff --git a/doc/cfg_list/Makefile b/doc/cfg_list/Makefile
index ca86a8a..7824c82 100644
--- a/doc/cfg_list/Makefile
+++ b/doc/cfg_list/Makefile
@@ -22,20 +22,22 @@ files_list= \
 	$(COREPATH)/sctp_options.c:sctp \
 	$(COREPATH)/tcp_options.c:tcp \
 	$(COREPATH)/modules/tm/config.c:tm \
-	$(COREPATH)/modules_k/registrar/config.c:registrar \
-	$(COREPATH)/modules_k/siputils/config.c:siputils \
-	$(COREPATH)/modules_s/maxfwd/maxfwd.c:maxfwd \
+	$(COREPATH)/modules/registrar/config.c:registrar \
+	$(COREPATH)/modules/siputils/config.c:siputils \
+	$(COREPATH)/modules/maxfwd/maxfwd.c:maxfwd \
 	$(COREPATH)/modules/carrierroute/config.c:carrierroute \
 	$(COREPATH)/modules/malloc_test/malloc_test.c:malloc_test \
 	$(COREPATH)/modules/tls/tls_cfg.c:tls \
-	$(COREPATH)/modules_k/dispatcher/config.c:dispatcher
-
+	$(COREPATH)/modules/dispatcher/config.c:dispatcher \
+	$(COREPATH)/modules/websocket/config.c:websocket \
+	$(COREPATH)/modules/outbound/config.c:outbound \
+	$(COREPATH)/modules/stun/config.c:stun
 
 
 # list of excluded groups
 grp_exclude=pa
 # list of file prefixes to exclude (full path needed)
-file_exclude= $(COREPATH)/modules_s/tls/
+file_exclude= $(COREPATH)/modules/tls/
 
 # special per file group overrides
 # format= grp_filename=... ,where filename does not contain the extension
@@ -61,7 +63,7 @@ gcc=gcc
 
 # defines used by gcc
 c_defs=-D__CPU_i386 -D__OS_linux -DSER_VER=2099099 -DPKG_MALLOC -DSHM_MEM  \
-		-DSHM_MMAP -DDNS_IP_HACK -DUSE_IPV6 -DUSE_MCAST -DUSE_TCP \
+		-DSHM_MMAP -DDNS_IP_HACK -DUSE_MCAST -DUSE_TCP \
 		-DUSE_DNS_CACHE -DUSE_DNS_FAILOVER -DUSE_DST_BLACKLIST -DUSE_NAPTR \
 		-DUSE_TLS -DTLS_HOOKS -DFAST_LOCK   -DCC_GCC_LIKE_ASM \
 		-DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
diff --git a/doc/cfg_list/cfg_core.txt b/doc/cfg_list/cfg_core.txt
index be6a565..15a731f 100644
--- a/doc/cfg_list/cfg_core.txt
+++ b/doc/cfg_list/cfg_core.txt
@@ -254,8 +254,39 @@ Configuration Variables for core
         memory debugging information displayed on exit (flags):  0 -
         off, 1 - dump all the pkg used blocks (status), 2 - dump all
         the shm used blocks (status), 4 - summary of pkg used blocks, 8
-        - summary of shm used blocks.
+        - summary of shm used blocks, 16 - short status instead of
+        dump.
         Default: 3.
-        Range: 0 - 15.
+        Range: 0 - 31.
+        Type: integer.
+
+44. core.mem_safety
+        safety level for memory operations.
+        Default: 0.
+        Type: integer.
+
+45. core.mem_join
+        join free memory fragments.
+        Default: 0.
+        Type: integer.
+
+46. core.corelog
+        log level for non-critical core error messages.
+        Default: -1.
+        Type: integer.
+
+47. core.latency_log
+        log level for latency limits alert messages.
+        Default: -1.
+        Type: integer.
+
+48. core.latency_limit_db
+        limit is ms for alerting on time consuming db commands.
+        Default: 0.
+        Type: integer.
+
+49. core.latency_limit_action
+        limit is ms for alerting on time consuming config actions.
+        Default: 0.
         Type: integer.
 
diff --git a/doc/cfg_list/cfg_registrar.txt b/doc/cfg_list/cfg_registrar.txt
index b959ea1..231238b 100644
--- a/doc/cfg_list/cfg_registrar.txt
+++ b/doc/cfg_list/cfg_registrar.txt
@@ -4,62 +4,63 @@ Configuration Variables for registrar
                   [ this file is autogenerated, do not edit ]
 
 
- 1. registrar.default_expires
+ 1. registrar.realm_pref
+        Realm prefix to be removed. Default is "".
+        Default: <unknown:str>.
+        Type: string.
+
+ 2. registrar.default_expires
         Contains number of second to expire if no expire hf or contact
         expire present.
         Default: 3600.
         Type: integer.
 
- 2. registrar.default_expires_range
+ 3. registrar.default_expires_range
         Percent from default_expires that will be used in generating
         the range for the expire interval.
         Default: 0.
         Range: 0 - 100.
         Type: integer.
 
- 3. registrar.min_expires
+ 4. registrar.min_expires
         The minimum expires value of a Contact. Value 0 disables the
         checking. .
         Default: 60.
         Type: integer.
 
- 4. registrar.max_expires
+ 5. registrar.max_expires
         The maximum expires value of a Contact. Value 0 disables the
         checking. .
         Default: 0.
         Type: integer.
 
- 5. registrar.max_contacts
+ 6. registrar.max_contacts
         The maximum number of Contacts for an AOR. Value 0 disables the
         checking. .
         Default: 0.
         Type: integer.
 
- 6. registrar.retry_after
+ 7. registrar.retry_after
         If you want to add the Retry-After header field in 5xx replies,
         set this parameter to a value grater than zero.
         Default: 0.
         Type: integer.
 
- 7. registrar.case_sensitive
+ 8. registrar.case_sensitive
         If set to 1 then AOR comparison will be case sensitive.
         Recommended and default is 0, case insensitive.
         Default: 0.
         Type: integer.
 
- 8. registrar.default_q
+ 9. registrar.default_q
         The parameter represents default q value for new contacts..
         Default: -1.
         Range: -1 - 1000.
         Type: integer.
 
- 9. registrar.append_branches
+10. registrar.append_branches
         If set to 1(default), lookup will put all contacts found in msg
         structure.
         Default: 1.
         Type: integer.
 
-10. registrar.realm_pref
-        Realm prefix to be removed. Default is "".
-        Type: string.
-
diff --git a/doc/cfg_list/cfg_tcp.txt b/doc/cfg_list/cfg_tcp.txt
index a71fe53..e7f2872 100644
--- a/doc/cfg_list/cfg_tcp.txt
+++ b/doc/cfg_list/cfg_tcp.txt
@@ -20,121 +20,126 @@ Configuration Variables for tcp
         Type: integer.
 
  4. tcp.max_connections
-        maximum connection number, soft limit.
+        maximum tcp connections number, soft limit.
         Range: 0 - 2147483647.
         Type: integer.
 
- 5. tcp.no_connect
+ 5. tcp.max_tls_connections
+        maximum tls connections number, soft limit.
+        Range: 0 - 2147483647.
+        Type: integer.
+
+ 6. tcp.no_connect
         if set only accept new connections, never actively open new
         ones.
         Range: 0 - 1.
         Type: integer.
 
- 6. tcp.fd_cache
+ 7. tcp.fd_cache
         file descriptor cache for tcp_send.
         Range: 0 - 1.
         Type: integer. Read-only.
 
- 7. tcp.async
+ 8. tcp.async
         async mode for writes and connects.
         Range: 0 - 1.
         Type: integer. Read-only.
 
- 8. tcp.connect_wait
+ 9. tcp.connect_wait
         parallel simultaneous connects to the same dst. (0) or one
         connect.
         Range: 0 - 1.
         Type: integer. Read-only.
 
- 9. tcp.conn_wq_max
+10. tcp.conn_wq_max
         maximum bytes queued for write per connection (depends on
         async).
         Range: 0 - 1048576.
         Type: integer.
 
-10. tcp.wq_max
+11. tcp.wq_max
         maximum bytes queued for write allowed globally (depends on
         async).
         Range: 0 - 1073741824.
         Type: integer.
 
-11. tcp.defer_accept
+12. tcp.defer_accept
         0/1 on linux, seconds on freebsd (see docs).
         Range: 0 - 3600.
         Type: integer. Read-only.
 
-12. tcp.delayed_ack
+13. tcp.delayed_ack
         initial ack will be delayed and sent with the first data
         segment.
         Range: 0 - 1.
         Type: integer.
 
-13. tcp.syncnt
+14. tcp.syncnt
         number of syn retransmissions before aborting a connect (0=not
         set).
         Range: 0 - 1024.
         Type: integer.
 
-14. tcp.linger2
+15. tcp.linger2
         lifetime of orphaned sockets in FIN_WAIT2 state in s (0=not
         set).
         Range: 0 - 3600.
         Type: integer.
 
-15. tcp.keepalive
+16. tcp.keepalive
         enables/disables keepalives for tcp.
         Range: 0 - 1.
         Type: integer.
 
-16. tcp.keepidle
+17. tcp.keepidle
         time before sending a keepalive if the connection is idle
         (linux).
         Range: 0 - 86400.
         Type: integer.
 
-17. tcp.keepintvl
+18. tcp.keepintvl
         time interval between keepalive probes on failure (linux).
         Range: 0 - 86400.
         Type: integer.
 
-18. tcp.keepcnt
+19. tcp.keepcnt
         number of failed keepalives before dropping the connection
         (linux).
         Range: 0 - 1024.
         Type: integer.
 
-19. tcp.crlf_ping
+20. tcp.crlf_ping
         enable responding to CRLF SIP-level keepalives .
         Range: 0 - 1.
         Type: integer.
 
-20. tcp.accept_aliases
+21. tcp.accept_aliases
         turn on/off tcp aliases (see tcp_accept_aliases) .
         Range: 0 - 1.
         Type: integer.
 
-21. tcp.alias_flags
+22. tcp.alias_flags
         flags used for adding new aliases (FORCE_ADD:1 , REPLACE:2) .
         Range: 0 - 2.
         Type: integer.
 
-22. tcp.new_conn_alias_flags
+23. tcp.new_conn_alias_flags
         flags for the def. aliases for a new conn. (FORCE_ADD:1,
         REPLACE:2 .
         Range: 0 - 2.
         Type: integer.
 
-23. tcp.accept_no_cl
-        accept TCP messges without Content-Lenght .
+24. tcp.accept_no_cl
+        accept TCP messges without Content-Length .
         Range: 0 - 1.
         Type: integer.
 
-24. tcp.rd_buf_size
+25. tcp.rd_buf_size
         internal read buffer size (should be > max. expected datagram).
-        Range: 512 - 65536.
+        Range: 512 - 16777216.
         Type: integer.
 
-25. tcp.wq_blk_size
+26. tcp.wq_blk_size
         internal async write block size (debugging use only for now).
         Range: 1 - 65535.
         Type: integer.
diff --git a/doc/cfg_list/cfg_tm.txt b/doc/cfg_list/cfg_tm.txt
index 7478214..5600165 100644
--- a/doc/cfg_list/cfg_tm.txt
+++ b/doc/cfg_list/cfg_tm.txt
@@ -16,95 +16,100 @@ Configuration Variables for tm
         Range: 0 - 1.
         Type: integer.
 
- 3. tm.fr_timer
+ 3. tm.callid_matching
+        perform callid check in transaction matching.
+        Default: 0.
+        Type: integer.
+
+ 4. tm.fr_timer
         timer which hits if no final reply for a request or ACK for a
         negative INVITE reply arrives (in milliseconds).
         Default: 30000.
         Type: integer.
 
- 4. tm.fr_inv_timer
+ 5. tm.fr_inv_timer
         timer which hits if no final reply for an INVITE arrives after
         a provisional message was received (in milliseconds).
         Default: 120000.
         Type: integer.
 
- 5. tm.fr_inv_timer_next
+ 6. tm.fr_inv_timer_next
         The value [ms] of fr_inv_timer for subsequent branches during
         serial forking..
         Default: 30000.
         Type: integer.
 
- 6. tm.wt_timer
+ 7. tm.wt_timer
         time for which a transaction stays in memory to absorb delayed
         messages after it completed.
         Default: 5000.
         Type: integer.
 
- 7. tm.delete_timer
+ 8. tm.delete_timer
         time after which a to-be-deleted transaction currently ref-ed
         by a process will be tried to be deleted again..
         Default: 200.
         Type: integer.
 
- 8. tm.retr_timer1
+ 9. tm.retr_timer1
         initial retransmission period (in milliseconds).
         Default: 500.
         Type: integer.
 
- 9. tm.retr_timer2
+10. tm.retr_timer2
         maximum retransmission period (in milliseconds).
         Default: 4000.
         Type: integer.
 
-10. tm.max_inv_lifetime
+11. tm.max_inv_lifetime
         maximum time an invite transaction can live from the moment of
         creation.
         Default: 180000.
         Type: integer.
 
-11. tm.max_noninv_lifetime
+12. tm.max_noninv_lifetime
         maximum time a non-invite transaction can live from the moment
         of creation.
         Default: 32000.
         Type: integer.
 
-12. tm.noisy_ctimer
+13. tm.noisy_ctimer
         if set, INVITE transactions that time-out (FR INV timer) will
         be always replied.
         Default: 1.
         Range: 0 - 1.
         Type: integer.
 
-13. tm.auto_inv_100
+14. tm.auto_inv_100
         automatically send 100 to an INVITE.
         Default: 1.
         Range: 0 - 1.
         Type: integer.
 
-14. tm.auto_inv_100_reason
+15. tm.auto_inv_100_reason
         reason text of the automatically send 100 to an INVITE.
         Default: trying -- your call is important to us.
         Type: string.
 
-15. tm.unix_tx_timeout
+16. tm.unix_tx_timeout
         Unix socket transmission timeout, in milliseconds.
         Default: 500.
         Type: integer.
 
-16. tm.restart_fr_on_each_reply
+17. tm.restart_fr_on_each_reply
         restart final response timer on each provisional reply.
         Default: 1.
         Range: 0 - 1.
         Type: integer.
 
-17. tm.pass_provisional_replies
+18. tm.pass_provisional_replies
         enable/disable passing of provisional replies to
         TMCB_LOCAL_RESPONSE_OUT callbacks.
         Default: 0.
         Range: 0 - 1.
         Type: integer.
 
-18. tm.aggregate_challenges
+19. tm.aggregate_challenges
         if the final response is a 401 or a 407, aggregate all the
         authorization headers (challenges) (rfc3261 requires this to be
         on).
@@ -112,27 +117,27 @@ Configuration Variables for tm
         Range: 0 - 1.
         Type: integer.
 
-19. tm.unmatched_cancel
+20. tm.unmatched_cancel
         determines how CANCELs with no matching transaction are handled
         (0: statefull forwarding, 1: stateless forwarding, 2: drop).
         Default: 0.
         Range: 0 - 2.
         Type: integer.
 
-20. tm.default_code
+21. tm.default_code
         default SIP response code sent by t_reply(), if the function
         cannot retrieve its parameters.
         Default: 500.
         Range: 400 - 699.
         Type: integer.
 
-21. tm.default_reason
+22. tm.default_reason
         default SIP reason phrase sent by t_reply(), if the function
         cannot retrieve its parameters.
         Default: Server Internal Error.
         Type: string.
 
-22. tm.reparse_invite
+23. tm.reparse_invite
         if set to 1, the CANCEL and negative ACK requests are
         constructed from the INVITE message which was sent out instead
         of building them from the received request.
@@ -140,55 +145,55 @@ Configuration Variables for tm
         Range: 0 - 1.
         Type: integer.
 
-23. tm.ac_extra_hdrs
+24. tm.ac_extra_hdrs
         header fields prefixed by this parameter value are included in
         the CANCEL and negative ACK messages if they were present in
         the outgoing INVITE (depends on reparse_invite).
         Default: <unknown:str>.
         Type: string.
 
-24. tm.blst_503
+25. tm.blst_503
         if set to 1, blacklist 503 SIP response sources.
         Default: 0.
         Range: 0 - 1.
         Type: integer.
 
-25. tm.blst_503_def_timeout
+26. tm.blst_503_def_timeout
         default 503 blacklist time (in s), when no Retry-After header
         is present.
         Default: 0.
         Type: integer.
 
-26. tm.blst_503_min_timeout
+27. tm.blst_503_min_timeout
         minimum 503 blacklist time (in s).
         Default: 0.
         Type: integer.
 
-27. tm.blst_503_max_timeout
+28. tm.blst_503_max_timeout
         maximum 503 blacklist time (in s).
         Default: 3600.
         Type: integer.
 
-28. tm.blst_methods_add
+29. tm.blst_methods_add
         bitmap of method types that trigger blacklisting on transaction
         timeouts.
         Default: 1.
         Type: integer.
 
-29. tm.blst_methods_lookup
+30. tm.blst_methods_lookup
         Bitmap of method types that are looked-up in the blacklist
         before statefull forwarding.
         Default: -9.
         Type: integer.
 
-30. tm.cancel_b_method
+31. tm.cancel_b_method
         How to cancel branches on which no replies were received: 0 -
         fake reply, 1 - retransmitting the request, 2 - send cancel.
         Default: 1.
         Range: 0 - 2.
         Type: integer.
 
-31. tm.reparse_on_dns_failover
+32. tm.reparse_on_dns_failover
         if set to 1, the SIP message after a DNS failover is
         constructed from the outgoing message buffer of the failed
         branch instead of from the received request.
@@ -196,13 +201,13 @@ Configuration Variables for tm
         Range: 0 - 1.
         Type: integer.
 
-32. tm.disable_6xx_block
+33. tm.disable_6xx_block
         if set to 1, 6xx is treated like a normal reply (breaks rfc).
         Default: 0.
         Range: 0 - 1.
         Type: integer.
 
-33. tm.local_ack_mode
+34. tm.local_ack_mode
         if set to 1 or 2, local 200 ACKs are sent to the same address
         as the corresponding INVITE (1) or the source of the 200 reply
         (2) instead of using the contact and the route set (it breaks
@@ -212,14 +217,14 @@ Configuration Variables for tm
         Range: 0 - 2.
         Type: integer.
 
-34. tm.local_cancel_reason
+35. tm.local_cancel_reason
         if set to 1, a Reason header is added to locally generated
         CANCELs (see RFC3326).
         Default: 1.
         Range: 0 - 1.
         Type: integer.
 
-35. tm.e2e_cancel_reason
+36. tm.e2e_cancel_reason
         if set to 1, Reason headers from received CANCELs are copied
         into the corresponding generated hop-by-hop CANCELs.
         Default: 1.
diff --git a/doc/counter_list/Makefile b/doc/counter_list/Makefile
index 5b25e94..d07566b 100644
--- a/doc/counter_list/Makefile
+++ b/doc/counter_list/Makefile
@@ -57,7 +57,7 @@ gcc=gcc
 
 # defines used by gcc
 c_defs=-D__CPU_i386 -D__OS_linux -DSER_VER=2099099 -DPKG_MALLOC -DSHM_MEM  \
-		-DSHM_MMAP -DDNS_IP_HACK -DUSE_IPV6 -DUSE_MCAST -DUSE_TCP \
+		-DSHM_MMAP -DDNS_IP_HACK -DUSE_MCAST -DUSE_TCP \
 		-DUSE_DNS_CACHE -DUSE_DNS_FAILOVER -DUSE_DST_BLACKLIST -DUSE_NAPTR \
 		-DUSE_TLS -DTLS_HOOKS -DFAST_LOCK   -DCC_GCC_LIKE_ASM \
 		-DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
diff --git a/doc/rpc_list/Makefile b/doc/rpc_list/Makefile
index 4c2f9e0..69a9ba5 100644
--- a/doc/rpc_list/Makefile
+++ b/doc/rpc_list/Makefile
@@ -22,35 +22,52 @@ docbook_output_dir=docbook
 #
 files_list= \
 			$(COREPATH)/core_cmd.c:core \
+			$(COREPATH)/modules/app_lua/app_lua_mod.c:app_lua \
+			$(COREPATH)/modules/carrierroute/carrierroute.c:carrierroute \
 			$(COREPATH)/modules/cfg_rpc/cfg_rpc.c:cfg_rpc \
+			$(COREPATH)/modules/cnxcc/cnxcc_mod.c:cnxcc \
+			$(COREPATH)/modules/corex/corex_rpc.c:corex \
 			$(COREPATH)/modules/counters/counters.c:counters \
 			$(COREPATH)/modules/ctl/ctl.c:ctl \
 			$(COREPATH)/modules/db_flatstore/flat_rpc.c:db_flatstore \
+			$(COREPATH)/modules/db_flatstore/km_flatstore_mod.c:db_flatstore \
+			$(COREPATH)/modules/db_text/dbtext.c:db_text \
 			$(COREPATH)/modules/debugger/debugger_api.c:debugger \
+			$(COREPATH)/modules/dialog/dialog.c:dialog \
+			$(COREPATH)/modules/dialog_ng/dialog.c:dialog_ng \
 			$(COREPATH)/modules/dialplan/dialplan.c:dialplan \
+			$(COREPATH)/modules/dispatcher/dispatcher.c:dispatcher \
+			$(COREPATH)/modules/domain/domain_mod.c:domain \
+			$(COREPATH)/modules/drouting/drouting.c:drouting \
+			$(COREPATH)/modules/htable/htable.c:htable \
+			$(COREPATH)/modules/ims_usrloc_pcscf/ul_rpc.c:ims_usrloc_pcscf \
+			$(COREPATH)/modules/ims_usrloc_scscf/ul_rpc.c:ims_usrloc_scscf \
+			$(COREPATH)/modules/kex/pkg_stats.c:kex \
 			$(COREPATH)/modules/lcr/lcr_rpc.c:lcr \
 			$(COREPATH)/modules/malloc_test/malloc_test.c:malloc_test \
 			$(COREPATH)/modules/mi_rpc/mi_rpc_mod.c:mi_rpc \
+			$(COREPATH)/modules/msrp/msrp_cmap.c:msrp \
+			$(COREPATH)/modules/mtree/mtree_mod.c:mtree \
+			$(COREPATH)/modules/pdt/pdt.c:pdt \
+			$(COREPATH)/modules/permissions/permissions.c:permissions \
+			$(COREPATH)/modules/pike/pike_rpc.c:pike \
+			$(COREPATH)/modules/pipelimit/pipelimit.c:pipelimit \
 			$(COREPATH)/modules/prefix_route/pr_rpc.c:prefix_route \
+			$(COREPATH)/modules/presence/presence.c:presence \
+			$(COREPATH)/modules/pv/pv.c:pv \
 			$(COREPATH)/modules/ratelimit/ratelimit.c:ratelimit \
+			$(COREPATH)/modules/sca/sca.c:sca \
+			$(COREPATH)/modules/sctp/sctp_rpc.c:sctp \
+			$(COREPATH)/modules/sipcapture/sipcapture.c:sipcapture \
+			$(COREPATH)/modules/siptrace/siptrace.c:siptrace \
 			$(COREPATH)/modules/sl/sl_stats.c:sl \
 			$(COREPATH)/modules/tls/tls_rpc.c:tls \
 			$(COREPATH)/modules/tm/tm.c:tm \
-			$(COREPATH)/modules_k/dialog/dialog.c:dialog \
-			$(COREPATH)/modules_k/dispatcher/dispatcher.c:dispatcher \
-			$(COREPATH)/modules_k/domain/domain_mod.c:domain \
-			$(COREPATH)/modules_k/htable/htable.c:htable \
-			$(COREPATH)/modules_k/kex/pkg_stats.c:kex \
-			$(COREPATH)/modules_k/uac/uac_reg.c:uac \
-			$(COREPATH)/modules_k/usrloc/ul_rpc.c:usrloc \
-			$(COREPATH)/modules_s/cpl-c/cpl_rpc.c:cpl-c \
-			$(COREPATH)/modules_s/dispatcher/ds_rpc.c:dispatcher_s \
-			$(COREPATH)/modules_s/domain/domain_rpc.c:domain_s \
-			$(COREPATH)/modules_s/gflags/gflags.c:gflags \
-			$(COREPATH)/modules_s/pdt/pdt.c:pdt \
-			$(COREPATH)/modules_s/pike/rpc.c:pike \
-			$(COREPATH)/modules_s/presence_b2b/rpc.c:presence_b2b \
-			$(COREPATH)/modules_s/usrloc/ul_rpc.c:usrloc_s
+			$(COREPATH)/modules/uac/uac_reg.c:uac \
+			$(COREPATH)/modules/uid_domain/domain_rpc.c:uid_domain \
+			$(COREPATH)/modules/uid_gflags/uid_gflags.c:uid_gflags \
+			$(COREPATH)/modules/usrloc/ul_rpc.c:usrloc \
+			$(COREPATH)/modules/xhttp_pi/xhttp_pi.c:xhttp_pi
 
 # list of excluded groups
 grp_exclude=pa
@@ -84,7 +101,7 @@ gcc=gcc
 # -D__CPU_i386 -DARCH="i386"
 c_defsX= -D__CPU_x86_64 -D__OS_linux -DSER_VER=3003000 -DPKG_MALLOC -DSHM_MEM  \
 		-DVERSION='\"3.3.0-dev2\"' -DARCH='\"x86_64\"' -DOS=linux_ -DOS_QUOTED='\"linux\"' \
-		-DSHM_MMAP -DDNS_IP_HACK -DUSE_IPV6 -DUSE_MCAST -DUSE_TCP \
+		-DSHM_MMAP -DDNS_IP_HACK -DUSE_MCAST -DUSE_TCP \
 		-DUSE_DNS_CACHE -DUSE_DNS_FAILOVER -DUSE_DST_BLACKLIST -DUSE_NAPTR \
 		-DUSE_TLS -DTLS_HOOKS -DFAST_LOCK   -DCC_GCC_LIKE_ASM \
 		-DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
diff --git a/doc/rpc_list/docbook/rpc_app_lua.xml b/doc/rpc_list/docbook/rpc_app_lua.xml
new file mode 100644
index 0000000..0925d42
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_app_lua.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.app_lua">
+	<title>
+RPC Exports for app_lua
+	</title>
+
+
+<section id="app_lua.reload"><title>app_lua.reload</title>
+<para>
+        Reload lua script
+</para>
+<para>
+</para>
+</section>
+
+<section id="app_lua.list"><title>app_lua.list</title>
+<para>
+        list lua scripts
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_carrierroute.xml b/doc/rpc_list/docbook/rpc_carrierroute.xml
new file mode 100644
index 0000000..c424a8f
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_carrierroute.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.carrierroute">
+	<title>
+RPC Exports for carrierroute
+	</title>
+
+
+<section id="cr.reload_routes"><title>cr.reload_routes</title>
+<para>
+        Reload routes
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_cnxcc.xml b/doc/rpc_list/docbook/rpc_cnxcc.xml
new file mode 100644
index 0000000..03f6085
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_cnxcc.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.cnxcc">
+	<title>
+RPC Exports for cnxcc
+	</title>
+
+
+<section id="cnxcc.active_clients"><title>cnxcc.active_clients</title>
+<para>
+        List of clients with active calls
+</para>
+<para>
+</para>
+</section>
+
+<section id="cnxcc.check_client"><title>cnxcc.check_client</title>
+<para>
+        Check specific client calls
+</para>
+<para>
+</para>
+</section>
+
+<section id="cnxcc.kill_call"><title>cnxcc.kill_call</title>
+<para>
+        Kill call using its call ID
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_core.xml b/doc/rpc_list/docbook/rpc_core.xml
index dd7e5be..851d770 100644
--- a/doc/rpc_list/docbook/rpc_core.xml
+++ b/doc/rpc_list/docbook/rpc_core.xml
@@ -163,31 +163,33 @@ RPC Exports for core
 </para>
 </section>
 
-<section id="core.sctp_options"><title>core.sctp_options</title>
+<section id="core.tcp_list"><title>core.tcp_list</title>
 <para>
-        Returns active sctp options. With one parameter it returns the
-        sctp options set in the kernel for a specific
-        socket(debugging), with 0 filled in for non-kernel related
-        options. The parameter can be: "default" |
-        "first" | address[:port] . With no parameters it
-        returns ser's idea of the current sctp options (intended
-        non-debugging use).
+        Returns tcp connections details.
 </para>
 <para>
 </para>
 </section>
 
-<section id="core.sctp_info"><title>core.sctp_info</title>
+<section id="core.udp4_raw_info"><title>core.udp4_raw_info</title>
 <para>
-        Returns sctp related info.
+        Returns udp4_raw related info.
 </para>
 <para>
 </para>
 </section>
 
-<section id="core.udp4_raw_info"><title>core.udp4_raw_info</title>
+<section id="core.aliases_list"><title>core.aliases_list</title>
 <para>
-        Returns udp4_raw related info.
+        List local SIP server host aliases
+</para>
+<para>
+</para>
+</section>
+
+<section id="core.sockets_list"><title>core.sockets_list</title>
+<para>
+        List local SIP server listen sockets
 </para>
 <para>
 </para>
diff --git a/doc/rpc_list/docbook/rpc_corex.xml b/doc/rpc_list/docbook/rpc_corex.xml
new file mode 100644
index 0000000..fcc4f48
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_corex.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.corex">
+	<title>
+RPC Exports for corex
+	</title>
+
+
+<section id="corex.list_sockets"><title>corex.list_sockets</title>
+<para>
+        List listening sockets
+</para>
+<para>
+</para>
+</section>
+
+<section id="corex.list_aliases"><title>corex.list_aliases</title>
+<para>
+        List socket aliases
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_cpl-c.xml b/doc/rpc_list/docbook/rpc_cpl-c.xml
deleted file mode 100644
index bb22ae6..0000000
--- a/doc/rpc_list/docbook/rpc_cpl-c.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- this file is autogenerated, do not edit! -->
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<chapter id="rpc_exports.cpl-c">
-	<title>
-RPC Exports for cpl-c
-	</title>
-
-
-<section id="cpl.load"><title>cpl.load</title>
-<para>
-        Load a CPL script to the server.
-</para>
-<para>
-</para>
-</section>
-
-<section id="cpl.remove"><title>cpl.remove</title>
-<para>
-        Remove a CPL script from server.
-</para>
-<para>
-</para>
-</section>
-
-<section id="cpl.get"><title>cpl.get</title>
-<para>
-        Return a CPL script.
-</para>
-<para>
-</para>
-</section>
-
-</chapter>
diff --git a/doc/rpc_list/docbook/rpc_db_flatstore.xml b/doc/rpc_list/docbook/rpc_db_flatstore.xml
index 013ae62..fe37391 100644
--- a/doc/rpc_list/docbook/rpc_db_flatstore.xml
+++ b/doc/rpc_list/docbook/rpc_db_flatstore.xml
@@ -8,9 +8,9 @@ RPC Exports for db_flatstore
 	</title>
 
 
-<section id="flatstore.rotate"><title>flatstore.rotate</title>
+<section id="flatstore.k_rotate"><title>flatstore.k_rotate</title>
 <para>
-        Documentation missing (flat_rotate_doc).
+        Close and reopen flatrotate files during log rotation.
 </para>
 <para>
 </para>
diff --git a/doc/rpc_list/docbook/rpc_db_text.xml b/doc/rpc_list/docbook/rpc_db_text.xml
new file mode 100644
index 0000000..ba99147
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_db_text.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.db_text">
+	<title>
+RPC Exports for db_text
+	</title>
+
+
+<section id="db_text.dump"><title>db_text.dump</title>
+<para>
+        Write back to disk modified tables
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_debugger.xml b/doc/rpc_list/docbook/rpc_debugger.xml
index 893691f..59ce7bf 100644
--- a/doc/rpc_list/docbook/rpc_debugger.xml
+++ b/doc/rpc_list/docbook/rpc_debugger.xml
@@ -10,7 +10,7 @@ RPC Exports for debugger
 
 <section id="dbg.bp"><title>dbg.bp</title>
 <para>
-        Documentation missing (dbg_rpc_bp_doc).
+        Breakpoint command
 </para>
 <para>
 </para>
@@ -32,4 +32,20 @@ RPC Exports for debugger
 </para>
 </section>
 
+<section id="dbg.mod_level"><title>dbg.mod_level</title>
+<para>
+        Specify module log level
+</para>
+<para>
+</para>
+</section>
+
+<section id="dbg.reset_msgid"><title>dbg.reset_msgid</title>
+<para>
+        Reset msgid on all process
+</para>
+<para>
+</para>
+</section>
+
 </chapter>
diff --git a/doc/rpc_list/docbook/rpc_dialog_ng.xml b/doc/rpc_list/docbook/rpc_dialog_ng.xml
new file mode 100644
index 0000000..33a4da9
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_dialog_ng.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.dialog_ng">
+	<title>
+RPC Exports for dialog_ng
+	</title>
+
+
+<section id="dlg2.list"><title>dlg2.list</title>
+<para>
+        Print all dialogs
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_dialplan.xml b/doc/rpc_list/docbook/rpc_dialplan.xml
index 72eae46..b2f64dd 100644
--- a/doc/rpc_list/docbook/rpc_dialplan.xml
+++ b/doc/rpc_list/docbook/rpc_dialplan.xml
@@ -16,7 +16,7 @@ RPC Exports for dialplan
 </para>
 </section>
 
-<section id="dialplan.dump"><title>dialplan.dump</title>
+<section id="dialplan.translate"><title>dialplan.translate</title>
 <para>
         Perform dialplan translation
 </para>
diff --git a/doc/rpc_list/docbook/rpc_dispatcher_s.xml b/doc/rpc_list/docbook/rpc_dispatcher_s.xml
deleted file mode 100644
index 7a86537..0000000
--- a/doc/rpc_list/docbook/rpc_dispatcher_s.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- this file is autogenerated, do not edit! -->
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<chapter id="rpc_exports.dispatcher_s">
-	<title>
-RPC Exports for dispatcher_s
-	</title>
-
-
-<section id="dispatcher.dump"><title>dispatcher.dump</title>
-<para>
-        Dump dispatcher set configuration
-</para>
-<para>
-</para>
-</section>
-
-<section id="dispatcher.reload"><title>dispatcher.reload</title>
-<para>
-        Reload dispatcher list from file
-</para>
-<para>
-</para>
-</section>
-
-</chapter>
diff --git a/doc/rpc_list/docbook/rpc_domain.xml b/doc/rpc_list/docbook/rpc_domain.xml
index 0168ef9..6486642 100644
--- a/doc/rpc_list/docbook/rpc_domain.xml
+++ b/doc/rpc_list/docbook/rpc_domain.xml
@@ -10,7 +10,7 @@ RPC Exports for domain
 
 <section id="domain.reload"><title>domain.reload</title>
 <para>
-        Reload domain table from database
+        Reload domain tables from database
 </para>
 <para>
 </para>
@@ -18,7 +18,7 @@ RPC Exports for domain
 
 <section id="domain.dump"><title>domain.dump</title>
 <para>
-        Return the contents of domain table
+        Return the contents of domain and domain_attrs tables
 </para>
 <para>
 </para>
diff --git a/doc/rpc_list/docbook/rpc_domain_s.xml b/doc/rpc_list/docbook/rpc_domain_s.xml
deleted file mode 100644
index 171c0c6..0000000
--- a/doc/rpc_list/docbook/rpc_domain_s.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- this file is autogenerated, do not edit! -->
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<chapter id="rpc_exports.domain_s">
-	<title>
-RPC Exports for domain_s
-	</title>
-
-
-<section id="domain.reload"><title>domain.reload</title>
-<para>
-        Reload domain table from database
-</para>
-<para>
-</para>
-</section>
-
-<section id="domain.dump"><title>domain.dump</title>
-<para>
-        Return the contents of domain table
-</para>
-<para>
-</para>
-</section>
-
-</chapter>
diff --git a/doc/rpc_list/docbook/rpc_drouting.xml b/doc/rpc_list/docbook/rpc_drouting.xml
new file mode 100644
index 0000000..11af66d
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_drouting.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.drouting">
+	<title>
+RPC Exports for drouting
+	</title>
+
+
+<section id="drouting.reload"><title>drouting.reload</title>
+<para>
+        Write back to disk modified tables
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_gflags.xml b/doc/rpc_list/docbook/rpc_gflags.xml
deleted file mode 100644
index 141a714..0000000
--- a/doc/rpc_list/docbook/rpc_gflags.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- this file is autogenerated, do not edit! -->
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<chapter id="rpc_exports.gflags">
-	<title>
-RPC Exports for gflags
-	</title>
-
-
-<section id="gflags.set"><title>gflags.set</title>
-<para>
-        Load a CPL script to the server.
-</para>
-<para>
-</para>
-</section>
-
-<section id="gflags.is_set"><title>gflags.is_set</title>
-<para>
-        Load a CPL script to the server.
-</para>
-<para>
-</para>
-</section>
-
-<section id="gflags.reset"><title>gflags.reset</title>
-<para>
-        Load a CPL script to the server.
-</para>
-<para>
-</para>
-</section>
-
-<section id="gflags.flush"><title>gflags.flush</title>
-<para>
-        Load a CPL script to the server.
-</para>
-<para>
-</para>
-</section>
-
-<section id="gflags.dump"><title>gflags.dump</title>
-<para>
-        Load a CPL script to the server.
-</para>
-<para>
-</para>
-</section>
-
-<section id="global.reload"><title>global.reload</title>
-<para>
-        Reload global attributes from database
-</para>
-<para>
-</para>
-</section>
-
-</chapter>
diff --git a/doc/rpc_list/docbook/rpc_htable.xml b/doc/rpc_list/docbook/rpc_htable.xml
index ddfa8fd..84d02c6 100644
--- a/doc/rpc_list/docbook/rpc_htable.xml
+++ b/doc/rpc_list/docbook/rpc_htable.xml
@@ -16,4 +16,60 @@ RPC Exports for htable
 </para>
 </section>
 
+<section id="htable.delete"><title>htable.delete</title>
+<para>
+        Delete one key from a hash table.
+</para>
+<para>
+</para>
+</section>
+
+<section id="htable.get"><title>htable.get</title>
+<para>
+        Get one key from a hash table.
+</para>
+<para>
+</para>
+</section>
+
+<section id="htable.sets"><title>htable.sets</title>
+<para>
+        Set one key in a hash table to a string value.
+</para>
+<para>
+</para>
+</section>
+
+<section id="htable.seti"><title>htable.seti</title>
+<para>
+        Set one key in a hash table to an integer value.
+</para>
+<para>
+</para>
+</section>
+
+<section id="htable.listTables"><title>htable.listTables</title>
+<para>
+        List all htables.
+</para>
+<para>
+</para>
+</section>
+
+<section id="htable.reload"><title>htable.reload</title>
+<para>
+        Reload hash table.
+</para>
+<para>
+</para>
+</section>
+
+<section id="htable.stats"><title>htable.stats</title>
+<para>
+        Statistics about htables.
+</para>
+<para>
+</para>
+</section>
+
 </chapter>
diff --git a/doc/rpc_list/docbook/rpc_ims_usrloc_pcscf.xml b/doc/rpc_list/docbook/rpc_ims_usrloc_pcscf.xml
new file mode 100644
index 0000000..eaf758c
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_ims_usrloc_pcscf.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.ims_usrloc_pcscf">
+	<title>
+RPC Exports for ims_usrloc_pcscf
+	</title>
+
+
+<section id="ulpcscf.status"><title>ulpcscf.status</title>
+<para>
+        Dump PCSCF contacts and associated identitites
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_ims_usrloc_scscf.xml b/doc/rpc_list/docbook/rpc_ims_usrloc_scscf.xml
new file mode 100644
index 0000000..57b2864
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_ims_usrloc_scscf.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.ims_usrloc_scscf">
+	<title>
+RPC Exports for ims_usrloc_scscf
+	</title>
+
+
+<section id="ulscscf.status"><title>ulscscf.status</title>
+<para>
+        Dump SCSCF user location tables
+</para>
+<para>
+</para>
+</section>
+
+<section id="ulscscf.showimpu"><title>ulscscf.showimpu</title>
+<para>
+        Dump SCSCF IMPU information
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_lcr.xml b/doc/rpc_list/docbook/rpc_lcr.xml
index 7dc8d82..3662eb9 100644
--- a/doc/rpc_list/docbook/rpc_lcr.xml
+++ b/doc/rpc_list/docbook/rpc_lcr.xml
@@ -32,4 +32,12 @@ RPC Exports for lcr
 </para>
 </section>
 
+<section id="lcr.defunct_gw"><title>lcr.defunct_gw</title>
+<para>
+        Defunct gateway until specified time (Unix timestamp).
+</para>
+<para>
+</para>
+</section>
+
 </chapter>
diff --git a/doc/rpc_list/docbook/rpc_list.xml b/doc/rpc_list/docbook/rpc_list.xml
index 4d031e4..ad06aab 100644
--- a/doc/rpc_list/docbook/rpc_list.xml
+++ b/doc/rpc_list/docbook/rpc_list.xml
@@ -8,41 +8,58 @@
 <book id="rpc_list" xmlns:xi="http://www.w3.org/2001/XInclude">
 	<title>RPC Exports List</title>
 	<bookinfo><revhistory><revision>
-		<revnumber>sip-router git-0ea931</revnumber>
-		<date>Fri, 25 Nov 2011 23:59:50 +0100</date>
+		<revnumber>sip-router git-99c4af</revnumber>
+		<date>Wed, 04 Dec 2013 14:45:52 +0100</date>
 		<revremark>
 			Automatically generated by:
 			make -C doc/rpc_list all
 		</revremark>
 	</revision></revhistory></bookinfo>
 		<xi:include href="rpc_core.xml"/>
+		<xi:include href="rpc_app_lua.xml"/>
+		<xi:include href="rpc_carrierroute.xml"/>
 		<xi:include href="rpc_cfg_rpc.xml"/>
+		<xi:include href="rpc_cnxcc.xml"/>
+		<xi:include href="rpc_corex.xml"/>
 		<xi:include href="rpc_counters.xml"/>
 		<xi:include href="rpc_ctl.xml"/>
 		<xi:include href="rpc_db_flatstore.xml"/>
+		<xi:include href="rpc_db_flatstore.xml"/>
+		<xi:include href="rpc_db_text.xml"/>
 		<xi:include href="rpc_debugger.xml"/>
+		<xi:include href="rpc_dialog.xml"/>
+		<xi:include href="rpc_dialog_ng.xml"/>
 		<xi:include href="rpc_dialplan.xml"/>
+		<xi:include href="rpc_dispatcher.xml"/>
+		<xi:include href="rpc_domain.xml"/>
+		<xi:include href="rpc_drouting.xml"/>
+		<xi:include href="rpc_htable.xml"/>
+		<xi:include href="rpc_ims_usrloc_pcscf.xml"/>
+		<xi:include href="rpc_ims_usrloc_scscf.xml"/>
+		<xi:include href="rpc_kex.xml"/>
 		<xi:include href="rpc_lcr.xml"/>
 		<xi:include href="rpc_malloc_test.xml"/>
 		<xi:include href="rpc_mi_rpc.xml"/>
+		<xi:include href="rpc_msrp.xml"/>
+		<xi:include href="rpc_mtree.xml"/>
+		<xi:include href="rpc_pdt.xml"/>
+		<xi:include href="rpc_permissions.xml"/>
+		<xi:include href="rpc_pike.xml"/>
+		<xi:include href="rpc_pipelimit.xml"/>
 		<xi:include href="rpc_prefix_route.xml"/>
+		<xi:include href="rpc_presence.xml"/>
+		<xi:include href="rpc_pv.xml"/>
 		<xi:include href="rpc_ratelimit.xml"/>
+		<xi:include href="rpc_sca.xml"/>
+		<xi:include href="rpc_sctp.xml"/>
+		<xi:include href="rpc_sipcapture.xml"/>
+		<xi:include href="rpc_siptrace.xml"/>
 		<xi:include href="rpc_sl.xml"/>
 		<xi:include href="rpc_tls.xml"/>
 		<xi:include href="rpc_tm.xml"/>
-		<xi:include href="rpc_dialog.xml"/>
-		<xi:include href="rpc_dispatcher.xml"/>
-		<xi:include href="rpc_domain.xml"/>
-		<xi:include href="rpc_htable.xml"/>
-		<xi:include href="rpc_kex.xml"/>
 		<xi:include href="rpc_uac.xml"/>
+		<xi:include href="rpc_uid_domain.xml"/>
+		<xi:include href="rpc_uid_gflags.xml"/>
 		<xi:include href="rpc_usrloc.xml"/>
-		<xi:include href="rpc_cpl-c.xml"/>
-		<xi:include href="rpc_dispatcher_s.xml"/>
-		<xi:include href="rpc_domain_s.xml"/>
-		<xi:include href="rpc_gflags.xml"/>
-		<xi:include href="rpc_pdt.xml"/>
-		<xi:include href="rpc_pike.xml"/>
-		<xi:include href="rpc_presence_b2b.xml"/>
-		<xi:include href="rpc_usrloc_s.xml"/>
+		<xi:include href="rpc_xhttp_pi.xml"/>
 </book>
diff --git a/doc/rpc_list/docbook/rpc_msrp.xml b/doc/rpc_list/docbook/rpc_msrp.xml
new file mode 100644
index 0000000..8868d37
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_msrp.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.msrp">
+	<title>
+RPC Exports for msrp
+	</title>
+
+
+<section id="msrp.cmaplist"><title>msrp.cmaplist</title>
+<para>
+        Return the content of dispatcher sets
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_mtree.xml b/doc/rpc_list/docbook/rpc_mtree.xml
new file mode 100644
index 0000000..c9026e9
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_mtree.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.mtree">
+	<title>
+RPC Exports for mtree
+	</title>
+
+
+<section id="mtree.summary"><title>mtree.summary</title>
+<para>
+        Print summary of loaded mtree tables
+</para>
+<para>
+</para>
+</section>
+
+<section id="mtree.reload"><title>mtree.reload</title>
+<para>
+        Reload mtrees from database to memory
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_pdt.xml b/doc/rpc_list/docbook/rpc_pdt.xml
index 5a1a124..249bac3 100644
--- a/doc/rpc_list/docbook/rpc_pdt.xml
+++ b/doc/rpc_list/docbook/rpc_pdt.xml
@@ -8,17 +8,9 @@ RPC Exports for pdt
 	</title>
 
 
-<section id="pdt.add"><title>pdt.add</title>
+<section id="pdt.reload"><title>pdt.reload</title>
 <para>
-        Add new prefix/domain translation rule.
-</para>
-<para>
-</para>
-</section>
-
-<section id="pdt.delete"><title>pdt.delete</title>
-<para>
-        Delete prefix/domain translation rule.
+        Reload PDT database records
 </para>
 <para>
 </para>
@@ -26,10 +18,9 @@ RPC Exports for pdt
 
 <section id="pdt.list"><title>pdt.list</title>
 <para>
-        List existin prefix/domain translation rules
+        List PDT memory records
 </para>
 <para>
-        Returns an array.
 </para>
 </section>
 
diff --git a/doc/rpc_list/docbook/rpc_permissions.xml b/doc/rpc_list/docbook/rpc_permissions.xml
new file mode 100644
index 0000000..fdc1f35
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_permissions.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.permissions">
+	<title>
+RPC Exports for permissions
+	</title>
+
+
+<section id="permissions.trustedReload"><title>permissions.trustedReload</title>
+<para>
+        Reload permissions trusted table
+</para>
+<para>
+</para>
+</section>
+
+<section id="permissions.addressReload"><title>permissions.addressReload</title>
+<para>
+        Reload permissions address table
+</para>
+<para>
+</para>
+</section>
+
+<section id="permissions.trustedDump"><title>permissions.trustedDump</title>
+<para>
+        Dump permissions trusted table
+</para>
+<para>
+</para>
+</section>
+
+<section id="permissions.addressDump"><title>permissions.addressDump</title>
+<para>
+        Dump permissions address table
+</para>
+<para>
+</para>
+</section>
+
+<section id="permissions.subnetDump"><title>permissions.subnetDump</title>
+<para>
+        Dump permissions subnet table
+</para>
+<para>
+</para>
+</section>
+
+<section id="permissions.domainDump"><title>permissions.domainDump</title>
+<para>
+        Dump permissions domain name table
+</para>
+<para>
+</para>
+</section>
+
+<section id="permissions.testUri"><title>permissions.testUri</title>
+<para>
+        Tests if (URI, Contact) pair is allowed according to allow/deny
+        files
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_pike.xml b/doc/rpc_list/docbook/rpc_pike.xml
index ef90c0b..b8f06a6 100644
--- a/doc/rpc_list/docbook/rpc_pike.xml
+++ b/doc/rpc_list/docbook/rpc_pike.xml
@@ -10,7 +10,7 @@ RPC Exports for pike
 
 <section id="pike.top"><title>pike.top</title>
 <para>
-        pike.top doc.
+        pike.top Dump parts of the pike table
 </para>
 <para>
 </para>
diff --git a/doc/rpc_list/docbook/rpc_pipelimit.xml b/doc/rpc_list/docbook/rpc_pipelimit.xml
new file mode 100644
index 0000000..f9e308f
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_pipelimit.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.pipelimit">
+	<title>
+RPC Exports for pipelimit
+	</title>
+
+
+<section id="pl.stats"><title>pl.stats</title>
+<para>
+        Print pipelimit statistics: <id> <load>
+        <counter>
+</para>
+<para>
+</para>
+</section>
+
+<section id="pl.get_pipes"><title>pl.get_pipes</title>
+<para>
+        Print pipes info: <id> <algorithm> <limit>
+        <counter>
+</para>
+<para>
+</para>
+</section>
+
+<section id="pl.set_pipe"><title>pl.set_pipe</title>
+<para>
+        Sets a pipe params: <pipe_id> <pipe_algorithm>
+        <pipe_limit>
+</para>
+<para>
+</para>
+</section>
+
+<section id="pl.get_pid"><title>pl.get_pid</title>
+<para>
+        Print PID Controller parameters for the FEEDBACK algorithm:
+        <ki> <kp> <kd>
+</para>
+<para>
+</para>
+</section>
+
+<section id="pl.set_pid"><title>pl.set_pid</title>
+<para>
+        Sets the PID Controller parameters for the FEEDBACK algorithm:
+        <ki> <kp> <kd>
+</para>
+<para>
+</para>
+</section>
+
+<section id="pl.push_load"><title>pl.push_load</title>
+<para>
+        Force the value of the load parameter for FEEDBACK algorithm:
+        <load>
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_prefix_route.xml b/doc/rpc_list/docbook/rpc_prefix_route.xml
index 83efa27..e3b45c6 100644
--- a/doc/rpc_list/docbook/rpc_prefix_route.xml
+++ b/doc/rpc_list/docbook/rpc_prefix_route.xml
@@ -10,7 +10,7 @@ RPC Exports for prefix_route
 
 <section id="prefix_route.reload"><title>prefix_route.reload</title>
 <para>
-        Documentation missing (rpc_reload_doc).
+        Reload prefix routes from DB
 </para>
 <para>
 </para>
@@ -18,7 +18,7 @@ RPC Exports for prefix_route
 
 <section id="prefix_route.dump"><title>prefix_route.dump</title>
 <para>
-        Documentation missing (rpc_dump_doc).
+        Dump the prefix route tree
 </para>
 <para>
 </para>
diff --git a/doc/rpc_list/docbook/rpc_presence.xml b/doc/rpc_list/docbook/rpc_presence.xml
new file mode 100644
index 0000000..07279b3
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_presence.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.presence">
+	<title>
+RPC Exports for presence
+	</title>
+
+
+<section id="presence.cleanup"><title>presence.cleanup</title>
+<para>
+        Manually triggers the cleanup functions for the
+        active_watchers, presentity, and watchers tables.
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_presence_b2b.xml b/doc/rpc_list/docbook/rpc_presence_b2b.xml
deleted file mode 100644
index 5501611..0000000
--- a/doc/rpc_list/docbook/rpc_presence_b2b.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- this file is autogenerated, do not edit! -->
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<chapter id="rpc_exports.presence_b2b">
-	<title>
-RPC Exports for presence_b2b
-	</title>
-
-
-<section id="presence_b2b.test"><title>presence_b2b.test</title>
-<para>
-        Testing events.
-</para>
-<para>
-</para>
-</section>
-
-<section id="presence_b2b.trace"><title>presence_b2b.trace</title>
-<para>
-        Trace events.
-</para>
-<para>
-</para>
-</section>
-
-</chapter>
diff --git a/doc/rpc_list/docbook/rpc_pv.xml b/doc/rpc_list/docbook/rpc_pv.xml
new file mode 100644
index 0000000..c0ef277
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_pv.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.pv">
+	<title>
+RPC Exports for pv
+	</title>
+
+
+<section id="pv.shvSet"><title>pv.shvSet</title>
+<para>
+        Set a shared variable (args: name type value)
+</para>
+<para>
+</para>
+</section>
+
+<section id="pv.shvGet"><title>pv.shvGet</title>
+<para>
+        Get the value of a shared variable. If no argument, dumps all
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_sca.xml b/doc/rpc_list/docbook/rpc_sca.xml
new file mode 100644
index 0000000..e50fb1c
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_sca.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.sca">
+	<title>
+RPC Exports for sca
+	</title>
+
+
+<section id="sca.all_subscriptions"><title>sca.all_subscriptions</title>
+<para>
+        Documentation missing (sca_rpc_show_all_subscriptions_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.subscription_count"><title>sca.subscription_count</title>
+<para>
+        Documentation missing (sca_rpc_subscription_count_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.show_subscription"><title>sca.show_subscription</title>
+<para>
+        Documentation missing (sca_rpc_show_subscription_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.subscribers"><title>sca.subscribers</title>
+<para>
+        Documentation missing (sca_rpc_show_subscribers_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.deactivate_all_subscriptions"><title>sca.deactivate_all_subscriptions</title>
+<para>
+        Documentation missing
+        (sca_rpc_deactivate_all_subscriptions_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.deactivate_subscription"><title>sca.deactivate_subscription</title>
+<para>
+        Documentation missing (sca_rpc_deactivate_subscription_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.all_appearances"><title>sca.all_appearances</title>
+<para>
+        Documentation missing (sca_rpc_show_all_appearances_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.show_appearance"><title>sca.show_appearance</title>
+<para>
+        Documentation missing (sca_rpc_show_appearance_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.seize_appearance"><title>sca.seize_appearance</title>
+<para>
+        Documentation missing (sca_rpc_seize_appearance_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.update_appearance"><title>sca.update_appearance</title>
+<para>
+        Documentation missing (sca_rpc_update_appearance_doc).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sca.release_appearance"><title>sca.release_appearance</title>
+<para>
+        Documentation missing (sca_rpc_release_appearance_doc).
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_sctp.xml b/doc/rpc_list/docbook/rpc_sctp.xml
new file mode 100644
index 0000000..5609e3e
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_sctp.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.sctp">
+	<title>
+RPC Exports for sctp
+	</title>
+
+
+<section id="sctp.options"><title>sctp.options</title>
+<para>
+        Returns active sctp options. With one parameter it returns the
+        sctp options set in the kernel for a specific
+        socket(debugging), with 0 filled in for non-kernel related
+        options. The parameter can be: "default" |
+        "first" | address[:port] . With no parameters it
+        returns ser's idea of the current sctp options (intended
+        non-debugging use).
+</para>
+<para>
+</para>
+</section>
+
+<section id="sctp.info"><title>sctp.info</title>
+<para>
+        Returns sctp related info.
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_sipcapture.xml b/doc/rpc_list/docbook/rpc_sipcapture.xml
new file mode 100644
index 0000000..21aee48
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_sipcapture.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.sipcapture">
+	<title>
+RPC Exports for sipcapture
+	</title>
+
+
+<section id="sipcapture.status"><title>sipcapture.status</title>
+<para>
+        Get status or turn on/off sipcapture.
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_siptrace.xml b/doc/rpc_list/docbook/rpc_siptrace.xml
new file mode 100644
index 0000000..deca4be
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_siptrace.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.siptrace">
+	<title>
+RPC Exports for siptrace
+	</title>
+
+
+<section id="siptrace.status"><title>siptrace.status</title>
+<para>
+        Get status or turn on/off siptrace. Parameters: on, off or
+        check.
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_sl.xml b/doc/rpc_list/docbook/rpc_sl.xml
index a352b75..cd1fdbc 100644
--- a/doc/rpc_list/docbook/rpc_sl.xml
+++ b/doc/rpc_list/docbook/rpc_sl.xml
@@ -10,7 +10,7 @@ RPC Exports for sl
 
 <section id="sl.stats"><title>sl.stats</title>
 <para>
-        Documentation missing (rpc_stats_doc).
+        Print reply statistics.
 </para>
 <para>
 </para>
diff --git a/doc/rpc_list/docbook/rpc_tls.xml b/doc/rpc_list/docbook/rpc_tls.xml
index a730de8..57cede2 100644
--- a/doc/rpc_list/docbook/rpc_tls.xml
+++ b/doc/rpc_list/docbook/rpc_tls.xml
@@ -10,7 +10,7 @@ RPC Exports for tls
 
 <section id="tls.reload"><title>tls.reload</title>
 <para>
-        Documentation missing (tls_reload_doc).
+        Reload TLS configuration file
 </para>
 <para>
 </para>
@@ -18,7 +18,7 @@ RPC Exports for tls
 
 <section id="tls.list"><title>tls.list</title>
 <para>
-        Documentation missing (tls_list_doc).
+        List currently open TLS connections
 </para>
 <para>
         Returns an array.
@@ -27,7 +27,7 @@ RPC Exports for tls
 
 <section id="tls.info"><title>tls.info</title>
 <para>
-        Documentation missing (tls_info_doc).
+        Returns internal tls related info.
 </para>
 <para>
 </para>
@@ -35,7 +35,7 @@ RPC Exports for tls
 
 <section id="tls.options"><title>tls.options</title>
 <para>
-        Documentation missing (tls_options_doc).
+        Dumps all the tls config options.
 </para>
 <para>
 </para>
diff --git a/doc/rpc_list/docbook/rpc_tm.xml b/doc/rpc_list/docbook/rpc_tm.xml
index 9147b1f..6b59300 100644
--- a/doc/rpc_list/docbook/rpc_tm.xml
+++ b/doc/rpc_list/docbook/rpc_tm.xml
@@ -10,7 +10,7 @@ RPC Exports for tm
 
 <section id="tm.cancel"><title>tm.cancel</title>
 <para>
-        Documentation missing (rpc_cancel_doc).
+        Cancel a pending transaction
 </para>
 <para>
 </para>
@@ -18,7 +18,7 @@ RPC Exports for tm
 
 <section id="tm.reply"><title>tm.reply</title>
 <para>
-        Documentation missing (rpc_reply_doc).
+        Reply transaction
 </para>
 <para>
 </para>
@@ -26,7 +26,7 @@ RPC Exports for tm
 
 <section id="tm.stats"><title>tm.stats</title>
 <para>
-        Documentation missing (tm_rpc_stats_doc).
+        Print transaction statistics.
 </para>
 <para>
 </para>
@@ -34,7 +34,8 @@ RPC Exports for tm
 
 <section id="tm.hash_stats"><title>tm.hash_stats</title>
 <para>
-        Documentation missing (tm_rpc_hash_stats_doc).
+        Prints hash table statistics (can be used only if tm is
+        compiled with -DTM_HASH_STATS).
 </para>
 <para>
 </para>
@@ -42,7 +43,9 @@ RPC Exports for tm
 
 <section id="tm.t_uac_start"><title>tm.t_uac_start</title>
 <para>
-        Documentation missing (rpc_t_uac_start_doc).
+        starts a tm uac using  a list of string parameters: method,
+        ruri, dst_uri, send_sock, headers (CRLF separated) and body
+        (optional)
 </para>
 <para>
 </para>
@@ -50,7 +53,9 @@ RPC Exports for tm
 
 <section id="tm.t_uac_wait"><title>tm.t_uac_wait</title>
 <para>
-        Documentation missing (rpc_t_uac_wait_doc).
+        starts a tm uac and waits for the final reply, using a list of
+        string parameters: method, ruri, dst_uri send_sock, headers
+        (CRLF separated) and body (optional)
 </para>
 <para>
         Returns an array.
diff --git a/doc/rpc_list/docbook/rpc_uid_domain.xml b/doc/rpc_list/docbook/rpc_uid_domain.xml
new file mode 100644
index 0000000..93543d6
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_uid_domain.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.uid_domain">
+	<title>
+RPC Exports for uid_domain
+	</title>
+
+
+<section id="domain.reload"><title>domain.reload</title>
+<para>
+        Reload domain table from database
+</para>
+<para>
+</para>
+</section>
+
+<section id="domain.dump"><title>domain.dump</title>
+<para>
+        Return the contents of domain table
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_uid_gflags.xml b/doc/rpc_list/docbook/rpc_uid_gflags.xml
new file mode 100644
index 0000000..4364788
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_uid_gflags.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.uid_gflags">
+	<title>
+RPC Exports for uid_gflags
+	</title>
+
+
+<section id="gflags.set"><title>gflags.set</title>
+<para>
+        Load a CPL script to the server.
+</para>
+<para>
+</para>
+</section>
+
+<section id="gflags.is_set"><title>gflags.is_set</title>
+<para>
+        Load a CPL script to the server.
+</para>
+<para>
+</para>
+</section>
+
+<section id="gflags.reset"><title>gflags.reset</title>
+<para>
+        Load a CPL script to the server.
+</para>
+<para>
+</para>
+</section>
+
+<section id="gflags.flush"><title>gflags.flush</title>
+<para>
+        Load a CPL script to the server.
+</para>
+<para>
+</para>
+</section>
+
+<section id="gflags.dump"><title>gflags.dump</title>
+<para>
+        Load a CPL script to the server.
+</para>
+<para>
+</para>
+</section>
+
+<section id="global.reload"><title>global.reload</title>
+<para>
+        Reload global attributes from database
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/docbook/rpc_usrloc.xml b/doc/rpc_list/docbook/rpc_usrloc.xml
index 1661978..23510f5 100644
--- a/doc/rpc_list/docbook/rpc_usrloc.xml
+++ b/doc/rpc_list/docbook/rpc_usrloc.xml
@@ -16,4 +16,71 @@ RPC Exports for usrloc
 </para>
 </section>
 
+<section id="ul.lookup"><title>ul.lookup</title>
+<para>
+        Lookup one AOR in the usrloc location table
+</para>
+<para>
+</para>
+</section>
+
+<section id="ul.rm"><title>ul.rm</title>
+<para>
+        Delete a address of record including its contacts
+</para>
+<para>
+</para>
+</section>
+
+<section id="ul.rm_contact"><title>ul.rm_contact</title>
+<para>
+        Delete a contact from an AOR record
+</para>
+<para>
+</para>
+</section>
+
+<section id="ul.flush"><title>ul.flush</title>
+<para>
+        Flush the usrloc memory cache to DB
+</para>
+<para>
+</para>
+</section>
+
+<section id="ul.add"><title>ul.add</title>
+<para>
+        Add a new contact for an address of record
+</para>
+<para>
+</para>
+</section>
+
+<section id="ul.db_users"><title>ul.db_users</title>
+<para>
+        Tell number of different unexpired users (AoRs) in database
+        table (db_mode!=0 only)
+</para>
+<para>
+</para>
+</section>
+
+<section id="ul.db_contacts"><title>ul.db_contacts</title>
+<para>
+        Tell number of unexpired contacts in database table (db_mode=3
+        only)
+</para>
+<para>
+</para>
+</section>
+
+<section id="ul.db_expired_contacts"><title>ul.db_expired_contacts</title>
+<para>
+        Tell number of expired contacts in database table (db_mode=3
+        only)
+</para>
+<para>
+</para>
+</section>
+
 </chapter>
diff --git a/doc/rpc_list/docbook/rpc_usrloc_k.xml b/doc/rpc_list/docbook/rpc_usrloc_k.xml
deleted file mode 100644
index 38c7a0e..0000000
--- a/doc/rpc_list/docbook/rpc_usrloc_k.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- this file is autogenerated, do not edit! -->
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<chapter id="rpc_exports.usrloc_k">
-	<title>
-RPC Exports for usrloc_k
-	</title>
-
-
-<section id="ul.dump"><title>ul.dump</title>
-<para>
-        Dump user location tables
-</para>
-<para>
-</para>
-</section>
-
-</chapter>
diff --git a/doc/rpc_list/docbook/rpc_usrloc_s.xml b/doc/rpc_list/docbook/rpc_usrloc_s.xml
deleted file mode 100644
index adb2f15..0000000
--- a/doc/rpc_list/docbook/rpc_usrloc_s.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- this file is autogenerated, do not edit! -->
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<chapter id="rpc_exports.usrloc_s">
-	<title>
-RPC Exports for usrloc_s
-	</title>
-
-
-<section id="usrloc.stats"><title>usrloc.stats</title>
-<para>
-        Documentation missing (rpc_stats_doc).
-</para>
-<para>
-        Returns an array.
-</para>
-</section>
-
-<section id="usrloc.delete_uid"><title>usrloc.delete_uid</title>
-<para>
-        Documentation missing (rpc_delete_uid_doc).
-</para>
-<para>
-</para>
-</section>
-
-<section id="usrloc.delete_contact"><title>usrloc.delete_contact</title>
-<para>
-        Documentation missing (rpc_delete_contact_doc).
-</para>
-<para>
-</para>
-</section>
-
-<section id="usrloc.dump"><title>usrloc.dump</title>
-<para>
-        Documentation missing (rpc_dump_doc).
-</para>
-<para>
-</para>
-</section>
-
-<section id="usrloc.dump_file"><title>usrloc.dump_file</title>
-<para>
-        Documentation missing (rpc_dump_file_doc).
-</para>
-<para>
-</para>
-</section>
-
-<section id="usrloc.flush"><title>usrloc.flush</title>
-<para>
-        Documentation missing (rpc_flush_doc).
-</para>
-<para>
-</para>
-</section>
-
-<section id="usrloc.add_contact"><title>usrloc.add_contact</title>
-<para>
-        Documentation missing (rpc_add_contact_doc).
-</para>
-<para>
-</para>
-</section>
-
-<section id="usrloc.show_contacts"><title>usrloc.show_contacts</title>
-<para>
-        Documentation missing (rpc_show_contacts_doc).
-</para>
-<para>
-        Returns an array.
-</para>
-</section>
-
-</chapter>
diff --git a/doc/rpc_list/docbook/rpc_xhttp_pi.xml b/doc/rpc_list/docbook/rpc_xhttp_pi.xml
new file mode 100644
index 0000000..9f6f90b
--- /dev/null
+++ b/doc/rpc_list/docbook/rpc_xhttp_pi.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this file is autogenerated, do not edit! -->
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<chapter id="rpc_exports.xhttp_pi">
+	<title>
+RPC Exports for xhttp_pi
+	</title>
+
+
+<section id="xhttp_pi.reload"><title>xhttp_pi.reload</title>
+<para>
+        Reload the xml framework
+</para>
+<para>
+</para>
+</section>
+
+</chapter>
diff --git a/doc/rpc_list/rpc_app_lua.txt b/doc/rpc_list/rpc_app_lua.txt
new file mode 100644
index 0000000..a1393de
--- /dev/null
+++ b/doc/rpc_list/rpc_app_lua.txt
@@ -0,0 +1,12 @@
+RPC Exports for app_lua
+=======================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. app_lua.reload
+        Reload lua script
+
+ 2. app_lua.list
+        list lua scripts
+
diff --git a/doc/rpc_list/rpc_carrierroute.txt b/doc/rpc_list/rpc_carrierroute.txt
new file mode 100644
index 0000000..80a250b
--- /dev/null
+++ b/doc/rpc_list/rpc_carrierroute.txt
@@ -0,0 +1,9 @@
+RPC Exports for carrierroute
+============================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. cr.reload_routes
+        Reload routes
+
diff --git a/doc/rpc_list/rpc_cnxcc.txt b/doc/rpc_list/rpc_cnxcc.txt
new file mode 100644
index 0000000..f8af0ad
--- /dev/null
+++ b/doc/rpc_list/rpc_cnxcc.txt
@@ -0,0 +1,15 @@
+RPC Exports for cnxcc
+=====================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. cnxcc.active_clients
+        List of clients with active calls
+
+ 2. cnxcc.check_client
+        Check specific client calls
+
+ 3. cnxcc.kill_call
+        Kill call using its call ID
+
diff --git a/doc/rpc_list/rpc_core.txt b/doc/rpc_list/rpc_core.txt
index 9387896..97369a5 100644
--- a/doc/rpc_list/rpc_core.txt
+++ b/doc/rpc_list/rpc_core.txt
@@ -69,88 +69,86 @@ RPC Exports for core
 18. core.tcp_options
         Returns active tcp options.
 
-19. core.sctp_options
-        Returns active sctp options. With one parameter it returns the
-        sctp options set in the kernel for a specific
-        socket(debugging), with 0 filled in for non-kernel related
-        options. The parameter can be: "default" | "first" |
-        address[:port] . With no parameters it returns ser's idea of
-        the current sctp options (intended non-debugging use).
-
-20. core.sctp_info
-        Returns sctp related info.
-
-21. core.udp4_raw_info
+19. core.tcp_list
+        Returns tcp connections details.
+
+20. core.udp4_raw_info
         Returns udp4_raw related info.
 
-22. dns.mem_info
+21. core.aliases_list
+        List local SIP server host aliases
+
+22. core.sockets_list
+        List local SIP server listen sockets
+
+23. dns.mem_info
         dns cache memory info.
 
-23. dns.debug
+24. dns.debug
         dns debug  info.
 
-24. dns.debug_all
+25. dns.debug_all
         complete dns debug  dump
 
-25. dns.view
+26. dns.view
         dns cache dump in a human-readable format
 
-26. dns.lookup
+27. dns.lookup
         perform a dns lookup
 
-27. dns.delete_all
+28. dns.delete_all
         deletes all the non-permanent entries from the DNS cache
 
-28. dns.delete_all_force
+29. dns.delete_all_force
         deletes all the entries from the DNS cache including the
         permanent ones
 
-29. dns.add_a
+30. dns.add_a
         adds an A record to the DNS cache
 
-30. dns.add_aaaa
+31. dns.add_aaaa
         adds an AAAA record to the DNS cache
 
-31. dns.add_srv
+32. dns.add_srv
         adds an SRV record to the DNS cache
 
-32. dns.delete_a
+33. dns.delete_a
         deletes an A record from the DNS cache
 
-33. dns.delete_aaaa
+34. dns.delete_aaaa
         deletes an AAAA record from the DNS cache
 
-34. dns.delete_srv
+35. dns.delete_srv
         deletes an SRV record from the DNS cache
 
-35. dns.delete_naptr
+36. dns.delete_naptr
         deletes a NAPTR record from the DNS cache
 
-36. dns.delete_cname
+37. dns.delete_cname
         deletes a CNAME record from the DNS cache
 
-37. dns.delete_txt
+38. dns.delete_txt
         deletes a TXT record from the DNS cache
 
-38. dns.delete_ebl
+39. dns.delete_ebl
         deletes an EBL record from the DNS cache
 
-39. dns.delete_ptr
+40. dns.delete_ptr
         deletes an PTR record from the DNS cache
 
-40. dst_blacklist.mem_info
+41. dst_blacklist.mem_info
         dst blacklist memory usage info.
 
-41. dst_blacklist.debug
+42. dst_blacklist.debug
         dst blacklist  debug  info.
 
-42. dst_blacklist.view
+43. dst_blacklist.view
         dst blacklist dump in human-readable format.
 
-43. dst_blacklist.delete_all
+44. dst_blacklist.delete_all
         Deletes all the entries from the dst blacklist except the
         permanent ones.
 
-44. dst_blacklist.add
+45. dst_blacklist.add
         Adds a new entry to the dst blacklist.
 
diff --git a/doc/rpc_list/rpc_corex.txt b/doc/rpc_list/rpc_corex.txt
new file mode 100644
index 0000000..db5125c
--- /dev/null
+++ b/doc/rpc_list/rpc_corex.txt
@@ -0,0 +1,12 @@
+RPC Exports for corex
+=====================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. corex.list_sockets
+        List listening sockets
+
+ 2. corex.list_aliases
+        List socket aliases
+
diff --git a/doc/rpc_list/rpc_cpl-c.txt b/doc/rpc_list/rpc_cpl-c.txt
deleted file mode 100644
index 9f4db55..0000000
--- a/doc/rpc_list/rpc_cpl-c.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-RPC Exports for cpl-c
-=====================
-
-                  [ this file is autogenerated, do not edit ]
-
-
- 1. cpl.load
-        Load a CPL script to the server.
-
- 2. cpl.remove
-        Remove a CPL script from server.
-
- 3. cpl.get
-        Return a CPL script.
-
diff --git a/doc/rpc_list/rpc_db_flatstore.txt b/doc/rpc_list/rpc_db_flatstore.txt
index f4b0b9c..f8322c1 100644
--- a/doc/rpc_list/rpc_db_flatstore.txt
+++ b/doc/rpc_list/rpc_db_flatstore.txt
@@ -4,6 +4,6 @@ RPC Exports for db_flatstore
                   [ this file is autogenerated, do not edit ]
 
 
- 1. flatstore.rotate
-        Documentation missing (flat_rotate_doc).
+ 1. flatstore.k_rotate
+        Close and reopen flatrotate files during log rotation.
 
diff --git a/doc/rpc_list/rpc_db_text.txt b/doc/rpc_list/rpc_db_text.txt
new file mode 100644
index 0000000..4f682f4
--- /dev/null
+++ b/doc/rpc_list/rpc_db_text.txt
@@ -0,0 +1,9 @@
+RPC Exports for db_text
+=======================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. db_text.dump
+        Write back to disk modified tables
+
diff --git a/doc/rpc_list/rpc_debugger.txt b/doc/rpc_list/rpc_debugger.txt
index 3db09a0..53e7afa 100644
--- a/doc/rpc_list/rpc_debugger.txt
+++ b/doc/rpc_list/rpc_debugger.txt
@@ -5,7 +5,7 @@ RPC Exports for debugger
 
 
  1. dbg.bp
-        Documentation missing (dbg_rpc_bp_doc).
+        Breakpoint command
 
  2. dbg.ls
         List debugging process array
@@ -13,3 +13,9 @@ RPC Exports for debugger
  3. dbg.trace
         Config trace command
 
+ 4. dbg.mod_level
+        Specify module log level
+
+ 5. dbg.reset_msgid
+        Reset msgid on all process
+
diff --git a/doc/rpc_list/rpc_dialog_ng.txt b/doc/rpc_list/rpc_dialog_ng.txt
new file mode 100644
index 0000000..598cc3b
--- /dev/null
+++ b/doc/rpc_list/rpc_dialog_ng.txt
@@ -0,0 +1,9 @@
+RPC Exports for dialog_ng
+=========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. dlg2.list
+        Print all dialogs
+
diff --git a/doc/rpc_list/rpc_dialplan.txt b/doc/rpc_list/rpc_dialplan.txt
index 47831b5..9297855 100644
--- a/doc/rpc_list/rpc_dialplan.txt
+++ b/doc/rpc_list/rpc_dialplan.txt
@@ -7,6 +7,6 @@ RPC Exports for dialplan
  1. dialplan.reload
         Reload dialplan table from database
 
- 2. dialplan.dump
+ 2. dialplan.translate
         Perform dialplan translation
 
diff --git a/doc/rpc_list/rpc_dispatcher_s.txt b/doc/rpc_list/rpc_dispatcher_s.txt
deleted file mode 100644
index 45f9fcb..0000000
--- a/doc/rpc_list/rpc_dispatcher_s.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-RPC Exports for dispatcher_s
-============================
-
-                  [ this file is autogenerated, do not edit ]
-
-
- 1. dispatcher.dump
-        Dump dispatcher set configuration
-
- 2. dispatcher.reload
-        Reload dispatcher list from file
-
diff --git a/doc/rpc_list/rpc_domain.txt b/doc/rpc_list/rpc_domain.txt
index 1d8b17b..fe69077 100644
--- a/doc/rpc_list/rpc_domain.txt
+++ b/doc/rpc_list/rpc_domain.txt
@@ -5,8 +5,8 @@ RPC Exports for domain
 
 
  1. domain.reload
-        Reload domain table from database
+        Reload domain tables from database
 
  2. domain.dump
-        Return the contents of domain table
+        Return the contents of domain and domain_attrs tables
 
diff --git a/doc/rpc_list/rpc_domain_s.txt b/doc/rpc_list/rpc_domain_s.txt
deleted file mode 100644
index bd547ca..0000000
--- a/doc/rpc_list/rpc_domain_s.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-RPC Exports for domain_s
-========================
-
-                  [ this file is autogenerated, do not edit ]
-
-
- 1. domain.reload
-        Reload domain table from database
-
- 2. domain.dump
-        Return the contents of domain table
-
diff --git a/doc/rpc_list/rpc_drouting.txt b/doc/rpc_list/rpc_drouting.txt
new file mode 100644
index 0000000..0ae9979
--- /dev/null
+++ b/doc/rpc_list/rpc_drouting.txt
@@ -0,0 +1,9 @@
+RPC Exports for drouting
+========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. drouting.reload
+        Write back to disk modified tables
+
diff --git a/doc/rpc_list/rpc_gflags.txt b/doc/rpc_list/rpc_gflags.txt
deleted file mode 100644
index 2855345..0000000
--- a/doc/rpc_list/rpc_gflags.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-RPC Exports for gflags
-======================
-
-                  [ this file is autogenerated, do not edit ]
-
-
- 1. gflags.set
-        Load a CPL script to the server.
-
- 2. gflags.is_set
-        Load a CPL script to the server.
-
- 3. gflags.reset
-        Load a CPL script to the server.
-
- 4. gflags.flush
-        Load a CPL script to the server.
-
- 5. gflags.dump
-        Load a CPL script to the server.
-
- 6. global.reload
-        Reload global attributes from database
-
diff --git a/doc/rpc_list/rpc_htable.txt b/doc/rpc_list/rpc_htable.txt
index 6e071db..1314ba5 100644
--- a/doc/rpc_list/rpc_htable.txt
+++ b/doc/rpc_list/rpc_htable.txt
@@ -7,3 +7,24 @@ RPC Exports for htable
  1. htable.dump
         Dump the contents of hash table.
 
+ 2. htable.delete
+        Delete one key from a hash table.
+
+ 3. htable.get
+        Get one key from a hash table.
+
+ 4. htable.sets
+        Set one key in a hash table to a string value.
+
+ 5. htable.seti
+        Set one key in a hash table to an integer value.
+
+ 6. htable.listTables
+        List all htables.
+
+ 7. htable.reload
+        Reload hash table.
+
+ 8. htable.stats
+        Statistics about htables.
+
diff --git a/doc/rpc_list/rpc_ims_usrloc_pcscf.txt b/doc/rpc_list/rpc_ims_usrloc_pcscf.txt
new file mode 100644
index 0000000..dd21183
--- /dev/null
+++ b/doc/rpc_list/rpc_ims_usrloc_pcscf.txt
@@ -0,0 +1,9 @@
+RPC Exports for ims_usrloc_pcscf
+================================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. ulpcscf.status
+        Dump PCSCF contacts and associated identitites
+
diff --git a/doc/rpc_list/rpc_ims_usrloc_scscf.txt b/doc/rpc_list/rpc_ims_usrloc_scscf.txt
new file mode 100644
index 0000000..5859d71
--- /dev/null
+++ b/doc/rpc_list/rpc_ims_usrloc_scscf.txt
@@ -0,0 +1,12 @@
+RPC Exports for ims_usrloc_scscf
+================================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. ulscscf.status
+        Dump SCSCF user location tables
+
+ 2. ulscscf.showimpu
+        Dump SCSCF IMPU information
+
diff --git a/doc/rpc_list/rpc_lcr.txt b/doc/rpc_list/rpc_lcr.txt
index cb3be62..1de7652 100644
--- a/doc/rpc_list/rpc_lcr.txt
+++ b/doc/rpc_list/rpc_lcr.txt
@@ -13,3 +13,6 @@ RPC Exports for lcr
  3. lcr.dump_rules
         Dump the contents of the lcr_rules table.
 
+ 4. lcr.defunct_gw
+        Defunct gateway until specified time (Unix timestamp).
+
diff --git a/doc/rpc_list/rpc_msrp.txt b/doc/rpc_list/rpc_msrp.txt
new file mode 100644
index 0000000..20993d0
--- /dev/null
+++ b/doc/rpc_list/rpc_msrp.txt
@@ -0,0 +1,9 @@
+RPC Exports for msrp
+====================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. msrp.cmaplist
+        Return the content of dispatcher sets
+
diff --git a/doc/rpc_list/rpc_mtree.txt b/doc/rpc_list/rpc_mtree.txt
new file mode 100644
index 0000000..4efb500
--- /dev/null
+++ b/doc/rpc_list/rpc_mtree.txt
@@ -0,0 +1,12 @@
+RPC Exports for mtree
+=====================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. mtree.summary
+        Print summary of loaded mtree tables
+
+ 2. mtree.reload
+        Reload mtrees from database to memory
+
diff --git a/doc/rpc_list/rpc_pdt.txt b/doc/rpc_list/rpc_pdt.txt
index 3034874..2881877 100644
--- a/doc/rpc_list/rpc_pdt.txt
+++ b/doc/rpc_list/rpc_pdt.txt
@@ -4,13 +4,9 @@ RPC Exports for pdt
                   [ this file is autogenerated, do not edit ]
 
 
- 1. pdt.add
-        Add new prefix/domain translation rule.
+ 1. pdt.reload
+        Reload PDT database records
 
- 2. pdt.delete
-        Delete prefix/domain translation rule.
-
- 3. pdt.list
-        List existin prefix/domain translation rules
-        Returns an array.
+ 2. pdt.list
+        List PDT memory records
 
diff --git a/doc/rpc_list/rpc_permissions.txt b/doc/rpc_list/rpc_permissions.txt
new file mode 100644
index 0000000..fcc46c8
--- /dev/null
+++ b/doc/rpc_list/rpc_permissions.txt
@@ -0,0 +1,28 @@
+RPC Exports for permissions
+===========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. permissions.trustedReload
+        Reload permissions trusted table
+
+ 2. permissions.addressReload
+        Reload permissions address table
+
+ 3. permissions.trustedDump
+        Dump permissions trusted table
+
+ 4. permissions.addressDump
+        Dump permissions address table
+
+ 5. permissions.subnetDump
+        Dump permissions subnet table
+
+ 6. permissions.domainDump
+        Dump permissions domain name table
+
+ 7. permissions.testUri
+        Tests if (URI, Contact) pair is allowed according to allow/deny
+        files
+
diff --git a/doc/rpc_list/rpc_pike.txt b/doc/rpc_list/rpc_pike.txt
index 177d5b3..68217b9 100644
--- a/doc/rpc_list/rpc_pike.txt
+++ b/doc/rpc_list/rpc_pike.txt
@@ -5,5 +5,5 @@ RPC Exports for pike
 
 
  1. pike.top
-        pike.top doc.
+        pike.top Dump parts of the pike table
 
diff --git a/doc/rpc_list/rpc_pipelimit.txt b/doc/rpc_list/rpc_pipelimit.txt
new file mode 100644
index 0000000..163076c
--- /dev/null
+++ b/doc/rpc_list/rpc_pipelimit.txt
@@ -0,0 +1,27 @@
+RPC Exports for pipelimit
+=========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. pl.stats
+        Print pipelimit statistics: <id> <load> <counter>
+
+ 2. pl.get_pipes
+        Print pipes info: <id> <algorithm> <limit> <counter>
+
+ 3. pl.set_pipe
+        Sets a pipe params: <pipe_id> <pipe_algorithm> <pipe_limit>
+
+ 4. pl.get_pid
+        Print PID Controller parameters for the FEEDBACK algorithm:
+        <ki> <kp> <kd>
+
+ 5. pl.set_pid
+        Sets the PID Controller parameters for the FEEDBACK algorithm:
+        <ki> <kp> <kd>
+
+ 6. pl.push_load
+        Force the value of the load parameter for FEEDBACK algorithm:
+        <load>
+
diff --git a/doc/rpc_list/rpc_prefix_route.txt b/doc/rpc_list/rpc_prefix_route.txt
index 8f51fa9..8093294 100644
--- a/doc/rpc_list/rpc_prefix_route.txt
+++ b/doc/rpc_list/rpc_prefix_route.txt
@@ -5,8 +5,8 @@ RPC Exports for prefix_route
 
 
  1. prefix_route.reload
-        Documentation missing (rpc_reload_doc).
+        Reload prefix routes from DB
 
  2. prefix_route.dump
-        Documentation missing (rpc_dump_doc).
+        Dump the prefix route tree
 
diff --git a/doc/rpc_list/rpc_presence.txt b/doc/rpc_list/rpc_presence.txt
new file mode 100644
index 0000000..c7338c6
--- /dev/null
+++ b/doc/rpc_list/rpc_presence.txt
@@ -0,0 +1,10 @@
+RPC Exports for presence
+========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. presence.cleanup
+        Manually triggers the cleanup functions for the
+        active_watchers, presentity, and watchers tables.
+
diff --git a/doc/rpc_list/rpc_presence_b2b.txt b/doc/rpc_list/rpc_presence_b2b.txt
deleted file mode 100644
index bf7a317..0000000
--- a/doc/rpc_list/rpc_presence_b2b.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-RPC Exports for presence_b2b
-============================
-
-                  [ this file is autogenerated, do not edit ]
-
-
- 1. presence_b2b.test
-        Testing events.
-
- 2. presence_b2b.trace
-        Trace events.
-
diff --git a/doc/rpc_list/rpc_pv.txt b/doc/rpc_list/rpc_pv.txt
new file mode 100644
index 0000000..effd938
--- /dev/null
+++ b/doc/rpc_list/rpc_pv.txt
@@ -0,0 +1,12 @@
+RPC Exports for pv
+==================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. pv.shvSet
+        Set a shared variable (args: name type value)
+
+ 2. pv.shvGet
+        Get the value of a shared variable. If no argument, dumps all
+
diff --git a/doc/rpc_list/rpc_sca.txt b/doc/rpc_list/rpc_sca.txt
new file mode 100644
index 0000000..9dec0cc
--- /dev/null
+++ b/doc/rpc_list/rpc_sca.txt
@@ -0,0 +1,40 @@
+RPC Exports for sca
+===================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. sca.all_subscriptions
+        Documentation missing (sca_rpc_show_all_subscriptions_doc).
+
+ 2. sca.subscription_count
+        Documentation missing (sca_rpc_subscription_count_doc).
+
+ 3. sca.show_subscription
+        Documentation missing (sca_rpc_show_subscription_doc).
+
+ 4. sca.subscribers
+        Documentation missing (sca_rpc_show_subscribers_doc).
+
+ 5. sca.deactivate_all_subscriptions
+        Documentation missing
+        (sca_rpc_deactivate_all_subscriptions_doc).
+
+ 6. sca.deactivate_subscription
+        Documentation missing (sca_rpc_deactivate_subscription_doc).
+
+ 7. sca.all_appearances
+        Documentation missing (sca_rpc_show_all_appearances_doc).
+
+ 8. sca.show_appearance
+        Documentation missing (sca_rpc_show_appearance_doc).
+
+ 9. sca.seize_appearance
+        Documentation missing (sca_rpc_seize_appearance_doc).
+
+10. sca.update_appearance
+        Documentation missing (sca_rpc_update_appearance_doc).
+
+11. sca.release_appearance
+        Documentation missing (sca_rpc_release_appearance_doc).
+
diff --git a/doc/rpc_list/rpc_sctp.txt b/doc/rpc_list/rpc_sctp.txt
new file mode 100644
index 0000000..771bf14
--- /dev/null
+++ b/doc/rpc_list/rpc_sctp.txt
@@ -0,0 +1,17 @@
+RPC Exports for sctp
+====================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. sctp.options
+        Returns active sctp options. With one parameter it returns the
+        sctp options set in the kernel for a specific
+        socket(debugging), with 0 filled in for non-kernel related
+        options. The parameter can be: "default" | "first" |
+        address[:port] . With no parameters it returns ser's idea of
+        the current sctp options (intended non-debugging use).
+
+ 2. sctp.info
+        Returns sctp related info.
+
diff --git a/doc/rpc_list/rpc_sipcapture.txt b/doc/rpc_list/rpc_sipcapture.txt
new file mode 100644
index 0000000..d59bb13
--- /dev/null
+++ b/doc/rpc_list/rpc_sipcapture.txt
@@ -0,0 +1,9 @@
+RPC Exports for sipcapture
+==========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. sipcapture.status
+        Get status or turn on/off sipcapture.
+
diff --git a/doc/rpc_list/rpc_siptrace.txt b/doc/rpc_list/rpc_siptrace.txt
new file mode 100644
index 0000000..dedb583
--- /dev/null
+++ b/doc/rpc_list/rpc_siptrace.txt
@@ -0,0 +1,10 @@
+RPC Exports for siptrace
+========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. siptrace.status
+        Get status or turn on/off siptrace. Parameters: on, off or
+        check.
+
diff --git a/doc/rpc_list/rpc_sl.txt b/doc/rpc_list/rpc_sl.txt
index 5e1e52c..8b46005 100644
--- a/doc/rpc_list/rpc_sl.txt
+++ b/doc/rpc_list/rpc_sl.txt
@@ -5,5 +5,5 @@ RPC Exports for sl
 
 
  1. sl.stats
-        Documentation missing (rpc_stats_doc).
+        Print reply statistics.
 
diff --git a/doc/rpc_list/rpc_tls.txt b/doc/rpc_list/rpc_tls.txt
index ff372cd..520ac59 100644
--- a/doc/rpc_list/rpc_tls.txt
+++ b/doc/rpc_list/rpc_tls.txt
@@ -5,15 +5,15 @@ RPC Exports for tls
 
 
  1. tls.reload
-        Documentation missing (tls_reload_doc).
+        Reload TLS configuration file
 
  2. tls.list
-        Documentation missing (tls_list_doc).
+        List currently open TLS connections
         Returns an array.
 
  3. tls.info
-        Documentation missing (tls_info_doc).
+        Returns internal tls related info.
 
  4. tls.options
-        Documentation missing (tls_options_doc).
+        Dumps all the tls config options.
 
diff --git a/doc/rpc_list/rpc_tm.txt b/doc/rpc_list/rpc_tm.txt
index 177ff05..60b0802 100644
--- a/doc/rpc_list/rpc_tm.txt
+++ b/doc/rpc_list/rpc_tm.txt
@@ -5,21 +5,26 @@ RPC Exports for tm
 
 
  1. tm.cancel
-        Documentation missing (rpc_cancel_doc).
+        Cancel a pending transaction
 
  2. tm.reply
-        Documentation missing (rpc_reply_doc).
+        Reply transaction
 
  3. tm.stats
-        Documentation missing (tm_rpc_stats_doc).
+        Print transaction statistics.
 
  4. tm.hash_stats
-        Documentation missing (tm_rpc_hash_stats_doc).
+        Prints hash table statistics (can be used only if tm is
+        compiled with -DTM_HASH_STATS).
 
  5. tm.t_uac_start
-        Documentation missing (rpc_t_uac_start_doc).
+        starts a tm uac using  a list of string parameters: method,
+        ruri, dst_uri, send_sock, headers (CRLF separated) and body
+        (optional)
 
  6. tm.t_uac_wait
-        Documentation missing (rpc_t_uac_wait_doc).
+        starts a tm uac and waits for the final reply, using a list of
+        string parameters: method, ruri, dst_uri send_sock, headers
+        (CRLF separated) and body (optional)
         Returns an array.
 
diff --git a/doc/rpc_list/rpc_uid_domain.txt b/doc/rpc_list/rpc_uid_domain.txt
new file mode 100644
index 0000000..042d110
--- /dev/null
+++ b/doc/rpc_list/rpc_uid_domain.txt
@@ -0,0 +1,12 @@
+RPC Exports for uid_domain
+==========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. domain.reload
+        Reload domain table from database
+
+ 2. domain.dump
+        Return the contents of domain table
+
diff --git a/doc/rpc_list/rpc_uid_gflags.txt b/doc/rpc_list/rpc_uid_gflags.txt
new file mode 100644
index 0000000..5746339
--- /dev/null
+++ b/doc/rpc_list/rpc_uid_gflags.txt
@@ -0,0 +1,24 @@
+RPC Exports for uid_gflags
+==========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. gflags.set
+        Load a CPL script to the server.
+
+ 2. gflags.is_set
+        Load a CPL script to the server.
+
+ 3. gflags.reset
+        Load a CPL script to the server.
+
+ 4. gflags.flush
+        Load a CPL script to the server.
+
+ 5. gflags.dump
+        Load a CPL script to the server.
+
+ 6. global.reload
+        Reload global attributes from database
+
diff --git a/doc/rpc_list/rpc_usrloc.txt b/doc/rpc_list/rpc_usrloc.txt
index 3514a2b..02a7aba 100644
--- a/doc/rpc_list/rpc_usrloc.txt
+++ b/doc/rpc_list/rpc_usrloc.txt
@@ -7,3 +7,30 @@ RPC Exports for usrloc
  1. ul.dump
         Dump user location tables
 
+ 2. ul.lookup
+        Lookup one AOR in the usrloc location table
+
+ 3. ul.rm
+        Delete a address of record including its contacts
+
+ 4. ul.rm_contact
+        Delete a contact from an AOR record
+
+ 5. ul.flush
+        Flush the usrloc memory cache to DB
+
+ 6. ul.add
+        Add a new contact for an address of record
+
+ 7. ul.db_users
+        Tell number of different unexpired users (AoRs) in database
+        table (db_mode!=0 only)
+
+ 8. ul.db_contacts
+        Tell number of unexpired contacts in database table (db_mode=3
+        only)
+
+ 9. ul.db_expired_contacts
+        Tell number of expired contacts in database table (db_mode=3
+        only)
+
diff --git a/doc/rpc_list/rpc_usrloc_k.txt b/doc/rpc_list/rpc_usrloc_k.txt
deleted file mode 100644
index 2800197..0000000
--- a/doc/rpc_list/rpc_usrloc_k.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-RPC Exports for usrloc_k
-========================
-
-                  [ this file is autogenerated, do not edit ]
-
-
- 1. ul.dump
-        Dump user location tables
-
diff --git a/doc/rpc_list/rpc_usrloc_s.txt b/doc/rpc_list/rpc_usrloc_s.txt
deleted file mode 100644
index 830100d..0000000
--- a/doc/rpc_list/rpc_usrloc_s.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-RPC Exports for usrloc_s
-========================
-
-                  [ this file is autogenerated, do not edit ]
-
-
- 1. usrloc.stats
-        Documentation missing (rpc_stats_doc).
-        Returns an array.
-
- 2. usrloc.delete_uid
-        Documentation missing (rpc_delete_uid_doc).
-
- 3. usrloc.delete_contact
-        Documentation missing (rpc_delete_contact_doc).
-
- 4. usrloc.dump
-        Documentation missing (rpc_dump_doc).
-
- 5. usrloc.dump_file
-        Documentation missing (rpc_dump_file_doc).
-
- 6. usrloc.flush
-        Documentation missing (rpc_flush_doc).
-
- 7. usrloc.add_contact
-        Documentation missing (rpc_add_contact_doc).
-
- 8. usrloc.show_contacts
-        Documentation missing (rpc_show_contacts_doc).
-        Returns an array.
-
diff --git a/doc/rpc_list/rpc_xhttp_pi.txt b/doc/rpc_list/rpc_xhttp_pi.txt
new file mode 100644
index 0000000..f2ba4e3
--- /dev/null
+++ b/doc/rpc_list/rpc_xhttp_pi.txt
@@ -0,0 +1,9 @@
+RPC Exports for xhttp_pi
+========================
+
+                  [ this file is autogenerated, do not edit ]
+
+
+ 1. xhttp_pi.reload
+        Reload the xml framework
+
diff --git a/doc/select_list/Makefile b/doc/select_list/Makefile
index ae84037..2b658f6 100644
--- a/doc/select_list/Makefile
+++ b/doc/select_list/Makefile
@@ -67,7 +67,7 @@ gcc=gcc
 
 # defines used by gcc
 c_defs=-D__CPU_i386 -D__OS_linux -DSER_VER=2099099 -DPKG_MALLOC -DSHM_MEM  \
-		-DSHM_MMAP -DDNS_IP_HACK -DUSE_IPV6 -DUSE_MCAST -DUSE_TCP \
+		-DSHM_MMAP -DDNS_IP_HACK -DUSE_MCAST -DUSE_TCP \
 		-DUSE_DNS_CACHE -DUSE_DNS_FAILOVER -DUSE_DST_BLACKLIST -DUSE_NAPTR \
 		-DUSE_TLS -DTLS_HOOKS -DFAST_LOCK   -DCC_GCC_LIKE_ASM \
 		-DHAVE_GETHOSTBYNAME2 -DHAVE_UNION_SEMUN -DHAVE_SCHED_YIELD \
diff --git a/doc/stylesheets/dbschema_k/xsl/mysql.xsl b/doc/stylesheets/dbschema_k/xsl/mysql.xsl
index 627c734..641a4ef 100644
--- a/doc/stylesheets/dbschema_k/xsl/mysql.xsl
+++ b/doc/stylesheets/dbschema_k/xsl/mysql.xsl
@@ -43,8 +43,10 @@
     <xsl:template name="table.close">
 	<xsl:text>)</xsl:text>
 	<xsl:if test="type[@db=$db]">
-	    <xsl:text> ENGINE=</xsl:text>
-	    <xsl:value-of select="normalize-space(type[@db=$db])"/>
+            <xsl:if test="not(type[@db]='')">
+		<xsl:text> ENGINE=</xsl:text>
+		<xsl:value-of select="normalize-space(type[@db=$db])"/>
+	    </xsl:if>
 	</xsl:if>
 	<xsl:text>;&#x0A;&#x0A;</xsl:text>	
     </xsl:template>
diff --git a/dprint.c b/dprint.c
index 12259d4..b99174d 100644
--- a/dprint.c
+++ b/dprint.c
@@ -115,12 +115,29 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val)
 
 /* the local debug log level */
 static int _local_debug_level = UNSET_LOCAL_DEBUG_LEVEL;
+/* callback to get per module debug level */
+static get_module_debug_level_f _module_debug_level = NULL;
+
+/**
+ * @brief set callback function for per module debug level
+ */
+void set_module_debug_level_cb(get_module_debug_level_f f)
+{
+	_module_debug_level = f;
+}
 
 /**
  * @brief return the log level - the local one if it set,
  *   otherwise the global value
  */
-int get_debug_level(void) {
+int get_debug_level(char *mname, int mnlen) {
+	int mlevel = L_DBG;
+	/*important -- no LOGs inside, because it will loop */
+	if(unlikely(_module_debug_level!=NULL && mnlen>0)) {
+		if(_module_debug_level(mname, mnlen, &mlevel)==0) {
+			return mlevel;
+		}
+	}
 	return (_local_debug_level != UNSET_LOCAL_DEBUG_LEVEL) ?
 				_local_debug_level : cfg_get(core, core_cfg, debug);
 }
diff --git a/dprint.h b/dprint.h
index 285c9f1..0842988 100644
--- a/dprint.h
+++ b/dprint.h
@@ -59,8 +59,10 @@
 #ifdef NO_DEBUG
 #	ifdef MOD_NAME
 #		define LOC_INFO		MOD_NAME ": "
+#		define LOG_MNAME	MOD_NAME
 #	else
 #		define LOC_INFO		"<core>: "
+#		define LOG_MNAME	"core"
 #	endif
 #else
 #	define XCT2STR(i) #i
@@ -68,8 +70,10 @@
 #
 #	ifdef MOD_NAME
 #		define LOC_INFO		MOD_NAME " [" __FILE__ ":" CT2STR(__LINE__) "]: "
+#		define LOG_MNAME	MOD_NAME
 #	else
 #		define LOC_INFO		"<core> [" __FILE__ ":" CT2STR(__LINE__) "]: "
+#		define LOG_MNAME	"core"
 #	endif
 #
 #	ifdef NO_LOG
@@ -77,6 +81,7 @@
 #	endif
 #endif /* NO_DEBUG */
 
+#define LOG_MNAME_LEN		(sizeof(LOG_MNAME)-1)
 
 /*
  * Log levels
@@ -121,11 +126,13 @@ struct log_level_info {
 };
 
 /** @brief per process debug level handling */
-int get_debug_level(void);
+int get_debug_level(char *mname, int mnlen);
 void set_local_debug_level(int level);
 void reset_local_debug_level(void);
+typedef int (*get_module_debug_level_f)(char *mname, int mnlen, int *mlevel);
+void set_module_debug_level_cb(get_module_debug_level_f f);
 
-#define is_printable(level) (get_debug_level()>=(level))
+#define is_printable(level) (get_debug_level(LOG_MNAME, LOG_MNAME_LEN)>=(level))
 extern struct log_level_info log_level_info[];
 extern char *log_name;
 
@@ -179,7 +186,7 @@ void dprint_term_color(char f, char b, str *obuf);
 #	ifdef __SUNPRO_C
 #		define LOG_(facility, level, prefix, fmt, ...) \
 			do { \
-				if (unlikely(get_debuglevel() >= (level) && \
+				if (unlikely(get_debug_level(LOG_MNAME, LOG_MNAME_LEN) >= (level) && \
 						DPRINT_NON_CRIT)) { \
 					DPRINT_CRIT_ENTER; \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \
@@ -245,7 +252,7 @@ void dprint_term_color(char f, char b, str *obuf);
 #	else /* ! __SUNPRO_C */
 #		define LOG_(facility, level, prefix, fmt, args...) \
 			do { \
-				if (get_debug_level() >= (level) && \
+				if (get_debug_level(LOG_MNAME, LOG_MNAME_LEN) >= (level) && \
 						DPRINT_NON_CRIT) { \
 					DPRINT_CRIT_ENTER; \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \
diff --git a/dset.c b/dset.c
index 31b8b38..13b000b 100644
--- a/dset.c
+++ b/dset.c
@@ -37,6 +37,7 @@
 #include "dprint.h"
 #include "config.h"
 #include "parser/parser_f.h"
+#include "parser/parse_uri.h"
 #include "parser/msg_parser.h"
 #include "ut.h"
 #include "hash_func.h"
@@ -215,7 +216,8 @@ void set_branch_iterator(int n)
  */
 char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 		 str* path, unsigned int *flags,
-		 struct socket_info** force_socket)
+		 struct socket_info** force_socket,
+		 str *ruid, str *instance, str *location_ua)
 {
 	if (i < nr_branches) {
 		*len = branches[i].len;
@@ -232,6 +234,19 @@ char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 			*force_socket = branches[i].force_send_socket;
 		if (flags)
 			*flags = branches[i].flags;
+		if (ruid) {
+			ruid->len = branches[i].ruid_len;
+			ruid->s = (ruid->len)?branches[i].ruid:0;
+		}
+		if (instance) {
+			instance->len = branches[i].instance_len;
+			instance->s = (instance->len)?branches[i].instance:0;
+		}
+		if (location_ua) {
+			location_ua->len = branches[i].location_ua_len;
+			location_ua->s
+				= (location_ua->len)?branches[i].location_ua:0;
+		}
 		return branches[i].uri;
 	} else {
 		*len = 0;
@@ -248,6 +263,18 @@ char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 			*force_socket = 0;
 		if (flags)
 			*flags = 0;
+		if (ruid) {
+			ruid->s = 0;
+			ruid->len = 0;
+		}
+		if (instance) {
+			instance->s = 0;
+			instance->len = 0;
+		}
+		if (location_ua) {
+			location_ua->s = 0;
+			location_ua->len = 0;
+		}
 		return 0;
 	}
 }
@@ -258,12 +285,13 @@ char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
  * 0 is returned if there are no more branches
  */
 char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
-		  unsigned int* flags, struct socket_info** force_socket)
+		  unsigned int* flags, struct socket_info** force_socket,
+		  str* ruid, str *instance, str *location_ua)
 {
 	char* ret;
 	
 	ret=get_branch(branch_iterator, len, q, dst_uri, path, flags,
-		       force_socket);
+		       force_socket, ruid, instance, location_ua);
 	if (likely(ret))
 		branch_iterator++;
 	return ret;
@@ -297,7 +325,8 @@ void clear_branches(void)
 int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
 		  qvalue_t q, unsigned int flags,
 		  struct socket_info* force_socket,
-		  str* instance, unsigned int reg_id)
+		  str* instance, unsigned int reg_id,
+		  str* ruid, str* location_ua)
 {
 	str luri;
 
@@ -381,6 +410,37 @@ int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
 	/* copy reg_id */
 	branches[nr_branches].reg_id = reg_id;
 
+	/* copy ruid string */
+	if (unlikely(ruid && ruid->len && ruid->s)) {
+		if (unlikely(ruid->len > MAX_RUID_SIZE - 1)) {
+			LOG(L_ERR, "too long ruid: %.*s\n",
+			    ruid->len, ruid->s);
+			return -1;
+		}
+		memcpy(branches[nr_branches].ruid, ruid->s,
+		       ruid->len);
+		branches[nr_branches].ruid[ruid->len] = 0;
+		branches[nr_branches].ruid_len = ruid->len;
+	} else {
+		branches[nr_branches].ruid[0] = '\0';
+		branches[nr_branches].ruid_len = 0;
+	}
+
+	if (unlikely(location_ua && location_ua->len && location_ua->s)) {
+		if (unlikely(location_ua->len > MAX_UA_SIZE)) {
+			LOG(L_ERR, "too long location_ua: %.*s\n",
+			    location_ua->len, location_ua->s);
+			return -1;
+		}
+		memcpy(branches[nr_branches].location_ua, location_ua->s,
+		       location_ua->len);
+		branches[nr_branches].location_ua[location_ua->len] = 0;
+		branches[nr_branches].location_ua_len = location_ua->len;
+	} else {
+		branches[nr_branches].location_ua[0] = '\0';
+		branches[nr_branches].location_ua_len = 0;
+	}
+	
 	nr_branches++;
 	return 1;
 }
@@ -417,7 +477,7 @@ char* print_dset(struct sip_msg* msg, int* len)
 	crt_branch = get_branch_iterator();
 
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0))) {
 		cnt++;
 		*len += uri.len + 1 /*'<'*/;
 		if (q != Q_UNSPECIFIED) {
@@ -460,7 +520,7 @@ char* print_dset(struct sip_msg* msg, int* len)
 	}
 
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0))) {
 		if (i) {
 			memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
 			p += CONTACT_DELIM_LEN;
@@ -546,3 +606,274 @@ int rewrite_uri(struct sip_msg* _m, str* _s)
 	return 1;
 }
 
+/**
+ * return src ip, port and proto as a SIP uri or proxy address
+ * - value stored in a static buffer
+ * - mode=0 return uri, mode=1 return proxy address
+ */
+int msg_get_src_addr(sip_msg_t *msg, str *uri, int mode)
+{
+	static char buf[80];
+	char* p;
+	str ip, port;
+	int len;
+	str proto;
+
+	if (msg==NULL || uri==NULL) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	ip.s = ip_addr2a(&msg->rcv.src_ip);
+	ip.len = strlen(ip.s);
+
+	port.s = int2str(msg->rcv.src_port, &port.len);
+
+	switch(msg->rcv.proto) {
+		case PROTO_NONE:
+		case PROTO_UDP:
+			if(mode==0) {
+				proto.s = 0; /* Do not add transport parameter, UDP is default */
+				proto.len = 0;
+			} else {
+				proto.s = "udp";
+				proto.len = 3;
+			}
+		break;
+
+		case PROTO_TCP:
+			proto.s = "tcp";
+			proto.len = 3;
+		break;
+
+		case PROTO_TLS:
+			proto.s = "tls";
+			proto.len = 3;
+		break;
+
+		case PROTO_SCTP:
+			proto.s = "sctp";
+			proto.len = 4;
+		break;
+
+		case PROTO_WS:
+		case PROTO_WSS:
+			proto.s = "ws";
+			proto.len = 2;
+		break;
+
+		default:
+			LM_ERR("unknown transport protocol\n");
+		return -1;
+	}
+
+	len = ip.len + 2*(msg->rcv.src_ip.af==AF_INET6)+ 1 + port.len;
+	if (mode==0) {
+		len += 4;
+		if(proto.s) {
+			len += TRANSPORT_PARAM_LEN;
+			len += proto.len;
+		}
+	} else {
+		len += proto.len + 1;
+	}
+
+	if (len > 79) {
+		LM_ERR("buffer too small\n");
+		return -1;
+	}
+
+	p = buf;
+	if(mode==0) {
+		memcpy(p, "sip:", 4);
+		p += 4;
+	} else {
+		memcpy(p, proto.s, proto.len);
+		p += proto.len;
+		*p++ = ':';
+	}
+
+	if (msg->rcv.src_ip.af==AF_INET6)
+		*p++ = '[';
+	memcpy(p, ip.s, ip.len);
+	p += ip.len;
+	if (msg->rcv.src_ip.af==AF_INET6)
+		*p++ = ']';
+
+	*p++ = ':';
+
+	memcpy(p, port.s, port.len);
+	p += port.len;
+
+	if (mode==0 && proto.s) {
+		memcpy(p, TRANSPORT_PARAM, TRANSPORT_PARAM_LEN);
+		p += TRANSPORT_PARAM_LEN;
+
+		memcpy(p, proto.s, proto.len);
+		p += proto.len;
+	}
+
+	uri->s = buf;
+	uri->len = len;
+	uri->s[uri->len] = '\0';
+
+	return 0;
+}
+
+/**
+ * add alias parameter with encoding of source address
+ * - nuri->s must point to a buffer of nuri->len size
+ */
+int uri_add_rcv_alias(sip_msg_t *msg, str *uri, str *nuri)
+{
+	char* p;
+	str ip, port;
+	int len;
+
+	if (msg==NULL || uri==NULL || nuri==NULL) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	ip.s = ip_addr2a(&msg->rcv.src_ip);
+	ip.len = strlen(ip.s);
+
+	port.s = int2str(msg->rcv.src_port, &port.len);
+
+	/*uri;alias=[ip]~port~proto*/
+	len = uri->len+ip.len+port.len+12;
+	if(len>=nuri->len) {
+		LM_ERR("not enough space for new uri: %d\n", len);
+		return -1;
+	}
+	p = nuri->s;
+	memcpy(p, uri->s, uri->len);
+	p += uri->len;
+	memcpy(p, ";alias=", 7);
+	p += 7;
+	if (msg->rcv.src_ip.af == AF_INET6)
+		*p++ = '[';
+	memcpy(p, ip.s, ip.len);
+	p += ip.len;
+	if (msg->rcv.src_ip.af == AF_INET6)
+		*p++ = ']';
+	*p++ = '~';
+	memcpy(p, port.s, port.len);
+	p += port.len;
+	*p++ = '~';
+	*p++ = msg->rcv.proto + '0';
+	nuri->len = p - nuri->s;
+	nuri->s[nuri->len] = '\0';
+
+	LM_DBG("encoded <%.*s> => [%.*s]\n",
+			uri->len, uri->s, nuri->len, nuri->s);
+	return 0;
+}
+
+/**
+ * restore from alias parameter with encoding of source address
+ * - nuri->s must point to a buffer of nuri->len size
+ * - suri->s must point to a buffer of suri->len size
+ */
+int uri_restore_rcv_alias(str *uri, str *nuri, str *suri)
+{
+	char* p;
+	str skip;
+	str ip, port, sproto;
+	int proto;
+
+	if (uri==NULL || nuri==NULL || suri==NULL) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	/* sip:x;alias=1.1.1.1~0~0 */
+	if(uri->len < 23) {
+		/* no alias possible */
+		return -2;
+	}
+	p = uri->s + uri->len-18;
+	skip.s = 0;
+	while(p>uri->s+5) {
+		if(strncmp(p, ";alias=", 7)==0) {
+			skip.s = p;
+			break;
+		}
+		p--;
+	}
+	if(skip.s==0) {
+		/* alias parameter not found */
+		return -2;
+	}
+	p += 7;
+	ip.s = p;
+	p = (char*)memchr(ip.s, '~', (size_t)(uri->s+uri->len-ip.s));
+	if(p==NULL) {
+		/* proper alias parameter not found */
+		return -2;
+	}
+	ip.len = p - ip.s;
+	p++;
+	if(p>=uri->s+uri->len) {
+		/* proper alias parameter not found */
+		return -2;
+	}
+	port.s = p;
+	p = (char*)memchr(port.s, '~', (size_t)(uri->s+uri->len-port.s));
+	if(p==NULL) {
+		/* proper alias parameter not found */
+		return -2;
+	}
+	port.len = p - port.s;
+	p++;
+	if(p>=uri->s+uri->len) {
+		/* proper alias parameter not found */
+		return -2;
+	}
+	proto = (int)(*p - '0');
+	p++;
+
+	if(p!=uri->s+uri->len && *p!=';') {
+		/* proper alias parameter not found */
+		return -2;
+	}
+	skip.len = (int)(p - skip.s);
+
+	if(suri->len<=4+ip.len+1+port.len+11/*;transport=*/+4) {
+		LM_ERR("address buffer too small\n");
+		return -1;
+	}
+	if(nuri->len<=uri->len - skip.len) {
+		LM_ERR("uri buffer too small\n");
+		return -1;
+	}
+
+	p = nuri->s;
+	memcpy(p, uri->s, (size_t)(skip.s-uri->s));
+	p += skip.s-uri->s;
+	memcpy(p, skip.s+skip.len, (size_t)(uri->s+uri->len - skip.s - skip.len));
+	p += uri->s+uri->len - skip.s - skip.len;
+	nuri->len = p - nuri->s;
+
+	p = suri->s;
+	strncpy(p, "sip:", 4);
+	p += 4;
+	strncpy(p, ip.s, ip.len);
+	p += ip.len;
+	*p++ = ':';
+	strncpy(p, port.s, port.len);
+	p += port.len;
+	proto_type_to_str((unsigned short)proto, &sproto);
+	if(sproto.len>0 && proto!=PROTO_UDP) {
+		strncpy(p, ";transport=", 11);
+		p += 11;
+		strncpy(p, sproto.s, sproto.len);
+		p += sproto.len;
+	}
+	suri->len = p - suri->s;
+
+	LM_DBG("decoded <%.*s> => [%.*s] [%.*s]\n",
+			uri->len, uri->s, nuri->len, nuri->s, suri->len, suri->s);
+
+	return 0;
+}
diff --git a/dset.h b/dset.h
index bc131ef..af90312 100644
--- a/dset.h
+++ b/dset.h
@@ -66,6 +66,13 @@ struct branch
     /* reg-id contact header param value */
     unsigned int reg_id;
 
+    /* ruid value from usrloc */
+    char ruid[MAX_RUID_SIZE];
+    unsigned int ruid_len;
+
+    char location_ua[MAX_UA_SIZE + 1];
+    unsigned int location_ua_len;
+
     /* Branch flags */
     flag_t flags;
 };
@@ -88,11 +95,12 @@ int drop_sip_branch(int idx);
 int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
 		  qvalue_t q, unsigned int flags,
 		  struct socket_info* force_socket,
-		  str* instance, unsigned int reg_id);
+		  str* instance, unsigned int reg_id,
+		  str* ruid, str* location_ua);
 
 /*! \brief kamailio compatible version */
 #define km_append_branch(msg, uri, dst_uri, path, q, flags, force_socket) \
-    append_branch(msg, uri, dst_uri, path, q, flags, force_socket, 0, 0)
+    append_branch(msg, uri, dst_uri, path, q, flags, force_socket, 0, 0, 0, 0)
 
 /*! \brief ser compatible append_branch version.
  *  append_branch version compatible with ser: no path or branch flags support
@@ -109,7 +117,7 @@ static inline int ser_append_branch(struct sip_msg* msg,
     s_uri.len=uri_len;
     s_dst_uri.s=dst_uri;
     s_dst_uri.len=dst_uri_len;
-    return append_branch(msg, &s_uri, &s_dst_uri, 0, q, 0, force_socket, 0, 0);
+    return append_branch(msg, &s_uri, &s_dst_uri, 0, q, 0, force_socket, 0, 0, 0, 0);
 }
 
 
@@ -134,11 +142,13 @@ void set_branch_iterator(int n);
  *  *len) or 0 if there are no more branches.
  */
 char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
-		  unsigned int* flags, struct socket_info** force_socket);
+		  unsigned int* flags, struct socket_info** force_socket,
+		  str *ruid, str *instance, str *location_ua);
 
 char* get_branch( unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 		  str* path, unsigned int *flags,
-		  struct socket_info** force_socket);
+		  struct socket_info** force_socket,
+		  str* ruid, str *instance, str *location_ua);
 
 /*! \brief
  * Empty the array of branches
@@ -160,6 +170,11 @@ void set_ruri_q(qvalue_t q);
 
 
 /*! \brief
+ * Get src ip, port and proto as SIP uri or proxy address
+ */
+int msg_get_src_addr(sip_msg_t *msg, str *uri, int mode);
+
+/*! \brief
  * Get the q value of the Request-URI
  */
 qvalue_t get_ruri_q(void);
@@ -240,4 +255,7 @@ int getbflagsval(unsigned int branch, flag_t* res);
  */
 int setbflagsval(unsigned int branch, flag_t val);
 
+int uri_add_rcv_alias(sip_msg_t *msg, str *uri, str *nuri);
+int uri_restore_rcv_alias(str *uri, str *nuri, str *suri);
+
 #endif /* _DSET_H */
diff --git a/dst_blacklist.c b/dst_blacklist.c
index d368e51..1e48a16 100644
--- a/dst_blacklist.c
+++ b/dst_blacklist.c
@@ -338,12 +338,10 @@ static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data);
 inline static void dst_blst_entry2ip(struct ip_addr* ip,
 										struct dst_blst_entry* e)
 {
-#ifdef USE_IPV6
 	if (e->flags & BLST_IS_IPV6){
 		ip->af=AF_INET6;
 		ip->len=16;
 	}else
-#endif /* USE_IPV6 */
 	{
 		ip->af=AF_INET;
 		ip->len=4;
@@ -566,12 +564,7 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
 	unsigned char type;
 
 	head=&dst_blst_hash[hash].first;
-#ifdef USE_IPV6
 	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
-#else  /* USE_IPV6 */
-	if (unlikely(ip->af!=AF_INET)) return 0;
-	type=0;
-#endif /* USE_IPV6 */
 	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
 		e=*crt;
 		prefetch_loc_r((*crt)->next, 1);
@@ -612,12 +605,7 @@ inline static int _dst_blacklist_del(
 	unsigned char type;
 	
 	head=&dst_blst_hash[hash].first;
-#ifdef USE_IPV6
 	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
-#else  /* USE_IPV6 */
-	if (unlikely(ip->af!=AF_INET)) return 0;
-	type=0;
-#endif /* USE_IPV6 */
 	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
 		e=*crt;
 		prefetch_loc_r((*crt)->next, 1);
@@ -1159,24 +1147,14 @@ void dst_blst_add(rpc_t* rpc, void* ctx)
 	}
 
 	if (err_flags & BLST_IS_IPV6) {
-#ifdef USE_IPV6
 		/* IPv6 address is specified */
 		ip_addr = str2ip6(&ip);
-#else  /* USE_IPV6 */
-		rpc->fault(ctx, 400, "IPv6 support disabled");
-		return;
-#endif /* USE_IPV6 */
 	} else {
 		/* try IPv4 first, than IPv6 */
 		ip_addr = str2ip(&ip);
 		if (!ip_addr) {
-#ifdef USE_IPV6
 			ip_addr = str2ip6(&ip);
 			err_flags |= BLST_IS_IPV6;
-#else  /* USE_IPV6 */
-			rpc->fault(ctx, 400, "Malformed or IPv6 ip address");
-			return;
-#endif /* USE_IPV6 */
 		}
 	}
 	if (!ip_addr) {
diff --git a/etc/kamailio-basic.cfg b/etc/kamailio-basic.cfg
new file mode 100644
index 0000000..5f403ab
--- /dev/null
+++ b/etc/kamailio-basic.cfg
@@ -0,0 +1,612 @@
+#!KAMAILIO
+#
+# Kamailio (OpenSER) SIP Server v4.0 - default configuration script
+#     - web: http://www.kamailio.org
+#     - git: http://sip-router.org
+#
+# Direct your questions about this file to: <sr-users at lists.sip-router.org>
+#
+# Refer to the Core CookBook at http://www.kamailio.org/wiki/
+# for an explanation of possible statements, functions and parameters.
+#
+# Several features can be enabled using '#!define WITH_FEATURE' directives:
+#
+# *** To run in debug mode: 
+#     - define WITH_DEBUG
+#
+# *** To enable mysql: 
+#     - define WITH_MYSQL
+#
+# *** To enable authentication execute:
+#     - enable mysql
+#     - define WITH_AUTH
+#     - add users using 'kamctl'
+#
+# *** To enable IP authentication execute:
+#     - enable mysql
+#     - enable authentication
+#     - define WITH_IPAUTH
+#     - add IP addresses with group id '1' to 'address' table
+#
+# *** To enable persistent user location execute:
+#     - enable mysql
+#     - define WITH_USRLOCDB
+#
+# *** To enable nat traversal execute:
+#     - define WITH_NAT
+#     - install RTPProxy: http://www.rtpproxy.org
+#     - start RTPProxy:
+#        rtpproxy -l _your_public_ip_ -s udp:localhost:7722
+#
+# *** To enable TLS support execute:
+#     - adjust CFGDIR/tls.cfg as needed
+#     - define WITH_TLS
+#
+# *** To enhance accounting execute:
+#     - enable mysql
+#     - define WITH_ACCDB
+#     - add following columns to database
+#!ifdef ACCDB_COMMENT
+  ALTER TABLE acc ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN src_ip varchar(64) NOT NULL default '';
+  ALTER TABLE acc ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN src_ip varchar(64) NOT NULL default '';
+  ALTER TABLE missed_calls ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT '';
+#!endif
+
+####### Include Local Config If Exists #########
+import_file "kamailio-local.cfg"
+
+####### Defined Values #########
+
+# *** Value defines - IDs used later in config
+#!ifdef WITH_MYSQL
+# - database URL - used to connect to database server by modules such
+#       as: auth_db, acc, usrloc, a.s.o.
+#!ifndef DBURL
+#!define DBURL "mysql://kamailio:kamailiorw@localhost/kamailio"
+#!endif
+#!endif
+#!define MULTIDOMAIN 0
+
+# - flags
+#   FLT_ - per transaction (message) flags
+#	FLB_ - per branch flags
+#!define FLT_ACC 1
+#!define FLT_ACCMISSED 2
+#!define FLT_ACCFAILED 3
+#!define FLT_NATS 5
+
+#!define FLB_NATB 6
+#!define FLB_NATSIPPING 7
+
+####### Global Parameters #########
+
+### LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR
+#!ifdef WITH_DEBUG
+debug=4
+log_stderror=yes
+#!else
+debug=2
+log_stderror=no
+#!endif
+
+memdbg=5
+memlog=5
+
+log_facility=LOG_LOCAL0
+
+fork=yes
+children=4
+
+/* uncomment the next line to disable TCP (default on) */
+#disable_tcp=yes
+
+/* uncomment the next line to disable the auto discovery of local aliases
+   based on reverse DNS on IPs (default on) */
+#auto_aliases=no
+
+/* add local domain aliases */
+#alias="sip.mydomain.com"
+
+/* uncomment and configure the following line if you want Kamailio to 
+   bind on a specific interface/port/proto (default bind on all available) */
+#listen=udp:10.0.0.10:5060
+
+/* port to listen to
+ * - can be specified more than once if needed to listen on many ports */
+port=5060
+
+#!ifdef WITH_TLS
+enable_tls=yes
+#!endif
+
+# life time of TCP connection when there is no traffic
+# - a bit higher than registration expires to cope with UA behind NAT
+tcp_connection_lifetime=3605
+
+####### Modules Section ########
+
+# set paths to location of modules (to sources or installation folders)
+#!ifdef WITH_SRCPATH
+mpath="modules_k:modules"
+#!else
+mpath="/usr/local/lib/kamailio/modules_k/:/usr/local/lib/kamailio/modules/"
+#!endif
+
+#!ifdef WITH_MYSQL
+loadmodule "db_mysql.so"
+#!endif
+
+loadmodule "mi_fifo.so"
+loadmodule "kex.so"
+loadmodule "corex.so"
+loadmodule "tm.so"
+loadmodule "tmx.so"
+loadmodule "sl.so"
+loadmodule "rr.so"
+loadmodule "pv.so"
+loadmodule "maxfwd.so"
+loadmodule "usrloc.so"
+loadmodule "registrar.so"
+loadmodule "textops.so"
+loadmodule "siputils.so"
+loadmodule "xlog.so"
+loadmodule "sanity.so"
+loadmodule "ctl.so"
+loadmodule "cfg_rpc.so"
+loadmodule "mi_rpc.so"
+loadmodule "acc.so"
+
+#!ifdef WITH_AUTH
+loadmodule "auth.so"
+loadmodule "auth_db.so"
+#!ifdef WITH_IPAUTH
+loadmodule "permissions.so"
+#!endif
+#!endif
+
+#!ifdef WITH_NAT
+loadmodule "nathelper.so"
+loadmodule "rtpproxy.so"
+#!endif
+
+#!ifdef WITH_TLS
+loadmodule "tls.so"
+#!endif
+
+#!ifdef WITH_DEBUG
+loadmodule "debugger.so"
+#!endif
+
+# ----------------- setting module-specific parameters ---------------
+
+
+# ----- mi_fifo params -----
+modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
+
+
+# ----- tm params -----
+# auto-discard branches from previous serial forking leg
+modparam("tm", "failure_reply_mode", 3)
+# default retransmission timeout: 30sec
+modparam("tm", "fr_timer", 30000)
+# default invite retransmission timeout after 1xx: 120sec
+modparam("tm", "fr_inv_timer", 120000)
+
+
+# ----- rr params -----
+# add value to ;lr param to cope with most of the UAs
+modparam("rr", "enable_full_lr", 1)
+# do not append from tag to the RR (no need for this script)
+modparam("rr", "append_fromtag", 0)
+
+
+# ----- registrar params -----
+modparam("registrar", "method_filtering", 1)
+/* uncomment the next line to disable parallel forking via location */
+# modparam("registrar", "append_branches", 0)
+/* uncomment the next line not to allow more than 10 contacts per AOR */
+#modparam("registrar", "max_contacts", 10)
+# max value for expires of registrations
+modparam("registrar", "max_expires", 3600)
+# set it to 1 to enable GRUU
+modparam("registrar", "gruu_enabled", 0)
+
+
+# ----- acc params -----
+/* what special events should be accounted ? */
+modparam("acc", "early_media", 0)
+modparam("acc", "report_ack", 0)
+modparam("acc", "report_cancels", 0)
+/* by default ww do not adjust the direct of the sequential requests.
+   if you enable this parameter, be sure the enable "append_fromtag"
+   in "rr" module */
+modparam("acc", "detect_direction", 0)
+/* account triggers (flags) */
+modparam("acc", "log_flag", FLT_ACC)
+modparam("acc", "log_missed_flag", FLT_ACCMISSED)
+modparam("acc", "log_extra", 
+	"src_user=$fU;src_domain=$fd;src_ip=$si;"
+	"dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
+modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)
+/* enhanced DB accounting */
+#!ifdef WITH_ACCDB
+modparam("acc", "db_flag", FLT_ACC)
+modparam("acc", "db_missed_flag", FLT_ACCMISSED)
+modparam("acc", "db_url", DBURL)
+modparam("acc", "db_extra",
+	"src_user=$fU;src_domain=$fd;src_ip=$si;"
+	"dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
+#!endif
+
+
+# ----- usrloc params -----
+/* enable DB persistency for location entries */
+#!ifdef WITH_USRLOCDB
+modparam("usrloc", "db_url", DBURL)
+modparam("usrloc", "db_mode", 2)
+modparam("usrloc", "use_domain", MULTIDOMAIN)
+#!endif
+
+
+# ----- auth_db params -----
+#!ifdef WITH_AUTH
+modparam("auth_db", "db_url", DBURL)
+modparam("auth_db", "calculate_ha1", yes)
+modparam("auth_db", "password_column", "password")
+modparam("auth_db", "load_credentials", "")
+modparam("auth_db", "use_domain", MULTIDOMAIN)
+
+# ----- permissions params -----
+#!ifdef WITH_IPAUTH
+modparam("permissions", "db_url", DBURL)
+modparam("permissions", "db_mode", 1)
+#!endif
+
+#!endif
+
+
+#!ifdef WITH_NAT
+# ----- rtpproxy params -----
+modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:7722")
+
+# ----- nathelper params -----
+modparam("nathelper", "natping_interval", 30)
+modparam("nathelper", "ping_nated_only", 1)
+modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
+modparam("nathelper", "sipping_from", "sip:pinger at kamailio.org")
+
+# params needed for NAT traversal in other modules
+modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")
+modparam("usrloc", "nat_bflag", FLB_NATB)
+#!endif
+
+
+#!ifdef WITH_TLS
+# ----- tls params -----
+modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg")
+#!endif
+
+#!ifdef WITH_DEBUG
+# ----- debugger params -----
+modparam("debugger", "cfgtrace", 1)
+#!endif
+
+####### Routing Logic ########
+
+
+# Main SIP request routing logic
+# - processing of any incoming SIP request starts with this route
+# - note: this is the same as route { ... }
+request_route {
+
+	# per request initial checks
+	route(REQINIT);
+
+	# NAT detection
+	route(NATDETECT);
+
+	# CANCEL processing
+	if (is_method("CANCEL")) {
+		if (t_check_trans()) {
+			route(RELAY);
+		}
+		exit;
+	}
+
+	# handle requests within SIP dialogs
+	route(WITHINDLG);
+
+	### only initial requests (no To tag)
+
+	t_check_trans();
+
+	# authentication
+	route(AUTH);
+
+	# record routing for dialog forming requests (in case they are routed)
+	# - remove preloaded route headers
+	remove_hf("Route");
+	if (is_method("INVITE|SUBSCRIBE"))
+		record_route();
+
+	# account only INVITEs
+	if (is_method("INVITE")) {
+		setflag(FLT_ACC); # do accounting
+	}
+
+	# dispatch requests to foreign domains
+	route(SIPOUT);
+
+	### requests for my local domains
+
+	# handle registrations
+	route(REGISTRAR);
+
+	if ($rU==$null) {
+		# request with no Username in RURI
+		sl_send_reply("484","Address Incomplete");
+		exit;
+	}
+
+	# user location service
+	route(LOCATION);
+}
+
+
+route[RELAY] {
+	# enable additional event routes for forwarded requests
+	# - serial forking, RTP relaying handling, a.s.o.
+	if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
+		if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
+	}
+	if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
+		if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
+	}
+	if (is_method("INVITE")) {
+		if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
+	}
+
+	if (!t_relay()) {
+		sl_reply_error();
+	}
+	exit;
+}
+
+# Per SIP request initial checks
+route[REQINIT] {
+#!ifdef WITH_ANTIFLOOD
+	# flood dection from same IP and traffic ban for a while
+	# be sure you exclude checking trusted peers, such as pstn gateways
+	# - local host excluded (e.g., loop to self)
+	if(src_ip!=myself) {
+		if($sht(ipban=>$si)!=$null) {
+			# ip is already blocked
+			xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
+			exit;
+		}
+		if (!pike_check_req()) {
+			xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
+			$sht(ipban=>$si) = 1;
+			exit;
+		}
+	}
+#!endif
+
+	if (!mf_process_maxfwd_header("10")) {
+		sl_send_reply("483","Too Many Hops");
+		exit;
+	}
+
+	if(!sanity_check("1511", "7")) {
+		xlog("Malformed SIP message from $si:$sp\n");
+		exit;
+	}
+}
+
+# Handle requests within SIP dialogs
+route[WITHINDLG] {
+	if (has_totag()) {
+		# sequential request withing a dialog should
+		# take the path determined by record-routing
+		if (loose_route()) {
+			route(DLGURI);
+			if (is_method("BYE")) {
+				setflag(FLT_ACC); # do accounting ...
+				setflag(FLT_ACCFAILED); # ... even if the transaction fails
+			}
+			else if ( is_method("ACK") ) {
+				# ACK is forwarded statelessy
+				route(NATMANAGE);
+			}
+			else if ( is_method("NOTIFY") ) {
+				# Add Record-Route for in-dialog NOTIFY as per RFC 6665.
+				record_route();
+			}
+			route(RELAY);
+		} else {
+			if ( is_method("ACK") ) {
+				if ( t_check_trans() ) {
+					# no loose-route, but stateful ACK;
+					# must be an ACK after a 487
+					# or e.g. 404 from upstream server
+					route(RELAY);
+					exit;
+				} else {
+					# ACK without matching transaction ... ignore and discard
+					exit;
+				}
+			}
+			sl_send_reply("404","Not here");
+		}
+		exit;
+	}
+}
+
+# Handle SIP registrations
+route[REGISTRAR] {
+	if (is_method("REGISTER")) {
+		if(isflagset(FLT_NATS)) {
+			setbflag(FLB_NATB);
+			# uncomment next line to do SIP NAT pinging 
+			## setbflag(FLB_NATSIPPING);
+		}
+		if (!save("location"))
+			sl_reply_error();
+
+		exit;
+	}
+}
+
+# USER location service
+route[LOCATION] {
+	if (!lookup("location")) {
+		$var(rc) = $rc;
+		t_newtran();
+		switch ($var(rc)) {
+			case -1:
+			case -3:
+				send_reply("404", "Not Found");
+				exit;
+			case -2:
+				send_reply("405", "Method Not Allowed");
+				exit;
+		}
+	}
+
+	# when routing via usrloc, log the missed calls also
+	if (is_method("INVITE")) {
+		setflag(FLT_ACCMISSED);
+	}
+
+	route(RELAY);
+	exit;
+}
+
+
+# Authentication route
+route[AUTH] {
+#!ifdef WITH_AUTH
+
+#!ifdef WITH_IPAUTH
+	if((!is_method("REGISTER")) && allow_source_address()) {
+		# source IP allowed
+		return;
+	}
+#!endif
+
+	if (is_method("REGISTER") || from_uri==myself) {
+		# authenticate requests
+		if (!auth_check("$fd", "subscriber", "1")) {
+			auth_challenge("$fd", "0");
+			exit;
+		}
+		# user authenticated - remove auth header
+		if(!is_method("REGISTER|PUBLISH"))
+			consume_credentials();
+	}
+	# if caller is not local subscriber, then check if it calls
+	# a local destination, otherwise deny, not an open relay here
+	if (from_uri!=myself && uri!=myself) {
+		sl_send_reply("403","Not relaying");
+		exit;
+	}
+
+#!endif
+	return;
+}
+
+# Caller NAT detection route
+route[NATDETECT] {
+#!ifdef WITH_NAT
+	force_rport();
+	if (nat_uac_test("19")) {
+		if (is_method("REGISTER")) {
+			fix_nated_register();
+		} else {
+			add_contact_alias();
+		}
+		setflag(FLT_NATS);
+	}
+#!endif
+	return;
+}
+
+# RTPProxy control
+route[NATMANAGE] {
+#!ifdef WITH_NAT
+	if (is_request()) {
+		if(has_totag()) {
+			if(check_route_param("nat=yes")) {
+				setbflag(FLB_NATB);
+			}
+		}
+	}
+	if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB)))
+		return;
+
+	rtpproxy_manage("co");
+
+	if (is_request()) {
+		if (!has_totag()) {
+			if(t_is_branch_route()) {
+				add_rr_param(";nat=yes");
+			}
+		}
+	}
+	if (is_reply()) {
+		if(isbflagset(FLB_NATB)) {
+			add_contact_alias();
+		}
+	}
+#!endif
+	return;
+}
+
+# URI update for dialog requests
+route[DLGURI] {
+#!ifdef WITH_NAT
+	if(!isdsturiset()) {
+		handle_ruri_alias();
+	}
+#!endif
+	return;
+}
+
+# Routing to foreign domains
+route[SIPOUT] {
+	if (!uri==myself) {
+		append_hf("P-hint: outbound\r\n");
+		route(RELAY);
+	}
+}
+
+# manage outgoing branches
+branch_route[MANAGE_BRANCH] {
+	xdbg("new branch [$T_branch_idx] to $ru\n");
+	route(NATMANAGE);
+}
+
+# manage incoming replies
+onreply_route[MANAGE_REPLY] {
+	xdbg("incoming reply\n");
+	if(status=~"[12][0-9][0-9]")
+		route(NATMANAGE);
+}
+
+# manage failure routing cases
+failure_route[MANAGE_FAILURE] {
+	route(NATMANAGE);
+
+	if (t_is_canceled()) {
+		exit;
+	}
+}
diff --git a/etc/kamailio.cfg b/etc/kamailio.cfg
index 911b7d6..ca49340 100644
--- a/etc/kamailio.cfg
+++ b/etc/kamailio.cfg
@@ -1,6 +1,6 @@
 #!KAMAILIO
 #
-# Kamailio (OpenSER) SIP Server v4.0 - default configuration script
+# Kamailio (OpenSER) SIP Server v4.1 - default configuration script
 #     - web: http://www.kamailio.org
 #     - git: http://sip-router.org
 #
@@ -207,9 +207,9 @@ voicemail.srv_port = "5060" desc "VoiceMail Port"
 
 # set paths to location of modules (to sources or installation folders)
 #!ifdef WITH_SRCPATH
-mpath="modules_k:modules"
+mpath="modules/"
 #!else
-mpath="/usr/local/lib/kamailio/modules_k/:/usr/local/lib/kamailio/modules/"
+mpath="/usr/local/lib/kamailio/modules/"
 #!endif
 
 #!ifdef WITH_MYSQL
@@ -680,21 +680,25 @@ route[PRESENCE] {
 	if(!is_method("PUBLISH|SUBSCRIBE"))
 		return;
 
+	if(is_method("SUBSCRIBE") && $hdr(Event)=="message-summary") {
+		route(TOVOICEMAIL);
+		# returns here if no voicemail server is configured
+		sl_send_reply("404", "No voicemail service");
+		exit;
+	}
+
 #!ifdef WITH_PRESENCE
 	if (!t_newtran())
 	{
 		sl_reply_error();
 		exit;
-	};
+	}
 
 	if(is_method("PUBLISH"))
 	{
 		handle_publish();
 		t_release();
-	}
-	else
-	if( is_method("SUBSCRIBE"))
-	{
+	} else if(is_method("SUBSCRIBE")) {
 		handle_subscribe();
 		t_release();
 	}
@@ -753,7 +757,8 @@ route[NATDETECT] {
 		if (is_method("REGISTER")) {
 			fix_nated_register();
 		} else {
-			add_contact_alias();
+			if(is_first_hop())
+				set_contact_alias();
 		}
 		setflag(FLT_NATS);
 	}
@@ -785,7 +790,8 @@ route[NATMANAGE] {
 	}
 	if (is_reply()) {
 		if(isbflagset(FLB_NATB)) {
-			add_contact_alias();
+			if(is_first_hop())
+				set_contact_alias();
 		}
 	}
 #!endif
@@ -868,7 +874,7 @@ route[XMLRPC] {
 # route to voicemail server
 route[TOVOICEMAIL] {
 #!ifdef WITH_VOICEMAIL
-	if(!is_method("INVITE"))
+	if(!is_method("INVITE|SUBSCRIBE"))
 		return;
 
 	# check if VoiceMail server IP is defined
@@ -876,11 +882,17 @@ route[TOVOICEMAIL] {
 		xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
 		return;
 	}
-	if($avp(oexten)==$null)
-		return;
-
-	$ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
+	if(is_method("INVITE")) {
+		if($avp(oexten)==$null)
+			return;
+		$ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
 				+ ":" + $sel(cfg_get.voicemail.srv_port);
+	} else {
+		if($rU==$null)
+			return;
+		$ru = "sip:" + $rU + "@" + $sel(cfg_get.voicemail.srv_ip)
+				+ ":" + $sel(cfg_get.voicemail.srv_port);
+	}
 	route(RELAY);
 	exit;
 #!endif
diff --git a/events.c b/events.c
index d26ae9b..a72eb93 100644
--- a/events.c
+++ b/events.c
@@ -27,11 +27,57 @@
 
 #include "dprint.h"
 #include "mem/mem.h"
+#include "route.h"
 #include "events.h"
 
 static sr_event_cb_t _sr_events_list;
 static int _sr_events_inited = 0;
 
+typedef struct _sr_core_ert {
+	int init_parse_error;
+} sr_core_ert_t;
+
+static sr_core_ert_t _sr_core_ert_list;
+
+/**
+ *
+ */
+void sr_core_ert_init(void)
+{
+	memset(&_sr_core_ert_list, 0, sizeof(sr_core_ert_t));
+	/* 0 - is not a valid index in event_route blocks list */
+	_sr_core_ert_list.init_parse_error = route_get(&event_rt,
+											"core:receive-parse-error");
+	if(_sr_core_ert_list.init_parse_error<=0
+				|| event_rt.rlist[_sr_core_ert_list.init_parse_error]==NULL) {
+		_sr_core_ert_list.init_parse_error = -1;
+	} else {
+		LM_DBG("event_route[core:receive-parse-error] is defined\n");
+	}
+}
+
+/**
+ *
+ */
+void sr_core_ert_run(sip_msg_t *msg, int e)
+{
+	struct run_act_ctx ctx;
+	int rtb;
+
+	switch(e) {
+		case SR_CORE_ERT_RECEIVE_PARSE_ERROR:
+			if(likely(_sr_core_ert_list.init_parse_error<=0))
+				return;
+			rtb = get_route_type();
+			set_route_type(REQUEST_ROUTE);
+			init_run_actions_ctx(&ctx);
+			run_top_route(event_rt.rlist[_sr_core_ert_list.init_parse_error],
+					msg, &ctx);
+			set_route_type(rtb);
+		break;
+	}
+}
+
 /**
  *
  */
@@ -106,6 +152,11 @@ int sr_event_register_cb(int type, sr_event_cb_f f)
 					_sr_events_list.tcp_ws_frame_out = f;
 				else return -1;
 			break;
+		case SREV_STUN_IN:
+				if(_sr_events_list.stun_in==0)
+					_sr_events_list.stun_in = f;
+				else return -1;
+			break;
 		default:
 			return -1;
 	}
@@ -209,6 +260,12 @@ int sr_event_exec(int type, void *data)
 					ret = _sr_events_list.tcp_ws_frame_out(data);
 					return ret;
 				} else return 1;
+		case SREV_STUN_IN:
+				if(unlikely(_sr_events_list.stun_in!=0))
+				{
+					ret = _sr_events_list.stun_in(data);
+					return ret;
+				} else return 1;
 		default:
 			return -1;
 	}
@@ -242,6 +299,8 @@ int sr_event_enabled(int type)
 				return (_sr_events_list.tcp_ws_frame_in!=0)?1:0;
 		case SREV_TCP_WS_FRAME_OUT:
 				return (_sr_events_list.tcp_ws_frame_out!=0)?1:0;
+		case SREV_STUN_IN:
+				return (_sr_events_list.stun_in!=0)?1:0;
 	}
 	return 0;
 }
diff --git a/events.h b/events.h
index 734e90c..376da07 100644
--- a/events.h
+++ b/events.h
@@ -28,12 +28,13 @@
 #define SREV_CORE_STATS			3
 #define SREV_CFG_RUN_ACTION		4
 #define SREV_PKG_SET_USED		5
-#define SREV_PKG_SET_REAL_USED	6
+#define SREV_PKG_SET_REAL_USED		6
 #define SREV_NET_DGRAM_IN		7
 #define SREV_TCP_HTTP_100C		8
 #define SREV_TCP_MSRP_FRAME		9
 #define SREV_TCP_WS_FRAME_IN		10
 #define SREV_TCP_WS_FRAME_OUT		11
+#define SREV_STUN_IN			12
 
 
 typedef int (*sr_event_cb_f)(void *data);
@@ -50,6 +51,7 @@ typedef struct sr_event_cb {
 	sr_event_cb_f tcp_msrp_frame;
 	sr_event_cb_f tcp_ws_frame_in;
 	sr_event_cb_f tcp_ws_frame_out;
+	sr_event_cb_f stun_in;
 } sr_event_cb_t;
 
 void sr_event_cb_init(void);
@@ -57,4 +59,12 @@ int sr_event_register_cb(int type, sr_event_cb_f f);
 int sr_event_exec(int type, void *data);
 int sr_event_enabled(int type);
 
+
+/* shortcut types for core event routes */
+/* initial parsing error in message receive function */
+#define SR_CORE_ERT_RECEIVE_PARSE_ERROR		1
+
+void sr_core_ert_init(void);
+void sr_core_ert_run(sip_msg_t *msg, int e);
+
 #endif
diff --git a/examples/icscf/icscf.cfg b/examples/icscf/icscf.cfg
index e782557..a8cea37 100644
--- a/examples/icscf/icscf.cfg
+++ b/examples/icscf/icscf.cfg
@@ -17,16 +17,20 @@
 # Set a forced CX/DX-Peer, do not try to find one
 #!define CXDX_FORCED_PEER "hss.kamailio-ims.org"
 
+# Allowed IPs for XML-RPC-Queries
+#!define XMLRPC_WHITELIST_1 "127.0.0.1"
+##!define XMLRPC_WHITELIST_2 "127.0.0.1"
+##!define XMLRPC_WHITELIST_3 "127.0.0.1"
+
 # *** To run in debug mode: 
 #     - define WITH_DEBUG
 #
-# *** To enable TLS support execute:
-#     - adjust CFGDIR/tls.cfg as needed
-#     - define WITH_TLS
+# *** To enable TCP support execute:
+#     - define WITH_TCP
 #
 # *** To enable XMLRPC support execute:
 #     - define WITH_XMLRPC
-#     - adjust route[XMLRPC] for access policy
+#     - this will automagically enable TCP
 #
 # *** To enable a Homer SIP-Capter-Node:
 #     - define CAPTURE_NODE with a proper address
diff --git a/examples/icscf/kamailio.cfg b/examples/icscf/kamailio.cfg
index c68f83f..0da30a8 100644
--- a/examples/icscf/kamailio.cfg
+++ b/examples/icscf/kamailio.cfg
@@ -60,16 +60,23 @@ dns_srv_lb=yes
 # Always: Also try IPv6:
 dns_try_ipv6=yes
 
-#!ifdef WITH_TLS
+#!ifdef WITH_XMLRPC
+#!ifndef WITH_TCP
 #!define WITH_TCP
-enable_tls=yes
+#!endif
+#!ifndef TCP_PROCESSES
+# Number of TCP Processes
+#!define TCP_PROCESSES 3
+#!endif
 #!endif
 
-/* uncomment the next line to disable TCP (default on) */
 #!ifdef WITH_TCP
 # life time of TCP connection when there is no traffic
 # - a bit higher than registration expires to cope with UA behind NAT
 tcp_connection_lifetime=3615
+#!ifdef TCP_PROCESSES
+tcp_children=TCP_PROCESSES
+#!endif
 #!else
 disable_tcp=yes
 #!endif
@@ -260,8 +267,18 @@ route[REQINIT] {
 ######################################################################
 #!ifdef WITH_XMLRPC
 route[XMLRPC] {
-	# allow XMLRPC from localhost
-	if ((method=="POST" || method=="GET") && (src_ip==127.0.0.1)) {
+	if ((method=="POST" || method=="GET")
+#!ifdef XMLRPC_WHITELIST_1
+&& ((src_ip == XMLRPC_WHITELIST_1)
+#!ifdef XMLRPC_WHITELIST_2
+ || (src_ip == XMLRPC_WHITELIST_2)
+#!endif
+#!ifdef XMLRPC_WHITELIST_3
+ || (src_ip == XMLRPC_WHITELIST_3)
+#!endif
+)
+#!endif
+) {
 		# close connection only for xmlrpclib user agents (there is a bug in
 		# xmlrpclib: it waits for EOF before interpreting the response).
 		if ($hdr(User-Agent) =~ "xmlrpclib")
@@ -295,29 +312,44 @@ route[register]
 		#free this from the failed I_scscf_select call
 		I_scscf_drop();
 		# Do an asynchronous UAR:
-		I_perform_user_authorization_request("0");
-		if ($avp(uaa_return_code) == 1) {
-			if (I_scscf_select("0")) {
-				t_on_reply("register_reply");
-				t_on_failure("register_failure");
-				if (!t_relay()) {
-					t_reply("500","Error forwarding towards S-CSCF");
-					break;
-				}
-				break;
-			} else {
-				I_scscf_drop();
-				t_reply("500", "Server error on UAR select S-CSCF");
-				break;
-			}
-		} else {
-			t_reply("500", "Server error on UAR select S-CSCF");
-			break;
-		}    
+                I_perform_user_authorization_request("REG_UAR_REPLY","0"); #0=REG/DEREG; 1=REG+Capabilities
+                exit;    
 	}
 	break;
 }
 
+route[REG_UAR_REPLY]
+{
+    #this is async so to know status we have to check the reply avp
+    switch ($avp(s:uaa_return_code)){
+            case 1: #success
+                    if (I_scscf_select("0")){
+                            t_on_failure("register_failure");
+                            t_on_reply("register_reply");
+                            #now relay to appropriate SCSCF
+                            if (!t_relay()) {
+                                    t_reply("500", "Error forwarding to SCSCF");
+                            }
+                    } else {#select failed
+                            I_scscf_drop();
+                            t_reply("500", "Server error on SCSCF Select (UAR)");
+                    }
+                    break;
+            case -1: #failure
+                    xlog("L_ERR", "UAR failure - error response sent from module\n");
+                    break;
+            case -2: #error
+                    xlog("L_ERR", "UAR error - sending error response now\n");
+                    t_reply("500", "UAR failed");
+                    break;
+            default:
+                    xlog("L_ERR", "Unknown return code from UAR, value is [$avp(s:uaa_return_code)]\n");
+                    t_reply("500", "Unknown response code from UAR");
+                    break;
+    }
+}
+
+
 ######################################################################
 # Replies to REGISTER requests, 
 ######################################################################
@@ -371,7 +403,10 @@ failure_route[register_failure]
 ######################################################################
 route[initial_request]
 {
-	I_perform_location_information_request("0");
+	I_perform_location_information_request("LIR_REPLY", "0");
+}
+
+route[LIR_REPLY] {
 	if ($avp(lia_return_code) == 1) {
 		if (I_scscf_select("0")) {
 			append_branch();
diff --git a/examples/ims_dnszone/kamailio-ims.org.dnszone b/examples/ims_dnszone/kamailio-ims.org.dnszone
new file mode 100644
index 0000000..9ee6ff5
--- /dev/null
+++ b/examples/ims_dnszone/kamailio-ims.org.dnszone
@@ -0,0 +1,34 @@
+$ORIGIN kamailio-ims.org.
+$TTL 1W
+@                       1D IN SOA       localhost. root.localhost. (
+                                        2006101001      ; serial
+                                        3H              ; refresh
+                                        15M             ; retry
+                                        1W              ; expiry
+                                        1D )            ; minimum
+
+                        1D IN NS        ns
+ns                      1D IN A         127.0.0.1
+
+pcscf                   1D IN A         127.0.0.1
+_sip.pcscf              1D SRV 0 0 5060 pcscf
+_sip._udp.pcscf         1D SRV 0 0 5060 pcscf
+_sip._tcp.pcscf         1D SRV 0 0 5060 pcscf
+
+
+icscf                   1D IN A         127.0.0.1
+_sip                    1D SRV 0 0 5060 icscf
+_sip._udp               1D SRV 0 0 5060 icscf
+_sip._tcp               1D SRV 0 0 5060 icscf
+
+kamailio-ims.org.       1D IN A         127.0.0.1
+kamailio-ims.org.       1D IN NAPTR 10 50 "s" "SIP+D2U"	""	_sip._udp
+kamailio-ims.org.       1D IN NAPTR 20 50 "s" "SIP+D2T"	""	_sip._tcp
+
+scscf                   1D IN A         127.0.0.1
+_sip.scscf              1D SRV 0 0 5060 scscf
+_sip._udp.scscf         1D SRV 0 0 5060 scscf
+_sip._tcp.scscf         1D SRV 0 0 5060 scscf
+
+hss                     1D IN A         127.0.0.1
+
diff --git a/examples/outbound/edge.cfg b/examples/outbound/edge.cfg
new file mode 100644
index 0000000..2bdf93b
--- /dev/null
+++ b/examples/outbound/edge.cfg
@@ -0,0 +1,172 @@
+#!KAMAILIO
+#
+# Edge proxy configuration
+#
+
+#!substdef "!REGISTRAR_IP!a.b.c.d!g"
+#!substdef "!REGISTRAR_PORT!5060!g"
+#!substdef "!FLOW_TIMER!20!g"
+
+####### Global Parameters #########
+
+debug=2
+log_stderror=no
+log_facility=LOG_LOCAL0
+fork=yes
+children=4
+alias="example.com"
+mpath="/usr/lib64/kamailio/modules"
+tcp_connection_lifetime=30 # FLOW_TIMER + 10
+force_rport=yes
+
+
+####### Modules Section ########
+
+loadmodule "tm.so"
+loadmodule "sl.so"
+loadmodule "outbound.so"
+loadmodule "rr.so"
+loadmodule "path.so"
+loadmodule "pv.so"
+loadmodule "maxfwd.so"
+loadmodule "xlog.so"
+loadmodule "sanity.so"
+loadmodule "ctl.so"
+loadmodule "mi_rpc.so"
+loadmodule "mi_fifo.so"
+loadmodule "textops.so"
+loadmodule "siputils.so"
+loadmodule "stun.so"
+
+# ----------------- setting module-specific parameters ---------------
+
+# ----- mi_fifo params -----
+modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
+
+# ----- tm params -----
+modparam("tm", "failure_reply_mode", 3)
+
+# ----- rr params -----
+modparam("rr", "append_fromtag", 0)
+
+
+####### Routing Logic ########
+
+request_route {
+	route(REQINIT);
+
+	if (is_method("CANCEL")) {
+		if (t_check_trans()) {
+			route(RELAY);
+		}
+		exit;
+	}
+
+	route(WITHINDLG);
+
+	t_check_trans();
+
+	if (is_method("REGISTER")) {
+		remove_hf("Route");
+		add_path();
+		$du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
+	} else {
+		if (is_method("INVITE|SUBSCRIBE"))
+			record_route();
+
+		if (@via[2] == "") {
+			# From client so route to registrar...
+
+			if ($rU == $null) {
+				sl_send_reply("484", "Address Incomplete");
+				exit;
+			}
+			remove_hf("Route");
+			$du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
+		} else {
+			# From registrar so route using "Route:" headers...
+
+			if (!loose_route()) {
+				switch($rc) {
+				case -2:
+					sl_send_reply("403", "Forbidden");
+					exit;
+				default:
+					xlog("L_ERR", "in request_route\n");
+					sl_reply_error();
+					exit;
+				}
+			}
+
+			t_on_failure("FAIL_OUTBOUND");
+		}
+	}
+
+	route(RELAY);
+}
+
+route[RELAY] {
+	if (!t_relay()) {
+		sl_reply_error();
+	}
+	exit;
+}
+
+route[REQINIT] {
+	if (!mf_process_maxfwd_header("10")) {
+		sl_send_reply("483","Too Many Hops");
+		exit;
+	}
+
+	if(!sanity_check("1511", "7"))
+	{
+		xlog("Malformed SIP message from $si:$sp\n");
+		exit;
+	}
+}
+
+route[WITHINDLG] {
+	if (has_totag()) {
+		if (!loose_route()) {
+			switch($rc) {
+			case -2:
+				sl_send_reply("403", "Forbidden");
+				exit;
+			default:
+				if (is_method("ACK")) {
+					if ( t_check_trans() ) {
+						route(RELAY);
+						exit;
+					} else {
+						exit;
+					}
+				}
+				sl_send_reply("404","Not Found");
+			}
+		} else {
+			if (is_method("NOTIFY")) {
+				record_route();
+			}
+			route(RELAY);
+		}
+		exit;
+	}
+}
+
+onreply_route {
+	if (!t_check_trans()) {
+		drop;
+	}
+
+	if ($rm == "REGISTER" && $rs >= 200 && $rs <= 299) {
+		remove_hf("Flow-Timer");
+		if ($(hdr(Require)[*])=~"outbound")
+			insert_hf("Flow-Timer: FLOW_TIMER\r\n", "Call-ID");
+	}
+}
+
+failure_route[FAIL_OUTBOUND] {
+	if (t_branch_timeout() || !t_branch_replied()) {
+		send_reply("430", "Flow Failed");
+	}
+}
diff --git a/examples/outbound/edge_websocket.cfg b/examples/outbound/edge_websocket.cfg
new file mode 100644
index 0000000..843ec20
--- /dev/null
+++ b/examples/outbound/edge_websocket.cfg
@@ -0,0 +1,293 @@
+#!KAMAILIO
+#
+# Edge proxy configuration with SIP over WebSocket support
+#
+
+#!substdef "!DBURL!sqlite:///etc/kamailio/db.sqlite!g"
+#!substdef "!MY_IP_ADDR!a.b.c.d!g"
+#!substdef "!MY_DOMAIN!example.com!g"
+#!substdef "!MY_WS_PORT!80!g"
+#!substdef "!MY_WSS_PORT!443!g"
+#!substdef "!MY_WS_ADDR!tcp:MY_IP_ADDR:MY_WS_PORT!g"
+#!substdef "!MY_WSS_ADDR!tls:MY_IP_ADDR:MY_WSS_PORT!g"
+
+#!substdef "!REGISTRAR_IP!e.f.g.h!g"
+#!substdef "!REGISTRAR_PORT!5060!g"
+#!substdef "!FLOW_TIMER!20!g"
+
+#!define WITH_TLS
+#!define WITH_WEBSOCKETS
+
+
+####### Global Parameters #########
+
+debug=2
+log_stderror=no
+log_facility=LOG_LOCAL0
+fork=yes
+children=4
+mpath="/usr/lib64/kamailio/modules/"
+force_rport=yes
+
+#!ifdef WITH_TLS
+enable_tls=1
+#!endif
+
+listen=MY_IP_ADDR
+#!ifdef WITH_WEBSOCKETS
+listen=MY_WS_ADDR
+#!ifdef WITH_TLS
+listen=MY_WSS_ADDR
+#!endif
+#!endif
+
+tcp_connection_lifetime=30 # FLOW_TIMER + 10
+tcp_accept_no_cl=yes
+tcp_rd_buf_size=16384
+
+
+####### Modules Section ########
+
+loadmodule "tm.so"
+loadmodule "sl.so"
+loadmodule "outbound.so"
+loadmodule "rr.so"
+loadmodule "path.so"
+loadmodule "pv.so"
+loadmodule "maxfwd.so"
+loadmodule "xlog.so"
+loadmodule "sanity.so"
+loadmodule "ctl.so"
+loadmodule "mi_rpc.so"
+loadmodule "mi_fifo.so"
+loadmodule "textops.so"
+loadmodule "siputils.so"
+loadmodule "stun.so"
+loadmodule "kex.so"
+loadmodule "corex.so"
+#!ifdef WITH_TLS
+loadmodule "tls.so"
+#!endif
+#!ifdef WITH_WEBSOCKETS
+loadmodule "xhttp.so"
+loadmodule "websocket.so"
+#!endif
+
+# ----------------- setting module-specific parameters ---------------
+
+# ----- mi_fifo params -----
+modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
+
+# ----- tm params -----
+modparam("tm", "failure_reply_mode", 3)
+
+# ----- rr params -----
+modparam("rr", "append_fromtag", 0)
+
+# ----- corex params -----
+modparam("corex", "alias_subdomains", "MY_DOMAIN")
+
+#!ifdef WITH_TLS
+# ----- tls params -----
+modparam("tls", "tls_method", "SSLv23")
+modparam("tls", "certificate", "/etc/pki/CA/ser1_cert.pem")
+modparam("tls", "private_key", "/etc/pki/CA/privkey.pem")
+modparam("tls", "ca_list", "/etc/pki/CA/calist.pem")
+#!endif
+
+#!ifdef WITH_WEBSOCKETS
+# ----- websocket params -----
+modparam("websocket", "keepalive_timeout", 25) # FLOW_TIMER + 5
+#!endif
+
+
+####### Routing Logic ########
+
+request_route {
+	if (($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
+		&& !(proto == WS || proto == WSS)) {
+		xlog("L_WARN", "SIP request received on $Rp\n");
+		sl_send_reply("403", "Forbidden");
+		exit;
+	}
+
+	route(REQINIT);
+
+	if (is_method("CANCEL")) {
+		if (t_check_trans()) {
+			route(RELAY);
+		}
+		exit;
+	}
+
+	route(WITHINDLG);
+
+	t_check_trans();
+
+	if (is_method("REGISTER")) {
+		remove_hf("Route");
+		add_path();
+		$du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
+	} else {
+		if (is_method("INVITE|SUBSCRIBE"))
+			record_route();
+
+		if (@via[2] == "") {
+			# From client so route to registrar...
+
+			if ($rU == $null) {
+				sl_send_reply("484", "Address Incomplete");
+				exit;
+			}
+			remove_hf("Route");
+			$du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
+		} else {
+			# From registrar so route using "Route:" headers...
+
+			if (!loose_route()) {
+				switch($rc) {
+				case -2:
+					sl_send_reply("403", "Forbidden");
+					exit;
+				default:
+					xlog("L_ERR", "in request_route\n");
+					sl_reply_error();
+					exit;
+				}
+			}
+
+			t_on_failure("FAIL_OUTBOUND");
+		}
+	}
+
+	route(RELAY);
+}
+
+route[RELAY] {
+	if (!t_relay()) {
+		sl_reply_error();
+	}
+	exit;
+}
+
+route[REQINIT] {
+	if (!mf_process_maxfwd_header("10")) {
+		sl_send_reply("483","Too Many Hops");
+		exit;
+	}
+
+	if(!sanity_check("1511", "7"))
+	{
+		xlog("Malformed SIP message from $si:$sp\n");
+		exit;
+	}
+}
+
+route[WITHINDLG] {
+	if (has_totag()) {
+		if (!loose_route()) {
+			switch($rc) {
+			case -2:
+				sl_send_reply("403", "Forbidden");
+				exit;
+			default:
+				if (is_method("ACK")) {
+					if ( t_check_trans() ) {
+						route(RELAY);
+						exit;
+					} else {
+						exit;
+					}
+				}
+				sl_send_reply("404","Not Found");
+			}
+		} else {
+			if (is_method("NOTIFY")) {
+				record_route();
+			}
+			route(RELAY);
+		}
+		exit;
+	}
+}
+
+onreply_route {
+	if (($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
+		&& !(proto == WS || proto == WSS)) {
+		xlog("L_WARN", "SIP response received on $Rp\n");
+		drop;
+	}
+
+	if (!t_check_trans()) {
+		drop;
+	}
+
+	if ($rm == "REGISTER" && $rs >= 200 && $rs <= 299) {
+		remove_hf("Flow-Timer");
+		if ($(hdr(Require)[*])=~"outbound")
+			insert_hf("Flow-Timer: FLOW_TIMER\r\n", "Call-ID");
+	}
+}
+
+failure_route[FAIL_OUTBOUND] {
+	if (t_branch_timeout() || !t_branch_replied()) {
+		send_reply("430", "Flow Failed");
+	}
+}
+
+event_route[xhttp:request] {
+	set_reply_close();
+	set_reply_no_connect();
+
+	if ($Rp != MY_WS_PORT
+#!ifdef WITH_TLS
+		&& $Rp != MY_WSS_PORT
+#!endif
+	) {
+		xlog("L_WARN", "HTTP request received on $Rp\n");
+		xhttp_reply("403", "Forbidden", "", "");
+		exit;
+	}
+
+	xlog("L_DBG", "HTTP Request Received\n");
+
+	if ($hdr(Upgrade)=~"websocket"
+			&& $hdr(Connection)=~"Upgrade"
+			&& $rm=~"GET") {
+
+		# Validate Host - make sure the client is using the correct
+		# alias for WebSockets
+		if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) {
+			xlog("L_WARN", "Bad host $hdr(Host)\n");
+			xhttp_reply("403", "Forbidden", "", "");
+			exit;
+		}
+
+		# Optional... validate Origin - make sure the client is from an
+		# authorised website.  For example,
+		#
+		# if ($hdr(Origin) != "http://communicator.MY_DOMAIN"
+		#     && $hdr(Origin) != "https://communicator.MY_DOMAIN") {
+		#	xlog("L_WARN", "Unauthorised client $hdr(Origin)\n");
+		#	xhttp_reply("403", "Forbidden", "", "");
+		#	exit;
+                # }
+
+		# Optional... perform HTTP authentication
+
+		# ws_handle_handshake() exits (no further configuration file
+		# processing of the request) when complete.
+		if (ws_handle_handshake())
+		{
+			# Optional... cache some information about the
+			# successful connection
+			exit;
+		}
+	}
+
+	xhttp_reply("404", "Not Found", "", "");
+}
+
+event_route[websocket:closed] {
+	xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
+}
diff --git a/examples/outbound/registrar.cfg b/examples/outbound/registrar.cfg
new file mode 100644
index 0000000..db920fa
--- /dev/null
+++ b/examples/outbound/registrar.cfg
@@ -0,0 +1,202 @@
+#!KAMAILIO
+#
+# Registrar configuration
+#
+
+
+####### Global Parameters #########
+
+debug=2
+log_stderror=no
+log_facility=LOG_LOCAL0
+fork=yes
+children=4
+alias="example.com"
+mpath="/usr/lib64/kamailio/modules"
+
+
+####### Modules Section ########
+
+loadmodule "tm.so"
+loadmodule "tmx.so"
+loadmodule "sl.so"
+loadmodule "rr.so"
+loadmodule "pv.so"
+loadmodule "maxfwd.so"
+loadmodule "xlog.so"
+loadmodule "sanity.so"
+loadmodule "ctl.so"
+loadmodule "mi_rpc.so"
+loadmodule "mi_fifo.so"
+loadmodule "textops.so"
+loadmodule "siputils.so"
+loadmodule "usrloc.so"
+loadmodule "registrar.so"
+
+# ----------------- setting module-specific parameters ---------------
+
+# ----- mi_fifo params -----
+modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
+
+
+# ----- tm params -----
+modparam("tm", "failure_reply_mode", 3)
+modparam("tm", "restart_fr_on_each_reply", 0)
+modparam("tm", "contact_flows_avp", "tm_contact_flows")
+modparam("tm", "contacts_avp", "tm_contacts")
+
+# ----- rr params -----
+modparam("rr", "append_fromtag", 0)
+
+# ----- registrar params -----
+modparam("registrar", "use_path", 1)
+modparam("registrar", "gruu_enabled", 1)
+modparam("registrar", "outbound_mode", 1)
+
+
+####### Routing Logic ########
+
+request_route {
+	route(REQINIT);
+
+	if (is_method("CANCEL")) {
+		if (t_check_trans()) {
+			route(RELAY);
+		}
+		exit;
+	}
+
+	route(WITHINDLG);
+
+	t_check_trans();
+
+	remove_hf("Route");
+	if (is_method("INVITE|SUBSCRIBE"))
+		record_route();
+
+	route(REGISTRAR);
+
+	if ($rU==$null) {
+		xlog("L_INFO", "Address Incomplete\n");
+		send_reply("484","Address Incomplete");
+		exit;
+	}
+
+	route(LOCATION);
+}
+
+
+route[RELAY] {
+	if (!t_relay()) {
+		xlog("L_ERR", "t_relay() failed\n");
+		sl_reply_error();
+	}
+	exit;
+}
+
+route[REQINIT] {
+	if (!mf_process_maxfwd_header("10")) {
+		xlog("L_INFO", "Too Many Hops\n");
+		send_reply("483","Too Many Hops");
+		exit;
+	}
+
+	if(!sanity_check("1511", "7"))
+	{
+		xlog("Malformed SIP message from $si:$sp\n");
+		exit;
+	}
+}
+
+route[WITHINDLG] {
+	if (has_totag()) {
+		if (loose_route()) {
+			if (is_method("NOTIFY")) {
+				record_route();
+			}
+			route(RELAY);
+		} else {
+			if (is_method("ACK")) {
+				if (t_check_trans()) {
+					route(RELAY);
+					exit;
+				} else {
+					exit;
+				}
+			}
+			xlog("L_INFO", "Not Found");
+			send_reply("404","Not Found");
+		}
+		exit;
+	}
+}
+
+route[REGISTRAR] {
+	if (is_method("REGISTER"))
+	{
+		if (!save("location")) {
+			xlog("L_ERR", "Unable to save location\n");
+			sl_reply_error();
+		}
+		exit;
+	}
+}
+
+route[LOCATION] {
+	if (!lookup("location")) {
+		$var(rc) = $rc;
+		t_newtran();
+		switch ($var(rc)) {
+			case -1:
+			case -3:
+				send_reply("404", "Not Found");
+				exit;
+			case -2:
+				send_reply("405", "Method Not Allowed");
+				exit;
+		}
+	}
+
+	if (!t_load_contacts() || !t_next_contacts()) {
+		xlog("L_ERR", "t_(load|next)_contacts() failed\n");
+		sl_reply_error();
+		exit;
+	}
+
+	t_on_failure("FAIL_TRANSACTION");
+	t_on_branch_failure("FAIL-BRANCH");
+	route(RELAY);
+	exit;
+}
+
+onreply_route {
+	if (!t_check_trans()) {
+		drop;
+	}
+}
+
+failure_route[FAIL_TRANSACTION] {
+	if (!t_check_status("6[0-9][0-9]")) {
+		if (t_next_contacts()) {
+			t_relay();
+			exit;
+		}
+	}
+
+	if (t_check_status("430")) {
+		t_reply("480", "Temporarily Unavailable");
+		exit;
+	}
+}
+
+event_route[tm:branch-failure:FAIL-BRANCH] {
+	if (t_check_status("403|430")
+			|| (t_branch_timeout() && !t_branch_replied())) {
+		unregister("location", "$tu", "$T_reply_ruid");
+
+		if (t_next_contact_flow()) {
+			t_on_branch_failure("FAIL-BRANCH");
+			t_relay();
+		}
+	}
+}
diff --git a/examples/pcscf/kamailio.cfg b/examples/pcscf/kamailio.cfg
index 8daf8b1..c44d587 100644
--- a/examples/pcscf/kamailio.cfg
+++ b/examples/pcscf/kamailio.cfg
@@ -46,7 +46,6 @@ sip_warning=no
 children=64
 #!endif
 
-syn_branch=0
 # Locks all ser pages into memory making it unswappable (in general one 
 # doesn't want his sip proxy swapped out )
 mlock_pages=yes
@@ -90,10 +89,19 @@ auto_aliases=no
 #!ifndef WITH_TCP
 #!define WITH_TCP
 #!endif
-
 enable_tls=yes
 #!endif
 
+#!ifdef WITH_XMLRPC
+#!ifndef WITH_TCP
+#!define WITH_TCP
+#!endif
+#!ifndef TCP_PROCESSES
+# Number of TCP Processes
+#!define TCP_PROCESSES 3
+#!endif
+#!endif
+
 # Check, if NAT is enabled (in case you want to Force all calls through the RTPProxy)
 #!ifdef FORCE_RTPRELAY
 #!ifndef WITH_NAT
@@ -101,6 +109,13 @@ enable_tls=yes
 #!endif
 #!endif
 
+# Check, if NAT is enabled (in case you want to Force all calls through the RTPProxy)
+#!ifdef WITH_RTPIPV4
+#!ifndef WITH_NAT
+#!define WITH_NAT
+#!endif
+#!endif
+
 #!ifdef WITH_TCP
 # life time of TCP connection when there is no traffic
 # - a bit higher than registration expires to cope with UA behind NAT
@@ -115,6 +130,9 @@ tcp_connection_lifetime=3615
 tcp_accept_aliases=no
 # Enable SIP outbound TCP keep-alive using PING-PONG (CRLFCRLF - CRLF).
 tcp_crlf_ping=yes
+#!ifdef TCP_PROCESSES
+tcp_children=TCP_PROCESSES
+#!endif
 #!else
 disable_tcp=yes
 #!endif
@@ -137,8 +155,6 @@ loadmodule "textops"
 loadmodule "textopsx"
 loadmodule "maxfwd"
 loadmodule "xlog"
-loadmodule "pua"
-loadmodule "db_sqlite"
 loadmodule "ims_registrar_pcscf"
 loadmodule "sanity"
 loadmodule "siputils"
@@ -191,11 +207,6 @@ modparam("mi_fifo", "fifo_mode", 0666)
 modparam("mi_fifo", "fifo_user", "kamailio")
 modparam("mi_fifo", "fifo_group", "kamailio")
 
-# ----- pua params -----
-# Database is disabled (for now)
-modparam("pua", "db_mode", 0)
-modparam("pua", "db_url", "sqlite:///etc/kamailio/kamailio.db")
-
 # ----- tm params -----
 # auto-discard branches from previous serial forking leg
 modparam("tm", "failure_reply_mode", 3)
@@ -455,8 +466,18 @@ route[REQINIT] {
 ######################################################################
 #!ifdef WITH_XMLRPC
 route[XMLRPC] {
-	# allow XMLRPC from localhost
-	if ((method=="POST" || method=="GET") && (src_ip==127.0.0.1)) {
+	if ((method=="POST" || method=="GET")
+#!ifdef XMLRPC_WHITELIST_1
+&& ((src_ip == XMLRPC_WHITELIST_1)
+#!ifdef XMLRPC_WHITELIST_2
+ || (src_ip == XMLRPC_WHITELIST_2)
+#!endif
+#!ifdef XMLRPC_WHITELIST_3
+ || (src_ip == XMLRPC_WHITELIST_3)
+#!endif
+)
+#!endif
+) {
 		# close connection only for xmlrpclib user agents (there is a bug in
 		# xmlrpclib: it waits for EOF before interpreting the response).
 		if ($hdr(User-Agent) =~ "xmlrpclib")
diff --git a/examples/pcscf/pcscf.cfg b/examples/pcscf/pcscf.cfg
index 69c8cb8..5e38d7f 100644
--- a/examples/pcscf/pcscf.cfg
+++ b/examples/pcscf/pcscf.cfg
@@ -13,6 +13,11 @@
 # SIP-Address of capturing node, if not set, capturing is disabled.
 ##!define CAPTURE_NODE "sip:10.0.6.1"
 
+# Allowed IPs for XML-RPC-Queries
+#!define XMLRPC_WHITELIST_1 "127.0.0.1"
+##!define XMLRPC_WHITELIST_2 "127.0.0.1"
+##!define XMLRPC_WHITELIST_3 "127.0.0.1"
+
 # IP-Adress(es) of the RTP-Proxy
 #!define RTPPROXY_ADDRESS "udp:127.0.0.1:22222"
 #
@@ -28,13 +33,25 @@
 #     - start RTPProxy:
 #        rtpproxy -l _your_public_ip_ -s udp:localhost:7722
 #
+# *** To force alls calls through the RTP-Proxy
+#     - this will automagically enable NAT-Traversal
+#     - define FORCE_RTPRELAY
+#
+# *** To enable IPv4/IPv6 Translation (RTPProxy)
+#     - this will automagically enable NAT-Traversal
+#     - define WITH_RTPIPV4
+#
+# *** To enable TCP support execute:
+#     - define WITH_TCP
+#
 # *** To enable TLS support execute:
 #     - adjust CFGDIR/tls.cfg as needed
 #     - define WITH_TLS
+#     - this will automagically enable TCP
 #
 # *** To enable XMLRPC support execute:
 #     - define WITH_XMLRPC
-#     - adjust route[XMLRPC] for access policy
+#     - this will automagically enable TCP
 #
 # *** To enable anti-flood detection execute:
 #     - adjust pike and htable=>ipban settings as needed (default is
@@ -51,8 +68,12 @@
 # Enabled Features for this host:
 ##!define WITH_DEBUG
 ##!define WITH_NAT
+##!define FORCE_RTPRELAY
 ##!define WITH_TLS
 #!define WITH_XMLRPC
 #!define WITH_ANTIFLOOD
 ##!define WITH_RX
+##!define WITH_TCP
+##!define WITH_RTPIPV4
+
 
diff --git a/examples/scscf/kamailio.cfg b/examples/scscf/kamailio.cfg
index 4fa09b0..b8c9f1b 100644
--- a/examples/scscf/kamailio.cfg
+++ b/examples/scscf/kamailio.cfg
@@ -73,15 +73,23 @@ dns_try_ipv6=yes
 # Try onle IPv6:
 dns_cache_flags=6
 
-#!ifdef WITH_TLS
+#!ifdef WITH_XMLRPC
+#!ifndef WITH_TCP
 #!define WITH_TCP
-enable_tls=yes
+#!endif
+#!ifndef TCP_PROCESSES
+# Number of TCP Processes
+#!define TCP_PROCESSES 3
+#!endif
 #!endif
 
 #!ifdef WITH_TCP
 # life time of TCP connection when there is no traffic
 # - a bit higher than registration expires to cope with UA behind NAT
 tcp_connection_lifetime=3615
+#!ifdef TCP_PROCESSES
+tcp_children=TCP_PROCESSES
+#!endif
 #!else
 disable_tcp=yes
 #!endif
@@ -223,11 +231,11 @@ modparam("siptrace", "hep_mode_on", 1)
 # -- ims_auth params --
 modparam("ims_auth", "name", URI)
 modparam("ims_auth", "registration_default_algorithm", REG_AUTH_DEFAULT_ALG)
-modparam("ims_auth","ignore_failed_auth",1)
 #!ifdef CXDX_FORCED_PEER
 modparam("ims_auth", "cxdx_forced_peer", CXDX_FORCED_PEER)
 #!endif
 modparam("ims_auth", "cxdx_dest_realm", NETWORKNAME)
+modparam("ims_auth", "av_check_only_impu", 1)
 
 # -- ims_registrar_scscf params --
 #!ifdef WITH_DEBUG
@@ -286,9 +294,9 @@ modparam("dispatcher", "ds_probing_mode", 1)
 # - processing of any incoming SIP request starts with this route
 
 route {
-#!ifdef WITH_DEBUG
+##!ifdef WITH_DEBUG
 	xlog("L_ERR", "$rm ($fu ($si:$sp) to $tu, $ci)\n");
-#!endif
+##!endif
 
 	# per request initial checks
 	route(REQINIT);
@@ -345,7 +353,8 @@ route {
 		if (uri=~"sip:(.*)@"+NETWORKNAME_ESC +"(.*)" || uri=~"tel:.*") {
 			if (!term_impu_registered("location")) {
 				xlog("L_ERR", "We need to do an UNREG server SAR assignemnt");
-		                assign_server_unreg("location", "term");
+                                assign_server_unreg("UNREG_SAR_REPLY", "location", "term");
+                                exit;
 		        }
 		} else {
 			sl_send_reply("403","Forbidden - Dialog not found on S-CSCF or Terminating user not suitable for unregistered services");
@@ -356,6 +365,28 @@ route {
 	}
 }
 
+route[UNREG_SAR_REPLY]
+{
+        xlog("L_DBG","saa_return code is $avp(s:saa_return_code)\n");
+        switch ($avp(s:saa_return_code)){
+            case 1: #success
+                    xlog("L_DBG", "SAR success - will route message\n");
+                route(term);
+                break;
+            case -1: #failure
+                    xlog("L_ERR", "SAR failure - error response sent from module\n");
+                break;
+            case -2: #error
+                    xlog("L_ERR", "SAR error - error response sent from module\n");
+                break;
+            default:
+                    xlog("L_ERR", "Unknown return code from SAR, value is [$avp(s:saa_return_code)]\n");
+                break;
+        }
+        exit;
+}
+
+
 ######################################################################
 # Helper routes (Basic-Checks, NAT-Handling/RTP-Control, XML-RPC)
 ######################################################################
@@ -411,8 +442,18 @@ route[subscribe]
 ######################################################################
 #!ifdef WITH_XMLRPC
 route[XMLRPC] {
-	# allow XMLRPC from localhost
-	if ((method=="POST" || method=="GET") && (src_ip==127.0.0.1)) {
+	if ((method=="POST" || method=="GET")
+#!ifdef XMLRPC_WHITELIST_1
+&& ((src_ip == XMLRPC_WHITELIST_1)
+#!ifdef XMLRPC_WHITELIST_2
+ || (src_ip == XMLRPC_WHITELIST_2)
+#!endif
+#!ifdef XMLRPC_WHITELIST_3
+ || (src_ip == XMLRPC_WHITELIST_3)
+#!endif
+)
+#!endif
+) {
 		# close connection only for xmlrpclib user agents (there is a bug in
 		# xmlrpclib: it waits for EOF before interpreting the response).
 		if ($hdr(User-Agent) =~ "xmlrpclib")
@@ -430,34 +471,103 @@ route[XMLRPC] {
 # Route for handling Registrations:
 ######################################################################
 route[REGISTER] {
-	xlog("L_ERR", "Enter register block");
-	t_newtran();
-	
-	ims_www_authenticate(NETWORKNAME);
-
-	#check to see if user is authenticated - ie sip header has auth information - (already challenged)
-	if ($avp(maa_return_code) == 1) {
-		# user has not been authenticated. Lets send a challenge via 401 Unauthorized
-		ims_www_challenge("$td"); 
-		exit;
+        if (!ims_www_authenticate(NETWORKNAME)) {
+                if ($? == -2) {
+                        t_reply("403", "Authentication Failed");
+                        exit;
+                } else if ($? == -3) {
+                        t_reply("400", "Bad Request");
+                        exit;
+                } else {
+                        #user has not been authenticated. Lets send a challenge via 401 Unauthorized
+                        xlog("L_DBG","About to challenge! auth_ims\n");
+                        ims_www_challenge("REG_MAR_REPLY", "$td");
+                        exit;
+                }
 	} else {
+		xlog("L_DBG", "Auth succeeded\n");
 		# We need to check if this user is registered or not
 		if (!impu_registered("location")) {
-			save("location");
-			if ($avp(saa_return_code) == 1) {
-				isc_match_filter_reg("0","location");
-				exit;
-			}
+			xlog("L_ERR", "Not REGISTERED\n");
+			save("PRE_REG_SAR_REPLY","location");
+                        exit;
 		} else {
-			save("location");
-			if($avp(saa_return_code) == 1) {
-				isc_match_filter_reg("1","location");
-				exit;
-			}
+			isc_match_filter_reg("1","location");
+                        save("REG_SAR_REPLY","location");
+                        exit;
 		}
 	}
 }
 
+route[REG_MAR_REPLY]
+{
+     #this is async so to know status we have to check the reply avp
+     xlog("L_DBG","maa_return code is $avp(s:maa_return_code)\n");   
+
+     switch ($avp(s:maa_return_code)){
+             case 1: #success
+                     xlog("L_DBG", "MAR success - 401/407 response sent from module\n");
+                     break;
+             case -1: #failure
+                     xlog("L_ERR", "MAR failure - error response sent from module\n");
+                     break;
+             case -2: #error
+                     xlog("L_ERR", "MAR error - sending error response now\n");
+                     t_reply("500", "MAR failed");
+                     break;
+             default:
+                     xlog("L_ERR", "Unknown return code from MAR, value is [$avp(s:uaa_return_code)]\n");
+                     t_reply("500", "Unknown response code from MAR");
+                     break;
+     }
+     exit;
+}
+
+route[PRE_REG_SAR_REPLY]
+{
+    xlog("L_DBG","saa_return code is $avp(s:saa_return_code)\n");
+        #this is async so to know status we have to check the reply avp
+    xlog("L_DBG","saa_return code (for scscf_save on register) is $avp(s:saa_return_code)\n");
+    switch ($avp(s:saa_return_code)){
+            case 1: #success
+                   xlog("L_DBG", "SAR success - 200 response sent from module\n");
+                    isc_match_filter_reg("0","location");
+                    exit;
+            case -1: #failure
+                    xlog("L_ERR", "SAR failure - error response sent from module\n");
+                    break;
+            case -2: #error
+                    xlog("L_ERR", "SAR error - error response sent from module\n");
+                    break;
+            default:
+                    xlog("L_ERR", "Unknown return code from SAR, value is [$avp(s:uaa_return_code)]\n");
+                    break;
+    }
+    exit;
+}
+
+route[REG_SAR_REPLY]
+{
+    xlog("L_DBG","saa_return code is $avp(s:saa_return_code)\n");
+    #this is async so to know status we have to check the reply avp
+    xlog("L_DBG","saa_return code (for scscf_save on register) is $avp(s:saa_return_code)\n");
+    switch ($avp(s:saa_return_code)){
+            case 1: #success
+                   xlog("L_DBG", "SAR success - 200 response sent from module\n");
+                    exit;
+            case -1: #failure
+                    xlog("L_ERR", "SAR failure - error response sent from module\n");
+                    break;
+            case -2: #error
+                    xlog("L_ERR", "SAR error - error response sent from module\n");
+                    break;
+            default:
+                    xlog("L_ERR", "Unknown return code from SAR, value is [$avp(s:uaa_return_code)]\n");
+                    break;
+    }
+    exit;
+}
+
 ######################################################################
 # Apply privacy, if requested
 ######################################################################
diff --git a/examples/scscf/scscf.cfg b/examples/scscf/scscf.cfg
index 5da0b25..b1ffdc1 100644
--- a/examples/scscf/scscf.cfg
+++ b/examples/scscf/scscf.cfg
@@ -26,14 +26,25 @@
 # Let the HSS decide
 ##!define REG_AUTH_DEFAULT_ALG "HSS-Selected"
 
+# Number of TCP Processes
+#!define TCP_PROCESSES 3
+
+# Allowed IPs for XML-RPC-Queries
+#!define XMLRPC_WHITELIST_1 "127.0.0.1"
+##!define XMLRPC_WHITELIST_2 "127.0.0.1"
+##!define XMLRPC_WHITELIST_3 "127.0.0.1"
+
 # Several features can be enabled using '#!define WITH_FEATURE' directives:
 #
 # *** To run in debug mode: 
 #     - define WITH_DEBUG
 #
+# *** To enable TCP support execute:
+#     - define WITH_TCP
+#
 # *** To enable XMLRPC support execute:
 #     - define WITH_XMLRPC
-#     - adjust route[XMLRPC] for access policy
+#     - this will automagically enable TCP
 #
 # *** To enable basic dialplan support:
 #     - define WITH_DIALPLAN
diff --git a/examples/websocket.cfg b/examples/websocket.cfg
index 4176af0..9fa4229 100644
--- a/examples/websocket.cfg
+++ b/examples/websocket.cfg
@@ -45,14 +45,12 @@ tcp_connection_lifetime=3604
 tcp_accept_no_cl=yes
 tcp_rd_buf_size=16384
 
-syn_branch=0
-
 #!ifdef LOCAL_TEST_RUN
 debug=2
-mpath="modules_k:modules"
+mpath="modules"
 #!else
 debug=0
-mpath="/usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/"
+mpath="/usr/lib64/kamailio/modules/"
 #!endif
 
 loadmodule "db_sqlite.so"
@@ -345,7 +343,6 @@ onreply_route {
 		&& !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) {
 		xlog("L_WARN", "SIP response received on $Rp\n");
 		drop;
-		exit;
 	}
 
 	if (nat_uac_test(64)) {
diff --git a/forward.c b/forward.c
index 380b204..81a0e1d 100644
--- a/forward.c
+++ b/forward.c
@@ -120,9 +120,7 @@
 
 static int mhomed_sock_cache_disabled = 0;
 static int sock_inet = -1;
-#ifdef USE_IPV6
 static int sock_inet6 = -1;
-#endif /* USE_IPV6 */
 
 static void apply_force_send_socket(struct dest_info* dst, struct sip_msg* msg);
 
@@ -155,7 +153,6 @@ retry:
 		temp_sock = &sock_inet;
 		break;
 	}
-#ifdef USE_IPV6
 	case AF_INET6 : {
 		if(unlikely(sock_inet6 < 0)){
 			sock_inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
@@ -167,7 +164,6 @@ retry:
 		temp_sock = &sock_inet6;
 		break;
 	}
-#endif /* USE_IPV6 */
 	default: {
 		LM_ERR("Unknown protocol family \n");
 		return 0;
@@ -189,12 +185,10 @@ retry:
 				close(sock_inet);
 				sock_inet=-1;
 			}
-#ifdef USE_IPV6
 			if (sock_inet6>=0){
 				close(sock_inet6);
 				sock_inet6=-1;
 			}
-#endif /* USE_IPV6 */
 			goto retry;
 		}
 		LOG(L_ERR, "ERROR: get_out_socket: connect failed: %s\n",
@@ -332,10 +326,8 @@ not_forced:
 				/* FIXME */
 				case AF_INET:	send_sock=sendipv4_tcp;
 								break;
-#ifdef USE_IPV6
 				case AF_INET6:	send_sock=sendipv6_tcp;
 								break;
-#endif
 				default:	LOG(L_ERR, "get_send_socket: BUG: don't know how"
 									" to forward to af %d\n", to->s.sa_family);
 			}
@@ -348,10 +340,8 @@ not_forced:
 				/* FIXME */
 				case AF_INET:	send_sock=sendipv4_tls;
 								break;
-#ifdef USE_IPV6
 				case AF_INET6:	send_sock=sendipv6_tls;
 								break;
-#endif
 				default:	LOG(L_ERR, "get_send_socket: BUG: don't know how"
 									" to forward to af %d\n", to->s.sa_family);
 			}
@@ -365,10 +355,8 @@ not_forced:
 				switch(to->s.sa_family){
 					case AF_INET:	send_sock=sendipv4_sctp;
 									break;
-#ifdef USE_IPV6
 					case AF_INET6:	send_sock=sendipv6_sctp;
 									break;
-#endif
 					default:	LOG(L_ERR, "get_send_socket: BUG: don't know"
 										" how to forward to af %d\n",
 										to->s.sa_family);
@@ -383,10 +371,8 @@ not_forced:
 				switch(to->s.sa_family){
 					case AF_INET:	send_sock=sendipv4;
 									break;
-#ifdef USE_IPV6
 					case AF_INET6:	send_sock=sendipv6;
 									break;
-#endif
 					default:	LOG(L_ERR, "get_send_socket: BUG: don't know"
 										" how to forward to af %d\n",
 										to->s.sa_family);
@@ -549,31 +535,23 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
 		}
 	}/* dst */
 	send_info->send_flags=msg->fwd_send_flags;
-	/* calculate branch for outbound request;  if syn_branch is turned off,
+	/* calculate branch for outbound request;
 	   calculate is from transaction key, i.e., as an md5 of From/To/CallID/
 	   CSeq exactly the same way as TM does; good for reboot -- than messages
 	   belonging to transaction lost due to reboot will still be forwarded
 	   with the same branch parameter and will be match-able downstream
-	
-	   if it is turned on, we don't care about reboot; we simply put a simple
-	   value in there; better for performance
 	*/
-	if (syn_branch ) {
-	        memcpy(msg->add_to_branch_s, "z9hG4bKcydzigwkX", 16);
-		msg->add_to_branch_len=16;
-	} else {
-		if (!char_msg_val( msg, md5 )) 	{ /* parses transaction key */
-			LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");
-			ret=E_UNSPEC;
-			goto error;
-		}
-		msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number);
-		if (!branch_builder( msg->hash_index, 0, md5, 0 /* 0-th branch */,
-					msg->add_to_branch_s, &msg->add_to_branch_len )) {
-			LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n");
-			ret=E_UNSPEC;
-			goto error;
-		}
+	if (!char_msg_val( msg, md5 )) 	{ /* parses transaction key */
+		LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");
+		ret=E_UNSPEC;
+		goto error;
+	}
+	msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number);
+	if (!branch_builder( msg->hash_index, 0, md5, 0 /* 0-th branch */,
+				msg->add_to_branch_s, &msg->add_to_branch_len )) {
+		LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n");
+		ret=E_UNSPEC;
+		goto error;
 	}
 	/* try to send the message until success or all the ips are exhausted
 	 *  (if dns lookup is performed && the dns cache used ) */
diff --git a/forward.h b/forward.h
index 0e1d725..4680a8e 100644
--- a/forward.h
+++ b/forward.h
@@ -57,7 +57,7 @@
 #include "tcp_conn.h"
 #endif
 #ifdef USE_SCTP
-#include "sctp_server.h"
+#include "sctp_core.h"
 #endif
 
 #include "compiler_opt.h"
@@ -261,7 +261,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len)
 				}
 				dst=&new_dst;
 			}
-			if (unlikely(sctp_msg_send(dst, outb.s, outb.len)<0)){
+			if (unlikely(sctp_core_msg_send(dst, outb.s, outb.len)<0)){
 				STATS_TX_DROPS;
 				LOG(L_ERR, "msg_send: ERROR: sctp_msg_send failed\n");
 				goto error;
diff --git a/globals.h b/globals.h
index 01b6f28..b535ca8 100644
--- a/globals.h
+++ b/globals.h
@@ -111,7 +111,6 @@ extern int dont_daemonize;
 extern int check_via;
 extern int phone2tel;
 extern int received_dns;
-extern int syn_branch;
 /* extern int process_no; */
 extern int child_rank;
 extern int sip_warning;
@@ -136,15 +135,7 @@ extern int mcast_loopback;
 extern int mcast_ttl;
 #endif /* USE_MCAST */
 
-#ifdef USE_STUN
-extern unsigned int stun_refresh_interval;
-extern int stun_allow_stun;
-extern int stun_allow_fp;
-#endif
-
-#ifdef USE_IPV6
 extern int auto_bind_ipv6;
-#endif
 
 extern int tos;
 extern int pmtu_discovery;
@@ -215,7 +206,7 @@ extern int rt_timer2_prio;  /* "slow" timer */
 extern int rt_timer1_policy; /* "fast" timer, SCHED_OTHER */
 extern int rt_timer2_policy; /* "slow" timer, SCHED_OTHER */
 
-extern int http_reply_hack;
+extern int http_reply_parse;
 
 #ifdef USE_DNS_CACHE
 extern int dns_cache_init; /* if 0, the DNS cache is not initialized at startup */
diff --git a/ip_addr.c b/ip_addr.c
index c071f83..5f8881e 100644
--- a/ip_addr.c
+++ b/ip_addr.c
@@ -184,10 +184,8 @@ int mk_net_str(struct net* dst, str* s)
 	
 	/* test for ip only */
 	t = str2ip(s);
-#ifdef USE_IPV6
 	if (unlikely(t == 0))
 		t = str2ip6(s);
-#endif /* USE_IPV6 */
 	if (likely(t))
 		return mk_net_bitlen(dst, t, t->len*8);
 	/* not a simple ip, maybe an ip/netmask pair */
@@ -212,7 +210,6 @@ int mk_net_str(struct net* dst, str* s)
 			/* error */
 			return -1;
 		}
-#ifdef USE_IPV6
 		else {
 			t = str2ip6(&addr);
 			if (likely(t)) {
@@ -227,7 +224,6 @@ int mk_net_str(struct net* dst, str* s)
 				return -1;
 			}
 		}
-#endif /* USE_IPV6 */
 	}
 	return -1;
 }
@@ -246,7 +242,6 @@ void print_ip(char* p, struct ip_addr* ip, char *s)
 								(s)?s:""
 								);
 			break;
-#ifdef USE_IPV6
 		case AF_INET6:
 			DBG("%s%x:%x:%x:%x:%x:%x:%x:%x%s", (p)?p:"",
 											htons(ip->u.addr16[0]),
@@ -260,7 +255,6 @@ void print_ip(char* p, struct ip_addr* ip, char *s)
 											(s)?s:""
 				);
 			break;
-#endif /* USE_IPV6 */
 		default:
 			DBG("print_ip: warning unknown address family %d\n", ip->af);
 	}
@@ -277,7 +271,6 @@ void stdout_print_ip(struct ip_addr* ip)
 								ip->u.addr[2],
 								ip->u.addr[3]);
 			break;
-#ifdef USE_IPV6
 		case AF_INET6:
 			printf("%x:%x:%x:%x:%x:%x:%x:%x",	htons(ip->u.addr16[0]),
 											htons(ip->u.addr16[1]),
@@ -289,7 +282,6 @@ void stdout_print_ip(struct ip_addr* ip)
 											htons(ip->u.addr16[7])
 				);
 			break;
-#endif /* USE_IPV6 */
 		default:
 			DBG("print_ip: warning unknown address family %d\n", ip->af);
 	}
@@ -319,10 +311,8 @@ int is_mcast(struct ip_addr* ip)
 
 	if (ip->af==AF_INET){
 		return IN_MULTICAST(htonl(ip->u.addr32[0]));
-#ifdef USE_IPV6
 	} else if (ip->af==AF_INET6){
 		return IN6_IS_ADDR_MULTICAST((struct in6_addr*)ip->u.addr32);
-#endif /* USE_IPV6 */
 	} else {
 		LOG(L_ERR, "ERROR: is_mcast: Unsupported protocol family\n");
 		return -1;
@@ -351,9 +341,8 @@ char* get_proto_name(unsigned int proto)
 		case PROTO_SCTP:
 			return "sctp";
 		case PROTO_WS:
-			return "ws";
 		case PROTO_WSS:
-			return "wss";
+			return "ws";
 		default:
 			return "unknown";
 	}
diff --git a/ip_addr.h b/ip_addr.h
index 115e4b4..20b3ec2 100644
--- a/ip_addr.h
+++ b/ip_addr.h
@@ -82,9 +82,7 @@ struct net{
 union sockaddr_union{
 		struct sockaddr     s;
 		struct sockaddr_in  sin;
-	#ifdef USE_IPV6
 		struct sockaddr_in6 sin6;
-	#endif
 };
 
 
@@ -217,13 +215,9 @@ struct socket_id{
 #ifdef HAVE_SOCKADDR_SA_LEN
 #define sockaddru_len(su)	((su).s.sa_len)
 #else
-#ifdef USE_IPV6
 #define sockaddru_len(su)	\
 			(((su).s.sa_family==AF_INET6)?sizeof(struct sockaddr_in6):\
 					sizeof(struct sockaddr_in))
-#else
-#define sockaddru_len(su)	sizeof(struct sockaddr_in)
-#endif /*USE_IPV6*/
 #endif /* HAVE_SOCKADDR_SA_LEN*/
 	
 /* inits an ip_addr with the addr. info from a hostent structure
@@ -243,11 +237,7 @@ struct socket_id{
 /* gets the protocol family corresponding to a specific address family
  * ( PF_INET - AF_INET, PF_INET6 - AF_INET6, af for others)
  */
-#ifdef USE_IPV6
 #define AF2PF(af)   (((af)==AF_INET)?PF_INET:((af)==AF_INET6)?PF_INET6:(af))
-#else
-#define AF2PF(af)   (((af)==AF_INET)?PF_INET:(af))
-#endif
 
 
 
@@ -294,10 +284,8 @@ inline static int ip_addr_loopback(struct ip_addr* ip)
 {
 	if (ip->af==AF_INET)
 		return ip->u.addr32[0]==htonl(INADDR_LOOPBACK);
-#ifdef USE_IPV6
 	else if (ip->af==AF_INET6)
 		return IN6_IS_ADDR_LOOPBACK((struct in6_addr*)ip->u.addr32);
-#endif /* USE_IPV6 */
 	return 0;
 }
 
@@ -311,7 +299,6 @@ inline static void ip_addr_mk_any(int af, struct ip_addr* ip)
 		ip->len=4;
 		ip->u.addr32[0]=0;
 	}
-#ifdef USE_IPV6
 	else{
 		ip->len=16;
 #if (defined (ULONG_MAX) && ULONG_MAX > 4294967295) || defined LP64
@@ -325,7 +312,6 @@ inline static void ip_addr_mk_any(int af, struct ip_addr* ip)
 		ip->u.addr32[3]=0;
 #endif /* ULONG_MAX */
 	}
-#endif
 }
 
 /* returns 1 if ip & net.mask == net.ip ; 0 otherwise & -1 on error 
@@ -359,13 +345,11 @@ static inline void sockaddr2ip_addr(struct ip_addr* ip, struct sockaddr* sa)
 			ip->len=4;
 			memcpy(ip->u.addr, &((struct sockaddr_in*)sa)->sin_addr, 4);
 			break;
-#ifdef USE_IPV6
 	case AF_INET6:
 			ip->af=AF_INET6;
 			ip->len=16;
 			memcpy(ip->u.addr, &((struct sockaddr_in6*)sa)->sin6_addr, 16);
 			break;
-#endif
 	default:
 			LOG(L_CRIT, "sockaddr2ip_addr: BUG: unknown address family %d\n",
 					sa->sa_family);
@@ -390,11 +374,9 @@ static inline int su_cmp(const union sockaddr_union* s1,
 		case AF_INET:
 			return (s1->sin.sin_port==s2->sin.sin_port)&&
 					(memcmp(&s1->sin.sin_addr, &s2->sin.sin_addr, 4)==0);
-#ifdef USE_IPV6
 		case AF_INET6:
 			return (s1->sin6.sin6_port==s2->sin6.sin6_port)&&
 					(memcmp(&s1->sin6.sin6_addr, &s2->sin6.sin6_addr, 16)==0);
-#endif
 		default:
 			LOG(L_CRIT,"su_cmp: BUG: unknown address family %d\n",
 						s1->s.sa_family);
@@ -410,10 +392,8 @@ static inline unsigned short su_getport(const union sockaddr_union* su)
 	switch(su->s.sa_family){
 		case AF_INET:
 			return ntohs(su->sin.sin_port);
-#ifdef USE_IPV6
 		case AF_INET6:
 			return ntohs(su->sin6.sin6_port);
-#endif
 		default:
 			LOG(L_CRIT,"su_get_port: BUG: unknown address family %d\n",
 						su->s.sa_family);
@@ -430,11 +410,9 @@ static inline void su_setport(union sockaddr_union* su, unsigned short port)
 		case AF_INET:
 			su->sin.sin_port=htons(port);
 			break;
-#ifdef USE_IPV6
 		case AF_INET6:
 			 su->sin6.sin6_port=htons(port);
 			 break;
-#endif
 		default:
 			LOG(L_CRIT,"su_set_port: BUG: unknown address family %d\n",
 						su->s.sa_family);
@@ -452,13 +430,11 @@ static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su)
 					ip->len=4;
 					memcpy(ip->u.addr, &su->sin.sin_addr, 4);
 					break;
-#ifdef USE_IPV6
 	case AF_INET6:
 					ip->af=AF_INET6;
 					ip->len=16;
 					memcpy(ip->u.addr, &su->sin6.sin6_addr, 16);
 					break;
-#endif
 	default:
 					LOG(L_CRIT,"su2ip_addr: BUG: unknown address family %d\n",
 							su->s.sa_family);
@@ -479,7 +455,6 @@ static inline int init_su( union sockaddr_union* su,
 	memset(su, 0, sizeof(union sockaddr_union));/*needed on freebsd*/
 	su->s.sa_family=ip->af;
 	switch(ip->af){
-#ifdef USE_IPV6
 	case	AF_INET6:
 		memcpy(&su->sin6.sin6_addr, ip->u.addr, ip->len); 
 		#ifdef HAVE_SOCKADDR_SA_LEN
@@ -487,7 +462,6 @@ static inline int init_su( union sockaddr_union* su,
 		#endif
 		su->sin6.sin6_port=htons(port);
 		break;
-#endif
 	case AF_INET:
 		memcpy(&su->sin.sin_addr, ip->u.addr, ip->len);
 		#ifdef HAVE_SOCKADDR_SA_LEN
@@ -516,7 +490,6 @@ static inline int hostent2su( union sockaddr_union* su,
 	memset(su, 0, sizeof(union sockaddr_union)); /*needed on freebsd*/
 	su->s.sa_family=he->h_addrtype;
 	switch(he->h_addrtype){
-#ifdef USE_IPV6
 	case	AF_INET6:
 		memcpy(&su->sin6.sin6_addr, he->h_addr_list[idx], he->h_length);
 		#ifdef HAVE_SOCKADDR_SA_LEN
@@ -524,7 +497,6 @@ static inline int hostent2su( union sockaddr_union* su,
 		#endif
 		su->sin6.sin6_port=htons(port);
 		break;
-#endif
 	case AF_INET:
 		memcpy(&su->sin.sin_addr, he->h_addr_list[idx], he->h_length);
 		#ifdef HAVE_SOCKADDR_SA_LEN
@@ -546,7 +518,6 @@ static inline int hostent2su( union sockaddr_union* su,
 #define IP6_MAX_STR_SIZE 39 /*1234:5678:9012:3456:7890:1234:5678:9012*/
 #define IP4_MAX_STR_SIZE 15 /*123.456.789.012*/
 
-#ifdef USE_IPV6
 /* converts a raw ipv6 addr (16 bytes) to ascii */
 static inline int ip6tosbuf(unsigned char* ip6, char* buff, int len)
 {
@@ -619,7 +590,6 @@ static inline int ip6tosbuf(unsigned char* ip6, char* buff, int len)
 	
 	return offset;
 }
-#endif /* USE_IPV6 */
 
 
 
@@ -688,11 +658,9 @@ static inline int ip4tosbuf(unsigned char* ip4, char* buff, int len)
 static inline int ip_addr2sbuf(struct ip_addr* ip, char* buff, int len)
 {
 	switch(ip->af){
-	#ifdef USE_IPV6
 		case AF_INET6:
 			return ip6tosbuf(ip->u.addr, buff, len);
 			break;
-	#endif /* USE_IPV6 */
 		case AF_INET:
 			return ip4tosbuf(ip->u.addr, buff, len);
 			break;
@@ -736,7 +704,6 @@ static inline char* su2a(union sockaddr_union* su, int su_len)
 	static char buf[SU2A_MAX_STR_SIZE];
 	int offs;
 
-#ifdef USE_IPV6
 	if (unlikely(su->s.sa_family==AF_INET6)){
 		if (unlikely(su_len<sizeof(su->sin6)))
 			return "<addr. error>";
@@ -746,7 +713,6 @@ static inline char* su2a(union sockaddr_union* su, int su_len)
 		buf[offs]=']';
 		offs++;
 	}else
-#endif /* USE_IPV6*/
 	if (unlikely(su_len<sizeof(su->sin)))
 		return "<addr. error>";
 	else
@@ -766,7 +732,6 @@ static inline char* suip2a(union sockaddr_union* su, int su_len)
 	static char buf[SUIP2A_MAX_STR_SIZE];
 	int offs;
 
-#ifdef USE_IPV6
 	if (unlikely(su->s.sa_family==AF_INET6)){
 		if (unlikely(su_len<sizeof(su->sin6)))
 			return "<addr. error>";
@@ -776,7 +741,6 @@ static inline char* suip2a(union sockaddr_union* su, int su_len)
 		buf[offs]=']';
 		offs++;
 	}else
-#endif /* USE_IPV6*/
 	if (unlikely(su_len<sizeof(su->sin)))
 		return "<addr. error>";
 	else
diff --git a/lib/ims/ims_getters.c b/lib/ims/ims_getters.c
index d1c84c7..05450f1 100644
--- a/lib/ims/ims_getters.c
+++ b/lib/ims/ims_getters.c
@@ -990,6 +990,109 @@ str cscf_get_charging_vector(struct sip_msg *msg, struct hdr_field **h)
 	return cv;
 }
 
+int cscf_get_p_charging_vector(struct sip_msg *msg, str * icid, str * orig_ioi,
+		str * term_ioi) {
+	struct hdr_field* header = 0;
+	str header_body = { 0, 0 };
+	char * p;
+	int index;
+	str temp = { 0, 0 };
+
+	if (parse_headers(msg, HDR_EOH_F, 0) < 0) {
+		LM_ERR("cscf_get_p_charging_vector: error parsing headers\n");
+		return 0;
+	}
+	header = msg->headers;
+	while (header) {
+		if (header->name.len == cscf_p_charging_vector.len
+				&& strncasecmp(header->name.s, cscf_p_charging_vector.s, cscf_p_charging_vector.len) == 0)
+			break;
+		header = header->next;
+	}
+	if (!header) {
+		LM_DBG("no header %.*s was found\n", cscf_p_charging_vector.len, cscf_p_charging_vector.s);
+		return 0;
+	}
+	if (!header->body.s || !header->body.len)
+		return 0;
+
+	str_dup(header_body, header->body, pkg);
+
+	LM_DBG("p_charging_vector body is %.*s\n", header_body.len, header_body.s);
+
+	p = strtok(header_body.s, " ;:\r\t\n\"=");
+	loop: if (p > (header_body.s + header_body.len))
+		return 1;
+
+	if (strncmp(p, "icid-value", 10) == 0) {
+		p = strtok(NULL, " ;:\r\t\n\"=");
+		if (p > (header_body.s + header_body.len)) {
+			LM_ERR("cscf_get_p_charging_vector: no value for icid\n");
+			return 0;
+		}
+		temp.s = p;
+		temp.len = 0;
+		while (*p != '\"') {
+			temp.len = temp.len + 1;
+			p++;
+		}
+		icid->len = temp.len;
+		index = temp.s - header_body.s;
+		LM_DBG("icid len %i, index %i\n", temp.len, index);
+		icid->s = header->body.s + index;
+		LM_DBG("icid is %.*s\n", icid->len, icid->s);
+		p = strtok(NULL, " ;:\r\t\n\"=");
+		goto loop;
+	} else if (strncmp(p, "orig-ioi", 8) == 0) {
+
+		p = strtok(NULL, " ;:\r\t\n\"=");
+		if (p > (header_body.s + header_body.len)) {
+			LM_ERR("cscf_get_p_charging_vector: no value for icid\n");
+			return 0;
+		}
+		temp.s = p;
+		temp.len = 0;
+		while (*p != '\"') {
+			temp.len = temp.len + 1;
+			p++;
+		}
+		orig_ioi->len = temp.len;
+		index = temp.s - header_body.s;
+		LM_DBG("orig ioi len %i, index %i\n", temp.len, index);
+		orig_ioi->s = header->body.s + index;
+		LM_DBG("orig_ioi is %.*s\n", orig_ioi->len, orig_ioi->s);
+		p = strtok(NULL, " ;:\r\t\n\"=");
+		goto loop;
+	} else if (strncmp(p, "term-ioi", 8) == 0) {
+
+		p = strtok(NULL, " ;:\r\t\n\"=");
+		if (p > (header_body.s + header_body.len)) {
+			LM_ERR("cscf_get_p_charging_vector: no value for icid\n");
+			return 0;
+		}
+		temp.s = p;
+		temp.len = 0;
+		while (*p != '\"') {
+			temp.len = temp.len + 1;
+			p++;
+		}
+		term_ioi->len = temp.len;
+		term_ioi->s = header->body.s + (temp.s - header_body.s);
+		p = strtok(NULL, " ;:\r\t\n\"=");
+		goto loop;
+	} else {
+		p = strtok(NULL, " ;:\r\t\n\"=");
+		goto loop;
+	}
+
+	LM_DBG("end\n");
+	str_free(header_body, pkg);
+	return 1;
+	out_of_memory:
+	LM_ERR("cscf_get_p_charging_vector:out of pkg memory\n");
+	return 0;
+}
+
 /**
  * Get the from tag
  * @param msg - the SIP message to look into
diff --git a/lib/ims/ims_getters.h b/lib/ims/ims_getters.h
index a36e0f3..e78310f 100644
--- a/lib/ims/ims_getters.h
+++ b/lib/ims/ims_getters.h
@@ -294,6 +294,14 @@ str cscf_get_access_network_info(struct sip_msg *msg, struct hdr_field **h);
 
 str cscf_get_charging_vector(struct sip_msg *msg, struct hdr_field **h);
 
+/**
+ * Return the P-Charging-Vector tokens
+ * @param msg - the SIP message
+ * @returns the str with icid, orig_ioi and term_ioi
+ */
+int cscf_get_p_charging_vector(struct sip_msg *msg, str * icid, str * orig_ioi,
+	str * term_ioi);
+
 
 /**
  * Get the to tag
diff --git a/lib/kcore/parse_pai.c b/lib/kcore/parse_pai.c
deleted file mode 100644
index d0dda3d..0000000
--- a/lib/kcore/parse_pai.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2006 Juha Heinanen
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*!
- * \file
- * \brief P-Asserted-Identity header parser
- * \ingroup parser
- */
-
-#include "../../parser/parse_from.h"
-#include "../../parser/parse_to.h"
-#include <stdlib.h>
-#include <string.h>
-#include "../../dprint.h"
-#include "../../parser/msg_parser.h"
-#include "../../ut.h"
-#include "../../mem/mem.h"
-
-/*!
- * This method is used to parse P-Asserted-Identity header (RFC 3325).
- *
- * Currently only one name-addr / addr-spec is supported in the header
- * and it must contain a sip or sips URI.
- * \param msg sip msg
- * \return 0 on success, -1 on failure.
- */
-int parse_pai_header( struct sip_msg *msg )
-{
-	struct to_body* pai_b;
-
-	if ( !msg->pai && (parse_headers(msg, HDR_PAI_F,0)==-1 || !msg->pai)) {
-		goto error;
-	}
-
-	/* maybe the header is already parsed! */
-	if (msg->pai->parsed)
-		return 0;
- 
-	/* bad luck! :-( - we have to parse it */
-	/* first, get some memory */
-	pai_b = pkg_malloc(sizeof(struct to_body));
-	if (pai_b == 0) {
-		LM_ERR("out of pkg_memory\n");
-		goto error;
-	}
- 
-	/* now parse it!! */
-	memset(pai_b, 0, sizeof(struct to_body));
-	parse_to(msg->pai->body.s, msg->pai->body.s + msg->pai->body.len+1, pai_b);
-	if (pai_b->error == PARSE_ERROR) {
-		LM_ERR("bad P-Asserted-Identity header\n");
-		free_to(pai_b);
-		goto error;
-	}
- 	msg->pai->parsed = pai_b;
- 
-	return 0;
-error:
-	return -1;
-}
diff --git a/lib/kcore/parse_pai.h b/lib/kcore/parse_pai.h
deleted file mode 100644
index 3f6c016..0000000
--- a/lib/kcore/parse_pai.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *
- * Copyright (C) 2006 Juha Heinanen
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/*!
- * \file
- * \brief P-Asserted-Identity header parser
- * \ingroup parser
- */
-
-#ifndef PARSE_PAI_H
-#define PARSE_PAI_H
-
-#include "../../parser/msg_parser.h"
-#include "../../parser/parse_to.h"
-
-
-/*! casting macro for accessing P-Asserted-Identity body */
-#define get_pai(p_msg)  ((struct to_body*)(p_msg)->pai->parsed)
-
-
-/*!
- * P-Asserted-Identity header field parser
- */
-int parse_pai_header( struct sip_msg *msg);
-
-#endif /* PARSE_PAI_H */
diff --git a/lib/kcore/parse_ppi.c b/lib/kcore/parse_ppi.c
deleted file mode 100644
index 863f061..0000000
--- a/lib/kcore/parse_ppi.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2006 Juha Heinanen
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*!
- * \file
- * \brief P-Preferred-Identity header parser
- * \ingroup parser
- */
-
-#include "parse_ppi.h"
-#include "../../parser/parse_to.h"
-#include "../../parser/parse_uri.h"
-#include <stdlib.h>
-#include <string.h>
-#include "../../dprint.h"
-#include "../../parser/msg_parser.h"
-#include "../../ut.h"
-#include "../../mem/mem.h"
-
-
-/*!
- * \brief This method is used to parse P-Preferred-Identity header (RFC 3325).
- *
- * Currently only one name-addr / addr-spec is supported in the header
- * and it must contain a sip or sips URI.
- * \param msg sip msg
- * \return 0 on success, -1 on failure.
- */
-int parse_ppi_header( struct sip_msg *msg )
-{
-    struct to_body* ppi_b;
-
-    if ( !msg->ppi &&
-	 (parse_headers(msg, HDR_PPI_F,0)==-1 || !msg->ppi)) {
-	goto error;
-    }
- 
-    /* maybe the header is already parsed! */
-    if (msg->ppi->parsed)
-	return 0;
- 
-    /* bad luck! :-( - we have to parse it */
-    /* first, get some memory */
-    ppi_b = pkg_malloc(sizeof(struct to_body));
-    if (ppi_b == 0) {
-	LM_ERR("out of pkg_memory\n");
-	goto error;
-    }
- 
-    /* now parse it!! */
-    memset(ppi_b, 0, sizeof(struct to_body));
-    parse_to(msg->ppi->body.s,
-	     msg->ppi->body.s + msg->ppi->body.len+1,
-	     ppi_b);
-    if (ppi_b->error == PARSE_ERROR) {
-	LM_ERR("bad P-Preferred-Identity header\n");
-	free_to(ppi_b);
-	goto error;
-    }
- 	msg->ppi->parsed = ppi_b;
- 
- 	return 0;
- error:
- 	return -1;
-}
-
-
-/*!
- * \brief Parse P-Preferred-Identity header URI
- */
-struct sip_uri *parse_ppi_uri(struct sip_msg *msg)
-{
-	struct to_body *tb = NULL;
-	
-	if(msg==NULL)
-		return NULL;
-
-	if(parse_ppi_header(msg)<0)
-	{
-		LM_ERR("cannot parse P-P-I header\n");
-		return NULL;
-	}
-	
-	if(msg->ppi==NULL || get_ppi(msg)==NULL)
-		return NULL;
-
-	tb = get_ppi(msg);
-
-	if(tb->parsed_uri.user.s!=NULL || tb->parsed_uri.host.s!=NULL)
-		return &tb->parsed_uri;
-
-	if (parse_uri(tb->uri.s, tb->uri.len , &tb->parsed_uri)<0)
-	{
-		LM_ERR("failed to parse P-P-I URI\n");
-		memset(&tb->parsed_uri, 0, sizeof(struct sip_uri));
-		return NULL;
-	}
-
-	return &tb->parsed_uri;
-}
diff --git a/lib/kcore/parse_ppi.h b/lib/kcore/parse_ppi.h
deleted file mode 100644
index cb276b3..0000000
--- a/lib/kcore/parse_ppi.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2006 Juha Heinanen
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/*!
- * \file
- * \brief P-Preferred-Identity header parser
- * \ingroup parser
- */
-
-#ifndef PARSE_PPI_H
-#define PARSE_PPI_H
-
-#include "../../parser/msg_parser.h"
-#include "../../parser/parse_to.h"
-
-
-/*! casting macro for accessing P-Preferred-Identity body */
-#define get_ppi(p_msg)  ((struct to_body*)(p_msg)->ppi->parsed)
-
-
-/*!
- * \brief This method is used to parse P-Preferred-Identity header (RFC 3325).
- *
- * Currently only one name-addr / addr-spec is supported in the header
- * and it must contain a sip or sips URI.
- * \param msg sip msg
- * \return 0 on success, -1 on failure.
- */
-int parse_ppi_header( struct sip_msg *msg);
-
-struct sip_uri *parse_ppi_uri(struct sip_msg *msg);
- 
-#endif /* PARSE_PPI_H */
diff --git a/lib/kcore/parse_supported.c b/lib/kcore/parse_supported.c
deleted file mode 100644
index eb90290..0000000
--- a/lib/kcore/parse_supported.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*!
- * \file
- * \brief Supported parser
- * \ingroup parser
- */
-
-#include "../../mem/mem.h"
-#include "../../parser/keys.h"
-#include "parse_supported.h"
-
-#define _100r_ 0x72303031   /* "100r" for "100rel" */
-#define _time_ 0x656d6974   /*!< "time" */
-
-#define IS_DELIM(c) (*(c) == ' ' || *(c) == '\t' || *(c) == '\r' || *(c) == '\n' || *(c) == ',')
-
-/* from parser/parse_hname2.c: */
-#define LOWER_BYTE(b) ((b) | 0x20)
-#define LOWER_DWORD(d) ((d) | 0x20202020)
-#define READ(val) \
-	(*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
-
-
-/*!
- * Parse Supported HF body.
- */
-static inline int parse_supported_body(str *body, unsigned int *sup)
-{
-	register char* p;
-	register unsigned int val;
-	int len, pos = 0;
-
-	*sup = 0;
-
-	p = body->s;
-	len = body->len;
-
-	while (pos < len) {
-		/* skip spaces and commas */
-		for (; pos < len && IS_DELIM(p); ++pos, ++p);
-
-		val = LOWER_DWORD(READ(p));
-		switch (val) {
-
-			/* "path" */
-			case _path_:
-				if(pos + 4 <= len && IS_DELIM(p+4)) {
-					*sup |= F_SUPPORTED_PATH;
-					pos += 5; p += 5;
-				}
-				break;
-
-			/* "100rel" */
-			case _100r_:
-				if ( pos+6 <= len
-					 && LOWER_BYTE(*(p+4))=='e' && LOWER_BYTE(*(p+5))=='l'
-					 && IS_DELIM(p+6)) {
-					*sup |= F_SUPPORTED_100REL;
-					pos += SUPPORTED_100REL_LEN + 1;
-					p   += SUPPORTED_100REL_LEN + 1;
-				}
-				break;
-
-			/* "timer" */
-			case _time_:
-				if ( pos+5 <= len && LOWER_BYTE(*(p+4))=='r'
-					 && IS_DELIM(p+5) ) {
-					*sup |= F_SUPPORTED_TIMER;
-					pos += SUPPORTED_TIMER_LEN + 1;
-					p   += SUPPORTED_TIMER_LEN + 1;
-				}
-				break;
-
-			/* extra supported or unknown */
-			default:
-				if(pos+SUPPORTED_EVENTLIST_LEN<=len
-						&& strncasecmp(p, SUPPORTED_EVENTLIST_STR,
-							SUPPORTED_EVENTLIST_LEN)==0
-						&& IS_DELIM(p+SUPPORTED_EVENTLIST_LEN) ) {
-					*sup |= F_SUPPORTED_EVENTLIST;
-					pos += SUPPORTED_EVENTLIST_LEN + 1;
-					p   += SUPPORTED_EVENTLIST_LEN + 1;
-				} else if(pos+SUPPORTED_GRUU_LEN<=len
-						&& strncasecmp(p, SUPPORTED_GRUU_STR,
-							SUPPORTED_GRUU_LEN)==0
-						&& IS_DELIM(p+SUPPORTED_GRUU_LEN)) {
-					*sup |= F_SUPPORTED_GRUU;
-					pos += SUPPORTED_GRUU_LEN + 1;
-					p   += SUPPORTED_GRUU_LEN + 1;
-				} else if(pos+SUPPORTED_OUTBOUND_LEN<=len
-						&& strncasecmp(p, SUPPORTED_OUTBOUND_STR,
-							SUPPORTED_OUTBOUND_LEN)==0
-						&& IS_DELIM(p+SUPPORTED_OUTBOUND_LEN)) {
-					*sup |= F_SUPPORTED_OUTBOUND;
-					pos += SUPPORTED_OUTBOUND_LEN + 1;
-					p   += SUPPORTED_OUTBOUND_LEN + 1;
-				} else {
-					/* skip element */
-					for (; pos < len && !IS_DELIM(p); ++pos, ++p);
-				}
-				break;
-		}
-	}
-	
-	return 0;
-}
-
-
-/**
- * wrapper to free the content of parsed supported header
- */
-void hf_free_supported(void *parsed)
-{
-	struct supported_body *sb;
-	sb = (struct supported_body*)parsed;
-	free_supported(&sb);
-}
-
-/*!
- * Parse all Supported headers
- */
-int parse_supported( struct sip_msg *msg)
-{
-	unsigned int supported;
-	struct hdr_field  *hdr;
-	struct supported_body *sb;
-
-	/* maybe the header is already parsed! */
-	if (msg->supported && msg->supported->parsed)
-		return 0;
-
-	/* parse to the end in order to get all SUPPORTED headers */
-	if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->supported)
-		return -1;
-
-	/* bad luck! :-( - we have to parse them */
-	supported = 0;
-	for( hdr=msg->supported ; hdr ; hdr=next_sibling_hdr(hdr)) {
-		if (hdr->parsed) {
-			supported |= ((struct supported_body*)hdr->parsed)->supported;
-			continue;
-		}
-
-		sb = (struct supported_body*)pkg_malloc(sizeof(struct supported_body));
-		if (sb == 0) {
-			LM_ERR("out of pkg_memory\n");
-			return -1;
-		}
-
-		parse_supported_body(&(hdr->body), &(sb->supported));
-		sb->hfree = hf_free_supported;
-		sb->supported_all = 0;
-		hdr->parsed = (void*)sb;
-		supported |= sb->supported;
-	}
-
-	((struct supported_body*)msg->supported->parsed)->supported_all = 
-		supported;
-	return 0;
-}
-
-/* free supported header structure */
-void free_supported(struct supported_body **sb)
-{
-	if (sb && *sb) {
-		pkg_free(*sb);
-		*sb = 0;
-	}
-}
diff --git a/lib/kcore/parse_supported.h b/lib/kcore/parse_supported.h
deleted file mode 100644
index 2a37073..0000000
--- a/lib/kcore/parse_supported.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- *
- * History:
- * -------
- * 2006-03-02  parse_supported() parses and cumulates all SUPPORTED 
- *             headers (bogdan)
- */
-
-/*!
- * \file
- * \brief Supported parser
- * \ingroup parser
- */
-
-#ifndef PARSE_SUPPORTED_H
-#define PARSE_SUPPORTED_H
-
-#include "../../parser/msg_parser.h"
-#include "../../parser/hf.h"
-#include "../../mem/mem.h"
-
-
-#define F_SUPPORTED_PATH		(1 << 0)
-#define F_SUPPORTED_100REL		(1 << 1)
-#define F_SUPPORTED_TIMER		(1 << 2)
-#define F_SUPPORTED_EVENTLIST   (1 << 3)
-#define F_SUPPORTED_GRUU        (1 << 4)
-#define F_SUPPORTED_OUTBOUND    (1 << 5)
-
-#define SUPPORTED_PATH_STR		"path"
-#define SUPPORTED_PATH_LEN		(sizeof(SUPPORTED_PATH_STR)-1)
-
-/* RFC 3262 (PRACK) */
-#define SUPPORTED_100REL_STR	"100rel"
-#define SUPPORTED_100REL_LEN	(sizeof(SUPPORTED_100REL_STR)-1)
-
-/* RFC 4028 */
-#define SUPPORTED_TIMER_STR		"timer"
-#define SUPPORTED_TIMER_LEN		(sizeof(SUPPORTED_TIMER_STR)-1)
-
-/* RFC 4662 (RLS) */
-#define SUPPORTED_EVENTLIST_STR  "eventlist"
-#define SUPPORTED_EVENTLIST_LEN  (sizeof(SUPPORTED_EVENTLIST_STR)-1)
-
-/* RFC 5627 */
-#define SUPPORTED_GRUU_STR		"gruu"
-#define SUPPORTED_GRUU_LEN		(sizeof(SUPPORTED_GRUU_STR)-1)
-
-/* RFC 5626 */
-#define SUPPORTED_OUTBOUND_STR	"outbound"
-#define SUPPORTED_OUTBOUND_LEN	(sizeof(SUPPORTED_OUTBOUND_STR)-1)
-
-#define get_supported(p_msg) \
-	((p_msg)->supported ? ((struct supported_body*)(p_msg)->supported->parsed)->supported_all : 0)
-
-
-struct supported_body {
-	hf_parsed_free_f hfree;        /* function to free the content */
-	unsigned int supported;        /* supported mask for the current hdr */
-	unsigned int supported_all;    /* suppoted mask for the all "supported" hdr
-	                                *  - it's set only for the first hdr in 
-	                                *  sibling list*/
-};
-
-
-/*!
- * Parse all Supported headers.
- */
-int parse_supported( struct sip_msg *msg);
-
-
-void free_supported(struct supported_body **sb);
-
-#endif /* PARSE_SUPPORTED_H */
diff --git a/lib/kcore/statistics.c b/lib/kcore/statistics.c
index c94bde0..ec5c691 100644
--- a/lib/kcore/statistics.c
+++ b/lib/kcore/statistics.c
@@ -113,11 +113,37 @@ stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int out_codes)
  *       contents, to avoid a nasty memory leak.
  */
 int get_socket_list_from_proto(int **ipList, int protocol) {
+	return get_socket_list_from_proto_and_family(ipList, protocol, AF_INET);
+}
+
+
+/*!
+ * This function will retrieve a list of all ip addresses and ports that Kamailio
+ * is listening on, with respect to the transport protocol specified with
+ * 'protocol'. This function supports both IPv4 and IPv6
+ *
+ * The first parameter, ipList, is a pointer to a pointer. It will be assigned a
+ * new block of memory holding the IP Addresses and ports being listened to with
+ * respect to 'protocol'.  The array maps a 2D array into a 1 dimensional space,
+ * and is layed out as follows:
+ *
+ * The first NUM_IP_OCTETS indices will be the IP address, and the next index
+ * the port.  So if NUM_IP_OCTETS is equal to 4 and there are two IP addresses
+ * found, then:
+ *
+ *  - ipList[0] will be the first octet of the first ip address
+ *  - ipList[3] will be the last octet of the first ip address.
+ *  - iplist[4] will be the port of the first ip address
+ *  - 
+ *  - iplist[5] will be the first octet of the first ip address, 
+ *  - and so on.  
+ */
+int get_socket_list_from_proto_and_family(int **ipList, int protocol, int family) {
 
 	struct socket_info  *si;
 	struct socket_info** list;
 
-	int num_ip_octets   = 4;
+	int num_ip_octets   = family == AF_INET ? NUM_IP_OCTETS : NUM_IPV6_OCTETS;
 	int numberOfSockets = 0;
 	int currentRow      = 0;
 
@@ -136,6 +162,13 @@ int get_socket_list_from_proto(int **ipList, int protocol) {
 		return 0;
 	}
 #endif
+#ifndef USE_SCTP
+	if (protocol == PROTO_SCTP)
+	{
+		return 0;
+	}
+#endif
+	/* We have no "interfaces" for websockets */
 	if (protocol == PROTO_WS || protocol == PROTO_WSS)
 		return 0;
 
@@ -145,8 +178,7 @@ int get_socket_list_from_proto(int **ipList, int protocol) {
 	/* Find out how many sockets are in the list.  We need to know this so
 	 * we can malloc an array to assign to ipList. */
 	for(si=list?*list:0; si; si=si->next){
-		/* We only support IPV4 at this point. */
-		if (si->address.af == AF_INET) {
+		if (si->address.af == family) {
 			numberOfSockets++;
 		}
 	}
@@ -172,21 +204,18 @@ int get_socket_list_from_proto(int **ipList, int protocol) {
 
 	/* Extract out the IP Addresses and ports.  */
 	for(si=list?*list:0; si; si=si->next){
+		int i;
 
 		/* We currently only support IPV4. */
-		if (si->address.af != AF_INET) {
+		if (si->address.af != family) {
 			continue;
 		}
 
-		(*ipList)[currentRow*(num_ip_octets + 1)  ] = 
-			si->address.u.addr[0];
-		(*ipList)[currentRow*(num_ip_octets + 1)+1] = 
-			si->address.u.addr[1];
-		(*ipList)[currentRow*(num_ip_octets + 1)+2] = 
-			si->address.u.addr[2];
-		(*ipList)[currentRow*(num_ip_octets + 1)+3] = 
-			si->address.u.addr[3];
-		(*ipList)[currentRow*(num_ip_octets + 1)+4] = 
+		for (i = 0; i < num_ip_octets; i++) {
+			(*ipList)[currentRow*(num_ip_octets + 1) + i ] = 
+				si->address.u.addr[i];
+		}
+		(*ipList)[currentRow*(num_ip_octets + 1) + i] = 
 			si->port_no;
 		
 		currentRow++;
@@ -401,16 +430,27 @@ int get_total_bytes_waiting(void)
 	int *UDPList  = NULL;
 	int *TCPList  = NULL;
 	int *TLSList  = NULL;
+	int *UDP6List  = NULL;
+	int *TCP6List  = NULL;
+	int *TLS6List  = NULL;
 
 	int numUDPSockets  = 0;
 	int numTCPSockets  = 0; 
 	int numTLSSockets  = 0;
+	int numUDP6Sockets  = 0;
+	int numTCP6Sockets  = 0; 
+	int numTLS6Sockets  = 0;
 
 	/* Extract out the IP address address for UDP, TCP, and TLS, keeping
 	 * track of the number of IP addresses from each transport  */
 	numUDPSockets  = get_socket_list_from_proto(&UDPList,  PROTO_UDP);
 	numTCPSockets  = get_socket_list_from_proto(&TCPList,  PROTO_TCP);
 	numTLSSockets  = get_socket_list_from_proto(&TLSList,  PROTO_TLS);
+
+	numUDP6Sockets  = get_socket_list_from_proto_and_family(&UDP6List,  PROTO_UDP, AF_INET6);
+	numTCP6Sockets  = get_socket_list_from_proto_and_family(&TCP6List,  PROTO_TCP, AF_INET6);
+	numTLS6Sockets  = get_socket_list_from_proto_and_family(&TLS6List,  PROTO_TLS, AF_INET6);
+
 	/* Deliberately not looking at PROTO_WS or PROTO_WSS here as they are
 	   just upgraded TCP/TLS connections */
 
@@ -420,22 +460,38 @@ int get_total_bytes_waiting(void)
 	bytesWaiting  += get_used_waiting_queue(1, TCPList,  numTCPSockets);
 	bytesWaiting  += get_used_waiting_queue(1, TLSList,  numTLSSockets);
 
+	bytesWaiting  += get_used_waiting_queue(0, UDP6List,  numUDP6Sockets);
+	bytesWaiting  += get_used_waiting_queue(1, TCP6List,  numTCP6Sockets);
+	bytesWaiting  += get_used_waiting_queue(1, TLS6List,  numTLS6Sockets);
+
 	/* get_socket_list_from_proto() allocated a chunk of memory, so we need
 	 * to free it. */
 	if (numUDPSockets > 0)
 	{
 		pkg_free(UDPList);
 	}
+	if (numUDP6Sockets > 0)
+	{
+		pkg_free(UDP6List);
+	}
 
 	if (numTCPSockets > 0) 
 	{
 		pkg_free(TCPList);
 	}
+	if (numTCP6Sockets > 0) 
+	{
+		pkg_free(TCP6List);
+	}
 
 	if (numTLSSockets > 0)
 	{
 		pkg_free(TLSList);
 	}
+	if (numTLS6Sockets > 0)
+	{
+		pkg_free(TLS6List);
+	}
 
 	return bytesWaiting;
 }
diff --git a/lib/kcore/statistics.h b/lib/kcore/statistics.h
index 08bf20d..110f02c 100644
--- a/lib/kcore/statistics.h
+++ b/lib/kcore/statistics.h
@@ -40,6 +40,7 @@
 
 
 #define NUM_IP_OCTETS 4
+#define NUM_IPV6_OCTETS 16
 
 
 #ifdef STATISTICS
@@ -63,7 +64,7 @@ stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int in_codes);
 /*!
  * This function will retrieve a list of all ip addresses and ports that Kamailio
  * is listening on, with respect to the transport protocol specified with
- * 'protocol'. 
+ * 'protocol'. This function only returns IPv4 addresses.
  *
  * The first parameter, ipList, is a pointer to a pointer. It will be assigned a
  * new block of memory holding the IP Addresses and ports being listened to with
@@ -93,6 +94,13 @@ stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int in_codes);
  */
 int get_socket_list_from_proto(int **ipList, int protocol);
 
+/*! \brief Function to get a list of all IP addresses and ports in a specific
+ * family, like AF_INET or AF_INET6
+ *
+ * For documentation see \ref get_socket_list_from_proto()
+ */
+int get_socket_list_from_proto_and_family(int **ipList, int protocol, int family);
+
 
 /*!
  * Returns the sum of the number of bytes waiting to be consumed on all network
diff --git a/lib/srdb1/schema/acc_cdrs.xml b/lib/srdb1/schema/acc_cdrs.xml
new file mode 100644
index 0000000..22cba14
--- /dev/null
+++ b/lib/srdb1/schema/acc_cdrs.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE table PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN" 
+  "http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
+
+<!ENTITY % entities SYSTEM "entities.xml">
+%entities;
+
+]>
+
+<table id="acc_cdrs" xmlns:db="http://docbook.org/ns/docbook">
+    <name>acc_cdrs</name>
+    <version>1</version>
+    <type db="mysql">&MYSQL_TABLE_TYPE;</type>
+    <description>
+        <db:para>This table is used by the ACC module to report on CDRs relying on dialog callbacks. More information is available at: &KAMAILIO_MOD_DOC;acc.html
+        </db:para>
+    </description>
+
+    <column id="id">
+        <name>id</name>
+        <type>unsigned int</type>
+        <size>&table_id_len;</size>
+        <autoincrement/>
+        <primary/>
+        <type db="dbtext">int,auto</type>
+        <description>unique ID</description>
+    </column>
+
+	<column id="start_time">
+        <name>start_time</name>
+        <type>string</type>
+        <size>32</size>
+        <description>Start time</description>
+        <default/>
+    </column>
+
+    <column>
+        <name>end_time</name>
+        <type>string</type>
+        <size>32</size>
+        <description>End time</description>
+        <default/>
+    </column>
+
+    <column>
+        <name>duration</name>
+        <type>string</type>
+        <size>32</size>
+        <description>Duration</description>
+        <default/>
+    </column>
+
+    <index>
+        <name>start_time_idx</name>
+        <colref linkend="start_time"/>
+    </index>
+</table>
diff --git a/lib/srdb1/schema/dbaliases.xml b/lib/srdb1/schema/dbaliases.xml
index 04c2c03..12078e3 100644
--- a/lib/srdb1/schema/dbaliases.xml
+++ b/lib/srdb1/schema/dbaliases.xml
@@ -12,7 +12,10 @@
     <version>1</version>
     <type db="mysql">&MYSQL_TABLE_TYPE;</type>
     <description>
-        <db:para>This table us used by the alias_db module as an alternative for user aliases via userloc. More information about the alias_db module can be found at: &KAMAILIO_MOD_DOC;alias_db.html
+		<db:para>This table us used by the alias_db module as an
+			alternative for user aliases via userloc. More information
+			about the alias_db module can be found at:
+			&KAMAILIO_MOD_DOC;alias_db.html
         </db:para>
     </description>
 
@@ -61,10 +64,14 @@
     </column>
 
     <index>
+        <name>alias_user_idx</name>
+        <colref linkend="alias_username"/>
+    </index>
+
+    <index>
         <name>alias_idx</name>
         <colref linkend="alias_username"/>
         <colref linkend="alias_domain"/>
-        <unique/>
     </index>
 
     <index>
diff --git a/lib/srdb1/schema/entities.xml b/lib/srdb1/schema/entities.xml
index 2825157..526ac55 100644
--- a/lib/srdb1/schema/entities.xml
+++ b/lib/srdb1/schema/entities.xml
@@ -19,7 +19,7 @@
 <!ENTITY expires_len "11">
 <!ENTITY flag_len "11">
 <!ENTITY description_len "255">
-<!ENTITY MYSQL_TABLE_TYPE "MyISAM">
+<!ENTITY MYSQL_TABLE_TYPE "">
 <!ENTITY USERCOL "username">
 <!ENTITY DEFAULT_ALIASES_EXPIRES "2030-05-28 21:32:15">
 <!ENTITY DEFAULT_LOCATION_EXPIRES "2030-05-28 21:32:15">
diff --git a/lib/srdb1/schema/kamailio-acc.xml b/lib/srdb1/schema/kamailio-acc.xml
index 86ed8f0..eea6a06 100644
--- a/lib/srdb1/schema/kamailio-acc.xml
+++ b/lib/srdb1/schema/kamailio-acc.xml
@@ -10,5 +10,6 @@
 <database xmlns:xi="http://www.w3.org/2001/XInclude">
     <name>Accounting</name>
     <xi:include href="acc.xml"/>
+    <xi:include href="acc_cdrs.xml"/>
     <xi:include href="missed_calls.xml"/>
 </database>
diff --git a/lib/srdb1/schema/kamailio-mohqueue.xml b/lib/srdb1/schema/kamailio-mohqueue.xml
new file mode 100644
index 0000000..27d9a0d
--- /dev/null
+++ b/lib/srdb1/schema/kamailio-mohqueue.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE database PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN"
+  "http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
+
+<!ENTITY % entities SYSTEM "entities.xml">
+%entities;
+
+]>
+
+<database xmlns:xi="http://www.w3.org/2001/XInclude">
+    <name>mohqueue</name>
+    <xi:include href="mohqcalls.xml"/>
+    <xi:include href="mohqueues.xml"/>
+</database>
diff --git a/lib/srdb1/schema/kamailio-rtpproxy.xml b/lib/srdb1/schema/kamailio-rtpproxy.xml
new file mode 100644
index 0000000..50aadd2
--- /dev/null
+++ b/lib/srdb1/schema/kamailio-rtpproxy.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE database PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN"
+  "http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
+
+  <!ENTITY % entities SYSTEM "entities.xml">
+  %entities;
+]>
+
+<database xmlns:xi="http://www.w3.org/2001/XInclude">
+    <name>RTPProxy</name>
+    <xi:include href="rtpproxy.xml"/>
+</database>
diff --git a/lib/srdb1/schema/mohqcalls.xml b/lib/srdb1/schema/mohqcalls.xml
new file mode 100644
index 0000000..6c45c59
--- /dev/null
+++ b/lib/srdb1/schema/mohqcalls.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE table PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN" 
+  "http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
+
+<!ENTITY % entities SYSTEM "entities.xml">
+%entities;
+
+]>
+
+<table id="mohqcalls" xmlns:db="http://docbook.org/ns/docbook">
+  <name>mohqcalls</name>
+  <version>1</version>
+  <type db="mysql">&MYSQL_TABLE_TYPE;</type>
+  <description>
+    <db:para>This table is used by the mohqueue module to store call information. This is a read-only table from the viewpoint of outside processes. More information about the mohqueue module can be found at: &KAMAILIO_MOD_DOC;mohqueue.html
+    </db:para>
+  </description>
+
+  <column id="id">
+    <name>id</name>
+    <type>unsigned int</type>
+    <size>&table_id_len;</size>
+    <autoincrement/>
+    <primary/>
+    <type db="dbtext">int,auto</type>
+    <description>Unique ID</description>
+  </column>
+
+  <column id="mohq_id">
+    <name>mohq_id</name>
+    <type>unsigned int</type>
+    <size>&table_id_len;</size>
+    <description>queue id</description>
+  </column>
+
+  <column id="call_id">
+    <name>call_id</name>
+    <type>string</type>
+    <size>100</size>
+    <description>Call-ID header</description>
+  </column>
+
+  <column id="call_status">
+    <name>call_status</name>
+    <type>unsigned int</type>
+    <description>status of call</description>
+  </column>
+
+  <column id="call_from">
+    <name>call_from</name>
+    <type>string</type>
+    <size>100</size>
+    <description>From header</description>
+  </column>
+
+  <column id="call_contact">
+    <name>call_contact</name>
+    <type>string</type>
+    <size>100</size>
+    <null/>
+    <description>Contact header</description>
+  </column>
+
+  <column id="call_time">
+    <name>call_time</name>
+    <type>datetime</type>
+    <description>time when call first entered queue</description>
+  </column>
+
+  <index>
+    <name>mohqcalls_idx</name>
+    <colref linkend="call_id" />
+    <unique/>
+  </index>
+</table>
diff --git a/lib/srdb1/schema/mohqueues.xml b/lib/srdb1/schema/mohqueues.xml
new file mode 100644
index 0000000..168e1ca
--- /dev/null
+++ b/lib/srdb1/schema/mohqueues.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE table PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN" 
+  "http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
+
+<!ENTITY % entities SYSTEM "entities.xml">
+%entities;
+
+]>
+
+<table id="mohqueues" xmlns:db="http://docbook.org/ns/docbook">
+  <name>mohqueues</name>
+  <version>1</version>
+  <type db="mysql">&MYSQL_TABLE_TYPE;</type>
+  <description>
+    <db:para>This table is used by the mohqueue module to store queue definitions. This is a read-only table from the viewpoint of the module. More information about the mohqueue module can be found at: &KAMAILIO_MOD_DOC;mohqueue.html
+    </db:para>
+  </description>
+
+  <column id="id">
+    <name>id</name>
+    <type>unsigned int</type>
+    <size>&table_id_len;</size>
+    <autoincrement/>
+    <primary/>
+    <type db="dbtext">int,auto</type>
+    <description>Unique ID</description>
+  </column>
+
+  <column id="name">
+    <name>name</name>
+    <type>string</type>
+    <size>25</size>
+    <description>queue name</description>
+  </column>
+
+  <column id="uri">
+    <name>uri</name>
+    <type>string</type>
+    <size>100</size>
+    <description>URI for the queue</description>
+  </column>
+
+  <column id="mohdir">
+    <name>mohdir</name>
+    <type>string</type>
+    <size>100</size>
+    <null/>
+    <description>directory for MOH files</description>
+  </column>
+
+  <column id="mohfile">
+    <name>mohfile</name>
+    <type>string</type>
+    <size>100</size>
+    <description>base name for the MOH file</description>
+  </column>
+
+  <column id="debug">
+    <name>debug</name>
+    <type>int</type>
+    <description>debug flag</description>
+  </column>
+
+  <index>
+    <name>mohqueue_uri_idx</name>
+    <colref linkend="uri" />
+    <unique/>
+  </index>
+
+  <index>
+    <name>mohqueue_name_idx</name>
+    <colref linkend="name" />
+    <unique/>
+  </index>
+</table>
diff --git a/lib/srdb1/schema/rtpproxy.xml b/lib/srdb1/schema/rtpproxy.xml
new file mode 100644
index 0000000..bab9e0c
--- /dev/null
+++ b/lib/srdb1/schema/rtpproxy.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE table PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN" 
+  "http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
+
+<!ENTITY % entities SYSTEM "entities.xml">
+%entities;
+
+]>
+
+<table id="rtpproxy" xmlns:db="http://docbook.org/ns/docbook">
+    <name>rtpproxy</name>
+    <version>1</version>
+    <type db="mysql">&MYSQL_TABLE_TYPE;</type>
+    <description>
+        <db:para>This table is used by the rtpproxy module. It contains the sets of rtpproxy instances used for proxying media between endpoints. More information about the rtpproxy module can be found at: &KAMAILIO_MOD_DOC;rtpproxy.html
+        </db:para>
+    </description>
+
+    <column id="id">
+        <name>id</name>
+        <type>unsigned int</type>
+        <size>&table_id_len;</size>
+        <autoincrement/>
+        <primary/>
+        <type db="dbtext">int,auto</type>
+        <description>unique ID</description>
+    </column>
+
+    <column id="setid">
+        <name>setid</name>
+        <type>string</type>
+	<size>32</size>
+        <description>Set ID</description>
+        <default>00</default>
+    </column>
+
+    <column id="url">
+        <name>url</name>
+        <type>string</type>
+        <size>64</size>
+        <description>RTPProxy instance socket URL</description>
+        <default/>
+    </column>
+
+    <column id="flags">
+        <name>flags</name>
+        <type>int</type>
+        <description>Flags of the rtpproxy instance</description>
+        <default>0</default>
+        <natural/>
+    </column>
+
+    <column id="weight">
+        <name>weight</name>
+        <type>int</type>
+        <description>Weighting of this rtpproxy instance in the set</description>
+        <default>1</default>
+        <natural/>
+    </column>
+
+    <column>
+        <name>description</name>
+        <type>string</type>
+        <size>64</size>
+        <default/>
+        <description>Description for this instance</description>
+    </column>
+
+</table>
diff --git a/lvalue.c b/lvalue.c
index a89cfce..156e506 100644
--- a/lvalue.c
+++ b/lvalue.c
@@ -36,7 +36,16 @@
 #include "dprint.h"
 #include "route.h"
 
+/* callback to log assign actions */
+static log_assign_action_f _log_assign_action = NULL;
 
+/**
+ * @brief set callback function log assign actions
+ */
+void set_log_assign_action_cb(log_assign_action_f f)
+{
+	_log_assign_action = f;
+}
 
 /**
  * @brief eval rve and assign the result to an avp
@@ -255,7 +264,7 @@ inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
 		pv_get_null(msg, 0, &pval)
 	
 	destroy_pval=0;
-	pvar=&lv->lv.pvs;
+	pvar=lv->lv.pvs;
 	if (unlikely(!pv_is_w(pvar))){
 		ERR("read only pvar\n");
 		goto error;
@@ -406,6 +415,11 @@ int lval_assign(struct run_act_ctx* h, struct sip_msg* msg,
 			rve->fpos.s_line, rve->fpos.s_col,
 			rve->fpos.e_line, rve->fpos.e_col);
 	}
+	else
+	{
+		if(unlikely(_log_assign_action!=NULL))
+			_log_assign_action(msg, lv);
+	}
 	rval_destroy(rv);
 	return ret;
 error:
diff --git a/lvalue.h b/lvalue.h
index 566f84e..b5eccd4 100644
--- a/lvalue.h
+++ b/lvalue.h
@@ -35,7 +35,7 @@
 #include "action.h"
 
 union lval_u{
-	pv_spec_t pvs;
+	pv_spec_t *pvs;
 	avp_spec_t avps;
 };
 
@@ -51,7 +51,8 @@ struct lvalue{
 /* lval operators */
 #define EQ_T 254 /* k compatibility */
 
-
+typedef int (*log_assign_action_f)(struct sip_msg* msg, struct lvalue *lv);
+void set_log_assign_action_cb(log_assign_action_f f);
 
 /** eval rve and assign the result to lv
  * lv=eval(rve)
diff --git a/main.c b/main.c
index 31a31af..05d431e 100644
--- a/main.c
+++ b/main.c
@@ -145,6 +145,7 @@
 #include "script_cb.h"
 #include "nonsip_hooks.h"
 #include "ut.h"
+#include "events.h"
 #include "signals.h"
 #ifdef USE_RAW_SOCKS
 #include "raw_sock.h"
@@ -162,8 +163,7 @@
 #endif /* CORE_TLS */
 #endif /* USE_TCP */
 #ifdef USE_SCTP
-#include "sctp_options.h"
-#include "sctp_server.h"
+#include "sctp_core.h"
 #endif
 #include "usr_avp.h"
 #include "rpc_lookup.h"
@@ -383,8 +383,6 @@ int config_check = 0;
 int check_via =  0;
 /* translate user=phone URIs to TEL URIs */
 int phone2tel = 1;
-/* shall use stateful synonym branches? faster but not reboot-safe */
-int syn_branch = 1;
 /* debugging level for timer debugging */
 int timerlog = L_WARN;
 /* should replies include extensive warnings? by default no,
@@ -458,9 +456,7 @@ int mcast_ttl = -1; /* if -1, don't touch it, use the default (usually 1) */
 int tos = IPTOS_LOWDELAY;
 int pmtu_discovery = 0;
 
-#ifdef USE_IPV6
 int auto_bind_ipv6 = 0;
-#endif
 
 #if 0
 char* names[MAX_LISTEN];              /* our names */
@@ -504,15 +500,6 @@ unsigned short port_no=0; /* default port*/
 unsigned short tls_port_no=0; /* default port */
 #endif
 
-#ifdef USE_STUN
-/* refresh interval in miliseconds */
-unsigned int stun_refresh_interval=0;
-/* stun can be switch off even if it is compiled */
-int stun_allow_stun=1;
-/* use or don't use fingerprint */
-int stun_allow_fp=1;
-#endif
-
 struct host_alias* aliases=0; /* name aliases list */
 
 /* Parameter to child_init */
@@ -595,7 +582,7 @@ void cleanup(show_status)
 #endif /* USE_TLS */
 #endif /* USE_TCP */
 #ifdef USE_SCTP
-	destroy_sctp();
+	sctp_core_destroy();
 #endif
 	destroy_timer();
 	pv_destroy_api();
@@ -938,7 +925,7 @@ error:
 
 /* returns -1 on error, 0 on success
  * sets proto */
-static int parse_proto(unsigned char* s, long len, int* proto)
+int parse_proto(unsigned char* s, long len, int* proto)
 {
 #define PROTO2UINT3(a, b, c) ((	(((unsigned int)(a))<<16)+ \
 								(((unsigned int)(b))<<8)+  \
@@ -1459,11 +1446,9 @@ int main_loop(void)
 			if ((si->address.af==AF_INET)&&
 					((sendipv4==0)||(sendipv4->flags&(SI_IS_LO|SI_IS_MCAST))))
 				sendipv4=si;
-	#ifdef USE_IPV6
 			if ( ((sendipv6==0)||(sendipv6->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 					(si->address.af==AF_INET6))
 				sendipv6=si;
-	#endif
 			/* children_no per each socket */
 			cfg_register_child((si->workers>0)?si->workers:children_no);
 		}
@@ -1506,18 +1491,16 @@ int main_loop(void)
 #ifdef USE_SCTP
 		if (!sctp_disable){
 			for(si=sctp_listen; si; si=si->next){
-				if (sctp_init_sock(si)==-1)  goto error;
+				if (sctp_core_init_sock(si)==-1)  goto error;
 				/* get first ipv4/ipv6 socket*/
 				if ((si->address.af==AF_INET) &&
 						((sendipv4_sctp==0) ||
 							(sendipv4_sctp->flags&(SI_IS_LO|SI_IS_MCAST))))
 					sendipv4_sctp=si;
-		#ifdef USE_IPV6
 				if( ((sendipv6_sctp==0) || 
 							(sendipv6_sctp->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 						(si->address.af==AF_INET6))
 					sendipv6_sctp=si;
-		#endif
 				/* sctp_children_no per each socket */
 				cfg_register_child((si->workers>0)?si->workers:sctp_children_no);
 			}
@@ -1533,12 +1516,10 @@ int main_loop(void)
 						((sendipv4_tcp==0) ||
 							(sendipv4_tcp->flags&(SI_IS_LO|SI_IS_MCAST))))
 					sendipv4_tcp=si;
-		#ifdef USE_IPV6
 				if( ((sendipv6_tcp==0) ||
 							(sendipv6_tcp->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 						(si->address.af==AF_INET6))
 					sendipv6_tcp=si;
-		#endif
 			}
 			/* the number of sockets does not matter */
 			cfg_register_child(tcp_children_no + 1 /* tcp main */);
@@ -1553,12 +1534,10 @@ int main_loop(void)
 						((sendipv4_tls==0) ||
 							(sendipv4_tls->flags&(SI_IS_LO|SI_IS_MCAST))))
 					sendipv4_tls=si;
-		#ifdef USE_IPV6
 				if( ((sendipv6_tls==0) ||
 							(sendipv6_tls->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 						(si->address.af==AF_INET6))
 					sendipv6_tls=si;
-		#endif
 			}
 		}
 #endif /* USE_TLS */
@@ -1667,7 +1646,7 @@ int main_loop(void)
 #ifdef STATS
 						setstats( i+r*children_no );
 #endif
-						return sctp_rcv_loop();
+						return sctp_core_rcv_loop();
 					}
 				}
 			/*parent*/
@@ -1923,9 +1902,6 @@ int main(int argc, char** argv)
 #ifdef USE_TCP
 	init_tcp_options(); /* set the defaults before the config */
 #endif
-#ifdef USE_SCTP
-	init_sctp_options(); /* set defaults before the config */
-#endif
 	/* process command line (cfg. file path etc) */
 	optind = 1;  /* reset getopt */
 	/* switches required before script processing */
@@ -1963,12 +1939,6 @@ int main(int argc, char** argv)
 					printf("version: %s\n", full_version);
 					printf("flags: %s\n", ver_flags );
 					print_ct_constants();
-#ifdef USE_SCTP
-					tmp=malloc(256);
-					if (tmp && (sctp_check_compiled_sockopts(tmp, 256)!=0))
-						printf("sctp unsupported socket options: %s\n", tmp);
-					if (tmp) free(tmp);
-#endif
 					printf("id: %s\n", ver_id);
 					printf("compiled on %s with %s\n",
 							ver_compiled_time, ver_compiler );
@@ -2284,6 +2254,9 @@ try_again:
 	if (pv_reinit_buffer()<0)
 		goto error;
 
+	/* init lookup for core event routes */
+	sr_core_ert_init();
+
 	if (dont_fork_cnt)
 		dont_fork = dont_fork_cnt;	/* override by command line */
 
@@ -2303,7 +2276,7 @@ try_again:
 #ifdef USE_SCTP
 	if (sctp_disable!=1){
 		/* fix it */
-		if (sctp_check_support()==-1){
+		if (sctp_core_check_support()==-1){
 			/* check if sctp support is auto, if not warn about disabling it */
 			if (sctp_disable!=2){
 				fprintf(stderr, "ERROR: " "sctp enabled, but not supported by"
@@ -2424,12 +2397,6 @@ try_again:
 		goto error;
 	}
 #endif /* USE_TCP */
-#ifdef USE_SCTP
-	if (sctp_register_cfg()){
-		LOG(L_CRIT, "could not register the sctp configuration\n");
-		goto error;
-	}
-#endif /* USE_SCTP */
 	/*init timer, before parsing the cfg!*/
 	if (init_timer()<0){
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");
@@ -2475,7 +2442,7 @@ try_again:
 #endif /* USE_TCP */
 #ifdef USE_SCTP
 	if (!sctp_disable){
-		if (init_sctp()<0){
+		if (sctp_core_init()<0){
 			LOG(L_CRIT, "Could not initialize sctp, exiting...\n");
 			goto error;
 		}
diff --git a/mem/f_malloc.c b/mem/f_malloc.c
index 008874b..7a0e115 100644
--- a/mem/f_malloc.c
+++ b/mem/f_malloc.c
@@ -361,6 +361,8 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
 	MDBG("fm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
 			line);
 #endif
+	/*malloc(0) should return a valid pointer according to specs*/
+	if(unlikely(size==0)) size=4;
 	/*size must be a multiple of 8*/
 	size=ROUNDUP(size);
 /*	if (size>(qm->size-qm->real_used)) return 0; */
diff --git a/mem/q_malloc.c b/mem/q_malloc.c
index bfa46fd..50acab9 100644
--- a/mem/q_malloc.c
+++ b/mem/q_malloc.c
@@ -368,6 +368,8 @@ void* qm_malloc(struct qm_block* qm, unsigned long size)
 	MDBG("qm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
 			line);
 #endif
+	/*malloc(0) should return a valid pointer according to specs*/
+	if(unlikely(size==0)) size=4;
 	/*size must be a multiple of 8*/
 	size=ROUNDUP(size);
 	if (size>(qm->size-qm->real_used)) return 0;
diff --git a/modules/acc/README b/modules/acc/README
index 55bde38..f6b1c5c 100644
--- a/modules/acc/README
+++ b/modules/acc/README
@@ -125,6 +125,12 @@ Sven Knoblich
               6.42. cdr_start_id (string)
               6.43. cdr_end_id (string)
               6.44. cdr_duration_id (string)
+              6.45. cdr_log_enable (int)
+              6.46. cdrs_table (str)
+              6.47. time_mode (int)
+              6.48. time_attr (str)
+              6.49. time_exten (str)
+              6.50. time_format (str)
 
         7. Functions
 
@@ -181,10 +187,16 @@ Sven Knoblich
    1.42. cdr_start_id example
    1.43. cdr_end_id example
    1.44. cdr_duration_id example
-   1.45. acc_log_request usage
-   1.46. acc_db_request usage
-   1.47. acc_rad_request usage
-   1.48. acc_diam_request usage
+   1.45. cdr_log_enable example
+   1.46. cdrs_table example
+   1.47. time_mode example
+   1.48. time_attr example
+   1.49. time_exten example
+   1.50. time_format example
+   1.51. acc_log_request usage
+   1.52. acc_db_request usage
+   1.53. acc_rad_request usage
+   1.54. acc_diam_request usage
 
 Chapter 1. Admin Guide
 
@@ -273,6 +285,12 @@ Chapter 1. Admin Guide
         6.42. cdr_start_id (string)
         6.43. cdr_end_id (string)
         6.44. cdr_duration_id (string)
+        6.45. cdr_log_enable (int)
+        6.46. cdrs_table (str)
+        6.47. time_mode (int)
+        6.48. time_attr (str)
+        6.49. time_exten (str)
+        6.50. time_format (str)
 
    7. Functions
 
@@ -586,6 +604,7 @@ Note
 
 4.3.2.1. Example for a spiraled Proxy
 
+...
 # A calls B (transaction 1)
 $avp(caller)='A'
 $avp(callee)='B';
@@ -604,6 +623,7 @@ $dlg_var(chain)=$dlg_var(chain) + "|" + "C;cfnr;D";
 # C confirms call (200 reply of transaction 2)
 $dlg_var(caller) = $avp(caller); #caller='B'
 $dlg_var(callee) = $avp(callee); #callee='C'
+...
 
 4.3.3. Logged data
 
@@ -679,6 +699,12 @@ $dlg_var(callee) = $avp(callee); #callee='C'
    6.42. cdr_start_id (string)
    6.43. cdr_end_id (string)
    6.44. cdr_duration_id (string)
+   6.45. cdr_log_enable (int)
+   6.46. cdrs_table (str)
+   6.47. time_mode (int)
+   6.48. time_attr (str)
+   6.49. time_exten (str)
+   6.50. time_format (str)
 
 6.1. early_media (integer)
 
@@ -687,7 +713,9 @@ $dlg_var(callee) = $avp(callee); #callee='C'
    Default value is 0 (no).
 
    Example 1.1. early_media example
+...
 modparam("acc", "early_media", 1)
+...
 
 6.2. failed_transaction_flag (integer)
 
@@ -697,7 +725,9 @@ modparam("acc", "early_media", 1)
    Default value is not-set (no flag).
 
    Example 1.2. failed_transaction_flag example
+...
 modparam("acc", "failed_transaction_flag", 4)
+...
 
 6.3. failed_filter (string)
 
@@ -708,7 +738,9 @@ modparam("acc", "failed_transaction_flag", 4)
    Default value is not-set (failure filtering is off).
 
    Example 1.3. failed_filter example
+...
 modparam("acc", "failed_filter", "404,407")
+...
 
 6.4. report_ack (integer)
 
@@ -720,7 +752,9 @@ modparam("acc", "failed_filter", "404,407")
    Default value is 0 (no).
 
    Example 1.4. report_ack example
+...
 modparam("acc", "report_ack", 1)
+...
 
 6.5. report_cancels (integer)
 
@@ -731,7 +765,9 @@ modparam("acc", "report_ack", 1)
    Default value is 0 (no).
 
    Example 1.5. report_cancels example
+...
 modparam("acc", "report_cancels", 1)
+...
 
 6.6. detect_direction (integer)
 
@@ -746,7 +782,9 @@ modparam("acc", "report_cancels", 1)
    Default value is 0 (disabled).
 
    Example 1.6. detect_direction example
+...
 modparam("acc", "detect_direction", 1)
+...
 
 6.7. acc_prepare_flag (integer)
 
@@ -755,12 +793,14 @@ modparam("acc", "detect_direction", 1)
    failure_route). If this flag is not set and acc or missed_call flag are
    not set either in request route block, there is no way to mark the
    request for transaction later. If either acc or missed_call flags are
-   set in request route block, it is no need to set this flag.
+   set in request route block, there is no need to set this flag.
 
    Default value is not-set (no flag).
 
    Example 1.7. acc_prepare_flag example
+...
 modparam("acc", "acc_prepare_flag", 5)
+...
 
 6.8. multi_leg_info (string)
 
@@ -773,6 +813,7 @@ modparam("acc", "acc_prepare_flag", 5)
    Default value is 0 (disabled).
 
    Example 1.8. multi_leg_info example
+...
 # for syslog-based accounting, use any text you want to be printed
 modparam("acc", "multi_leg_info",
     "text1=$avp(src);text2=$avp(dst)")
@@ -785,6 +826,7 @@ modparam("acc", "multi_leg_info",
 # for DIAMETER-based accounting, use the DIAMETER AVP ID (as integer)
 modparam("acc", "multi_leg_info",
     "2345=$avp(src);2346=$avp(dst)")
+...
 
 6.9. log_flag (integer)
 
@@ -793,7 +835,9 @@ modparam("acc", "multi_leg_info",
    Default value is not-set (no flag).
 
    Example 1.9. log_flag example
+...
 modparam("acc", "log_flag", 2)
+...
 
 6.10. log_missed_flag (integer)
 
@@ -802,7 +846,9 @@ modparam("acc", "log_flag", 2)
    Default value is not-set (no flag).
 
    Example 1.10. log_missed_flag example
+...
 modparam("acc", "log_missed_flag", 3)
+...
 
 6.11. log_level (integer)
 
@@ -811,7 +857,9 @@ modparam("acc", "log_missed_flag", 3)
    Default value is L_NOTICE.
 
    Example 1.11. log_level example
+...
 modparam("acc", "log_level", 2)   # Set log_level to 2
+...
 
 6.12. log_facility (string)
 
@@ -822,7 +870,9 @@ modparam("acc", "log_level", 2)   # Set log_level to 2
    Default value is LOG_DAEMON.
 
    Example 1.12. log_facility example
+...
 modparam("acc", "log_facility", "LOG_DAEMON")
+...
 
 6.13. log_extra (string)
 
@@ -832,7 +882,9 @@ modparam("acc", "log_facility", "LOG_DAEMON")
    Default value is NULL.
 
    Example 1.13. log_extra example
+...
 modparam("acc", "log_extra", "ua=$hdr(User-Agent);uuid=$avp(i:123)")
+...
 
 6.14. radius_config (string)
 
@@ -848,7 +900,9 @@ modparam("acc", "log_extra", "ua=$hdr(User-Agent);uuid=$avp(i:123)")
    Default value is "NULL".
 
    Example 1.14. radius_config example
+...
 modparam("acc", "radius_config", "/etc/radiusclient/radiusclient.conf")
+...
 
 6.15. radius_flag (integer)
 
@@ -858,7 +912,9 @@ modparam("acc", "radius_config", "/etc/radiusclient/radiusclient.conf")
    Default value is not-set (no flag).
 
    Example 1.15. radius_flag example
+...
 modparam("acc", "radius_flag", 2)
+...
 
 6.16. radius_missed_flag (integer)
 
@@ -868,7 +924,9 @@ modparam("acc", "radius_flag", 2)
    Default value is not-set (no flag).
 
    Example 1.16. radius_missed_flag example
+...
 modparam("acc", "radius_missed_flag", 3)
+...
 
 6.17. service_type (integer)
 
@@ -877,7 +935,9 @@ modparam("acc", "radius_missed_flag", 3)
    Default value is 15 (SIP).
 
    Example 1.17. service_type example
+...
 modparam("acc", "service_type", 16)
+...
 
 6.18. radius_extra (string)
 
@@ -887,7 +947,9 @@ modparam("acc", "service_type", 16)
    Default value is NULL.
 
    Example 1.18. radius_extra example
+...
 modparam("acc", "radius_extra", "via=$hdr(Via[*]); email=$avp(s:email)")
+...
 
 6.19. db_flag (integer)
 
@@ -897,7 +959,9 @@ modparam("acc", "radius_extra", "via=$hdr(Via[*]); email=$avp(s:email)")
    Default value is not-set (no flag).
 
    Example 1.19. db_flag example
+...
 modparam("acc", "db_flag", 2)
+...
 
 6.20. db_missed_flag (integer)
 
@@ -907,7 +971,9 @@ modparam("acc", "db_flag", 2)
    Default value is not-set (no flag).
 
    Example 1.20. db_missed_flag example
+...
 modparam("acc", "db_missed_flag", 3)
+...
 
 6.21. db_table_acc (string)
 
@@ -917,8 +983,10 @@ modparam("acc", "db_missed_flag", 3)
    Default value is "acc"
 
    Example 1.21. db_table_acc example
+...
 modparam("acc", "db_table_acc", "myacc_table")
 modparam("acc", "db_table_acc", "acc_$time(year)_$time(mon)")
+...
 
 6.22. db_table_missed_calls (string)
 
@@ -928,7 +996,9 @@ modparam("acc", "db_table_acc", "acc_$time(year)_$time(mon)")
    Default value is "missed_calls"
 
    Example 1.22. db_table_missed_calls example
+...
 modparam("acc", "db_table_missed_calls", "myMC_table")
+...
 
 6.23. db_url (string)
 
@@ -938,7 +1008,9 @@ modparam("acc", "db_table_missed_calls", "myMC_table")
    Default value is "NULL" (SQL disabled).
 
    Example 1.23. db_url example
-modparam("acc", "db_url", "mysql://user:password@localhost/openser")
+...
+modparam("acc", "db_url", "mysql://user:password@localhost/kamailio")
+...
 
 6.24. acc_method_column (string)
 
@@ -948,7 +1020,9 @@ modparam("acc", "db_url", "mysql://user:password@localhost/openser")
    Default value is "method".
 
    Example 1.24. acc_method_column example
+...
 modparam("acc", "acc_method_column", "method")
+...
 
 6.25. acc_from_tag_column (string)
 
@@ -957,7 +1031,9 @@ modparam("acc", "acc_method_column", "method")
    Default value is "from_tag".
 
    Example 1.25. acc_from_tag_column example
+...
 modparam("acc", "acc_from_tag_column", "from_tag")
+...
 
 6.26. acc_to_tag_column (string)
 
@@ -966,7 +1042,9 @@ modparam("acc", "acc_from_tag_column", "from_tag")
    Default value is "to_tag".
 
    Example 1.26. acc_to_tag_column example
+...
 modparam("acc", "acc_to_tag_column", "to_tag")
+...
 
 6.27. acc_callid_column (string)
 
@@ -975,7 +1053,9 @@ modparam("acc", "acc_to_tag_column", "to_tag")
    Default value is "callid".
 
    Example 1.27. acc_callid_column example
+...
 modparam("acc", "acc_callid_column", "callid")
+...
 
 6.28. acc_sip_code_column (string)
 
@@ -985,7 +1065,9 @@ modparam("acc", "acc_callid_column", "callid")
    Default value is "sip_code".
 
    Example 1.28. acc_sip_code_column example
+...
 modparam("acc", "acc_sip_code_column", "sip_code")
+...
 
 6.29. acc_sip_reason_column (string)
 
@@ -995,7 +1077,9 @@ modparam("acc", "acc_sip_code_column", "sip_code")
    Default value is "sip_reason".
 
    Example 1.29. acc_sip_reason_column example
+...
 modparam("acc", "acc_sip_reason_column", "sip_reason")
+...
 
 6.30. acc_time_column (string)
 
@@ -1005,7 +1089,9 @@ modparam("acc", "acc_sip_reason_column", "sip_reason")
    Default value is "time".
 
    Example 1.30. acc_time_column example
+...
 modparam("acc", "acc_time_column", "time")
+...
 
 6.31. db_extra (string)
 
@@ -1015,7 +1101,9 @@ modparam("acc", "acc_time_column", "time")
    Default value is NULL.
 
    Example 1.31. db_extra example
+...
 modparam("acc", "db_extra", "ct=$hdr(Content-type); email=$avp(s:email)")
+...
 
 6.32. db_insert_mode (integer)
 
@@ -1026,7 +1114,9 @@ modparam("acc", "db_extra", "ct=$hdr(Content-type); email=$avp(s:email)")
    Default value is 0 (no INSERT DELAYED).
 
    Example 1.32. db_insert_mode example
+...
 modparam("acc", "db_insert_mode", 1)
+...
 
 6.33. diameter_flag (integer)
 
@@ -1036,7 +1126,9 @@ modparam("acc", "db_insert_mode", 1)
    Default value is not-set (no flag).
 
    Example 1.33. diameter_flag example
+...
 modparam("acc", "diameter_flag", 2)
+...
 
 6.34. diameter_missed_flag (integer)
 
@@ -1046,7 +1138,9 @@ modparam("acc", "diameter_flag", 2)
    Default value is not-set (no flag).
 
    Example 1.34. diameter_missed_flag example
+...
 modparam("acc", "diameter_missed_flag", 3)
+...
 
 6.35. diameter_client_host (string)
 
@@ -1056,7 +1150,9 @@ modparam("acc", "diameter_missed_flag", 3)
    Default value is "localhost".
 
    Example 1.35. diameter_client_host example
+...
 modparam("acc", "diameter_client_host", "3a_server.net")
+...
 
 6.36. diameter_client_port (int)
 
@@ -1066,7 +1162,9 @@ modparam("acc", "diameter_client_host", "3a_server.net")
    Default value is 3000.
 
    Example 1.36. diameter_client_host example
+...
 modparam("acc", "diameter_client_port", 3000)
+...
 
 6.37. diameter_extra (string)
 
@@ -1076,16 +1174,20 @@ modparam("acc", "diameter_client_port", 3000)
    Default value is NULL.
 
    Example 1.37. diameter_extra example
+...
 modparam("acc", "diameter_extra", "7846=$hdr(Content-type);7847=$avp(s:email)")
+...
 
 6.38. cdr_enable (integer)
 
    Should CDR-based logging be enabled?
 
-   0 - off (default) 1 - on
+   0 - off (default). 1 - on.
 
    Example 1.38. cdr_enable example
+...
 modparam("acc", "cdr_enable", 1)
+...
 
 6.39. cdr_start_on_confirmed (integer)
 
@@ -1096,7 +1198,9 @@ modparam("acc", "cdr_enable", 1)
    confirmation.
 
    Example 1.39. cdr_start_on_confirmed example
+...
 modparam("acc", "cdr_start_on_confirmed", 1)
+...
 
 6.40. cdr_facility (integer)
 
@@ -1106,7 +1210,9 @@ modparam("acc", "cdr_start_on_confirmed", 1)
    Default value is LOG_DAEMON.
 
    Example 1.40. cdr_facility example
+...
 modparam("acc", "cdr_facility", "LOG_DAEMON")
+...
 
 6.41. cdr_extra (string)
 
@@ -1116,34 +1222,127 @@ modparam("acc", "cdr_facility", "LOG_DAEMON")
    Default value is NULL.
 
    Example 1.41. cdr_extra example
+...
 modparam("acc", "cdr_extra", "c1=$dlg_var(caller);c2=$dlg_var(callee)"
+...
 
 6.42. cdr_start_id (string)
 
-   Modifying the start id which is used to store the start time.
+   Modifying the id which is used to store the start time.
 
-   Default value is 'st'
+   Default value is 'start_time'
 
    Example 1.42. cdr_start_id example
+...
 modparam("acc", "cdr_start_id", "start")
+...
 
 6.43. cdr_end_id (string)
 
-   Modifying the end id which is used to store the end time.
+   Modifying the id which is used to store the end time.
 
-   Default value is 'et'
+   Default value is 'end_time'
 
    Example 1.43. cdr_end_id example
+...
 modparam("acc", "cdr_end_id", "end")
+...
 
 6.44. cdr_duration_id (string)
 
-   Modifying the duration id which is used to store the duration.
+   Modify the id which is used to store the duration.
 
-   Default value is 'd'
+   Default value is 'duration'
 
    Example 1.44. cdr_duration_id example
-modparam("acc", "cdr_duration_id", "start")
+...
+modparam("acc", "cdr_duration_id", "d")
+...
+
+6.45. cdr_log_enable (int)
+
+   Control if CDR-based accounting should be written to syslog.
+
+   0 - off. 1 - on (default).
+
+   Example 1.45. cdr_log_enable example
+...
+modparam("acc", "cdr_log_enable", 0)
+...
+
+6.46. cdrs_table (str)
+
+   Name of db table to store dialog-based CDRs.
+
+   Default value is "" (no db storage for dialog-based CDRs).
+
+   Example 1.46. cdrs_table example
+...
+modparam("acc", "cdrs_table", "acc_cdrs")
+...
+
+6.47. time_mode (int)
+
+   Store additional value related to the time of event.
+
+   Values can be:
+     * 0 - (default), save only unix timestamp for syslog and datetime for
+       database.
+     * 1 - save seconds in time_attr and microseconds in time_exten.
+     * 2 - save seconds.miliseconds in time_attr.
+     * 3 - save formatted time according to time_format parameter, using
+       the output of localtime().
+     * 4 - save formatted time according to time_format parameter, using
+       the output of gmtime().
+
+   Example 1.47. time_mode example
+...
+modparam("acc", "time_mode", 1)
+...
+
+6.48. time_attr (str)
+
+   Name of the syslog attribute or database column where to store
+   additional value related to the time of event.
+
+   For db accounting, the column has to be of different types, depending
+   on time_mode value. When time_mode is:
+     * 1 - time_attr column has to be int.
+     * 2 - time_attr column has to be double.
+     * 3 - time_attr column has to be varchar(128).
+     * 4 - time_attr column has to be varchar(128).
+
+   For time_mode=1, this attribute is not written in syslog, because time
+   value is already unix timestamp, but in db accounting time value is
+   datetime and requires a function to get the timestamp.
+
+   Example 1.48. time_attr example
+...
+modparam("acc", "time_attr", "seconds")
+...
+
+6.49. time_exten (str)
+
+   Name of the syslog attribute or database column where to store extended
+   value related to the time of event.
+
+   It is used now only for time_mode=1 and database column has to be int:
+
+   Example 1.49. time_exten example
+...
+modparam("acc", "time_exten", "micorsecs")
+...
+
+6.50. time_format (str)
+
+   Specify the format to print the time for time_mode 3 or 4.
+
+   Default value is %Y-%m-%d %H:%M:%S".
+
+   Example 1.50. time_format example
+...
+modparam("acc", "time_format", "%Y/%m/%d %H:%M:%S")
+...
 
 7. Functions
 
@@ -1164,7 +1363,7 @@ modparam("acc", "cdr_duration_id", "start")
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.45. acc_log_request usage
+   Example 1.51. acc_log_request usage
 ...
 acc_log_request("Some comment");
 ...
@@ -1182,7 +1381,7 @@ acc_log_request("Some comment");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.46. acc_db_request usage
+   Example 1.52. acc_db_request usage
 ...
 acc_db_request("Some comment", "SomeTable");
 acc_db_request("Some comment", "acc_$time(year)_$time(mon)");
@@ -1198,7 +1397,7 @@ acc_db_request("Some comment", "acc_$time(year)_$time(mon)");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.47. acc_rad_request usage
+   Example 1.53. acc_rad_request usage
 ...
 acc_rad_request("Some comment");
 ...
@@ -1213,7 +1412,7 @@ acc_rad_request("Some comment");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.48. acc_diam_request usage
+   Example 1.54. acc_diam_request usage
 ...
 acc_diam_request("Some comment");
 ...
diff --git a/modules/acc/acc.c b/modules/acc/acc.c
index 0a563d6..efaebc0 100644
--- a/modules/acc/acc.c
+++ b/modules/acc/acc.c
@@ -75,6 +75,7 @@
 extern struct acc_extra *log_extra;
 extern struct acc_extra *leg_info;
 extern struct acc_enviroment acc_env;
+extern char *acc_time_format;
 
 #ifdef RAD_ACC
 extern struct acc_extra *rad_extra;
@@ -90,14 +91,17 @@ extern struct acc_extra *dia_extra;
 static db_func_t acc_dbf;
 static db1_con_t* db_handle=0;
 extern struct acc_extra *db_extra;
-extern int acc_db_insert_mode;
 #endif
 
 /* arrays used to collect the values before being
- * pushed to the storage backend (whatever used) */
-static str val_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
-static int int_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
-static char type_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG];
+ * pushed to the storage backend (whatever used)
+ * (3 = datetime + max 2 from time_mode) */
+static str val_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG+3];
+static int int_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG+3];
+static char type_arr[ACC_CORE_LEN+MAX_ACC_EXTRA+MAX_ACC_LEG+3];
+
+#define ACC_TIME_FORMAT_SIZE	128
+static char acc_time_format_buf[ACC_TIME_FORMAT_SIZE];
 
 /********************************************
  *        acc CORE function
@@ -173,7 +177,9 @@ int core2strar(struct sip_msg *req, str *c_vals, int *i_vals, char *t_vals)
 	c_vals[5] = acc_env.reason;
 	t_vals[5] = TYPE_STR;
 
-	acc_env.ts = time(NULL);
+	gettimeofday(&acc_env.tv, NULL);
+	acc_env.ts = acc_env.tv.tv_sec;
+
 	return ACC_CORE_LEN;
 }
 
@@ -224,6 +230,7 @@ int acc_log_request( struct sip_msg *rq)
 	int n;
 	int m;
 	int i;
+	struct tm *t;
 
 	/* get default values */
 	m = core2strar( rq, val_arr, int_arr, type_arr);
@@ -275,8 +282,38 @@ int acc_log_request( struct sip_msg *rq)
 	*(p++) = '\n';
 	*(p++) = 0;
 
-	LM_GEN2(log_facility, log_level, "%.*stimestamp=%lu%s",
-		acc_env.text.len, acc_env.text.s,(unsigned long) acc_env.ts, log_msg);
+	if(acc_time_mode==1) {
+		LM_GEN2(log_facility, log_level, "%.*stimestamp=%lu;%s=%u%s",
+			acc_env.text.len, acc_env.text.s,(unsigned long)acc_env.ts,
+			acc_time_exten.s, (unsigned int)acc_env.tv.tv_usec,
+			log_msg);
+	} else if(acc_time_mode==2) {
+		LM_GEN2(log_facility, log_level, "%.*stimestamp=%lu;%s=%.3f%s",
+			acc_env.text.len, acc_env.text.s,(unsigned long)acc_env.ts,
+			acc_time_attr.s,
+			(((double)(acc_env.tv.tv_sec * 1000)
+							+ (acc_env.tv.tv_usec / 1000)) / 1000),
+			log_msg);
+	} else if(acc_time_mode==3 || acc_time_mode==4) {
+		if(acc_time_mode==3) {
+			t = localtime(&acc_env.ts);
+		} else {
+			t = gmtime(&acc_env.ts);
+		}
+		if(strftime(acc_time_format_buf, ACC_TIME_FORMAT_SIZE,
+					acc_time_format, t)<0) {
+			acc_time_format_buf[0] = '\0';
+		}
+		LM_GEN2(log_facility, log_level, "%.*stimestamp=%lu;%s=%s%s",
+			acc_env.text.len, acc_env.text.s,(unsigned long)acc_env.ts,
+			acc_time_attr.s,
+			acc_time_format_buf,
+			log_msg);
+	} else {
+		LM_GEN2(log_facility, log_level, "%.*stimestamp=%lu%s",
+			acc_env.text.len, acc_env.text.s,(unsigned long)acc_env.ts,
+			log_msg);
+	}
 
 	return 1;
 }
@@ -288,11 +325,20 @@ int acc_log_request( struct sip_msg *rq)
 
 #ifdef SQL_ACC
 
-/* caution: keys need to be aligned to core format */
-static db_key_t db_keys[ACC_CORE_LEN+1+MAX_ACC_EXTRA+MAX_ACC_LEG];
-static db_val_t db_vals[ACC_CORE_LEN+1+MAX_ACC_EXTRA+MAX_ACC_LEG];
+/* caution: keys need to be aligned to core format
+ * (3 = datetime + max 2 from time_mode) */
+static db_key_t db_keys[ACC_CORE_LEN+3+MAX_ACC_EXTRA+MAX_ACC_LEG];
+static db_val_t db_vals[ACC_CORE_LEN+3+MAX_ACC_EXTRA+MAX_ACC_LEG];
 
 
+int acc_get_db_handlers(void **vf, void **vh) {
+	if(db_handle==0)
+		return -1;
+	*vf = (void*)&acc_dbf;
+	*vh = (void*)db_handle;
+	return 0;
+}
+
 static void acc_db_init_keys(void)
 {
 	struct acc_extra *extra;
@@ -311,6 +357,13 @@ static void acc_db_init_keys(void)
 	db_keys[n++] = &acc_sipreason_col;
 	db_keys[n++] = &acc_time_col;
 	time_idx = n-1;
+	if(acc_time_mode==1 || acc_time_mode==2
+			|| acc_time_mode==3 || acc_time_mode==4) {
+		db_keys[n++] = &acc_time_attr;
+		if(acc_time_mode==1) {
+			db_keys[n++] = &acc_time_exten;
+		}
+	}
 
 	/* init the extra db keys */
 	for(extra=db_extra; extra ; extra=extra->next)
@@ -326,6 +379,14 @@ static void acc_db_init_keys(void)
 		VAL_NULL(db_vals+i)=0;
 	}
 	VAL_TYPE(db_vals+time_idx)=DB1_DATETIME;
+	if(acc_time_mode==1) {
+		VAL_TYPE(db_vals+time_idx+1)=DB1_INT;
+		VAL_TYPE(db_vals+time_idx+2)=DB1_INT;
+	} else if(acc_time_mode==2) {
+		VAL_TYPE(db_vals+time_idx+1)=DB1_DOUBLE;
+	} else if(acc_time_mode==3 || acc_time_mode==4) {
+		VAL_TYPE(db_vals+time_idx+1)=DB1_STRING;
+	}
 }
 
 
@@ -376,6 +437,7 @@ int acc_db_request( struct sip_msg *rq)
 	int m;
 	int n;
 	int i;
+	struct tm *t;
 
 	/* formated database columns */
 	m = core2strar( rq, val_arr, int_arr, type_arr );
@@ -384,6 +446,29 @@ int acc_db_request( struct sip_msg *rq)
 		VAL_STR(db_vals+i) = val_arr[i];
 	/* time value */
 	VAL_TIME(db_vals+(m++)) = acc_env.ts;
+	/* extra time value */
+	if(acc_time_mode==1) {
+		VAL_INT(db_vals+(m++)) = (int)acc_env.tv.tv_sec;
+		i++;
+		VAL_INT(db_vals+(m++)) = (int)acc_env.tv.tv_usec;
+		i++;
+	} else if(acc_time_mode==2) {
+		VAL_DOUBLE(db_vals+(m++)) = ((double)(acc_env.tv.tv_sec * 1000)
+							+ (acc_env.tv.tv_usec / 1000)) / 1000;
+		i++;
+	} else if(acc_time_mode==3 || acc_time_mode==4) {
+		if(acc_time_mode==3) {
+			t = localtime(&acc_env.ts);
+		} else {
+			t = gmtime(&acc_env.ts);
+		}
+		if(strftime(acc_time_format_buf, ACC_TIME_FORMAT_SIZE,
+					acc_time_format, t)<0) {
+			acc_time_format_buf[0] = '\0';
+		}
+		VAL_STRING(db_vals+(m++)) = acc_time_format_buf;
+		i++;
+	}
 
 	/* extra columns */
 	m += extra2strar( db_extra, rq, val_arr+m, int_arr+m, type_arr+m);
diff --git a/modules/acc/acc.h b/modules/acc/acc.h
index ef9a922..12acf98 100644
--- a/modules/acc/acc.h
+++ b/modules/acc/acc.h
@@ -92,6 +92,7 @@ int  acc_db_init(const str* db_url);
 int  acc_db_init_child(const str* db_url);
 void acc_db_close(void);
 int  acc_db_request( struct sip_msg *req);
+int acc_get_db_handlers(void **vf, void **vh);
 #endif
 
 #ifdef RAD_ACC
diff --git a/modules/acc/acc_api.h b/modules/acc/acc_api.h
index bc52eee..aa51380 100644
--- a/modules/acc/acc_api.h
+++ b/modules/acc/acc_api.h
@@ -36,6 +36,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <sys/time.h>
 
 #include "../../str.h"
 #include "../../dprint.h"
@@ -57,6 +58,7 @@ typedef struct acc_enviroment {
 	struct hdr_field *to;
 	str text;
 	time_t ts;
+	struct timeval tv;
 } acc_enviroment_t;
 
 /* acc extra parameter */
@@ -104,7 +106,7 @@ typedef struct acc_engine {
 
 #define MAX_ACC_EXTRA 64
 #define MAX_ACC_LEG   16
-#define ACC_CORE_LEN 6
+#define ACC_CORE_LEN  6
 
 
 enum {TYPE_NULL = 0, TYPE_INT, TYPE_STR};
diff --git a/modules/acc/acc_cdr.c b/modules/acc/acc_cdr.c
index 996ebf4..68792e9 100644
--- a/modules/acc/acc_cdr.c
+++ b/modules/acc/acc_cdr.c
@@ -45,6 +45,10 @@
 #include "acc_extra.h"
 #include "acc.h"
 
+#ifdef SQL_ACC
+#include "../../lib/srdb1/db.h"
+#endif
+
 #include <sys/time.h>
 
 /* Solaris does not provide timersub macro in <sys/time.h> */
@@ -75,13 +79,15 @@ static const str empty_string = { "", 0};
 // buffers which are used to collect the crd data for writing
 static str cdr_attrs[ MAX_CDR_CORE + MAX_CDR_EXTRA];
 static str cdr_value_array[ MAX_CDR_CORE + MAX_CDR_EXTRA];
-static int cdr_int_arr[ MAX_CDR_CORE + MAX_CDR_EXTRA];
+static int cdr_int_array[ MAX_CDR_CORE + MAX_CDR_EXTRA];
 static char cdr_type_array[ MAX_CDR_CORE + MAX_CDR_EXTRA];
 
 extern struct tm_binds tmb;
 extern str cdr_start_str;
 extern str cdr_end_str;
 extern str cdr_duration_str;
+extern str acc_cdrs_table;
+extern int cdr_log_enable;
 
 /* write all basic information to buffers(e.g. start-time ...) */
 static int cdr_core2strar( struct dlg_cell* dlg,
@@ -115,8 +121,81 @@ static int cdr_core2strar( struct dlg_cell* dlg,
     return MAX_CDR_CORE;
 }
 
+#ifdef SQL_ACC
+/* caution: keys need to be aligned to core format */
+static db_key_t db_cdr_keys[ MAX_CDR_CORE + MAX_CDR_EXTRA];
+static db_val_t db_cdr_vals[ MAX_CDR_CORE + MAX_CDR_EXTRA];
+
 /* collect all crd data and write it to a syslog */
-static int write_cdr( struct dlg_cell* dialog,
+static int db_write_cdr( struct dlg_cell* dialog,
+                      struct sip_msg* message)
+{
+	int m = 0;
+	int i;
+	db_func_t *df=NULL;
+	db1_con_t *dh=NULL;
+	void *vf=NULL;
+	void *vh=NULL;
+
+	if(acc_cdrs_table.len<=0)
+		return 0;
+
+	if(acc_get_db_handlers(&vf, &vh)<0) {
+		LM_ERR("cannot get db handlers\n");
+		return -1;
+	}
+	df = (db_func_t*)vf;
+	dh = (db1_con_t*)vh;
+
+	/* get default values */
+	m = cdr_core2strar( dialog,
+						cdr_value_array,
+						cdr_int_array,
+						cdr_type_array);
+
+	for(i=0; i<m; i++) {
+		db_cdr_keys[i] = &cdr_attrs[i];
+		VAL_TYPE(db_cdr_vals+i)=DB1_STR;
+		VAL_NULL(db_cdr_vals+i)=0;
+		VAL_STR(db_cdr_vals+i) = cdr_value_array[i];
+	}
+
+    /* get extra values */
+	m += extra2strar( cdr_extra,
+						message,
+						cdr_value_array + m,
+						cdr_int_array + m,
+						cdr_type_array + m);
+	for( ; i<m; i++) {
+		db_cdr_keys[i] = &cdr_attrs[i];
+		VAL_TYPE(db_cdr_vals+i)=DB1_STR;
+		VAL_NULL(db_cdr_vals+i)=0;
+		VAL_STR(db_cdr_vals+i) = cdr_value_array[i];
+	}
+
+	if (df->use_table(dh, &acc_cdrs_table /*table*/) < 0) {
+		LM_ERR("error in use_table\n");
+		return -1;
+	}
+
+	if(acc_db_insert_mode==1 && df->insert_delayed!=NULL) {
+		if (df->insert_delayed(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
+			LM_ERR("failed to insert delayed into database\n");
+			return -1;
+		}
+	} else {
+		if (df->insert(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
+			LM_ERR("failed to insert into database\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+#endif
+
+/* collect all crd data and write it to a syslog */
+static int log_write_cdr( struct dlg_cell* dialog,
                       struct sip_msg* message)
 {
     static char cdr_message[ MAX_SYSLOG_SIZE];
@@ -127,23 +206,20 @@ static int write_cdr( struct dlg_cell* dialog,
     int message_index = 0;
     int counter = 0;
 
-    if( !dialog || !message)
-    {
-        LM_ERR( "dialog and/or message is/are empty!");
-        return -1;
-    }
+	if(cdr_log_enable==0)
+		return 0;
 
     /* get default values */
     message_index = cdr_core2strar( dialog,
                                     cdr_value_array,
-                                    cdr_int_arr,
+                                    cdr_int_array,
                                     cdr_type_array);
 
     /* get extra values */
     message_index += extra2strar( cdr_extra,
                                   message,
                                   cdr_value_array + message_index,
-                                  cdr_int_arr + message_index,
+                                  cdr_int_array + message_index,
                                   cdr_type_array + message_index);
 
     for( counter = 0, message_position = cdr_message;
@@ -194,6 +270,23 @@ static int write_cdr( struct dlg_cell* dialog,
     return 0;
 }
 
+/* collect all crd data and write it to a syslog */
+static int write_cdr( struct dlg_cell* dialog,
+                      struct sip_msg* message)
+{
+	int ret = 0;
+    if( !dialog || !message)
+    {
+        LM_ERR( "dialog or message is empty!");
+        return -1;
+    }
+	ret = log_write_cdr(dialog, message);
+#ifdef SQL_ACC
+	ret |= db_write_cdr(dialog, message);
+#endif
+	return ret;
+}
+
 /* convert a string into a timeval struct */
 static int string2time( str* time_str, struct timeval* time_value)
 {    
@@ -495,7 +588,7 @@ static void cdr_on_end( struct dlg_cell* dialog,
     }
 }
 
-/* callback for a expired dialog. */
+/* callback for an expired dialog. */
 static void cdr_on_expired( struct dlg_cell* dialog,
                             int type,
                             struct dlg_cb_params* params)
diff --git a/modules/acc/acc_logic.c b/modules/acc/acc_logic.c
index c9bdd20..50278fb 100644
--- a/modules/acc/acc_logic.c
+++ b/modules/acc/acc_logic.c
@@ -197,8 +197,7 @@ int acc_db_set_table_name(struct sip_msg *msg, void *param, str *table)
 			return -1;
 		}
 		strncpy(db_table_name_buf, dbtable.s, dbtable.len);
-                /* FS#327: since the buffer is static terminate the table name */
-                db_table_name_buf[dbtable.len] = '\0';
+		db_table_name_buf[dbtable.len] = '\0';
 		env_set_text(db_table_name_buf, dbtable.len);
 	} else {
 		if(table==NULL) {
diff --git a/modules/acc/acc_mod.c b/modules/acc/acc_mod.c
index 9f40e14..2fb9258 100644
--- a/modules/acc/acc_mod.c
+++ b/modules/acc/acc_mod.c
@@ -109,7 +109,17 @@ unsigned short failed_filter[MAX_FAILED_FILTER_COUNT + 1];
 static char* leg_info_str = 0;	/*!< multi call-leg support */
 struct acc_extra *leg_info = 0;
 int acc_prepare_flag = -1; /*!< should the request be prepared for later acc */
+char *acc_time_format = "%Y-%m-%d %H:%M:%S";
 
+/* ----- time mode variables ------- */
+/*! \name AccTimeModeVariables  Time Mode Variables */
+/*@{*/
+
+int acc_time_mode  = 0;
+str acc_time_attr  = str_init("time_attr");
+str acc_time_exten  = str_init("time_exten");
+
+/*@}*/
 
 /* ----- SYSLOG acc variables ----------- */
 /*! \name AccSyslogVariables  Syslog Variables */
@@ -130,15 +140,18 @@ struct acc_extra *log_extra = 0; /*!< Log extra attributes */
 /*@{*/
 
 int cdr_enable  = 0;
+int cdr_log_enable  = 1;
 int cdr_start_on_confirmed = 0;
 static char* cdr_facility_str = 0;
 static char* cdr_log_extra_str = 0;
 
-str cdr_start_str = str_init("st");
-str cdr_end_str = str_init("et");
-str cdr_duration_str = str_init("d");
+str cdr_start_str = str_init("start_time");
+str cdr_end_str = str_init("end_time");
+str cdr_duration_str = str_init("duration");
+/* name for db table to store dialog-based cdrs */
+str acc_cdrs_table = str_init("");
 
-/*@{*/
+/*@}*/
 
 /* ----- RADIUS acc variables ----------- */
 /*! \name AccRadiusVariables  Radius Variables */     
@@ -253,6 +266,7 @@ static param_export_t params[] = {
 	{"log_extra",            STR_PARAM, &log_extra_str        },
 	/* cdr specific */
 	{"cdr_enable",           INT_PARAM, &cdr_enable                 },
+	{"cdr_log_enable",         INT_PARAM, &cdr_log_enable           },
 	{"cdr_start_on_confirmed", INT_PARAM, &cdr_start_on_confirmed   },
 	{"cdr_facility",         STR_PARAM, &cdr_facility_str           },
 	{"cdr_extra",            STR_PARAM, &cdr_log_extra_str          },
@@ -291,6 +305,12 @@ static param_export_t params[] = {
 	{"acc_time_column",      STR_PARAM, &acc_time_col.s       },
 	{"db_insert_mode",       INT_PARAM, &acc_db_insert_mode   },
 #endif
+	/* time-mode-specific */
+	{"time_mode",            INT_PARAM, &acc_time_mode        },
+	{"time_attr",            PARAM_STR, &acc_time_attr        },
+	{"time_exten",           PARAM_STR, &acc_time_exten       },
+	{"cdrs_table",           PARAM_STR, &acc_cdrs_table       },
+	{"time_format",          STR_PARAM, &acc_time_format      },
 	{0,0,0}
 };
 
diff --git a/modules/acc/acc_mod.h b/modules/acc/acc_mod.h
index 5e7792a..98cef33 100644
--- a/modules/acc/acc_mod.h
+++ b/modules/acc/acc_mod.h
@@ -92,7 +92,14 @@ extern str acc_cseqno_col;
 extern str acc_sipcode_col;
 extern str acc_sipreason_col;
 extern str acc_time_col;
+
+extern int acc_db_insert_mode;
 #endif /* SQL_ACC */
 
+/* time mode */
+extern int acc_time_mode;
+extern str acc_time_attr;
+extern str acc_time_exten;
+
 
 #endif
diff --git a/modules/acc/doc/acc_admin.xml b/modules/acc/doc/acc_admin.xml
index a60ba34..97858be 100644
--- a/modules/acc/doc/acc_admin.xml
+++ b/modules/acc/doc/acc_admin.xml
@@ -373,7 +373,7 @@ if (uri=~"sip:+40") /* calls to Romania */ {
 						cdr_extra_definition = cdr_log_name '=' pseudo_variable
 						</emphasis></para></listitem>
 					</itemizedlist>
-					See also <xref linkend="cdr_extra"/>.
+					See also <xref linkend="acc.p.cdr_extra"/>.
 					<para>
 					The full list of supported pseudo-variables in Sip-Router is
 					available at:
@@ -415,6 +415,7 @@ if (uri=~"sip:+40") /* calls to Romania */ {
 				<section>
 					<title>Example for a spiraled Proxy</title>
 					<programlisting format="linespecific">
+...
 # A calls B (transaction 1)
 $avp(caller)='A'
 $avp(callee)='B';
@@ -433,6 +434,7 @@ $dlg_var(chain)=$dlg_var(chain) + "|" + "C;cfnr;D";
 # C confirms call (200 reply of transaction 2)
 $dlg_var(caller) = $avp(caller); #caller='B'
 $dlg_var(callee) = $avp(callee); #callee='C'
+...
 					</programlisting>
 				</section>
 			</section>
@@ -493,7 +495,7 @@ $dlg_var(callee) = $avp(callee); #callee='C'
 	<section id="ACC-param-id">
 	<title>Parameters</title>
 	<!-- Generic ACC parameters -->
-	<section>
+	<section id="acc.p.early_media">
 		<title><varname>early_media</varname> (integer)</title>
 		<para>
 		Should be early media (any provisional reply with body) accounted too ?
@@ -504,11 +506,13 @@ $dlg_var(callee) = $avp(callee); #callee='C'
 		<example>
 		<title>early_media example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "early_media", 1)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.failed_transaction_flag">
 		<title><varname>failed_transaction_flag</varname> (integer)</title>
 		<para>
 		Per transaction flag which says if the transaction should be 
@@ -520,11 +524,13 @@ modparam("acc", "early_media", 1)
 		<example>
 		<title>failed_transaction_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "failed_transaction_flag", 4)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.failed_filter">
 		<title><varname>failed_filter</varname> (string)</title>
 		<para>
 		A string of failure response codes from 300 to 999
@@ -538,11 +544,13 @@ modparam("acc", "failed_transaction_flag", 4)
 		<example>
 		<title>failed_filter example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "failed_filter", "404,407")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.report_ack">
 		<title><varname>report_ack</varname> (integer)</title>
 		<para>
 		Shall acc attempt to account e2e ACKs too ? Note that this is really 
@@ -556,11 +564,13 @@ modparam("acc", "failed_filter", "404,407")
 		<example>
 		<title>report_ack example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "report_ack", 1)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.report_cancels">
 		<title><varname>report_cancels</varname> (integer)</title>
 		<para>
 		By default, CANCEL reporting is disabled -- most accounting
@@ -573,11 +583,13 @@ modparam("acc", "report_ack", 1)
 		<example>
 		<title>report_cancels example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "report_cancels", 1)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.detect_direction">
 		<title><varname>detect_direction</varname> (integer)</title>
 		<para>
 		Controlles the direction detection for sequential requests. If 
@@ -595,11 +607,13 @@ modparam("acc", "report_cancels", 1)
 		<example>
 		<title>detect_direction example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "detect_direction", 1)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.acc_prepare_flag">
 		<title><varname>acc_prepare_flag</varname> (integer)</title>
 		<para>
 		Per transaction flag which says if the transaction may be accounted
@@ -607,7 +621,7 @@ modparam("acc", "detect_direction", 1)
 		failure_route). If this flag is not set and acc or missed_call flag
 		are not set either in request route block, there is no way to mark the
 		request for transaction later. If either acc or missed_call flags are
-		set in request route block, it is no need to set this flag.
+		set in request route block, there is no need to set this flag.
 		</para>
 		<para>
 		Default value is not-set (no flag).
@@ -615,11 +629,13 @@ modparam("acc", "detect_direction", 1)
 		<example>
 		<title>acc_prepare_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_prepare_flag", 5)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.multi_leg_info">
 		<title><varname>multi_leg_info</varname> (string)</title>
 		<para>
 		Defines the AVP set to be used in per-call-leg accounting.
@@ -635,6 +651,7 @@ modparam("acc", "acc_prepare_flag", 5)
 		<example>
 		<title>multi_leg_info example</title>
 		<programlisting format="linespecific">
+...
 # for syslog-based accounting, use any text you want to be printed
 modparam("acc", "multi_leg_info",
     "text1=$avp(src);text2=$avp(dst)")
@@ -647,11 +664,12 @@ modparam("acc", "multi_leg_info",
 # for DIAMETER-based accounting, use the DIAMETER AVP ID (as integer)
 modparam("acc", "multi_leg_info",
     "2345=$avp(src);2346=$avp(dst)")
+...
 </programlisting>
 		</example>
 	</section>
 	<!-- SYSLOG specific ACC parameters -->
-	<section>
+	<section id="acc.p.log_flag">
 		<title><varname>log_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account a transaction via syslog.
@@ -662,11 +680,13 @@ modparam("acc", "multi_leg_info",
 		<example>
 		<title>log_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "log_flag", 2)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.log_missed_flag">
 		<title><varname>log_missed_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account missed calls via syslog.
@@ -677,11 +697,13 @@ modparam("acc", "log_flag", 2)
 		<example>
 		<title>log_missed_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "log_missed_flag", 3)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.log_level">
 		<title><varname>log_level</varname> (integer)</title>
 		<para>
 		Log level at which accounting messages are issued to syslog.
@@ -692,11 +714,13 @@ modparam("acc", "log_missed_flag", 3)
 		<example>
 		<title>log_level example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "log_level", 2)   # Set log_level to 2
+...
 </programlisting>
 		</example>
 	</section>
-		<section>
+	<section id="acc.p.log_facility">
 		<title><varname>log_facility</varname> (string)</title>
 		<para>
 		Log facility to which accounting messages are issued to syslog.
@@ -709,11 +733,13 @@ modparam("acc", "log_level", 2)   # Set log_level to 2
 		<example>
 		<title>log_facility example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "log_facility", "LOG_DAEMON")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.log_extra">
 		<title><varname>log_extra</varname> (string)</title>
 		<para>
 		Extra values to be logged.
@@ -725,12 +751,14 @@ modparam("acc", "log_facility", "LOG_DAEMON")
 		<example>
 		<title>log_extra example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "log_extra", "ua=$hdr(User-Agent);uuid=$avp(i:123)")
+...
 </programlisting>
 		</example>
 	</section>
 	<!-- RADIUS specific ACC parameters -->
-	<section>
+	<section id="acc.p.radius_config">
 		<title><varname>radius_config</varname> (string)</title>
 		<para>
 		<emphasis>This parameter is radius specific.</emphasis> Path to 
@@ -750,11 +778,13 @@ modparam("acc", "log_extra", "ua=$hdr(User-Agent);uuid=$avp(i:123)")
 		<example>
 		<title>radius_config example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "radius_config", "/etc/radiusclient/radiusclient.conf")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section  id="acc.p.radius_flag">
 		<title><varname>radius_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account a 
@@ -766,11 +796,13 @@ modparam("acc", "radius_config", "/etc/radiusclient/radiusclient.conf")
 		<example>
 		<title>radius_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "radius_flag", 2)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.radius_missed_flag">
 		<title><varname>radius_missed_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account missed 
@@ -782,11 +814,13 @@ modparam("acc", "radius_flag", 2)
 		<example>
 		<title>radius_missed_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "radius_missed_flag", 3)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.service_type">
 		<title><varname>service_type</varname> (integer)</title>
 		<para>
 		Radius service type used for accounting.
@@ -797,11 +831,13 @@ modparam("acc", "radius_missed_flag", 3)
 		<example>
 		<title>service_type example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "service_type", 16)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.radius_extra">
 		<title><varname>radius_extra</varname> (string)</title>
 		<para>
 		Extra values to be logged via RADIUS - RADIUS specific.
@@ -813,12 +849,14 @@ modparam("acc", "service_type", 16)
 		<example>
 		<title>radius_extra example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "radius_extra", "via=$hdr(Via[*]); email=$avp(s:email)")
+...
 </programlisting>
 		</example>
 	</section>
 	<!-- SQL specific ACC parameters -->
-	<section>
+	<section id="acc.p.db_flag">
 		<title><varname>db_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account a 
@@ -830,11 +868,13 @@ modparam("acc", "radius_extra", "via=$hdr(Via[*]); email=$avp(s:email)")
 		<example>
 		<title>db_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "db_flag", 2)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.db_missed_flag">
 		<title><varname>db_missed_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account missed 
@@ -846,11 +886,13 @@ modparam("acc", "db_flag", 2)
 		<example>
 		<title>db_missed_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "db_missed_flag", 3)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section  id="acc.p.db_table_acc">
 		<title><varname>db_table_acc</varname> (string)</title>
 		<para>
 		Table name of accounting successfull calls -- database specific. It
@@ -862,12 +904,14 @@ modparam("acc", "db_missed_flag", 3)
 		<example>
 		<title>db_table_acc example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "db_table_acc", "myacc_table")
 modparam("acc", "db_table_acc", "acc_$time(year)_$time(mon)")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.db_table_missed_calls">
 		<title><varname>db_table_missed_calls</varname> (string)</title>
 		<para>
 		Table name for accounting missed calls -- database specific. It
@@ -879,11 +923,13 @@ modparam("acc", "db_table_acc", "acc_$time(year)_$time(mon)")
 		<example>
 		<title>db_table_missed_calls example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "db_table_missed_calls", "myMC_table")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.db_url">
 		<title><varname>db_url</varname> (string)</title>
 		<para>
 		SQL address -- database specific. If is set to NULL or emty string,
@@ -895,11 +941,13 @@ modparam("acc", "db_table_missed_calls", "myMC_table")
 		<example>
 		<title>db_url example</title>
 		<programlisting format="linespecific">
-modparam("acc", "db_url", "mysql://user:password@localhost/openser")
+...
+modparam("acc", "db_url", "mysql://user:password@localhost/kamailio")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section  id="acc.p.acc_method_column">
 		<title><varname>acc_method_column</varname> (string)</title>
 		<para>
 		Column name in accounting table to store the request's method name as
@@ -911,11 +959,13 @@ modparam("acc", "db_url", "mysql://user:password@localhost/openser")
 		<example>
 		<title>acc_method_column example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_method_column", "method")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.acc_from_tag_column">
 		<title><varname>acc_from_tag_column</varname> (string)</title>
 		<para>
 		Column name in accounting table to store the From header TAG parameter.
@@ -926,11 +976,13 @@ modparam("acc", "acc_method_column", "method")
 		<example>
 		<title>acc_from_tag_column example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_from_tag_column", "from_tag")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.acc_to_tag_column">
 		<title><varname>acc_to_tag_column</varname> (string)</title>
 		<para>
 		Column name in accounting table to store the To header TAG parameter.
@@ -941,11 +993,13 @@ modparam("acc", "acc_from_tag_column", "from_tag")
 		<example>
 		<title>acc_to_tag_column example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_to_tag_column", "to_tag")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.acc_callid_column">
 		<title><varname>acc_callid_column</varname> (string)</title>
 		<para>
 		Column name in accounting table to store the request's Callid value.
@@ -956,11 +1010,13 @@ modparam("acc", "acc_to_tag_column", "to_tag")
 		<example>
 		<title>acc_callid_column example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_callid_column", "callid")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.acc_sip_code_column">
 		<title><varname>acc_sip_code_column</varname> (string)</title>
 		<para>
 		Column name in accounting table to store the final reply's numric code
@@ -972,11 +1028,13 @@ modparam("acc", "acc_callid_column", "callid")
 		<example>
 		<title>acc_sip_code_column example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_sip_code_column", "sip_code")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.acc_sip_reason_column">
 		<title><varname>acc_sip_reason_column</varname> (string)</title>
 		<para>
 		Column name in accounting table to store the final reply's reason
@@ -988,11 +1046,13 @@ modparam("acc", "acc_sip_code_column", "sip_code")
 		<example>
 		<title>acc_sip_reason_column example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_sip_reason_column", "sip_reason")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.acc_time_column">
 		<title><varname>acc_time_column</varname> (string)</title>
 		<para>
 		Column name in accounting table to store the time stamp of the 
@@ -1004,11 +1064,13 @@ modparam("acc", "acc_sip_reason_column", "sip_reason")
 		<example>
 		<title>acc_time_column example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "acc_time_column", "time")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.db_extra">
 		<title><varname>db_extra</varname> (string)</title>
 		<para>
 		Extra values to be logged into database - DB specific.
@@ -1020,11 +1082,13 @@ modparam("acc", "acc_time_column", "time")
 		<example>
 		<title>db_extra example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "db_extra", "ct=$hdr(Content-type); email=$avp(s:email)")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.db_insert_mode">
 		<title><varname>db_insert_mode</varname> (integer)</title>
 		<para>
 		If set to 1, use INSERT DELAYED to add records to accounting tables
@@ -1037,12 +1101,14 @@ modparam("acc", "db_extra", "ct=$hdr(Content-type); email=$avp(s:email)")
 		<example>
 		<title>db_insert_mode example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "db_insert_mode", 1)
+...
 </programlisting>
 		</example>
 	</section>
 	<!-- DIAMETER specific ACC parameters -->
-	<section>
+	<section id="acc.p.diameter_flag">
 		<title><varname>diameter_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account a 
@@ -1054,11 +1120,13 @@ modparam("acc", "db_insert_mode", 1)
 		<example>
 		<title>diameter_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "diameter_flag", 2)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.diameter_missed_flag">
 		<title><varname>diameter_missed_flag</varname> (integer)</title>
 		<para>
 		Request flag which needs to be set to account missed 
@@ -1070,11 +1138,13 @@ modparam("acc", "diameter_flag", 2)
 		<example>
 		<title>diameter_missed_flag example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "diameter_missed_flag", 3)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.diameter_client_host">
 		<title><varname>diameter_client_host</varname> (string)</title>
 		<para>
 		Hostname of the machine where the DIAMETER Client is 
@@ -1086,11 +1156,13 @@ modparam("acc", "diameter_missed_flag", 3)
 		<example>
 		<title>diameter_client_host example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "diameter_client_host", "3a_server.net")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.diameter_client_port">
 		<title><varname>diameter_client_port</varname> (int)</title>
 		<para>
 		Port number where the Diameter Client is 
@@ -1102,11 +1174,13 @@ modparam("acc", "diameter_client_host", "3a_server.net")
 		<example>
 		<title>diameter_client_host example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "diameter_client_port", 3000)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.diameter_extra">
 		<title><varname>diameter_extra</varname> (string)</title>
 		<para>
 		Extra values to be logged via DIAMETER - DIAMETER specific.
@@ -1118,31 +1192,35 @@ modparam("acc", "diameter_client_port", 3000)
 		<example>
 		<title>diameter_extra example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "diameter_extra", "7846=$hdr(Content-type);7847=$avp(s:email)")
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.cdr_enable">
 		<title><varname>cdr_enable</varname> (integer)</title>
 		<para>
 		Should CDR-based logging be enabled?
 		</para>
 		<para>
-		0 - off (default)
-		1 - on
+		0 - off (default).
+		1 - on.
 		</para>
 		<example>
 		<title>cdr_enable example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "cdr_enable", 1)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.cdr_start_on_confirmed">
 		<title><varname>cdr_start_on_confirmed</varname> (integer)</title>
 		<para>
 		Should the start time be taken from the time when the dialog is created,
-        or when the dialog is confirmed?
+        	or when the dialog is confirmed?
 		</para>
 		<para>
 		0 - use time of dialog creation (default).
@@ -1151,11 +1229,13 @@ modparam("acc", "cdr_enable", 1)
 		<example>
 		<title>cdr_start_on_confirmed example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "cdr_start_on_confirmed", 1)
+...
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="acc.p.cdr_facility">
 		<title><varname>cdr_facility</varname> (integer)</title>
 		<para>
 		Log facility to which CDR messages are issued to syslog.
@@ -1168,11 +1248,13 @@ modparam("acc", "cdr_start_on_confirmed", 1)
 		<example>
 		<title>cdr_facility example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "cdr_facility", "LOG_DAEMON")
+...
 </programlisting>
 		</example>
 	</section>
-	<section id="cdr_extra">
+	<section id="acc.p.cdr_extra">
 		<title><varname>cdr_extra</varname> (string)</title>
 		<para>
 		Set of pseudo-variables defining custom CDR fields. See
@@ -1184,52 +1266,210 @@ modparam("acc", "cdr_facility", "LOG_DAEMON")
 		<example>
 		<title>cdr_extra example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "cdr_extra", "c1=$dlg_var(caller);c2=$dlg_var(callee)"
+...
 </programlisting>
 		</example>
 	</section>
-	<section id="cdr_start_id">
+	<section id="acc.p.cdr_start_id">
 		<title><varname>cdr_start_id</varname> (string)</title>
 		<para>
-		Modifying the start id which is used to store the start time.
+		Modifying the id which is used to store the start time.
 		</para>
 		<para>
-		Default value is 'st'
+		Default value is 'start_time'
 		</para>
 		<example>
 		<title>cdr_start_id example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "cdr_start_id", "start")
+...
 </programlisting>
 		</example>
 	</section>
-	<section id="cdr_end_id">
+	<section id="acc.p.cdr_end_id">
 		<title><varname>cdr_end_id</varname> (string)</title>
 		<para>
-		Modifying the end id which is used to store the end time.
+		Modifying the id which is used to store the end time.
 		</para>
 		<para>
-		Default value is 'et'
+		Default value is 'end_time'
 		</para>
 		<example>
 		<title>cdr_end_id example</title>
 		<programlisting format="linespecific">
+...
 modparam("acc", "cdr_end_id", "end")
+...
 </programlisting>
 		</example>
 	</section>
-		<section id="cdr_duration_id">
+	<section id="acc.p.cdr_duration_id">
 		<title><varname>cdr_duration_id</varname> (string)</title>
 		<para>
-		Modifying the duration id which is used to store the duration.
+		Modify the id which is used to store the duration.
 		</para>
 		<para>
-		Default value is 'd'
+		Default value is 'duration'
 		</para>
 		<example>
 		<title>cdr_duration_id example</title>
 		<programlisting format="linespecific">
-modparam("acc", "cdr_duration_id", "start")
+...
+modparam("acc", "cdr_duration_id", "d")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="acc.p.cdr_log_enable">
+		<title><varname>cdr_log_enable</varname> (int)</title>
+		<para>
+		Control if CDR-based accounting should be written to syslog.
+		</para>
+		<para>
+		0 - off.
+		1 - on (default).
+		</para>
+		<example>
+		<title>cdr_log_enable example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc", "cdr_log_enable", 0)
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="acc.p.cdrs_table">
+		<title><varname>cdrs_table</varname> (str)</title>
+		<para>
+		Name of db table to store dialog-based CDRs.
+		</para>
+		<para>
+		Default value is "" (no db storage for dialog-based CDRs).
+		</para>
+		<example>
+		<title>cdrs_table example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc", "cdrs_table", "acc_cdrs")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="acc.p.time_mode">
+		<title><varname>time_mode</varname> (int)</title>
+		<para>
+		Store additional value related to the time of event.
+		</para>
+		<para>
+		Values can be:
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>0</emphasis> -  (default), save only unix
+				timestamp for syslog and datetime for database.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>1</emphasis> - save seconds in time_attr and
+				microseconds in time_exten.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>2</emphasis> - save seconds.miliseconds
+				in time_attr.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>3</emphasis> - save formatted time according
+				to time_format parameter, using the output of localtime().
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>4</emphasis> - save formatted time according
+				to time_format parameter, using the output of gmtime().
+			</para>
+		</listitem>
+		</itemizedlist>
+
+		<example>
+		<title>time_mode example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc", "time_mode", 1)
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="acc.p.time_attr">
+		<title><varname>time_attr</varname> (str)</title>
+		<para>
+		Name of the syslog attribute or database column where to store additional
+		value related to the time of event.
+		</para>
+		<para>
+		For db accounting, the column has to be of different types, depending on
+		time_mode value. When time_mode is:
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>1</emphasis> - time_attr column has to be int.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>2</emphasis> - time_attr column has to be double.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>3</emphasis> - time_attr column has to be varchar(128).</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>4</emphasis> - time_attr column has to be varchar(128).</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		For time_mode=1, this attribute is not written in syslog, because time
+		value is already unix timestamp, but in db accounting time value is
+		datetime and requires a function to get the timestamp.
+		</para>
+		<example>
+		<title>time_attr example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc", "time_attr", "seconds")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="acc.p.time_exten">
+		<title><varname>time_exten</varname> (str)</title>
+		<para>
+		Name of the syslog attribute or database column where to store extended
+		value related to the time of event.
+		</para>
+		<para>
+		It is used now only for time_mode=1 and database column has to be int:
+		</para>
+		<example>
+		<title>time_exten example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc", "time_exten", "micorsecs")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="acc.p.time_format">
+		<title><varname>time_format</varname> (str)</title>
+		<para>
+		Specify the format to print the time for time_mode 3 or 4.
+		</para>
+		<para>
+		Default value is %Y-%m-%d %H:%M:%S".
+		</para>
+		<example>
+		<title>time_format example</title>
+		<programlisting format="linespecific">
+...
+modparam("acc", "time_format", "%Y/%m/%d %H:%M:%S")
+...
 </programlisting>
 		</example>
 	</section>
diff --git a/modules/acc_radius/acc_radius_mod.c b/modules/acc_radius/acc_radius_mod.c
index 07f39ff..11f3115 100644
--- a/modules/acc_radius/acc_radius_mod.c
+++ b/modules/acc_radius/acc_radius_mod.c
@@ -125,8 +125,10 @@ struct module_exports exports= {
 
 static int mod_init( void )
 {
-	if (radius_config==NULL || radius_config[0]=='\0')
-		return 0;
+	if (radius_config==NULL || radius_config[0]=='\0') {
+		LM_ERR("radius config file not set\n");
+		return -1;
+	}
 	
 	/* bind the ACC API */
 	if (acc_load_api(&accb)<0) {
diff --git a/modules/alias_db/README b/modules/alias_db/README
index 8a802cd..43fb904 100644
--- a/modules/alias_db/README
+++ b/modules/alias_db/README
@@ -126,7 +126,7 @@ Chapter 1. Admin Guide
 
    Database URL.
 
-   Default value is "mysql://kamailioro:kamailioro@localhost/kamailio".
+   Default value is "mysql://openserro:openserro@localhost/openser".
 
    Example 1.1. Set db_url parameter
 ...
diff --git a/modules/alias_db/alookup.c b/modules/alias_db/alookup.c
index 9aff3d8..4437549 100644
--- a/modules/alias_db/alookup.c
+++ b/modules/alias_db/alookup.c
@@ -202,7 +202,7 @@ int alias_db_lookup(struct sip_msg* _msg, str table_s)
 		} else {
 			user_s.s = useruri_buf;
 			if (append_branch(_msg, &user_s, 0, 0, MIN_Q, 0, 0,
-					  0, 0) == -1)
+					  0, 0, 0, 0) == -1)
 			{
 				LM_ERR("error while appending branches\n");
 				goto err_server;
diff --git a/modules/app_java/BUILDING_JAR.TXT b/modules/app_java/BUILDING_JAR.TXT
new file mode 100644
index 0000000..61eb724
--- /dev/null
+++ b/modules/app_java/BUILDING_JAR.TXT
@@ -0,0 +1,54 @@
+
+Prerequistites:
+1) Java JDK (either openjdk or oracle's)
+2) GNU Java Compiler (gcj)
+3) Apache ANT (http://ant.apache.org/)
+
+Build process:
+
+1) Open Kamailio.java with any text editor and change (if differs) a FULL PATH to app_java.so :
+   Example:
+        static
+        {
+            System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+        }
+
+2) Type: ant
+   Example: ant
+Buildfile: /opt/dev/kamailio/modules/app_java/build.xml
+
+clean:
+   [delete] Deleting directory /opt/dev/kamailio/modules/app_java/build
+   [delete] Deleting: /opt/dev/kamailio/modules/app_java/Kamailio.class
+
+make.dirs:
+    [mkdir] Created dir: /opt/dev/kamailio/modules/app_java/build
+
+siprouter_compile:
+    [javac] Compiling 4 source files to /opt/dev/kamailio/modules/app_java/build
+
+kamailio.jar:
+      [jar] Building jar: /opt/dev/kamailio/modules/app_java/kamailio.jar
+
+main_compile:
+    [javac] Compiling 1 source file to /opt/dev/kamailio/modules/app_java
+
+all:
+     [echo] Building Kamailio examples
+
+BUILD SUCCESSFUL
+Total time: 4 seconds
+
+3) If no errors, copy file kamailio.jar into 'java' directory (see file app_java.mod)
+4) Copy file Kamailio.class to 'java' folder.
+5) Enjoy! :)
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/app_java/Makefile b/modules/app_java/Makefile
new file mode 100644
index 0000000..6a95251
--- /dev/null
+++ b/modules/app_java/Makefile
@@ -0,0 +1,35 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=app_java.so
+
+#DEFS += -DEXTRA_DEBUG
+
+DIST = $(shell if [ -f "/etc/redhat-release" ]; then cat /etc/redhat-release | sed "s/.*\([0-9]\)\.[0-9].*/\1/g"; fi)
+ifeq ($(DIST),6)
+JVM_PATH = $(shell dirname `find /usr/lib/jvm/java/ -name "libjvm.so"`)
+DEFS += $(shell pkg-config libgcj-4.4 --cflags)
+LIBS += $(shell pkg-config libgcj-4.4 --cflags) -L$(JVM_PATH) -ljvm
+else
+# for now is hard coded, will resolve this later
+JAVA_HOME ?= /usr/lib/jvm/java-gcj-4.7
+DEFS += $(shell pkg-config libgcj-4.7 --cflags) -I$(JAVA_HOME)/include
+LIBS += $(shell pkg-config libgcj-4.7 --libs) -L$(JAVA_HOME)/lib  -ljvm
+
+ifeq ($(OS), freebsd)
+LIBS+=-pthread
+endif
+endif
+
+# disable optimisation for segfaults debugging
+INCLUDE += -O0 -g
+INCLUDES += -O0 -g
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+include ../../Makefile.modules
+
diff --git a/modules/app_java/QUICKSTART.TXT b/modules/app_java/QUICKSTART.TXT
new file mode 100644
index 0000000..3864af0
--- /dev/null
+++ b/modules/app_java/QUICKSTART.TXT
@@ -0,0 +1,25 @@
+
+Quick start:
+----------------------
+1) Supposed that kamailio home folder is '/opt/kamailio' (I'll use a term '<KAM_HOME>')
+2) mkdir <KAM_HOME>/java (I'll use a term <KAM_JAVA_HOME>)
+3) copy kamailio.jar to <KAM_JAVA_HOME>
+4) copy Kamailio.class to <KAM_JAVA_HOME>
+5) add to kamailio configuration file:
+
+loadmodule "app_java.so"
+modparam("app_java", "class_name", "Kamailio")
+modparam("app_java", "child_init_method", "child_init")
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=<KAM_HOME>/lib/kamailio/modules:<KAM_JAVA_HOME>:<KAM_JAVA_HOME>/kamailio.jar  -verbose:gc,jni")
+
+# This parameter forces execution a kamailio comnmand with java native method KamExec.
+# Note: this is an untested feature, may cause (but may not) a memory leaks if used from embedded languages.
+modparam("app_java", "force_cmd_exec", 1);
+
+
+
+Rebulding java stuff:
+----------------------
+
+For re-building kamailio.jar see: BUILD_JAR.TXT
+
diff --git a/modules/app_java/README b/modules/app_java/README
new file mode 100644
index 0000000..5bbad0b
--- /dev/null
+++ b/modules/app_java/README
@@ -0,0 +1,573 @@
+app_java Module
+
+Konstantin Mosesov
+
+Edited by
+
+Konstantin Mosesov
+
+   Copyright © 2013 Konstantin Mosesov
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Java runtime
+
+              3.1.
+
+        4. Parameters
+
+              4.1. class_name (string)
+              4.2. child_init_method (string)
+              4.3. java_options (string)
+              4.4. force_cmd_exec (int)
+
+        5. Functions
+
+              5.1. Common requirements
+              5.2. java_method_exec(method, method_signature, [param1[,
+                      param2[, ...]]])
+
+              5.3. java_staticmethod_exec(method, method_signature,
+                      [param1[, param2[, ...]]])
+
+              5.4. java_s_method_exec(method, method_signature, [param1[,
+                      param2[, ...]]])
+
+              5.5. java_s_staticmethod_exec(method, method_signature,
+                      [param1[, param2[, ...]]])
+
+        6. Java Module API
+
+              6.1. Minimal program skeleton
+
+   List of Examples
+
+   1.1. Set class_name parameter
+   1.2. Set child_init_method parameter
+   1.3. Set java_options parameter
+   1.4. Set java_options parameter (live configuration)
+   1.5. Set java_options parameter (verbose configuration)
+   1.6. Set java_options parameter (debug configuration)
+   1.7. Set force_cmd_exec parameter
+   1.8. Signature: "V"
+   1.9. Signature: "Ljava/lang/String;I"
+   1.10. Signature: "ZB"
+   1.11. Signature: "V"
+   1.12. Signature: "Ljava/lang/String;I"
+   1.13. Signature: "ZB"
+   1.14. Signature: "V"
+   1.15. Signature: "Ljava/lang/String;I"
+   1.16. Signature: "ZB"
+   1.17. Signature: "V"
+   1.18. Signature: "Ljava/lang/String;I"
+   1.19. Signature: "ZB"
+   1.20. Minimal program skeleton
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Java runtime
+
+        3.1.
+
+   4. Parameters
+
+        4.1. class_name (string)
+        4.2. child_init_method (string)
+        4.3. java_options (string)
+        4.4. force_cmd_exec (int)
+
+   5. Functions
+
+        5.1. Common requirements
+        5.2. java_method_exec(method, method_signature, [param1[, param2[,
+                ...]]])
+
+        5.3. java_staticmethod_exec(method, method_signature, [param1[,
+                param2[, ...]]])
+
+        5.4. java_s_method_exec(method, method_signature, [param1[,
+                param2[, ...]]])
+
+        5.5. java_s_staticmethod_exec(method, method_signature, [param1[,
+                param2[, ...]]])
+
+   6. Java Module API
+
+        6.1. Minimal program skeleton
+
+1. Overview
+
+   This module allows executing Java compiled classes from config file,
+   exporting functions to access the SIP message from Java using Java
+   Native Interface (JNI).
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following packages are runtime libraries, required to launch
+     * java-common Base of all Java packages.
+     * default-jre Standard Java or Java compatible Runtime.
+     * gcj-jre Java runtime environment using GIJ/classpath.
+     * libgcj12 (>=12) Java runtime library for use with gcj.
+
+   The following packages are optional, required for development
+     * ant Java based build tool like make.
+     * ant-contrib Collection of tasks, types and other tools for Apache
+       Ant.
+     * ant-gcj Java based build tool like make (GCJ).
+     * default-jdk Standard Java or Java compatible Development Kit
+     * gcj-jdk gcj and classpath development tools for Java(TM)
+     * libgcj13-dev (>=12) Java development headers for use with gcj
+     * jdk JDK Development Kit (either oracle jdk or openjdk)
+
+   The following libraries or applications must be compiled before running
+   Kamailio with this module loaded:
+
+   The following packages are runtime libraries, required to launch
+     * <class_name>.class
+     * kamailio.jar
+
+3. Java runtime
+
+   3.1.
+
+3.1.
+
+   Java runtime library (JRE or JDK) is required to use this module.
+
+4. Parameters
+
+   4.1. class_name (string)
+   4.2. child_init_method (string)
+   4.3. java_options (string)
+   4.4. force_cmd_exec (int)
+
+4.1. class_name (string)
+
+   The class name should have the same compiled file name. If the value is
+   "Kamailio", then the compiled file should be named as "Kamailio.class".
+
+   Default value is “Kamailio”.
+
+   Example 1.1. Set class_name parameter
+...
+modparam("app_java", "class_name", "Kamailio")
+...
+
+4.2. child_init_method (string)
+
+   TBD.
+
+   Default value is “child_init”.
+
+   Example 1.2. Set child_init_method parameter
+...
+modparam("app_java", "child_init_method", "my_mod_init")
+...
+
+4.3. java_options (string)
+
+   Java options for Java Virtual Machine. For more info read java docs
+
+   Default value is “-Djava.compiler=NONE”.
+
+   Example 1.3. Set java_options parameter
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE")
+...
+
+   Example 1.4. Set java_options parameter (live configuration)
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/pa
+th/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+
+   Example 1.5. Set java_options parameter (verbose configuration)
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE
+ -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/ja
+va/kamailio.jar")
+...
+
+   Example 1.6. Set java_options parameter (debug configuration)
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compi
+ler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kam
+ailio/java/kamailio.jar")
+...
+
+4.4. force_cmd_exec (int)
+
+   This parameter forces execution a kamailio comnmand with java native
+   method “KamExec”. # Note: this is an untested yet feature, may cause
+   (but may not) a memory leaks if used from embedded languages.
+
+   Default value is “0 (off)”.
+
+   Example 1.7. Set force_cmd_exec parameter
+...
+modparam("app_java", "force_cmd_exec", 1)
+...
+
+5. Functions
+
+   5.1. Common requirements
+   5.2. java_method_exec(method, method_signature, [param1[, param2[,
+          ...]]])
+
+   5.3. java_staticmethod_exec(method, method_signature, [param1[,
+          param2[, ...]]])
+
+   5.4. java_s_method_exec(method, method_signature, [param1[, param2[,
+          ...]]])
+
+   5.5. java_s_staticmethod_exec(method, method_signature, [param1[,
+          param2[, ...]]])
+
+5.1.  Common requirements
+
+   Each function has a required parameter “method_signature”. For more
+   info see Determine the signature of a method. Signature represents the
+   variable type. The mapping between the Java type and C type is
+                Type     Chararacter
+                boolean      Z
+                byte         B
+                char         C
+                double       D
+                float        F
+                int          I
+                long         J
+                object       L
+                short        S
+                void         V
+                Note that to specify an object, the "L" is followed by the objec
+t's class name and ends with a semi-colon, ';' .
+
+   app_java supports the following signatures:
+                Primitives: Z,B,C,D,F,I,J,L,S,V
+                Objects:
+                        Ljava/lang/Boolean;
+                        Ljava/lang/Byte;
+                        Ljava/lang/Character;
+                        Ljava/lang/Double;
+                        Ljava/lang/Float;
+                        Ljava/lang/Integer;
+                        Ljava/lang/Long;
+                        Ljava/lang/Short;
+                        Ljava/lang/String;
+                        NULL parameter: V
+
+        Each parameter passed to function will be cast according to given signat
+ure.
+
+        Parameters are optional, ommitting a parameter meant the passed value is
+ NULL.
+        Parameters count should be exactly the same as signature count.
+        Note 1: Arrays representation (symbol '[') is not supported yet.
+        Note 2: You shall use a correct signature, e.g. the following examples o
+f combinations are invalid:
+        java_method_exec("ExampleMethod", "ZI", "False");
+        java_method_exec("ExampleMethod", "LI", "something", "5");
+
+5.2. java_method_exec(method, method_signature, [param1[, param2[, ...]]])
+
+   Executes a java class method method. Parameter method_signature is
+   required.
+     * Example 1.8. Signature: "V"
+       Kamailio prototype
+java_method_exec("ExampleMethod", "V");
+       Java prototype
+public int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_method_exec("ExampleMethod", "V");
+
+# Java
+public int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.9. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");
+       Java prototype
+public int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.10. Signature: "ZB"
+       Kamailio prototype
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+5.3. java_staticmethod_exec(method, method_signature, [param1[, param2[,
+...]]])
+
+   Executes a java static method method. Parameter method_signature is
+   required.
+     * Example 1.11. Signature: "V"
+       Kamailio prototype
+java_staticmethod_exec("ExampleMethod", "V");
+       Java prototype
+public static int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.12. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5
+");
+       Java prototype
+public static int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.13. Signature: "ZB"
+       Kamailio prototype
+java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public static int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+5.4. java_s_method_exec(method, method_signature, [param1[, param2[, ...]]])
+
+   Executes a java class synchronized method method. Parameter
+   method_signature is required.
+
+   For more info see Synchronized Methods
+     * Example 1.14. Signature: "V"
+       Kamailio prototype
+java_s_method_exec("ExampleMethod", "V");
+       Java prototype
+public synchronized int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_s_method_exec("ExampleMethod", "V");
+
+# Java
+public synchronized int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.15. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");
+       Java prototype
+public synchronized int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLen
+ght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.16. Signature: "ZB"
+       Kamailio prototype
+java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public synchronized int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+5.5. java_s_staticmethod_exec(method, method_signature, [param1[, param2[,
+...]]])
+
+   Executes a java synchronized static method method. Parameter
+   method_signature is required.
+
+   For more info see Synchronized Methods
+     * Example 1.17. Signature: "V"
+       Kamailio prototype
+java_s_staticmethod_exec("ExampleMethod", "V");
+       Java prototype
+public static synchronized int ExampleMethod();
+       Example of usage:
+# Kamailio
+java_s_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static synchronized int ExampleMethod()
+{
+                ... do something;
+                return 1;
+}
+     * Example 1.18. Signature: "Ljava/lang/String;I"
+       Kamailio prototype
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world",
+"5");
+       Java prototype
+public static synchronized int ExampleMethod(String param1, int param2);
+       In the above scenario parameter 2 ("5") will be cast to integer
+       representation.
+       Example of usage:
+# Kamailio
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMes
+sageLenght)
+{
+                ... do something with buffer;
+                return 1;
+}
+     * Example 1.19. Signature: "ZB"
+       Kamailio prototype
+java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+       Java prototype
+public static synchronized int ExampleMethod(boolean param1, byte param2);
+       In the above scenario parameter 1 ("true") will be cast to boolean
+       representation.
+       Example of usage:
+# Kamailio
+java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+                if (flagSet)
+                {
+                        ... do something with flags;
+                }
+                return 1;
+}
+
+6. Java Module API
+
+   6.1. Minimal program skeleton
+
+6.1. Minimal program skeleton
+
+   Example 1.20. Minimal program skeleton
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+                /* Here you should specify a full path to app_java.so */
+                static
+                {
+                                System.load("/opt/kamailio/lib/kamailio/modules/
+app_java.so");
+                }
+
+                /* Constructor. Do not remove !!! */
+                public Kamailio()
+                {
+                }
+
+                /*
+                This method should be executed for each children process, immedi
+ately after forking.
+                Required. Do not remove !!!
+                */
+                public int child_init(int rank)
+                {
+                                return 1;
+                }
+}
diff --git a/modules/app_java/README-draft b/modules/app_java/README-draft
new file mode 100644
index 0000000..02c442b
--- /dev/null
+++ b/modules/app_java/README-draft
@@ -0,0 +1,837 @@
+app_java Module
+
+Konstantin Mosesov
+
+Edited by
+
+Konstantin Mosesov
+
+   <konstantinm at voipgroup.org.ua>
+
+   Copyright © 2013 Konstantin Mosesov
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+	      3.1. class_name (string)
+              3.2. child_init_method (string)
+	      3.3. java_options (string)
+	      3.4. force_cmd_exec (int)
+
+        4. Functions
+
+	      4.0. Common requirements.
+              4.1. java_method_exec(method, method_signature, [param1[, param2]])
+	      4.2. java_s_method_exec(method, method_signature, [param1[, param2]])
+	      4.3. java_staticmethod_exec(method, method_signature, [param1[, param2]])
+	      4.4. java_s_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+	5. Java module API
+
+	      5.0. Minimal program skeleton and structure of package org.siprouter
+		   5.0.1.  Minimal program skeleton
+		   5.0.2.  Structure of package org.siprouter
+	      5.1. abstract class NativeMethods
+	           5.1.1.  General logging
+			   5.1.1.0.   Logging levels and facilities
+			   5.1.1.1.   native void LM_GEN1(int logLevel, String s);
+			   5.1.1.2.   native void LM_GEN2(int logFacility, int logLevel, String s);
+			   5.1.1.3.   native void LM_ALERT(String s);
+			   5.1.1.4.   native void LM_CRIT(String s);
+			   5.1.1.5.   native void LM_WARN(String s);
+			   5.1.1.6.   native void LM_NOTICE(String s);
+			   5.1.1.7.   native void LM_ERR(String s);
+			   5.1.1.8.   native void LM_INFO(String s);
+			   5.1.1.9.   native void LM_DBG(String s);
+		   5.1.2.  Execution of kamailio commands
+			   5.1.2.1.   static native int KamExec(String fname, String... params);
+    			   5.1.2.2.   static native int SetURI(String ruri);
+    			   5.1.2.3.   static native int RewriteURI(String ruri);
+
+	      5.2. class IPPair.
+		   5.2.1.   final String ip;
+		   5.2.2.   final int port;
+	      5.3. abstract class SipMsg
+		   5.3.0.   Internal structure understanding.
+		   5.3.1.   int id;
+		   5.3.2.   int pid;
+		   5.3.3.   String eoh;
+		   5.3.4.   String unparsed;
+		   5.3.5.   String buf;
+		   5.3.6.   int len;
+		   5.3.7.   String new_uri;
+		   5.3.8.   String dst_uri;
+		   5.3.9.   int parsed_uri_ok;
+		   5.3.10.  int parsed_orig_ruri_ok;
+		   5.3.11.  String add_to_branch_s;
+		   5.3.12.  int add_to_branch_len;
+		   5.3.13.  int hash_index;
+		   5.3.14.  int msg_flags;
+		   5.3.15.  static native SipMsg ParseSipMsg();
+		   5.3.16.  static native String getMsgType();
+		   5.3.17.  static native String getRURI();
+		   5.3.18.  static native IPPair getSrcAddress();
+		   5.3.19.  static native IPPair getDstAddress();
+		   5.3.20.  static native String getBuffer();
+	      5.4. interface NativeInterface
+		   5.4.1.   abstract class Ranks
+			    5.4.1.1.  static final int PROC_MAIN
+			    5.4.1.2.  static final int PROC_TIMER
+			    5.4.1.3.  static final int PROC_RPC
+			    5.4.1.4.  static final int PROC_FIFO
+			    5.4.1.5.  static final int PROC_TCP_MAIN
+			    5.4.1.6.  static final int PROC_UNIXSOCK
+			    5.4.1.7.  static final int PROC_ATTENDANT
+			    5.4.1.8.  static final int PROC_INIT
+			    5.4.1.9.  static final int PROC_NOCHLDINIT
+			    5.4.1.10. static final int PROC_SIPINIT
+			    5.4.1.11. static final int PROC_SIPRPC
+			    5.4.1.12. static final int PROC_MIN
+		   5.4.2.   abstract class LogParams
+			    5.4.2.0.  Loggigng params
+			    5.4.2.1.  static final int L_ALERT
+			    5.4.2.2.  static final int L_BUG
+			    5.4.2.3.  static final int L_CRIT2
+			    5.4.2.4.  static final int L_CRIT
+			    5.4.2.5.  static final int L_ERR
+			    5.4.2.6.  static final int L_WARN
+			    5.4.2.7.  static final int L_NOTICE
+			    5.4.2.8.  static final int L_INFO
+			    5.4.2.9.  static final int L_DBG
+			    5.4.2.10. static final int DEFAULT_FACILITY
+	      5.5. Examples of usage Java API
+
+   List of Examples
+
+   1.1. Set class_name parameter
+   1.2. Set child_init_method parameter
+   1.3. Set java_options parameter
+   1.4. Set java_options parameter (live configuration)
+   1.5. Set java_options parameter (verbose configuration)
+   1.6. Set java_options parameter (debug configuration)
+
+   2.0. Example of usage signatures.
+   2.1. Example of usage java_method_exec()
+   2.2. Example of usage java_s_method_exec()
+   2.3. Example of usage java_staticmethod_exec()
+   3.4. Example of usage java_s_staticmethod_exec()
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. class_name (string)
+        3.2. child_init_method (string)
+        3.3. java_options (string)
+	3.4. force_cmd_exec (int)
+
+   4. Functions
+
+	4.0. Common requirements.
+        4.1. java_method_exec(method, method_signature, [param1[, param2]])         - class method
+        4.2. java_s_method_exec(method, method_signature, [param1[, param2]])       - class synchronized method
+        4.3. java_staticmethod_exec(method, method_signature, [param1[, param2]])   - static method
+        4.4. java_s_staticmethod_exec(method, method_signature, [param1[, param2]]) - static synchronized method
+
+1. Overview
+
+   This module allows executing Java compiled classes from config file, exporting
+   functions to access the SIP message from Java using Java Native Interface (JNI).
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+   2.3. Java runtime
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   Legend:
+      * - Runtime library, required to launch
+      R - Required
+      O - Optional
+      D - Development (for building-rebuilding java)
+      P - Dependance of package
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     [*]    java-common            - Base of all Java packages
+     [*]    default-jre            - Standard Java or Java compatible Runtime
+     [*]    gcj-jre                - Java runtime environment using GIJ/classpath
+     [*]    libgcj12 (>=12)        - Java runtime library for use with gcj
+     [DR]   ant                    - Java based build tool like make
+     [DO]   ant-contrib            - collection of tasks, types and other tools for Apache Ant
+     [DPO]  ant-gcj                - Java based build tool like make (GCJ)
+     [DPO]  ant-optional           - Java based build tool like make - optional libraries
+     [DPO]  ant-optional-gcj       - Java based build tool like make - optional libraries (GCJ)
+     [DR]   default-jdk            - Standard Java or Java compatible Development Kit
+     [DR]   gcj-jdk                - gcj and classpath development tools for Java(TM)
+     [DR]   libgcj13-dev (>=12)    - Java development headers for use with gcj
+     [DO]   jdk                    - JDK Development Kit (either oracle jdk or openjdk)
+
+   The following libraries or applications must be compiled before
+   running Kamailio with this module loaded:
+     [*]   <class_name>.class
+     [*]   kamailio.jar
+
+2.3. Java runtime
+
+   Java runtime library (JRE or JDK) is required to use this module.
+
+3. Parameters
+
+   3.1. class_name (string)
+   3.2. child_init_method (string)
+   3.3. java_options (string)
+   3.4. force_cmd_exec (int)
+
+3.1. class_name (string)
+
+   The class name should have the same compiled file name.
+   If the value is "Kamailio", then the compiled file should be named as "Kamailio.class".
+
+   Default value is “Kamailio”.
+
+   Example 1.1. Set class_name parameter
+...
+modparam("app_java", "class_name", "Kamailio")
+...
+
+3.2. child_init_method (string)
+
+   TBD.
+
+   Default value is “child_init”.
+
+   Example 1.2. Set child_init_method parameter
+...
+modparam("app_java", "child_init_method", "my_mod_init")
+...
+
+3.3. java_options (string)
+
+   Java options for Java Virtual Machine.
+   For more info see: http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html
+
+   Default value is “-Djava.compiler=NONE”.
+
+   Example 1.3. Set java_options parameter
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE")
+...
+
+   Example 1.4. Set java_options parameter (live configuration)
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/path/to/<class_name>_file_directory:/path/to/kamailio.jar")
+...
+
+   Example 1.5. Set java_options parameter (verbose configuration)
+...
+modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/path/to/class_name_file_directory:/path/to/kamailio.jar")
+...
+
+   Example 1.6. Set java_options parameter (debug configuration)
+...
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/path/to/class_name_file_directory:/path/to/kamailio.jar")
+...
+
+3.4. force_cmd_exec (int)
+
+   This parameter forces execution a kamailio comnmand with java native method KamExec_raw.
+   Note: may cause a memory leaks if used from embedded languages.
+
+   Default value is 0 (off).
+
+4. Functions
+
+   4.0. Common requirements.
+   4.1. java_method_exec(method, method_signature, [param1[, param2]])
+   4.2. java_s_method_exec(method, method_signature, [param1[, param2]])
+   4.3. java_staticmethod_exec(method, method_signature, [param1[, param2]])
+   4.4. java_s_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+4.0. Common requirements.
+
+   Each function has a required parameter “method_signature”.
+   For more info see: http://www.rgagnon.com/javadetails/java-0286.html
+   There are two parts to the signature. The first part is enclosed within the parentheses and represents the method's arguments. 
+   The second portion follows the closing parenthesis and represents the return type. The mapping between the Java type and C type is
+	Type     Chararacter 
+	boolean      Z 
+	byte         B 
+	char         C 
+	double       D 
+	float        F 
+	int          I 
+	long         J 
+	object       L 
+	short        S 
+	void         V 
+	array        [ 
+   Note that to specify an object, the "L" is followed by the object's class name and ends with a semi-colon, ';' .
+
+   app_java supports the following signatures
+      primitives: Z,B,C,D,F,I,J,L,S,V
+      objects: 
+		Ljava/lang/Boolean;
+		Ljava/lang/Byte;
+		Ljava/lang/Character;
+		Ljava/lang/Double;
+		Ljava/lang/Float;
+		Ljava/lang/Integer;
+		Ljava/lang/Long;
+		Ljava/lang/Short;
+		Ljava/lang/String;
+      NULL parameter: V
+
+   Each parameter passed to function will be cast according to given signature.
+
+   Example 2.0. Example of usage signatures.
+        0. Equivalent of java prototype:  public int ExampleMethod();
+...
+java_method_exec("ExampleMethod", "V");
+...
+
+        1. Equivalent of java prototype:  public int ExampleMethod(String param1, int param2);
+...
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");
+...
+           In the above scenario parameter 2 ("5") will be cast to integer representation.
+
+        2. Equivalent of java prototype:  public int ExampleMethod(boolean param1, byte param2);
+...
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+...
+           In the above scenario parameter 1 ("true") will be cast to boolean representation.
+
+   Parameters are optional, ommitting a parameter meant the passed value is NULL.
+   Parameters count should be exactly the same as signature count.
+   Note, you shall use a correct signature, e.g. the following examples of combinations are invalid:
+        *) java_method_exec("ExampleMethod", "ZI", "False");
+        *) java_method_exec("ExampleMethod", "VI", "", "5");
+        *) java_method_exec("ExampleMethod", "LI", "something", "5");
+
+
+4.1.  java_method_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java method “method”. Parameter “method_signature” is required (see 4.0).
+
+   Example 2.1. java_method_exec usage
+...
+# Equivalent of java prototype:  public int ExampleMethod();
+java_method_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+4.2.  java_s_method_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java synchronized method “method”. Parameter “method_signature” is required (see 4.0).
+   See a more info about to synchronization: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
+
+   Example 2.2. java_s_method_exec usage
+...
+# Equivalent of java prototype:  public synchronized int ExampleMethod();
+java_s_method_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+4.3.  java_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java static method “method”. Parameter “method_signature” is required (see 4.0).
+
+   Example 2.3. java_staticmethod_exec usage
+...
+# Equivalent of java prototype:  public static int ExampleMethod();
+java_staticmethod_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+4.4.  java_s_staticmethod_exec(method, method_signature, [param1[, param2]])
+
+   Executes a java synchronized static method “method”. Parameter “method_signature” is required (see 4.0).
+   See a more info about to synchronization: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
+
+   Example 2.4. java_s_staticmethod_exec usage
+...
+# Equivalent of java prototype:  public static synchronized int ExampleMethod();
+java_s_staticmethod_exec("ExampleMethod", "V");
+
+# Equivalent of java prototype:  public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght);
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+...
+
+
+5. Java module API
+
+
+5.0. Minimal program skeleton and structure of package org.siprouter
+
+   5.0.1.  Minimal program skeleton
+
+...
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+	/* Here you should specify a full path to app_java.so */
+        static
+        {
+            System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+        }
+
+        /* Constructor. Do not remove !!! */
+        public Kamailio()
+        {
+        }
+
+	/*
+	    This method should be executed for each children process, immediately after forking.
+	    Required. Do not remove !!!
+	*/
+        public int child_init(int rank)
+        {
+	    return 1;
+	}
+}
+...
+
+   5.0.2.  Structure of package org.siprouter
+
+            org.siprouter ---*---*--*-------> class NativeMethods
+                             |   |  +--> class IPPair
+                             |   +--> class SipMsg
+                             +--> interface NativeInterface
+                                        |
+                                        +--> class Ranks
+                                        +--> class LogParams
+
+
+5.1. abstract class NativeMethods
+
+   5.1.1.   General logging
+
+	5.1.1.0.   Log levels and facilities
+
+		   Log levels:
+			L_ALERT		= -5
+			L_BUG		= -4
+			L_CRIT2		= -3
+			L_CRIT		= -2
+			L_ERR		= -1
+			L_WARN		= 0
+			L_NOTICE	= 1
+			L_INFO		= 2
+			L_DBG		= 3
+
+		   Log facilities (see man syslog(3)):
+			DEFAULT_FACILITY	= 0  (LOG_KERN (Linux))
+
+		   1. Example of usage log levels and facilities:
+		     LM_GEN1(LogParams.L_BUG, "Hello World!\n");
+		     produces (example of output):
+		      0(3003) BUG: app_java [java_native_methods.c:255]: Hello World!
+
+		   2. Example of usage log levels and facilities:
+		     LM_GEN2(LogParams.DEFAULT_FACILITY, LogParams.L_WARN, "Hello World!\n");
+		     produces (example of output):
+		      2(3147) WARNING: app_java [java_native_methods.c:279]: Hello World!
+
+
+	5.1.1.1.   native void LM_GEN1(int logLevel, String s);
+	5.1.1.2.   native void LM_GEN2(int logFacility, int logLevel, String s);
+	5.1.1.3.   native void LM_ALERT(String s);
+        5.1.1.4.   native void LM_CRIT(String s);
+        5.1.1.5.   native void LM_WARN(String s);
+        5.1.1.6.   native void LM_NOTICE(String s);
+        5.1.1.7.   native void LM_ERR(String s);
+        5.1.1.8.   native void LM_INFO(String s);
+        5.1.1.9.   native void LM_DBG(String s);
+
+   5.1.2.   Execution of kamailio commands
+
+	5.1.2.1.   static native int KamExec(String fname, String... params);
+
+		   Executes a kamailio command.
+
+		   Parameter 'fname'  - Required. Kamailio function name.
+		   Parameter 'params' - An array of string parameters. Note, this method allows up to 6 params,
+					it will ignore all parameters if more than 6.
+
+		   Returns:
+			     1 - command was successfully executed.
+			    -1 - execution of command was failed.
+
+        5.1.2.2.   static native int SetURI(String ruri);
+
+		   Rewrites the request URI.
+
+		   Returns:
+			    1 - Ok
+			   -1 - Failed
+
+		   Online reference: http://www.kamailio.org/wiki/cookbooks/3.3.x/core#rewriteuri
+
+        5.1.2.3.   static native int RewriteURI(String ruri);
+
+		   Rewrites the request URI.
+		   Alias method: SetURI
+
+		   Returns:
+			    1 - Ok
+			   -1 - Failed
+
+		   Online reference: http://www.kamailio.org/wiki/cookbooks/3.3.x/core#rewriteuri
+
+
+
+5.2.   class IPPair.
+
+   Represents an IP-address pair (IP, Port)
+
+   5.2.1.   final String ip;
+
+	    IP Address
+
+   5.2.2.   final int port;
+
+	    Port
+
+
+5.3. abstract class SipMsg
+
+   5.3.0.   Internal structure understanding.
+
+	    The class SipMsg is partially incapsulating kamailio's struct sip_msg.
+	    References: parser/msg_parser.h, parser/parse_fline.h
+
+   5.3.1.   int id;
+
+	    Message id, unique/process
+
+   5.3.2.   int pid;
+
+	    Process ID
+
+   5.3.3.   String eoh;
+
+	    Pointer to the end of header (if found) or null
+
+   5.3.4.   String unparsed;
+
+	    Here we stopped parsing
+
+   5.3.5.   String buf;
+
+	    Scratch pad, holds a modified message, via, etc. point into it.
+
+   5.3.6.   int len;
+
+	    Message len (orig)
+
+   5.3.7.   String new_uri;
+
+	    Changed first line uri, when you change this
+
+   5.3.8.   String dst_uri;
+
+	    Destination URI, must be forwarded to this URI if dst_url lenght != 0
+
+   5.3.9.   int parsed_uri_ok;
+
+	    1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+
+   5.3.10.  int parsed_orig_ruri_ok;
+
+	    1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+
+   5.3.11.  String add_to_branch_s;
+
+	    Whatever whoever want to append to branch comes here
+
+   5.3.12.  int add_to_branch_len;
+
+	    Lenght of add_to_branch_s
+
+   5.3.13.  int hash_index;
+
+	    Index to TM hash table; stored in core to avoid unnecessary calculations
+
+   5.3.14.  int msg_flags;
+
+	    Flags used by core. Allows to set various flags on the message; may be used 
+	    for simple inter-module communication or remembering processing state reache.
+
+   5.3.15.  static native SipMsg ParseSipMsg();
+
+	    This method is using to get an instance of class SipMsg and populate a properties
+	    of this class with a fields specified at 5.3.1 - 5.3.14.
+
+   5.3.16.  static native String getMsgType();
+
+	    Gets a message type. Return value:
+		'SIP_REQUEST' - if message is request
+		'SIP_REPLY'   - if message is reply
+		'SIP_INVALID' - if invalid message
+
+   5.3.17.  static native String getRURI();
+
+	    Gets a request URI (RURI).
+
+   5.3.18.  static native IPPair getSrcAddress();
+
+	    Gets a source IP address and port.
+
+   5.3.19.  static native IPPair getDstAddress();
+
+	    Gets a destination IP address and port.
+
+   5.3.20.  static native String getBuffer();
+
+	    Gets a message buffer.
+
+
+5.4. interface NativeInterface
+
+   5.4.1.   abstract class Ranks
+
+	5.4.1.1.  static final int PROC_MAIN
+
+		  Main ser process
+
+        5.4.1.2.  static final int PROC_TIMER
+
+		  Timer attendant process
+
+        5.4.1.3.  static final int PROC_RPC
+
+		  RPC type process
+
+        5.4.1.4.  static final int PROC_FIFO
+
+		  FIFO attendant process.
+		  Alias to PROC_RPC.
+
+        5.4.1.5.  static final int PROC_TCP_MAIN
+
+		  TCP main process
+
+        5.4.1.6.  static final int PROC_UNIXSOCK
+
+		  Unix socket server
+
+        5.4.1.7.  static final int PROC_ATTENDANT
+
+		  Main "attendant process
+
+        5.4.1.8.  static final int PROC_INIT
+
+		  Special rank, the context is the main ser process, but this is
+		  guaranteed to be executed before any rocess is forked, so it
+		  can be used to setup shared variables that depend on some
+		  after mod_init available information (e.g. total number of processes).
+		  @warning child_init(PROC_MAIN) is again called in the same process (main)
+		  (before tcp), so make sure you don't init things twice, 
+		  both in PROC_MAIN and PROC_INT
+
+        5.4.1.9.  static final int PROC_NOCHLDINIT
+
+		  no child init functions will be called if this rank is used in fork_process()
+
+        5.4.1.10. static final int PROC_SIPINIT
+
+		  First SIP worker - some modules do special processing in this child, 
+		  like loading db data
+
+        5.4.1.11. static final int PROC_SIPRPC
+
+		  Used to init RPC worker as SIP commands handler.
+		  Don't do any special processing in the child init with this rank - 
+		  just bare child initialization
+
+        5.4.1.12. static final int PROC_MIN
+
+		  Minimum process rank.
+		  Alias to PROC_NOCHLDINIT.
+
+   5.4.2.   abstract class LogParams
+	5.4.2.0.  Loggigng params
+        5.4.2.1.  static final int L_ALERT
+        5.4.2.2.  static final int L_BUG
+        5.4.2.3.  static final int L_CRIT2
+        5.4.2.4.  static final int L_CRIT
+        5.4.2.5.  static final int L_ERR
+        5.4.2.6.  static final int L_WARN
+        5.4.2.7.  static final int L_NOTICE
+        5.4.2.8.  static final int L_INFO
+        5.4.2.9.  static final int L_DBG
+        5.4.2.10. static final int DEFAULT_FACILITY
+
+
+5.5. Examples of usage Java API
+
+...
+
+import java.lang.*;
+import java.io.*; 
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+	static
+	{
+	    System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+	}
+
+	/* Constructor. Do not remove !!! */
+	public Kamailio()
+	{
+	}
+
+
+	public int child_init(int rank)
+	{
+	    switch (rank)
+	    {
+		case Ranks.PROC_MAIN:
+		    LM_INFO("We're at PROC_MAIN\n");
+		    break;
+		case Ranks.PROC_TIMER:
+		    LM_INFO("We're at PROC_TIMER\n");
+		    break;
+		case Ranks.PROC_RPC:
+		    LM_INFO("We're at PROC_RPC/PROC_FIFO\n");
+		    break;
+		case Ranks.PROC_TCP_MAIN:
+		    LM_INFO("We're at PROC_TCP_MAIN\n");
+		    break;
+		case Ranks.PROC_UNIXSOCK:
+		    LM_INFO("We're at PROC_UNIXSOCK\n");
+		    break;
+		case Ranks.PROC_ATTENDANT:
+		    LM_INFO("We're at PROC_ATTENDANT\n");
+		    break;
+		case Ranks.PROC_INIT:
+		    LM_INFO("We're at PROC_INIT\n");
+		    break;
+		case Ranks.PROC_NOCHLDINIT:
+		    LM_INFO("We're at PROC_NOCHLDINIT/PROC_MIN\n");
+		    break;
+		case Ranks.PROC_SIPINIT:
+		    LM_INFO("We're at PROC_SIPINIT\n");
+		    break;
+		case Ranks.PROC_SIPRPC:
+		    LM_INFO("We're at PROC_SIPRPC\n");
+		    break;
+	    }
+
+	    return 1;
+	}
+
+	public int TestMethod()
+	{
+
+	    LM_INFO(String.format("Msg Type: %s\n", SipMsg.getMsgType()));
+
+	    IPPair src = SipMsg.getSrcAddress();
+	    if (src != null)
+	    {
+		LM_INFO(String.format("src address=%s, src port=%d\n", src.ip, src.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair src is null!");
+	    }
+
+	    IPPair dst = SipMsg.getDstAddress();
+	    if (dst != null)
+	    {
+		LM_INFO(String.format("dst address=%s, dst port=%d\n", dst.ip, dst.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair dst is null!");
+	    }
+
+	    LM_INFO(String.format("buffer:\n%s\n", SipMsg.getBuffer().trim()));
+
+	    SipMsg msg = SipMsg.ParseSipMsg();
+	    if (msg != null)
+	    {
+		LM_INFO("msg:\n");
+		LM_INFO(String.format("\tid=%d\n", msg.id));
+		LM_INFO(String.format("\tpid=%d\n", msg.pid));
+		LM_INFO(String.format("\teoh='%s'\n", msg.eoh));
+		LM_INFO(String.format("\tunparsed='%s'\n", msg.unparsed));
+		LM_INFO(String.format("\tbuf='%s'\n", msg.buf));
+		LM_INFO(String.format("\tlen=%d\n", msg.len));
+		LM_INFO(String.format("\tnew_uri='%s'\n", msg.new_uri));
+		LM_INFO(String.format("\tdst_uri='%s'\n", msg.dst_uri));
+		LM_INFO(String.format("\tparsed_uri_ok=%d\n", msg.parsed_uri_ok));
+		LM_INFO(String.format("\tparsed_orig_ruri_ok=%d\n", msg.parsed_orig_ruri_ok));
+		LM_INFO(String.format("\tadd_to_branch_s='%s'\n", msg.add_to_branch_s));
+		LM_INFO(String.format("\tadd_to_branch_len=%d\n", msg.add_to_branch_len));
+		LM_INFO(String.format("\thash_index=%d\n", msg.hash_index));
+		LM_INFO(String.format("\tmsg_flags=%d\n", msg.msg_flags));
+		LM_INFO(String.format("\tset_global_address='%s'\n", msg.set_global_address));
+		LM_INFO(String.format("\tset_global_port='%s'\n", msg.set_global_port));
+	    }
+	    else
+	    {
+		LM_ERR("SipMsg msg is null!\n");
+	    }
+
+	    return 1;
+	}
+}
+
+...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/app_java/doc/Makefile b/modules/app_java/doc/Makefile
new file mode 100644
index 0000000..d5a9f2c
--- /dev/null
+++ b/modules/app_java/doc/Makefile
@@ -0,0 +1,4 @@
+docs = app_java.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/app_java/doc/app_java.xml b/modules/app_java/doc/app_java.xml
new file mode 100644
index 0000000..0360392
--- /dev/null
+++ b/modules/app_java/doc/app_java.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding='utf-8'?>
+
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+	"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>app_java Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+	    <author>
+			<firstname>Konstantin</firstname>
+			<surname>Mosesov</surname>
+	    </author>
+	    <editor>
+	    	<firstname>Konstantin</firstname>
+	    	<surname>Mosesov</surname>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2013</year>
+		<holder>Konstantin Mosesov</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+	<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="app_java_admin.xml"/>
+    
+</book>
diff --git a/modules/app_java/doc/app_java_admin.xml b/modules/app_java/doc/app_java_admin.xml
new file mode 100644
index 0000000..f69f8ee
--- /dev/null
+++ b/modules/app_java/doc/app_java_admin.xml
@@ -0,0 +1,648 @@
+<?xml version="1.0" encoding='utf-8'?>
+
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" 
+	"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Module User's Guide -->
+
+<chapter>
+    
+    <title>&adminguide;</title>
+    
+    <!-- Section Overview -->
+    <section>
+		<title>Overview</title>
+		<para>
+			This module allows executing Java compiled classes from config file, exporting
+			functions to access the SIP message from Java using Java Native Interface (JNI).
+		</para>
+    </section>
+	<!-- end op section Overview -->
+	
+	<!-- Section Dependencies -->
+    <section>
+		<title>Dependencies</title>
+    	<!-- Section Modules -->
+		<section>
+		    <title>&kamailio; Modules</title>
+		    <para>
+			The following modules must be loaded before this module:
+		    	<itemizedlist>
+			    <listitem>
+				<para>
+				    <emphasis>none</emphasis>.
+				</para>
+			    </listitem>
+		    	</itemizedlist>
+		    </para>
+		</section>
+    	<!-- End of section Modules -->
+    	
+    	<!-- Section External Libraries or Applications -->
+		<section>
+		    <title>External Libraries or Applications</title>
+		    <para>
+<!--
+			The following libraries or applications must be installed before running
+			&kamailio; with this module loaded:
+-->			
+		    	<itemizedlist>
+		    		<para><emphasis>The following packages are runtime libraries, required to launch</emphasis></para>
+		    		<listitem override="disc"><para><emphasis>java-common</emphasis> Base of all Java packages.</para></listitem>
+		    		<listitem override="disc"><para><emphasis>default-jre</emphasis> Standard Java or Java compatible Runtime.</para></listitem>
+		    		<listitem override="disc"><para><emphasis>gcj-jre</emphasis> Java runtime environment using GIJ/classpath.</para></listitem>
+		    		<listitem override="disc"><para><emphasis>libgcj12 (>=12)</emphasis> Java runtime library for use with gcj.</para></listitem>
+		    	</itemizedlist>
+		    	<itemizedlist>
+		    		<para><emphasis>The following packages are optional, required for development</emphasis></para>
+		    		<listitem override="box"><para><emphasis>ant</emphasis> Java based build tool like make.</para></listitem>
+		    		<listitem override="box"><para><emphasis>ant-contrib</emphasis> Collection of tasks, types and other tools for Apache Ant.</para></listitem>
+		    		<listitem override="box"><para><emphasis>ant-gcj</emphasis> Java based build tool like make (GCJ).</para></listitem>
+		    		<listitem override="box"><para><emphasis>default-jdk</emphasis> Standard Java or Java compatible Development Kit</para></listitem>
+		    		<listitem override="box"><para><emphasis>gcj-jdk</emphasis> gcj and classpath development tools for Java(TM)</para></listitem>
+		    		<listitem override="box"><para><emphasis>libgcj13-dev (>=12)</emphasis> Java development headers for use with gcj</para></listitem>
+		    		<listitem override="box"><para><emphasis>jdk</emphasis> JDK Development Kit (either oracle jdk or openjdk)</para></listitem>
+		    	</itemizedlist>
+		    </para>
+			<para>
+				The following libraries or applications must be compiled before
+				running &kamailio; with this module loaded:
+				<itemizedlist>
+					<para><emphasis>The following packages are runtime libraries, required to launch</emphasis></para>
+					<listitem override="circle"><para><emphasis><class_name></emphasis>.class</para></listitem>
+					<listitem override="circle"><para><emphasis>&kamailiobinary;</emphasis>.jar</para></listitem>
+				</itemizedlist>
+			</para>
+		</section>
+    	<!-- end of section External Libraries or Applications -->
+    </section>
+	<!-- end of section Dependencies -->
+	
+	<!-- Section Java Runtime -->
+	<section>
+		<title>Java runtime</title>
+		<section>
+			<title/>
+			<para>Java runtime library (JRE or JDK) is required to use this module.</para>
+		</section>
+	</section>
+	<!-- end of section Java Runtime -->
+	
+	<!-- Section Parameters -->
+	<section>
+		<title>Parameters</title>
+
+		<!-- class_name -->
+		<section>
+			<title><varname>class_name</varname> (string)</title>
+		    <para>
+		    	The class name should have the same compiled file name.
+		    	If the value is <emphasis>"&kamailio;"</emphasis>, then the compiled file should be named as <emphasis>"&kamailio;.class"</emphasis>.
+		    </para>
+		    <para>
+				<emphasis>
+					Default value is <quote>&kamailio;</quote>.
+				</emphasis>
+		    </para>
+		    <example>
+		    	<title>Set <varname>class_name</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "class_name", "&kamailio;")
+...
+</programlisting>
+		    </example>
+		</section>
+
+		<!-- child_init_method -->
+		<section>
+			<title><varname>child_init_method</varname> (string)</title>
+			<para>
+				TBD.
+			</para>
+			<para>
+				<emphasis>
+					Default value is <quote>child_init</quote>.
+				</emphasis>
+			</para>
+			<example>
+				<title>Set <varname>child_init_method</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "child_init_method", "my_mod_init")
+...
+</programlisting>
+			</example>
+		</section>
+
+		<!-- java_options -->
+		<section>
+			<title><varname>java_options</varname> (string)</title>
+			<para>
+				Java options for Java Virtual Machine.
+				For more info read <ulink url="http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html"><citetitle>java docs</citetitle></ulink>
+			</para>
+			<para>
+				<emphasis>
+					Default value is <quote>-Djava.compiler=NONE</quote>.
+				</emphasis>
+			</para>
+			<example>
+				<title>Set <varname>java_options</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "java_options", "-Djava.compiler=NONE")
+...
+</programlisting>
+			</example>
+			<example>
+				<title>Set <varname>java_options</varname> parameter (live configuration)</title>
+				<programlisting format="linespecific">
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+</programlisting>
+			</example>
+			<example>
+				<title>Set <varname>java_options</varname> parameter (verbose configuration)</title>
+				<programlisting format="linespecific">
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+</programlisting>
+			</example>
+			<example>
+				<title>Set <varname>java_options</varname> parameter (debug configuration)</title>
+				<programlisting format="linespecific">
+...
+# Assumes "application java folder" is located at /opt/kamailio/java
+modparam("app_java", "java_options", "-Xdebug -verbose:gc,class,jni -Djava.compiler=NONE -Djava.class.path=/path/to/kamailio/modules:/opt/kamailio/java:/opt/kamailio/java/kamailio.jar")
+...
+</programlisting>
+			</example>
+		</section>
+
+		<!-- force_cmd_exec -->
+		<section>
+			<title><varname>force_cmd_exec</varname> (int)</title>
+			<para>
+				This parameter forces execution a &kamailiobinary; comnmand with java native method <quote>KamExec</quote>.
+				# Note: this is an untested yet feature, may cause (but may not) a memory leaks if used from embedded languages.
+			</para>
+			<para>
+				<emphasis>
+					Default value is <quote>0 (off)</quote>.
+				</emphasis>
+			</para>
+			<example>
+				<title>Set <varname>force_cmd_exec</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("app_java", "force_cmd_exec", 1)
+...
+</programlisting>
+			</example>
+		</section>
+	</section>
+	<!-- End of section Parameters -->
+	
+	<!-- Section Functions -->
+    <section>
+		<title>Functions</title>
+    	
+    	<!-- Section Common requirements -->
+    	<section>
+    		<title>
+    			Common requirements
+    		</title>
+    		<para>Each function has a required parameter <quote>method_signature</quote>. For more info
+				see <ulink url="http://www.rgagnon.com/javadetails/java-0286.html"
+						><citetitle>Determine the signature of a method</citetitle></ulink>.
+				Signature represents the variable type. The mapping between the Java type and C type
+				is
+				<programlisting format="linespecific">
+		Type     Chararacter 
+		boolean      Z 
+		byte         B 
+		char         C 
+		double       D 
+		float        F 
+		int          I 
+		long         J 
+		object       L 
+		short        S 
+		void         V 
+		Note that to specify an object, the "L" is followed by the object's class name and ends with a semi-colon, ';' .
+    			</programlisting>
+			</para>
+    		<para> app_java supports the following signatures:
+				<programlisting format="linespecific">
+		Primitives: Z,B,C,D,F,I,J,L,S,V
+		Objects: 
+			Ljava/lang/Boolean;
+			Ljava/lang/Byte;
+			Ljava/lang/Character;
+			Ljava/lang/Double;
+			Ljava/lang/Float;
+			Ljava/lang/Integer;
+			Ljava/lang/Long;
+			Ljava/lang/Short;
+			Ljava/lang/String;
+			NULL parameter: V
+
+	Each parameter passed to function will be cast according to given signature.
+	
+	Parameters are optional, ommitting a parameter meant the passed value is NULL.
+	Parameters count should be exactly the same as signature count.
+	Note 1: Arrays representation (symbol '[') is not supported yet.
+	Note 2: You shall use a correct signature, e.g. the following examples of combinations are invalid:    
+    	java_method_exec("ExampleMethod", "ZI", "False");
+        java_method_exec("ExampleMethod", "LI", "something", "5");
+</programlisting>
+			</para>
+
+ 
+    	</section>
+    	<!-- End of section Common Requirements -->
+  
+    	<!-- Section java_method_exec -->
+    	<section>
+    		<title>java_method_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java class method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<itemizedlist>
+	    		<listitem>
+			    	<example>
+						<title>Signature: "V"</title>
+			    		<para>&kamailio; prototype</para>
+			    		<programlisting format="linespecific">java_method_exec("ExampleMethod", "V");</programlisting>
+			    		<para>Java prototype</para>
+			    		<programlisting format="linespecific">public int ExampleMethod();</programlisting>
+			    		<para>Example of usage:</para>
+			    		<programlisting format="linespecific">
+# &kamailio;
+java_method_exec("ExampleMethod", "V");
+
+# Java
+public int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+			    	</example>
+	    		</listitem>
+    			
+	    		<listitem>
+	    			<example>
+	    				<title>Signature: "Ljava/lang/String;I"</title>
+	    				<para>&kamailio; prototype</para>
+		    			<programlisting format="linespecific">java_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+	    				<para>Java prototype</para>
+	    				<programlisting format="linespecific">public int ExampleMethod(String param1, int param2);</programlisting>
+	    				<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+	    				<para>Example of usage:</para>
+	    				<programlisting format="linespecific">
+# &kamailio;
+java_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+	    			</example>
+	    		</listitem>
+
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_method_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_method_exec -->
+
+    	<!-- Section java_staticmethod_method_exec -->
+    	<section>
+    		<title>java_staticmethod_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java static method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<itemizedlist>
+    			<listitem>
+    				<example>
+    					<title>Signature: "V"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_staticmethod_exec("ExampleMethod", "V");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static int ExampleMethod();</programlisting>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "Ljava/lang/String;I"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static int ExampleMethod(String param1, int param2);</programlisting>
+    					<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_staticmethod_exec -->
+    	
+    	<!-- Section java_s_method_exec -->
+    	<section>
+    		<title>java_s_method_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java class synchronized method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<para>For more info see <ulink url="http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html"><citetitle>Synchronized Methods</citetitle></ulink></para>
+    		<itemizedlist>
+    			<listitem>
+    				<example>
+    					<title>Signature: "V"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_method_exec("ExampleMethod", "V");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public synchronized int ExampleMethod();</programlisting>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_method_exec("ExampleMethod", "V");
+
+# Java
+public synchronized int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "Ljava/lang/String;I"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public synchronized int ExampleMethod(String param1, int param2);</programlisting>
+    					<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_method_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public synchronized int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_method_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_s_method_exec -->
+    	
+    	<!-- Section java_s_staticmethod_exec -->
+    	<section>
+    		<title>java_s_staticmethod_exec(method, method_signature, [param1[, param2[, ...]]])</title>
+    		<para>Executes a java synchronized static method <emphasis>method</emphasis>. Parameter <emphasis>method_signature</emphasis> is required.</para>
+    		<para>For more info see <ulink url="http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html"><citetitle>Synchronized Methods</citetitle></ulink></para>
+    		<itemizedlist>
+    			<listitem>
+    				<example>
+    					<title>Signature: "V"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_staticmethod_exec("ExampleMethod", "V");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static synchronized int ExampleMethod();</programlisting>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_staticmethod_exec("ExampleMethod", "V");
+
+# Java
+public static synchronized int ExampleMethod()
+{
+		... do something;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "Ljava/lang/String;I"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "Hello world", "5");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static synchronized int ExampleMethod(String param1, int param2);</programlisting>
+    					<para>In the above scenario parameter 2 ("5") will be cast to integer representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_staticmethod_exec("ExampleMethod", "Ljava/lang/String;I", "$mb", "$ml");
+
+# Java
+public static synchronized int ExampleMethod(String SipMessageBuffer, int SipMessageLenght)
+{
+		... do something with buffer;
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    			<listitem>
+    				<example>
+    					<title>Signature: "ZB"</title>
+    					<para>&kamailio; prototype</para>
+    					<programlisting format="linespecific">java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");</programlisting>
+    					<para>Java prototype</para>
+    					<programlisting format="linespecific">public static synchronized int ExampleMethod(boolean param1, byte param2);</programlisting>
+    					<para>In the above scenario parameter 1 ("true") will be cast to boolean representation.</para>
+    					<para>Example of usage:</para>
+    					<programlisting format="linespecific">
+# &kamailio;
+java_s_staticmethod_exec("ExampleMethod", "ZB", "true", "0x05");
+
+# Java
+public static synchronized int ExampleMethod(boolean flagSet, byte bFlag);
+{
+		if (flagSet)
+		{
+			... do something with flags;
+		}
+		return 1;
+}
+</programlisting>
+    				</example>
+    			</listitem>
+    			
+    		</itemizedlist>
+    	</section>
+    	<!-- end of section java_s_method_exec -->
+
+    </section>
+	<!-- End of section Functions -->
+	
+	<!-- Section Java API-->
+    <section>
+		<title>Java Module API</title>
+    	<para></para>
+    	
+    	<!-- Section Minimal program skeleton -->
+    	<section>
+    		<title>Minimal program skeleton</title>
+    		<para></para>
+    		<example>
+    			<title>Minimal program skeleton</title>
+    			<para></para>
+    			<programlisting format="linespecific">
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+		/* Here you should specify a full path to app_java.so */
+		static
+		{
+				System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+		}
+
+		/* Constructor. Do not remove !!! */
+		public Kamailio()
+		{
+		}
+
+		/*
+		This method should be executed for each children process, immediately after forking.
+		Required. Do not remove !!!
+		*/
+		public int child_init(int rank)
+		{
+				return 1;
+		}
+}
+</programlisting>
+    		</example>
+    	</section>
+    	<!-- End of section Minimal program skeleton -->
+    	
+    </section>
+	<!-- End of section Java API -->
+	
+</chapter>
+
diff --git a/modules/app_java/global.h b/modules/app_java/global.h
new file mode 100644
index 0000000..0fd8f8b
--- /dev/null
+++ b/modules/app_java/global.h
@@ -0,0 +1,48 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __GLOBAL_H__
+#define	__GLOBAL_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+#include "../../action.h"
+#include "../../mem/mem.h"
+#include "../../sr_module.h"
+#include "../../dset.h"
+#include "../../parser/msg_parser.h"
+
+#include <jni.h>
+
+JavaVM *jvm;
+JNIEnv *env;
+jclass KamailioClass;
+jclass KamailioClassRef;
+jclass KamailioClassInstanceRef;
+jobject KamailioClassInstance;
+jmethodID KamailioID;
+
+struct sip_msg *msg;
+
+#endif
diff --git a/modules/app_java/java_iface.c b/modules/app_java/java_iface.c
new file mode 100644
index 0000000..66cb5f5
--- /dev/null
+++ b/modules/app_java/java_iface.c
@@ -0,0 +1,284 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <string.h>
+#include <jni.h>
+
+#include "global.h"
+#include "java_iface.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_msgobj.h"
+#include "java_sig_parser.h"
+
+/*
+    example of java prototype: public int method_name();
+    example of kamailio invocation: java_method_exec("method_name", "V");
+*/
+int j_nst_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 0, 0, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public int method_name(int param);
+    example of kamailio invocation: java_method_exec("method_name", "I", "5");
+*/
+int j_nst_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 0, 0, method_name, signature, param);
+}
+/*
+    example of java prototype: public synchronized int method_name();
+    example of kamailio invocation: java_s_method_exec("method_name", "V");
+*/
+int j_s_nst_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 0, 1, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public synchronized int method_name(int param);
+    example of kamailio invocation: java_s_method_exec("method_name", "I", "5");
+*/
+int j_s_nst_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 0, 1, method_name, signature, param);
+}
+
+
+/*
+    example of java prototype: public static int method_name();
+    example of kamailio invocation: java_staticmethod_exec("method_name", "V");
+*/
+int j_st_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 1, 0, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public static int method_name(int param);
+    example of kamailio invocation: java_staticmethod_exec("method_name", "I", "5");
+*/
+int j_st_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 1, 0, method_name, signature, param);
+}
+/*
+    example of java prototype: public static synchronized int method_name();
+    example of kamailio invocation: java_s_staticmethod_exec("method_name", "V");
+*/
+int j_s_st_exec_0(struct sip_msg *msgp, char *method_name, char *signature)
+{
+    return java_exec(msgp, 1, 1, method_name, signature, NULL);
+}
+/*
+    example of java prototype: public static synchronized int method_name(int param);
+    example of kamailio invocation: java_s_staticmethod_exec("method_name", "I", "5");
+*/
+int j_s_st_exec_1(struct sip_msg *msgp, char *method_name, char *signature, char *param)
+{
+    return java_exec(msgp, 1, 1, method_name, signature, param);
+}
+
+
+int java_exec(struct sip_msg *msgp, int is_static, int is_synchronized, char *method_name, char *signature, char *param)
+{
+    char *retval_sig;
+    char *cs;
+    size_t cslen;
+    jint retval;
+    int locked;
+    jfieldID fid;
+    jclass cls;
+    jmethodID invk_method, invk_method_ref;
+    jvalue *jparam;
+
+    if (signature == NULL || !strcmp(signature, ""))
+    {
+	LM_ERR("java_method_exec(): signature is empty or invalid.\n");
+	return -1;
+    }
+
+    if (param == NULL && strcmp(signature, "V"))
+    {
+	LM_ERR("java_method_exec(): no paramter (parameter is NULL) but signature '%s' is not equals to 'V'.\n", signature);
+	return -1;
+    }
+
+    if (is_sig_allowed(signature) == 0)
+    {
+	LM_ERR("java_method_exec(): error: signature '%s' isn't supported yet.\n", signature);
+	return -1;
+    }
+
+    if (!strcmp(signature, "V"))
+    {
+	signature = "";
+    }
+
+    retval_sig = "I";
+
+    cslen = strlen(signature) + 2 + 1 + 1;	// '(' + 'signature' + ')' + 'return signature' + null terminator
+    cs = (char *)pkg_malloc(cslen * sizeof(char));
+    if (!cs)
+    {
+	LM_ERR("pkg_malloc() has failed. Can't allocate %lu bytes. Not enough memory!\n", (unsigned long)cslen);
+	return -1;
+    }
+    snprintf(cs, cslen, "(%s)%s", signature, retval_sig);
+    cs[cslen] = '\0';
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return -1;
+    }
+
+    cls = (*env)->GetObjectClass(env, KamailioClassInstance);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+        return -1;
+    }
+    fid = (*env)->GetFieldID(env, cls, "mop", "I");
+    if (!fid)
+    {
+        handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+        return -1;
+    }
+
+    msg = msgp;
+
+    // find a method by signature
+    invk_method = is_static ? 
+		    (*env)->GetStaticMethodID(env, KamailioClassRef, method_name, cs) : 
+		    (*env)->GetMethodID(env, KamailioClassRef, method_name, cs);
+    if (!invk_method || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+    	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    pkg_free(cs);
+
+    // keep local reference to method
+    invk_method_ref = (*env)->NewLocalRef(env, invk_method);
+    if (!invk_method_ref || (*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+	(*env)->DeleteLocalRef(env, invk_method_ref);
+	(*jvm)->DetachCurrentThread(jvm);
+        return -1;
+    }
+
+    retval = -1;
+
+    if (is_synchronized)
+    {
+	if ((*env)->MonitorEnter(env, invk_method_ref) != JNI_OK)
+        {
+	    locked = 0;
+	    LM_ERR("MonitorEnter() has failed!\n");
+	}
+	else
+	{
+	    locked = 1;
+	}
+    }
+
+    if (param == NULL)
+    {
+	retval = is_static ?
+		    (int)(*env)->CallStaticIntMethod(env, KamailioClassRef, invk_method_ref) :
+		    (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, invk_method_ref);
+    }
+    else
+    {
+	jparam = get_value_by_sig_type(signature, param);
+	if (jparam == NULL)
+	{
+	    (*env)->DeleteLocalRef(env, invk_method_ref);
+	    (*env)->DeleteLocalRef(env, invk_method);
+    	    (*jvm)->DetachCurrentThread(jvm);
+	    return -1;
+	}
+
+	retval = is_static ?
+		    (int)(*env)->CallStaticIntMethod(env, KamailioClassRef, invk_method_ref, *jparam) :
+		    (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, invk_method_ref, *jparam);
+    }
+
+    if ((*env)->ExceptionCheck(env))
+    {
+        LM_ERR("%s(): %s() has failed. See exception below.\n", 
+		(is_static ? 
+			(is_synchronized ? "java_s_staticmethod_exec" : "java_staticmethod_exec") :
+			(is_synchronized ? "java_s_method_exec" : "java_method_exec")
+		),
+		is_static ? "CallStaticIntMethod" : "CallIntMethod"
+	);
+
+        handle_exception();
+
+	(*env)->DeleteLocalRef(env, invk_method_ref);
+	(*env)->DeleteLocalRef(env, invk_method);
+        (*jvm)->DetachCurrentThread(jvm);
+
+        return -1;
+    }
+
+    if (is_synchronized && locked)
+    {
+	if ((*env)->MonitorExit(env, invk_method_ref) != JNI_OK)
+	{
+	    LM_ERR("MonitorExit) has failed!\n");
+	}
+    }
+
+    (*env)->DeleteLocalRef(env, invk_method_ref);
+    (*env)->DeleteLocalRef(env, invk_method);
+    (*jvm)->DetachCurrentThread(jvm);
+
+    return retval;
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/app_java/java_iface.h b/modules/app_java/java_iface.h
new file mode 100644
index 0000000..12acee9
--- /dev/null
+++ b/modules/app_java/java_iface.h
@@ -0,0 +1,44 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_IFACE_H__
+#define	__JAVA_IFACE_H__
+
+#include "../../parser/msg_parser.h"
+
+int j_nst_exec_0(struct sip_msg *, char *, char *);
+int j_nst_exec_1(struct sip_msg *, char *, char *, char *);
+int j_s_nst_exec_0(struct sip_msg *, char *, char *);
+int j_s_nst_exec_1(struct sip_msg *, char *, char *, char *);
+
+int j_st_exec_0(struct sip_msg *, char *, char *);
+int j_st_exec_1(struct sip_msg *, char *, char *, char *);
+int j_s_st_exec_0(struct sip_msg *, char *, char *);
+int j_s_st_exec_1(struct sip_msg *, char *, char *, char *);
+
+int java_exec(struct sip_msg *, int, int, char *, char *, char *);
+
+
+
+#endif
diff --git a/modules/app_java/java_mod.c b/modules/app_java/java_mod.c
new file mode 100644
index 0000000..3f992df
--- /dev/null
+++ b/modules/app_java/java_mod.c
@@ -0,0 +1,260 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <libgen.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+
+#include "java_native_methods.h"
+
+MODULE_VERSION
+
+static str class_name = {.s = "Kamailio", .len = 10};
+static str child_init_mname = { .s = "child_init", .len = 0};
+static str java_options_str = { .s = "-Djava.compiler=NONE", .len = 21};
+
+static int mod_init(void);
+static int child_init(int rank);
+static void mod_destroy(void);
+
+
+/** module parameters */
+static param_export_t params[] = {
+    {"class_name",         STR_PARAM, &class_name },
+    {"child_init_method",  STR_PARAM, &child_init_mname },
+    {"java_options",	   STR_PARAM, &java_options_str },
+    {"force_cmd_exec", INT_PARAM, &force_cmd_exec },
+    {0,0,0}
+};
+
+
+/*
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+    { "java_method_exec",		(cmd_function)j_nst_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_method_exec",		(cmd_function)j_nst_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+    { "java_s_method_exec",		(cmd_function)j_s_nst_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_s_method_exec",		(cmd_function)j_s_nst_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+
+    { "java_staticmethod_exec",		(cmd_function)j_st_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_staticmethod_exec",		(cmd_function)j_st_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+    { "java_s_staticmethod_exec",	(cmd_function)j_s_st_exec_0,	2,	NULL,	0,	ANY_ROUTE },
+    { "java_s_staticmethod_exec",	(cmd_function)j_s_st_exec_1,	3,	NULL,	0,	ANY_ROUTE },
+
+    { 0, 0, 0, 0, 0, 0 }
+};
+
+/** module exports */
+struct module_exports exports = {
+    "app_java",                     /* module name */
+//    RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
+    DEFAULT_DLFLAGS,		    /* dlopen flags */
+    cmds,                           /* exported functions */
+    params,                         /* exported parameters */
+    0,                              /* exported statistics */
+    0,                              /* exported MI functions */
+    0,                              /* exported pseudo-variables */
+    0,                              /* extra processes */
+    mod_init,                       /* module initialization function */
+    (response_function) NULL,       /* response handling function */
+    (destroy_function) mod_destroy, /* destroy function */
+    child_init                      /* per-child init function */
+};
+
+static int mod_init(void)
+{
+    JavaVMInitArgs  vm_args;
+    jint res;
+    JavaVMOption *options;
+    char **opts;
+    int nOptions;
+
+    if (force_cmd_exec < 0 || force_cmd_exec > 1)
+    {
+	LM_ERR("Parameter force_cmd_exec should be either 0 or 1\n");
+	return -1;
+    }
+
+    if (force_cmd_exec)
+    {
+	LM_NOTICE("app_java: Parameter force_cmd_exec may cause a memory leaks if used from embedded languages\n");
+    }
+
+    options = (JavaVMOption *)pkg_malloc(sizeof(JavaVMOption));
+    if (!options)
+    {
+	LM_ERR("pkg_malloc() failed: Couldn't initialize Java VM: Not enough memory\n");
+	return -1;
+    }
+    memset(options, 0, sizeof(JavaVMOption));
+
+    LM_INFO("Initializing Java VM with options: %s\n", java_options_str.s);
+
+    opts = split(java_options_str.s, " ");
+    for (nOptions=0; opts[nOptions] != NULL; nOptions++)
+    {
+	options[nOptions].optionString = opts[nOptions];
+    }
+
+    /* IMPORTANT: specify vm_args version # if you use JDK1.1.2 and beyond */
+    vm_args.version = JNI_VERSION_1_2;
+    vm_args.nOptions = nOptions;
+    vm_args.ignoreUnrecognized = JNI_FALSE;
+    vm_args.options = options;
+
+    res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
+    if (res < 0)
+    {
+	handle_VM_init_failure(res);
+	return -1;
+    }
+
+    LM_INFO("app_java: Java VM initialization OK\n");
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	return -1;
+    }
+
+    KamailioClass = (*env)->FindClass(env, class_name.s);
+    if (!KamailioClass || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    KamailioClassRef = (*env)->NewGlobalRef(env, KamailioClass);
+    if (!KamailioClassRef || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    KamailioID = (*env)->GetMethodID(env, KamailioClass, "<init>", "()V");
+    if (!KamailioID || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    // calling constructor
+    KamailioClassInstance = (*env)->NewObject(env, KamailioClass, KamailioID);
+    if (!KamailioClassInstance || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    // keep a reference to kamailio class instance
+    KamailioClassInstanceRef = (*env)->NewGlobalRef(env, KamailioClassInstance);
+    if (!KamailioClassInstanceRef || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    LM_INFO("app_java: module initialization OK\n");
+
+    if (jvm != NULL)
+        (*jvm)->DetachCurrentThread(jvm);
+
+    return 0;
+}
+
+static int child_init(int rank)
+{
+    int retval;
+    jmethodID child_init_id;
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return -1;
+    }
+
+    child_init_id = (*env)->GetMethodID(env, KamailioClass, "child_init", "(I)I");
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+    	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    retval = (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, child_init_id, rank);
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+    	(*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    (*env)->DeleteLocalRef(env, child_init_id);
+    (*jvm)->DetachCurrentThread(jvm);
+
+    msg = NULL;
+
+    return retval;
+}
+
+static void mod_destroy(void)
+{
+    if (env != NULL)
+    {
+	(*env)->DeleteGlobalRef(env, KamailioClassInstanceRef);
+	(*env)->DeleteGlobalRef(env, KamailioClassRef);
+    }
+
+    if (jvm != NULL)
+    {
+	(*jvm)->DetachCurrentThread(jvm);
+	(*jvm)->DestroyJavaVM(jvm);
+    }
+
+    if (msg)
+    {
+	pkg_free(msg);
+    }
+
+}
diff --git a/modules/app_java/java_mod.h b/modules/app_java/java_mod.h
new file mode 100644
index 0000000..c0961b0
--- /dev/null
+++ b/modules/app_java/java_mod.h
@@ -0,0 +1,30 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_MOD_H__
+#define	__JAVA_MOD_H__
+
+int force_cmd_exec;
+
+#endif
diff --git a/modules/app_java/java_msgobj.c b/modules/app_java/java_msgobj.c
new file mode 100644
index 0000000..8270fbe
--- /dev/null
+++ b/modules/app_java/java_msgobj.c
@@ -0,0 +1,324 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include "../../action.h"
+#include "../../mem/mem.h"
+#include "../../sr_module.h"
+#include "../../dset.h"
+#include "../../parser/msg_parser.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_msgobj.h"
+
+jobject *fill_sipmsg_object(JNIEnv *env, struct sip_msg *msg)
+{
+    jobject *SipMsgInstance;
+    jclass SipMsgClass;
+    jmethodID SipMsgClassID;
+    jfieldID fid;
+    jstring jStrParam;
+
+    SipMsgInstance = (jobject *)pkg_malloc(sizeof(jobject));
+    if (!SipMsgInstance)
+    {
+	LM_ERR("pkg_malloc() has failed. Not enough memory!\n");
+	return NULL;
+    }
+    memset(SipMsgInstance, 0, sizeof(jobject));
+
+    SipMsgClass = (*env)->FindClass(env, "org/siprouter/SipMsg");
+    if (!SipMsgClass || (*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+	pkg_free(SipMsgInstance);
+        return NULL;
+    }
+
+    SipMsgClassID = (*env)->GetMethodID(env, SipMsgClass, "<init>", "()V");
+    if (!SipMsgClassID || (*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // calling constructor
+    (*SipMsgInstance) = (*env)->NewObject(env, SipMsgClass, SipMsgClassID);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->id => SipMsg.id 
+    fid = (*env)->GetFieldID(env, SipMsgClass, "id", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.id\n");
+
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->id);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->pid => SipMsg.pid
+    fid = (*env)->GetFieldID(env, SipMsgClass, "pid", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.pid\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->pid);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->eoh => SipMsg.eoh
+    fid = (*env)->GetFieldID(env, SipMsgClass, "eoh", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.eoh\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->eoh);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->unparsed => SipMsg.unparsed
+    fid = (*env)->GetFieldID(env, SipMsgClass, "unparsed", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+	LM_ERR("Can't find symbol org.siprouter.SipMsg.unparsed\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->unparsed);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->buf => SipMsg.buf
+    fid = (*env)->GetFieldID(env, SipMsgClass, "buf", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.buf\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->buf);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->len => SipMsg.len
+    fid = (*env)->GetFieldID(env, SipMsgClass, "len", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.len\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->len);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->new_uri => SipMsg.new_uri
+    fid = (*env)->GetFieldID(env, SipMsgClass, "new_uri", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.new_uri\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->new_uri.len <= 0 ? "" : msg->new_uri.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->dst_uri => SipMsg.dst_uri
+    fid = (*env)->GetFieldID(env, SipMsgClass, "dst_uri", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.dst_uri\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, msg->dst_uri.len <= 0 ? "" : msg->dst_uri.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->parsed_orig_ruri_ok => SipMsg.parsed_orig_ruri_ok
+    fid = (*env)->GetFieldID(env, SipMsgClass, "parsed_orig_ruri_ok", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.parsed_orig_ruri_ok\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->parsed_orig_ruri_ok);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->add_to_branch_s => SipMsg.add_to_branch_s
+    fid = (*env)->GetFieldID(env, SipMsgClass, "add_to_branch_s", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.add_to_branch_s\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, (msg->add_to_branch_len <= 0 || msg->add_to_branch_s == NULL) ? "" : strdup(msg->add_to_branch_s));
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->add_to_branch_len => SipMsg.add_to_branch_len
+    fid = (*env)->GetFieldID(env, SipMsgClass, "add_to_branch_len", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.add_to_branch_len\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->add_to_branch_len);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->hash_index => SipMsg.hash_index
+    fid = (*env)->GetFieldID(env, SipMsgClass, "hash_index", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.hash_index\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->hash_index);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->msg_flags => SipMsg.msg_flags
+    fid = (*env)->GetFieldID(env, SipMsgClass, "msg_flags", "I");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.msg_flags\n");
+        return NULL;
+    }
+    (*env)->SetIntField(env, SipMsgInstance, fid, msg->msg_flags);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    // msg->set_global_address => SipMsg.set_global_address
+    fid = (*env)->GetFieldID(env, SipMsgClass, "set_global_address", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.set_global_address\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, (msg->set_global_address.len <= 0 || msg->set_global_address.s == NULL) ? "" : msg->set_global_address.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    // msg->set_global_port => SipMsg.set_global_port
+    fid = (*env)->GetFieldID(env, SipMsgClass, "set_global_port", "Ljava/lang/String;");
+    if (!fid)
+    {
+	(*env)->ExceptionClear(env);
+        LM_ERR("Can't find symbol org.siprouter.SipMsg.set_global_port\n");
+        return NULL;
+    }
+    jStrParam = (*env)->NewStringUTF(env, (msg->set_global_port.len <= 0 || msg->set_global_port.s == NULL) ? "" : msg->set_global_port.s);
+    (*env)->SetObjectField(env, SipMsgInstance, fid, jStrParam);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return NULL;
+    }
+    (*env)->DeleteLocalRef(env, jStrParam);
+
+    return SipMsgInstance;
+}
diff --git a/modules/app_java/java_msgobj.h b/modules/app_java/java_msgobj.h
new file mode 100644
index 0000000..22f362e
--- /dev/null
+++ b/modules/app_java/java_msgobj.h
@@ -0,0 +1,34 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_MSGOBJ_H__
+#define	__JAVA_MSGOBJ_H__
+
+#include "../../parser/msg_parser.h"
+
+#include <jni.h>
+
+jobject *fill_sipmsg_object(JNIEnv *, struct sip_msg *);
+
+#endif
diff --git a/modules/app_java/java_native_methods.c b/modules/app_java/java_native_methods.c
new file mode 100644
index 0000000..d53be22
--- /dev/null
+++ b/modules/app_java/java_native_methods.c
@@ -0,0 +1,1223 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "../../str.h"
+#include "../../sr_module.h"
+#include "../../ip_addr.h"
+#include "../../flags.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_msgobj.h"
+#include "java_native_methods.h"
+#include "java_sig_parser.h"
+
+
+//// native methods ////
+
+/*
+    java: native void LM_XXXXXX(Params XXXX);
+    c: JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1XXXXXX(JNIEnv *jenv, jobject this, Params XXXX)
+
+    Why (for example) Java_Kamailio_LM_1ERR but not Java_Kamailio_LM_ERR? 
+    See explaination here: http://qscribble.blogspot.ca/2012/04/underscores-in-jni-method-names.html
+
+    Also, from here: http://192.9.162.55/docs/books/jni/html/design.html
+    The JNI adopts a simple name-encoding scheme to ensure that all Unicode characters 
+    translate into valid C function names. The underscore ("_") character separates the 
+    components of fully qualified class names. Because a name or type descriptor never 
+    begins with a number, we can use _0, ..., _9 for escape sequences, as illustrated below:
+    +-------------------+------------------------------------+
+    |  Escape Sequence  |            Denotes                 |
+    +-------------------+------------------------------------+
+    |	_0XXXX          |  a Unicode character XXXX          |
+    |	_1              |  the character "_"                 |
+    |	_2              |  the character ";" in descriptors  |
+    |	_3              |  the character "[" in descriptors  |
+    +-------------------+------------------------------------+
+
+*/
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_ERR(Ljava/lang/String;)V
+    Prototype: public static native void LM_ERR(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ERR(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_ERR("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_WARN(Ljava/lang/String;)V
+    Prototype: public static native void LM_WARN(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1WARN(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_WARN("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_NOTICE(Ljava/lang/String;)V
+    Prototype: public static native void LM_NOTICE(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1NOTICE(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_NOTICE("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_INFO(Ljava/lang/String;)V
+    Prototype: public static native void LM_INFO(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1INFO(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_INFO("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_DBG(Ljava/lang/String;)V
+    Prototype: public static native void LM_DBG(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1DBG(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_DBG("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_CRIT(Ljava/lang/String;)V
+    Prototype: public static native void LM_CRIT(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1CRIT(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_CRIT("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+
+#ifdef LM_ALERT
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_ALERT(Ljava/lang/String;)V
+    Prototype: public static native void LM_ALERT(String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ALERT(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_ALERT("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_GEN2(ILjava/lang/String;)V
+    Prototype: public static native void LM_GEN1(int logLevel, String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN1(JNIEnv *jenv, jobject this, jint ll, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_GEN1((int)ll, "%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: LM_GEN2(IILjava/lang/String;)V
+    Prototype: public static native void LM_GEN2(int logLevel, int logFacility, String s);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN2(JNIEnv *jenv, jobject this, jint ll, jint lf, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_GEN2((int)ll, (int)lf, "%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: NativeMethods
+    Method: KamExec(Ljava/lang/String;[Ljava/lang/String;)I
+    Prototype: public static native int KamExec(String fname, String... params);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_NativeMethods_KamExec(JNIEnv *jenv, jobject this, jstring jfname, jobjectArray strArrParams)
+{
+    int retval;
+    char *fname;
+    int argc;
+    jsize pc;
+    int i;
+    char *argv[MAX_ACTIONS];
+    jboolean is_copy;
+    jstring strp;
+    char *strc;
+
+    if (jfname == NULL)
+    {
+	LM_ERR("app_java: KamExec() required at least 1 argument (function name)\n");
+	return -1;
+    }
+
+    fname = (char *)(*jenv)->GetStringUTFChars(jenv, jfname, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return -1;
+    }
+
+    memset(argv, 0, MAX_ACTIONS * sizeof(char *));
+    argc = 0;
+
+    pc = (*jenv)->GetArrayLength(jenv, strArrParams);
+    if (pc >= 6)
+    {
+	pc = 6;
+    }
+
+    for (i=0; i<pc; i++)
+    {
+	strp = (jstring)(*jenv)->GetObjectArrayElement(jenv, strArrParams, i);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+    	    handle_exception();
+    	    return -1;
+	}
+
+	strc = (char *)(*jenv)->GetStringUTFChars(jenv, strp, &is_copy);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+    	    handle_exception();
+    	    return -1;
+	}
+
+	if (strc)
+	{
+	    argv[argc++] = strc;
+	}
+    }
+    
+    retval = KamExec(jenv, fname, argc, argv);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, jfname, fname);
+
+    return (jint)retval;
+}
+
+int KamExec(JNIEnv *jenv, char *fname, int argc, char **argv)
+{
+    sr31_cmd_export_t *fexport;
+    unsigned mod_ver;
+    int rval;
+    int mod_type;
+    struct action *act;
+    struct run_act_ctx ra_ctx;
+    int i;
+
+    if (!msg)
+	return -1;
+
+    fexport = find_export_record(fname, argc, 0, &mod_ver);
+    if (!fexport)
+    {
+	LM_ERR("app_java: KamExec(): '%s' - no such function\n", fname);
+        return -1;
+    }
+
+    /* check fixups */
+    if (force_cmd_exec == 0 && fexport->fixup != NULL && fexport->free_fixup == NULL)
+    {
+        LM_ERR("app_java: KamExec(): function '%s' has fixup - cannot be used\n", fname);
+	return -1;
+    }
+
+    switch(fexport->param_no)
+    {
+    	case 0:			mod_type = MODULE0_T;	break;
+	case 1:			mod_type = MODULE1_T;	break;
+	case 2:			mod_type = MODULE2_T;	break;
+	case 3:			mod_type = MODULE3_T;	break;
+	case 4:			mod_type = MODULE4_T;	break;
+	case 5:			mod_type = MODULE5_T;	break;
+	case 6:			mod_type = MODULE6_T;	break;
+	case VAR_PARAM_NO:	mod_type = MODULEX_T;	break;
+	default:
+		LM_ERR("app_java: KamExec(): unknown/bad definition for function '%s' (%d params)\n", fname, fexport->param_no);
+		return -1;
+    }
+
+
+    act = mk_action(mod_type, (argc+2),			/* number of (type, value) pairs */
+                	MODEXP_ST, fexport,		/* function */
+                	NUMBER_ST, argc,		/* parameter number */
+			STRING_ST, argv[0],		/* param. 1 */
+			STRING_ST, argv[1],		/* param. 2 */
+			STRING_ST, argv[2],		/* param. 3 */
+			STRING_ST, argv[3],		/* param. 4 */
+			STRING_ST, argv[4],		/* param. 5 */
+			STRING_ST, argv[5]		/* param. 6 */
+                   );
+
+    if (!act)
+    {
+	LM_ERR("app_java: KamExec(): action structure couldn't be created\n");
+	return -1;
+    }
+
+
+    /* handle fixups */
+    if (fexport->fixup)
+    {
+        if (argc == 0)
+	{
+            rval = fexport->fixup(0, 0);
+            if (rval < 0)
+	    {
+		LM_ERR("app_java: KamExec(): (no params) Error in fixup (0) for '%s'\n", fname);
+                return -1;
+            }
+        }
+	else
+	{
+	    for (i=0; i<=argc; i++)
+	    {
+		if (act->val[i+2].u.data != 0x0)
+		{
+        	    rval = fexport->fixup(&(act->val[i+2].u.data), i+1);
+        	    if (rval < 0)
+		    {
+			LM_ERR("app_java: KamExec(): (params: %d) Error in fixup (%d) for '%s'\n", argc, i+1, fname);
+            		return -1;
+        	    }
+        	    act->val[i+2].type = MODFIXUP_ST;
+		}
+	    }
+        }
+    }
+
+    init_run_actions_ctx(&ra_ctx);
+    rval = do_action(&ra_ctx, act, msg);
+
+    /* free fixups */
+    if (fexport->free_fixup)
+    {
+	for (i=0; i<=argc; i++)
+	{
+	    if ((act->val[i+2].type == MODFIXUP_ST) && (act->val[i+2].u.data))
+	    {
+		fexport->free_fixup(&(act->val[i+2].u.data), i+1);
+	    }
+	}
+    }
+
+    pkg_free(act);
+
+    return rval;
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: ParseSipMsg()Lorg/siprouter/SipMsg;
+    Prototype: public static native org.siprouter.SipMsg ParseSipMsg();
+*/
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_ParseSipMsg(JNIEnv *jenv, jobject this)
+{
+    if (!msg)
+	return NULL;
+
+    return fill_sipmsg_object(jenv, msg);
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getMsgType()Ljava/org/String;
+    Prototype: public static native String getMsgType();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getMsgType(JNIEnv *jenv, jobject this)
+{
+    char *cs;
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    switch ((msg->first_line).type)
+    {
+        case SIP_REQUEST:
+            cs = "SIP_REQUEST";
+            break;
+
+        case SIP_REPLY:
+            cs = "SIP_REPLY";
+            break;
+
+        default:
+	    cs = "SIP_INVALID";
+	    break;
+    }
+
+    js = (*jenv)->NewStringUTF(jenv, cs);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getStatus()Ljava/org/String;
+    Prototype: public static native String getStatus();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getStatus(JNIEnv *jenv, jobject this)
+{
+    str *cs;
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    if ((msg->first_line).type != SIP_REQUEST)
+    {
+	LM_ERR("app_java: getStatus(): Unable to fetch status. Error: Not a request message - no method available.\n");
+        return NULL;
+    }
+
+    cs = &((msg->first_line).u.request.method);
+
+    js = (*jenv)->NewStringUTF(jenv, (cs && cs->s && cs->len > 0) ? cs->s : "");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getRURI()Ljava/org/String;
+    Prototype: public static native String getRURI();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getRURI(JNIEnv *jenv, jobject this)
+{
+    str *cs;
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    if ((msg->first_line).type != SIP_REQUEST)
+    {
+	LM_ERR("app_java: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n");
+        return NULL;
+    }
+
+    cs = &((msg->first_line).u.request.uri);
+
+    js = (*jenv)->NewStringUTF(jenv, (cs && cs->s && cs->len > 0) ? cs->s : "");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getSrcAddress()Lorg/siprouter/IPPair;
+    Prototype: public static native org.siprouter.IPPair getSrcAddress();
+*/
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getSrcAddress(JNIEnv *jenv, jobject this)
+{
+    jclass ippair_cls;
+    jmethodID ippair_cls_id;
+    jobject ippair_cls_instance;
+
+    char *ip;
+    jstring jip;
+    int port;
+
+    if (!msg)
+	return NULL;
+
+    ippair_cls = (*jenv)->FindClass(jenv, "org/siprouter/IPPair");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ippair_cls_id = (*jenv)->GetMethodID(jenv, ippair_cls, "<init>", "(Ljava/lang/String;I)V");
+    if (!ippair_cls_id || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ip = ip_addr2a(&msg->rcv.src_ip);
+    if (!ip)
+    {
+	LM_ERR("app_java: getSrcAddress(): Unable to fetch src ip address.\n");
+	return NULL;
+    }
+    jip = (*jenv)->NewStringUTF(jenv, ip);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    port = msg->rcv.src_port;
+    if (port == 0x0)
+    {
+	LM_ERR("app_java: getSrcAddress(): Unable to fetch src port.\n");
+	return NULL;
+    }
+
+    // calling constructor
+    ippair_cls_instance = (*jenv)->NewObject(jenv, ippair_cls, ippair_cls_id, (jstring)jip, (jint)port);
+    if (!ippair_cls_instance || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return ippair_cls_instance;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getDstAddress()Lorg/siprouter/IPPair;
+    Prototype: public static native org.siprouter.IPPair getDstAddress();
+*/
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getDstAddress(JNIEnv *jenv, jobject this)
+{
+    jclass ippair_cls;
+    jmethodID ippair_cls_id;
+    jobject ippair_cls_instance;
+
+    char *ip;
+    jstring jip;
+    int port;
+
+    if (!msg)
+	return NULL;
+
+    ippair_cls = (*jenv)->FindClass(jenv, "org/siprouter/IPPair");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ippair_cls_id = (*jenv)->GetMethodID(jenv, ippair_cls, "<init>", "(Ljava/lang/String;I)V");
+    if (!ippair_cls_id || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    ip = ip_addr2a(&msg->rcv.dst_ip);
+    if (!ip)
+    {
+	LM_ERR("app_java: getDstAddress(): Unable to fetch src ip address.\n");
+	return NULL;
+    }
+    jip = (*jenv)->NewStringUTF(jenv, ip);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    port = msg->rcv.dst_port;
+    if (port == 0x0)
+    {
+	LM_ERR("app_java: getDstAddress(): Unable to fetch src port.\n");
+	return NULL;
+    }
+
+    // calling constructor
+    ippair_cls_instance = (*jenv)->NewObject(jenv, ippair_cls, ippair_cls_id, (jstring)jip, (jint)port);
+    if (!ippair_cls_instance || (*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return ippair_cls_instance;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: SipMsg
+    Method: getBuffer()Ljava/org/String;
+    Prototype: public static native String getBuffer();
+*/
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getBuffer(JNIEnv *jenv, jobject this)
+{
+    jstring js;
+
+    if (!msg)
+	return NULL;
+
+    if ((msg->first_line).type != SIP_REQUEST)
+    {
+	LM_ERR("app_java: getRURI(): Unable to fetch ruri. Error: Not a request message - no method available.\n");
+        return NULL;
+    }
+
+    js = (*jenv)->NewStringUTF(jenv, msg->buf ? msg->buf : "");
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return NULL;
+    }
+
+    return js;
+}
+
+
+
+
+
+
+///// Core Functions /////
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: seturi(Ljava/org/String;)I
+    Prototype: public static native int seturi(String uri);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_seturi(JNIEnv *jenv, jobject this, jstring juri)
+{
+    return cf_seturi(jenv, this, juri, "seturi");
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: rewriteuri(Ljava/org/String;)I
+    Prototype: public static native int rewriteuri(String uri);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_rewriteuri(JNIEnv *jenv, jobject this, jstring juri)
+{
+    return cf_seturi(jenv, this, juri, "rewriteuri");
+}
+
+/* wrapped function */
+jint cf_seturi(JNIEnv *jenv, jobject this, jstring juri, char *fname)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *curi;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: %s: Can't process, msg=NULL\n", fname);
+	return -1;
+    }
+
+    curi = (char *)(*jenv)->GetStringUTFChars(jenv, juri, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+    	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = SET_URI_T;
+    act.val[0].type = STRING_ST;
+    act.val[0].u.str.s = curi;
+    act.val[0].u.str.len = strlen(curi);
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    (*jenv)->ReleaseStringUTFChars(jenv, juri, curi);
+    return (jint)retval;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: add_local_rport()I
+    Prototype: public static native int add_local_rport();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1local_1rport(JNIEnv *jenv, jobject this)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: add_local_rport: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = ADD_LOCAL_RPORT_T;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: append_branch()I
+    Method(o): append_branch(Ljava/lang/String)I
+    Prototype: public static native int append_branch();
+    Prototype(o): public static native int append_branch(String branch);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_append_1branch(JNIEnv *jenv, jobject this, jstring jbranch)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *cbranch;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: append_branch: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = APPEND_BRANCH_T;
+
+    cbranch = NULL;
+
+    if (jbranch)
+    {
+	cbranch = (char *)(*jenv)->GetStringUTFChars(jenv, jbranch, &is_copy);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+	    handle_exception();
+	    return -1;
+	}
+
+	act.val[0].type = STR_ST;
+	act.val[0].u.str.s = cbranch;
+	act.val[0].u.str.len = strlen(cbranch);
+    }
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    if (cbranch)
+    {
+	(*jenv)->ReleaseStringUTFChars(jenv, jbranch, cbranch);
+    }
+
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: drop()I
+    Prototype: public static native int drop();
+    Returns:
+	0 if action -> end of list(e.g DROP)
+        > 0 to continue processing next actions
+	< 0 on error
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_drop(JNIEnv *jenv, jobject this)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: drop: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = DROP_T;
+    act.val[0].type = NUMBER_ST;
+    act.val[0].u.number = 0;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: force_rport()I
+    Prototype: public static native int force_rport();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1rport(JNIEnv *jenv, jobject this)
+{
+    return cf_force_rport(jenv, this, "force_rport");
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: add_rport()I
+    Prototype: public static native int add_rport();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1rport(JNIEnv *jenv, jobject this)
+{
+    return cf_force_rport(jenv, this, "add_rport");
+}
+
+/* wrapped function */
+jint cf_force_rport(JNIEnv *jenv, jobject this, char *fname)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: %s: Can't process, msg=NULL\n", fname);
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = FORCE_RPORT_T;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: force_send_socket(Ljava/lang/String;I)I
+    Prototype: public static native int force_send_socket(String srchost, int srcport);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1send_1socket(JNIEnv *jenv, jobject this, jstring jsrchost, jint jsrcport)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    struct socket_id *si;
+    struct name_lst *nl;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: force_send_socket: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    nl = (struct name_lst *)pkg_malloc(sizeof(struct name_lst));
+    if (!nl)
+    {
+	LM_ERR("app_java: force_send_socket: pkg_malloc() has failed. Not enough memory!\n");
+	return -1;
+    }
+    
+    si = (struct socket_id *)pkg_malloc(sizeof(struct socket_id));
+    if (!si)
+    {
+	LM_ERR("app_java: force_send_socket: pkg_malloc() has failed. Not enough memory!\n");
+	return -1;
+    }
+    
+
+    memset(&act, 0, sizeof(act));
+    act.type = FORCE_SEND_SOCKET_T;
+
+    nl->name = (char *)(*jenv)->GetStringUTFChars(jenv, jsrchost, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+        handle_exception();
+        return -1;
+    }
+    nl->next = NULL;
+    nl->flags = 0;
+
+    si->addr_lst = nl;
+    si->flags = 0;
+    si->proto = PROTO_NONE;
+    si->port = (int)jsrcport;
+    
+    act.val[0].type = SOCKETINFO_ST;
+    act.val[0].u.data = si;
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, jsrchost, nl->name);
+    pkg_free(nl);
+    pkg_free(si);
+    return (jint)retval;
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: forward()I
+    Method(o): forward(Ljava/lang/String;I)I
+    Prototype: public static native int forward();
+    Prototype(o): public static native int forward(String ruri, int i);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_forward(JNIEnv *jenv, jobject this, jstring jrurihost, jint juriport)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *crurihost;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: forward: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = FORWARD_T;
+
+    crurihost = NULL;
+
+    if (jrurihost)
+    {
+	crurihost = (char *)(*jenv)->GetStringUTFChars(jenv, jrurihost, &is_copy);
+	if ((*jenv)->ExceptionCheck(jenv))
+	{
+    	    handle_exception();
+    	    return -1;
+	}
+
+	act.val[0].type = URIHOST_ST;
+	act.val[0].u.str.s = crurihost;
+	act.val[0].u.str.len = strlen(crurihost);
+
+	act.val[1].type = NUMBER_ST;
+	act.val[1].u.number = (int)juriport;
+    }
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    if (crurihost)
+    {
+	(*jenv)->ReleaseStringUTFChars(jenv, jrurihost, crurihost);
+    }
+
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: isflagset(I)Z
+    Prototype: public static native boolean isflagset(int flag);
+*/
+JNIEXPORT jboolean JNICALL Java_org_siprouter_CoreMethods_isflagset(JNIEnv *jenv, jobject this, jint jflag)
+{
+    if (!msg)
+    {
+	LM_ERR("app_java: isflagset: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    return isflagset(msg, (int)jflag) == 1 ? JNI_TRUE : JNI_FALSE;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: setflag(I)V
+    Prototype: public static native void setflag(int flag);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_setflag(JNIEnv *jenv, jobject this, jint jflag)
+{
+    if (!msg)
+    {
+	LM_ERR("app_java: setflag: Can't process, msg=NULL\n");
+	return;
+    }
+
+    setflag(msg, (int)jflag);
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: resetflag(I)V
+    Prototype: public static native void resetflag(int flag);
+*/
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_resetflag(JNIEnv *jenv, jobject this, jint jflag)
+{
+    if (!msg)
+    {
+	LM_ERR("app_java: resetflag: Can't process, msg=NULL\n");
+	return;
+    }
+
+    resetflag(msg, (int)jflag);
+}
+
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: revert_uri()I
+    Prototype: public static native int revert_uri();
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_revert_1uri(JNIEnv *jenv, jobject this)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+
+    if (!msg)
+    {
+	LM_ERR("app_java: revert_uri: Can't process, msg=NULL\n");
+	return -1;
+    }
+
+    memset(&act, 0, sizeof(act));
+    act.type = REVERT_URI_T;
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+    return (jint)retval;
+}
+
+/*
+    *** Java API ***
+    Package: org.siprouter
+    Class: CoreMethods
+    Method: route(Ljava/lang/String)I
+    Prototype: public static native int route(String target);
+*/
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_route(JNIEnv *jenv, jobject this, jstring jtarget)
+{
+    struct action act;
+    struct run_act_ctx ra_ctx;
+    int retval;
+    jboolean is_copy;
+    char *ctarget;
+
+    ctarget = (char *)(*jenv)->GetStringUTFChars(jenv, jtarget, &is_copy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return -1;
+    }
+
+    retval = route_lookup(&main_rt, ctarget);
+
+    if (retval == -1)	// route index lookup failed.
+    {
+	LM_ERR("app_java: route: failed to find route name '%s'\n", ctarget);
+	(*jenv)->ReleaseStringUTFChars(jenv, jtarget, ctarget);
+	return -1;
+    }
+
+    act.type = ROUTE_T;
+    act.val[0].type = NUMBER_ST;
+    act.val[0].u.number = retval;
+
+    init_run_actions_ctx(&ra_ctx);
+    retval = do_action(&ra_ctx, &act, msg);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, jtarget, ctarget);
+
+    return retval;
+}
+
diff --git a/modules/app_java/java_native_methods.h b/modules/app_java/java_native_methods.h
new file mode 100644
index 0000000..d96718c
--- /dev/null
+++ b/modules/app_java/java_native_methods.h
@@ -0,0 +1,86 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_NATIVE_METHODS_H__
+#define	__JAVA_NATIVE_METHODS_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ERR(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1WARN(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1NOTICE(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1INFO(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1DBG(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1CRIT(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1ALERT(JNIEnv *, jobject, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN1(JNIEnv *, jobject, jint, jstring);
+JNIEXPORT void JNICALL Java_org_siprouter_NativeMethods_LM_1GEN2(JNIEnv *, jobject, jint, jint, jstring);
+
+JNIEXPORT jint JNICALL Java_org_siprouter_NativeMethods_KamExec(JNIEnv *, jobject, jstring, jobjectArray);
+int KamExec(JNIEnv *, char *, int, char **);
+
+
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_ParseSipMsg(JNIEnv *, jobject);
+
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getMsgType(JNIEnv *, jobject);
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getStatus(JNIEnv *, jobject);
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getRURI(JNIEnv *, jobject);
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getSrcAddress(JNIEnv *, jobject);
+JNIEXPORT jobject JNICALL Java_org_siprouter_SipMsg_getDstAddress(JNIEnv *, jobject);
+JNIEXPORT jstring JNICALL Java_org_siprouter_SipMsg_getBuffer(JNIEnv *, jobject);
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_seturi(JNIEnv *, jobject, jstring);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_rewriteuri(JNIEnv *, jobject, jstring);
+jint cf_seturi(JNIEnv *, jobject, jstring, char *);
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1local_1rport(JNIEnv *, jobject);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_append_1branch(JNIEnv *, jobject, jstring);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_drop(JNIEnv *, jobject);
+
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1rport(JNIEnv *, jobject);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_add_1rport(JNIEnv *, jobject);
+jint cf_force_rport(JNIEnv *, jobject, char *);
+
+// not confirmed as working
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_force_1send_1socket(JNIEnv *, jobject, jstring, jint);
+
+// not confirmed as working
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_forward(JNIEnv *, jobject, jstring, jint);
+
+JNIEXPORT jboolean JNICALL Java_org_siprouter_CoreMethods_isflagset(JNIEnv *, jobject, jint);
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_setflag(JNIEnv *, jobject, jint);
+JNIEXPORT void JNICALL Java_org_siprouter_CoreMethods_resetflag(JNIEnv *, jobject, jint);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_revert_1uri(JNIEnv *, jobject);
+JNIEXPORT jint JNICALL Java_org_siprouter_CoreMethods_route(JNIEnv *, jobject, jobject);
+
+#endif
diff --git a/modules/app_java/java_sig_parser.c b/modules/app_java/java_sig_parser.c
new file mode 100644
index 0000000..90cd5d0
--- /dev/null
+++ b/modules/app_java/java_sig_parser.c
@@ -0,0 +1,439 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <float.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_sig_parser.h"
+
+int is_sig_allowed(char *s)
+{
+    if (s == NULL || strlen(s) < 1)
+	return 0;
+
+    if (!strcmp(s, " ") || !strcmp(s, "\n") || !strcmp(s, "\r") || !strcmp(s, "\t"))
+    {
+	LM_ERR("signature error: '%s' contains whitespaces or any unparsable chars.\n", s);
+	return 0;
+    }
+
+//    LM_ERR("s='%s', strlen(s)=%d\n", s, strlen(s));
+
+    if (strlen(s) == 1)			// signature is single modifier (primitive)
+    {
+	if (!strcmp(s, "["))		// invalid signature modifier definition
+	{
+	    LM_ERR("signature error: '%s': no type of array specified.\n", s);
+	    return 0;
+	}
+
+	if (!strcmp(s, "L"))		// invalid signature modifier definition
+	{
+	    LM_ERR("signature error '%s': no object specified.\n", s);
+	    return 0;
+	}
+
+#ifndef JAVA_INV_SUPP_TYPE_VOID
+	if (!strcmp(s, "V"))
+	{
+	    LM_ERR("signature error '%s': no object specified.\n", s);
+	    return 0;
+	}
+#endif
+
+    }
+    else				// a complex signature (object)
+    {
+#ifndef JAVA_INV_SUPP_TYPE_ARRAYS
+	if (strcmp(s, "[") > 0)
+	{
+	    LM_ERR("signature error: '%s' denotes array which isn't supported yet.\n", s);
+	    return 0;
+	}
+#endif
+
+
+	if (strrchr(&s[0], 'L') > 0)
+	{
+#ifndef JAVA_INV_SUPP_TYPE_OBJECTS
+	    LM_ERR("signature error: '%s' denotes object which isn't supported yet.\n", s);
+	    return 0;
+#else
+	    int f = 0;
+#ifdef	JAVA_INV_SUPP_TYPE_BOOLEAN
+	    if (!strcmp(s, "Ljava/lang/Boolean;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_BYTE
+	    if (!strcmp(s, "Ljava/lang/Byte;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_CHARACTER
+	    if (!strcmp(s, "Ljava/lang/Character;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_DOUBLE
+	    if (!strcmp(s, "Ljava/lang/Double;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_FLOAT
+	    if (!strcmp(s, "Ljava/lang/Float;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_INTEGER
+	    if (!strcmp(s, "Ljava/lang/Integer;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_LONG
+	    if (!strcmp(s, "Ljava/lang/Long;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_SHORT
+	    if (!strcmp(s, "Ljava/lang/Short;"))
+		f = 1;
+#endif
+#ifdef	JAVA_INV_SUPP_TYPE_STRING
+	    if (!strcmp(s, "Ljava/lang/String;"))
+		f = 1;
+#endif
+	    if (f == 0)
+	    {
+		LM_ERR("signature '%s' isn't supported yet.\n", s);
+		return 0;
+	    }
+#endif
+	}
+
+    }
+
+    return 1;
+}
+
+
+
+static char *get_conv_err_str(int en)
+{
+    switch(en)
+    {
+	case EINVAL:	return "The value of base constant is not supported or no conversion could be performed";
+	case ERANGE:	return "The given string was out of range; the value converted has been clamped.";
+	default:	return "General parse error";
+    }
+}
+
+
+/* explaination of jvalue fields:
+typedef union jvalue {
+    jboolean z;
+    jbyte    b;
+    jchar    c;
+    jshort   s;
+    jint     i;
+    jlong    j;
+    jfloat   f;
+    jdouble  d;
+    jobject  l;
+} jvalue;
+*/
+
+jvalue *get_value_by_sig_type(char *sig, char *pval)
+{
+    char *endptr;
+    char scptr;
+    int siptr;
+    long slptr;
+    short ssptr;
+    double sdptr;
+    float sfptr;
+    jstring sjptr;
+    jvalue *ret;
+
+    ret = (jvalue *)pkg_malloc(sizeof(jvalue));
+    if (!ret)
+    {
+	LM_ERR("pkg_malloc() has failed. Not enouph memory!\n");
+	return NULL;
+    }
+
+    if (sig == NULL || strlen(sig) <= 0)
+    {
+	LM_ERR("app_java: Can't process empty or NULL signature.\n");
+	pkg_free(ret);
+	return NULL;
+    }
+    if (pval == NULL || strlen(pval) <= 0)
+    {
+	LM_ERR("app_java: Can't process empty or NULL parameter value.\n");
+	pkg_free(ret);
+	return NULL;
+    }
+
+    // boolean
+    if (!strncmp(sig, "Z", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_BOOLEAN)
+	|| !strcmp(sig, "Ljava/lang/Boolean;")
+#endif
+	) {
+	    if (!strncasecmp(pval, "true", 4))
+		(*ret).z = (jboolean)JNI_TRUE;
+/* comment this block to avoid conversation '1' to 'true' */
+	    else if (!strncmp(pval, "1", 1))
+		(*ret).z = (jboolean)JNI_TRUE;
+	    else if (!strncasecmp(pval, "false", 5))
+		(*ret).z = (jboolean)JNI_FALSE;
+/* comment this block to avoid conversation '0' to 'false' */
+	    else if (!strncmp(pval, "0", 1))
+		(*ret).z = (jboolean)JNI_FALSE;
+	    else
+	    {
+    		LM_ERR("app_java: Can't cast '%s' to type '%s'.\n", pval, sig);
+		pkg_free(ret);
+		return NULL;
+	    }
+
+	    return ret;
+    }
+    else
+    // byte
+    if (!strncmp(sig, "B", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_BYTE)
+	|| !strcmp(sig, "Ljava/lang/Byte;")
+#endif
+	) {
+//	    skptr = (signed char)char2jbyte(pval);
+	    sscanf(pval, "%x", &siptr);
+	    if (siptr == 0 && errno != 0)
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (siptr < SCHAR_MAX || siptr > SCHAR_MAX)
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+            (*ret).b = (jbyte)siptr;
+	    return ret;
+    }
+    else
+    // char
+    if (!strncmp(sig, "C", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_CHARACTER)
+	|| !strcmp(sig, "Ljava/lang/Character;")
+#endif
+	) {
+	    sscanf(pval, "%c", &scptr);
+	    if (scptr == 0 && errno != 0)
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (scptr < CHAR_MIN || scptr > CHAR_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+            (*ret).c = (jchar)scptr;
+	    return ret;
+    }
+    else
+    // double
+    if (!strncmp(sig, "D", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_DOUBLE)
+	|| !strcmp(sig, "Ljava/lang/Double;")
+#endif
+	) {
+	    sdptr = (double)strtod(pval, &endptr);
+	    if ((sdptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (sdptr < LLONG_MIN || sdptr > LLONG_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).d = (jdouble)sdptr;
+	    return ret;
+    }
+    else
+    // float
+    if (!strncmp(sig, "F", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_FLOAT)
+	|| !strcmp(sig, "Ljava/lang/Float;")
+#endif
+	) {
+	    sfptr = (float)strtof(pval, &endptr);
+	    if ((sfptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+            if (sfptr < FLT_MIN || sfptr > FLT_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).f = (jfloat)sfptr;
+	    return ret;
+    }
+    else
+    // integer
+    if (!strncmp(sig, "I", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_INTEGER)
+	|| !strcmp(sig, "Ljava/lang/Integer;")
+#endif
+	) {
+	    slptr = strtol(pval, &endptr, 10);
+	    if ((slptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+	    if (slptr < INT_MIN || slptr > INT_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).i = (jint)slptr;
+	    return ret;
+    }
+    else
+    // long
+    if (!strncmp(sig, "J", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_LONG)
+	|| !strcmp(sig, "Ljava/lang/Long;")
+#endif
+	) {
+	    slptr = (long)strtol(pval, &endptr, 10);
+	    if ((slptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+	    if (slptr < LONG_MIN || slptr > LONG_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).j = (jlong)slptr;
+	    return ret;
+    }
+    else
+    // short
+    if (!strncmp(sig, "S", 1)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_SHORT)
+	|| !strcmp(sig, "Ljava/lang/Short;")
+#endif
+	) {
+	    ssptr = (short)strtod(pval, &endptr);
+	    if ((ssptr == 0 && errno != 0) || (pval == endptr))
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Error: %s.\n", pval, sig, get_conv_err_str(errno));
+		pkg_free(ret);
+                return NULL;
+	    }
+	    if (ssptr < SHRT_MIN || ssptr > SHRT_MAX)	// overflow
+	    {
+		LM_ERR("app_java: Can't cast '%s' to type '%s'. Reason: overflow.", pval, sig);
+		pkg_free(ret);
+                return NULL;
+	    }
+
+	    (*ret).s = (jshort)ssptr;
+	    return ret;
+    }
+    // String (object)
+#if defined(JAVA_INV_SUPP_TYPE_OBJECTS) && defined(JAVA_INV_SUPP_TYPE_STRING)
+    else
+    if (!strcmp(sig, "Ljava/lang/String;"))
+    {
+	    sjptr = (*env)->NewStringUTF(env, pval);
+	    if ((*env)->ExceptionCheck(env))
+	    {
+		pkg_free(ret);
+		handle_exception();
+		return NULL;
+	    }
+/*
+	    if (pval != NULL && sjptr == NULL)
+	    {
+		pkg_free(ret);
+                return NULL;
+	    }
+*/
+	    (*ret).l = (jstring)sjptr;
+	    return ret;
+    }
+#endif
+#ifdef JAVA_INV_SUPP_TYPE_VOID
+    else
+    if (!strncmp(sig, "V", 1))
+    {
+	pkg_free(ret);
+	return NULL;
+    }
+#endif
+    else
+    {
+	// unknown sig
+	LM_ERR("app_java: Can't cast '%s' to signature '%s'\n", pval, sig);
+	pkg_free(ret);
+	return NULL;
+    }
+
+    return NULL;
+}
+
diff --git a/modules/app_java/java_sig_parser.h b/modules/app_java/java_sig_parser.h
new file mode 100644
index 0000000..49038fd
--- /dev/null
+++ b/modules/app_java/java_sig_parser.h
@@ -0,0 +1,50 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_SIG_PARSER_H__
+#define	__JAVA_SIG_PARSER_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#define	JAVA_INV_SUPP_TYPE_OBJECTS
+
+#define	JAVA_INV_SUPP_TYPE_BOOLEAN
+#define	JAVA_INV_SUPP_TYPE_BYTE
+#define	JAVA_INV_SUPP_TYPE_CHARACTER
+#define	JAVA_INV_SUPP_TYPE_DOUBLE
+#define	JAVA_INV_SUPP_TYPE_FLOAT
+#define	JAVA_INV_SUPP_TYPE_INTEGER
+#define	JAVA_INV_SUPP_TYPE_LONG
+#define	JAVA_INV_SUPP_TYPE_SHORT
+#define	JAVA_INV_SUPP_TYPE_STRING
+#define	JAVA_INV_SUPP_TYPE_VOID
+
+int is_sig_allowed(char *);
+jvalue *get_value_by_sig_type(char *, char *);
+
+
+#endif
diff --git a/modules/app_java/java_support.c b/modules/app_java/java_support.c
new file mode 100644
index 0000000..452f368
--- /dev/null
+++ b/modules/app_java/java_support.c
@@ -0,0 +1,220 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <libgen.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+
+
+static char *_append_exception_trace_messages(char *msg_str, jthrowable a_exception, jmethodID a_mid_throwable_getCause, jmethodID a_mid_throwable_getStackTrace, jmethodID a_mid_throwable_toString, jmethodID a_mid_frame_toString)
+{
+    jobjectArray frames;
+    jsize frames_length, i;
+    jstring msg_obj;
+    jobject frame;
+    jthrowable cause;
+    jclass exClass;
+    jmethodID mid;
+    jboolean isCopy;
+
+    const char *tmpbuf;
+
+    // Get the array of StackTraceElements.
+    frames = (jobjectArray) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_getStackTrace);
+    if (!frames)
+    {
+        exClass = (*env)->GetObjectClass(env, a_exception);
+        mid = (*env)->GetMethodID(env, exClass, "toString", "()Ljava/lang/String;");
+        msg_obj = (jstring) (*env)->CallObjectMethod(env, a_exception, mid);
+
+        isCopy = JNI_FALSE;
+	tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, &isCopy);
+
+	strcat(msg_str, tmpbuf);
+	strcat(msg_str, "\n    <<No stacktrace available>>");
+
+        (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+        (*env)->DeleteLocalRef(env, msg_obj);
+
+	return msg_str;
+    }
+    else
+    {
+	frames_length = (*env)->GetArrayLength(env, frames);
+    }
+
+    // Add Throwable.toString() before descending stack trace messages.
+    if (frames != 0)
+    {
+        msg_obj = (jstring) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_toString);
+	tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, 0);
+	
+	strcat(msg_str, "Exception in thread \"main\" ");
+	strcat(msg_str, tmpbuf);
+
+        (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+        (*env)->DeleteLocalRef(env, msg_obj);
+    }
+
+
+    // Append stack trace messages if there are any.
+    if (frames_length > 0)
+    {
+        for (i=0; i<frames_length; i++)
+        {
+            // Get the string returned from the 'toString()'
+            // method of the next frame and append it to
+            // the error message.
+            frame = (*env)->GetObjectArrayElement(env, frames, i);
+            msg_obj = (jstring) (*env)->CallObjectMethod(env, frame, a_mid_frame_toString);
+
+            tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, 0);
+
+	    strcat(msg_str, "\n    at ");
+	    strcat(msg_str, tmpbuf);
+
+            (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+            (*env)->DeleteLocalRef(env, msg_obj);
+            (*env)->DeleteLocalRef(env, frame);
+        }
+    }
+    else
+    {
+	strcat(msg_str, "\n    <<No stacktrace available>>");
+    }
+
+
+    // If 'a_exception' has a cause then append the
+    // stack trace messages from the cause.
+    if (frames != 0)
+    {
+        cause = (jthrowable) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_getCause);
+        if (cause != 0)
+        {
+            tmpbuf = _append_exception_trace_messages(msg_str, cause, a_mid_throwable_getCause, a_mid_throwable_getStackTrace, a_mid_throwable_toString, a_mid_frame_toString);
+	    strcat(msg_str, tmpbuf);
+        }
+    }
+
+    if (msg_str != NULL)
+	return strdup(msg_str);
+    else
+	return NULL;
+}
+
+void handle_exception(void)
+{
+    char *error_msg = NULL;
+    char msg_str[8192];
+
+    jthrowable exception;
+    jclass throwable_class, frame_class;
+    jmethodID mid_throwable_getCause, mid_throwable_getStackTrace;
+    jmethodID mid_throwable_toString, mid_frame_toString;
+
+    if (!(*env)->ExceptionCheck(env))
+	return;
+
+    memset(&msg_str, 0, sizeof(msg_str));
+
+    // Get the exception and clear as no
+    // JNI calls can be made while an exception exists.
+    exception = (*env)->ExceptionOccurred(env);
+    if (exception)
+    {
+//	(*env)->ExceptionDescribe(env);
+	(*env)->ExceptionClear(env);
+
+	throwable_class = (*env)->FindClass(env, "java/lang/Throwable");
+
+	mid_throwable_getCause = (*env)->GetMethodID(env, throwable_class, "getCause", "()Ljava/lang/Throwable;");
+        mid_throwable_getStackTrace =  (*env)->GetMethodID(env, throwable_class, "getStackTrace",  "()[Ljava/lang/StackTraceElement;");
+	mid_throwable_toString = (*env)->GetMethodID(env, throwable_class, "toString", "()Ljava/lang/String;");
+
+        frame_class = (*env)->FindClass(env, "java/lang/StackTraceElement");
+	mid_frame_toString = (*env)->GetMethodID(env, frame_class, "toString", "()Ljava/lang/String;");
+
+        error_msg = _append_exception_trace_messages(msg_str, exception, mid_throwable_getCause, mid_throwable_getStackTrace, mid_throwable_toString, mid_frame_toString);    
+
+
+	(*env)->DeleteLocalRef(env, exception);
+    }
+
+    LM_ERR("Exception:\n%s\n", error_msg == NULL ? "(no info)" : error_msg);
+
+}
+
+void ThrowNewException(JNIEnv *env, char *fmt, ...)
+{
+    va_list ap;
+    char buf[1024];
+
+    memset(buf, 0, sizeof(char));
+
+    va_start(ap, fmt);
+    vsnprintf(buf, 1024, fmt, ap);
+    va_end(ap);
+
+    (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), buf);
+}
+
+void handle_VM_init_failure(int res)
+{
+    switch(res)
+    {
+	    case -1:
+		LM_ERR("Couldn't initialize Java VM: unknown error\n");
+		break;
+	    case -2:
+		LM_ERR("Couldn't initialize Java VM: thread detached from the VM\n");
+	        break;
+	    case -3:
+		LM_ERR("Couldn't initialize Java VM: JNI version error\n");
+		break;
+	    case -4:
+		LM_ERR("Couldn't initialize Java VM: not enough memory\n");
+		break;
+	    case -5:
+		LM_ERR("Couldn't initialize Java VM: VM already created\n");
+		break;
+	    case -6:
+		LM_ERR("Couldn't initialize Java VM: invalid arguments\n");
+		break;
+	    default:
+		LM_ERR("Couldn't initialize Java VM. Error code: %d\n", res);
+		break;
+    }
+}
+
+
diff --git a/modules/app_java/java_support.h b/modules/app_java/java_support.h
new file mode 100644
index 0000000..fec4a4a
--- /dev/null
+++ b/modules/app_java/java_support.h
@@ -0,0 +1,38 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_SUPPORT_H__
+#define	__JAVA_SUPPORT_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+void handle_exception(void);
+void ThrowNewException(JNIEnv *, char *, ...);
+void handle_VM_init_failure(int res);
+
+
+#endif
diff --git a/modules/app_java/kamailio_java_folder/java-untested/Kamailio.java b/modules/app_java/kamailio_java_folder/java-untested/Kamailio.java
new file mode 100644
index 0000000..f70676b
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/Kamailio.java
@@ -0,0 +1,388 @@
+
+import java.lang.*;
+import java.io.*; 
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+//import org.siprouter.CoreMethods.*;
+
+public class Kamailio extends NativeMethods
+{
+	static
+	{
+	    System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+	}
+
+	/* Constructor. Do not remove !!! */
+	public Kamailio()
+	{
+	}
+
+
+	public int child_init(int rank)
+	{
+	    return 1;
+	}
+
+	public int TestMethod()
+	{
+
+	    int retval = 0;
+	    boolean boolstate = false;
+
+/*
+	    LM_INFO(String.format("Msg Type: %s\n", SipMsg.getMsgType()));
+
+	    IPPair src = SipMsg.getSrcAddress();
+	    if (src != null)
+	    {
+		LM_INFO(String.format("src address=%s, src port=%d\n", src.ip, src.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair src is null!");
+	    }
+
+	    IPPair dst = SipMsg.getDstAddress();
+	    if (dst != null)
+	    {
+		LM_INFO(String.format("dst address=%s, dst port=%d\n", dst.ip, dst.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair dst is null!");
+	    }
+
+	    LM_INFO(String.format("buffer:\n%s\n", SipMsg.getBuffer().trim()));
+
+	    SipMsg msg = SipMsg.ParseSipMsg();
+	    if (msg != null)
+	    {
+		LM_INFO("msg:\n");
+		LM_INFO(String.format("\tid=%d\n", msg.id));
+		LM_INFO(String.format("\tpid=%d\n", msg.pid));
+		LM_INFO(String.format("\teoh='%s'\n", msg.eoh));
+		LM_INFO(String.format("\tunparsed='%s'\n", msg.unparsed));
+		LM_INFO(String.format("\tbuf='%s'\n", msg.buf));
+		LM_INFO(String.format("\tlen=%d\n", msg.len));
+		LM_INFO(String.format("\tnew_uri='%s'\n", msg.new_uri));
+		LM_INFO(String.format("\tdst_uri='%s'\n", msg.dst_uri));
+		LM_INFO(String.format("\tparsed_uri_ok=%d\n", msg.parsed_uri_ok));
+		LM_INFO(String.format("\tparsed_orig_ruri_ok=%d\n", msg.parsed_orig_ruri_ok));
+		LM_INFO(String.format("\tadd_to_branch_s='%s'\n", msg.add_to_branch_s));
+		LM_INFO(String.format("\tadd_to_branch_len=%d\n", msg.add_to_branch_len));
+		LM_INFO(String.format("\thash_index=%d\n", msg.hash_index));
+		LM_INFO(String.format("\tmsg_flags=%d\n", msg.msg_flags));
+		LM_INFO(String.format("\tset_global_address='%s'\n", msg.set_global_address));
+		LM_INFO(String.format("\tset_global_port='%s'\n", msg.set_global_port));
+	    }
+	    else
+	    {
+		LM_ERR("SipMsg msg is null!\n");
+	    }
+
+*/
+//	    retval = KamExec("append_hf", "P-hint: VOICEMAIL\r\n");
+
+//	    KamExec("sl_send_reply", "404", "Not relaying");
+
+//	    retval = KamExec("is_method", "INVITE|SUBSCRIBE");
+
+//	    LM_INFO(String.format("return value: %d\n", retval));
+
+
+
+
+//	    retval = CoreMethods.rewriteuri("sip:0002 at 192.168.254.99:5060");
+
+
+//	    retval = KamExec("rewriteuri", "sip:0002 at 192.168.254.99:5060");
+//	    retval = KamExec("sl_send_reply", "404", "relaying failed");
+
+//	    LM_INFO(String.format("return value: %d\n", retval));
+
+
+//	    retval = CoreMethods.add_local_rport();
+//	    retval = CoreMethods.drop();
+//	    retval = CoreMethods.force_rport();
+//	    retval = CoreMethods.force_send_socket("192.168.254.9", 50349);
+//	    retval = CoreMethods.forward("198.61.206.9", 5060);
+//	    retval = CoreMethods.forward();
+
+
+//	    CoreMethods.setflag(3);
+
+//	    boolstate = CoreMethods.isflagset(3);
+//	    LM_INFO("return state: " + boolstate + "\n");
+
+//	    retval = CoreMethods.revert_uri();
+    
+//	    retval = CoreMethods.route("NATDETECT");
+//	    retval = CoreMethods.route("5");
+
+	    retval = KamExec("is_method", "INVITE");
+
+	    LM_INFO(String.format("return value: %d\n", retval));
+
+
+
+	    return 1;
+	}
+
+
+	public static final int FLT_ACC		= 1;
+	public static final int FLT_ACCMISSED	= 2;
+	public static final int FLT_ACCFAILED	= 3;
+	public static final int FLT_NATS	= 5;
+	public static final int FLB_NATB	= 6;
+	public static final int FLB_NATSIPPING	= 7;
+
+
+	/// route ///
+	public int route()
+	{
+	    return 1;
+	}
+
+
+
+	/// request_route ///
+	public int request_route()
+	{
+
+	    // per request initial checks
+	    CoreMethods.route("REQINIT");
+
+	    // NAT detection
+    	    CoreMethods.route("NATDETECT");
+
+	    // CANCEL processing
+    	    if (WrappedMethods.is_method("CANCEL"))
+    	    {
+                if (WrappedMethods.t_check_trans())
+		{
+                    WrappedMethods.t_relay();
+		}
+
+                return 1;
+    	    }
+
+/*
+
+
+    	    // handle requests within SIP dialogs
+    	    CoreMethods.route("WITHINDLG");
+
+	    //### only initial requests (no To tag)
+	    WrappedMethods.t_check_trans();
+
+	    // authentication
+	    CoreMethods.route("AUTH");
+
+    	    // record routing for dialog forming requests (in case they are routed)
+	    // - remove preloaded route headers
+	    WrappedMethods.remove_hf("Route");
+	    if (WrappedMethods.is_method("INVITE|SUBSCRIBE"))
+	    {
+                WrappedMethods.record_route();
+	    }
+
+	    // account only INVITEs
+	    if (WrappedMethods.is_method("INVITE"))
+    	    {
+        	CoreMethods.setflag(FLT_ACC); // do accounting
+	    }
+
+	    // dispatch requests to foreign domains
+	    CoreMethods.route("SIPOUT");
+
+	    // ### requests for my local domains
+
+	    // handle presence related requests
+	    CoreMethods.route("PRESENCE");
+
+	    String ruri = SipMsg.getRURI();
+    	    if (ruri == null || ruri.length() <= 0)
+    	    {
+                // request with no Username in RURI
+                WrappedMethods.sl_send_reply("484", "Address Incomplete");
+                return 1;
+    	    }
+
+	    // dispatch destinations to PSTN
+    	    CoreMethods.route("PSTN");
+
+	    // user location service
+	    CoreMethods.route("LOCATION");
+
+	    CoreMethods.route("RELAY");
+
+*/
+
+	    return 1;
+	}
+
+
+
+
+
+
+
+
+	public int Route_REQINIT()
+	{
+	    return 1;
+	}
+
+	public int Route_NATDETECT()
+	{
+	    return 1;
+	}
+
+	public int Route_WITHINDLG()	
+	{
+	    if (WrappedMethods.has_totag())
+	    {
+		// sequential request withing a dialog should
+                // take the path determined by record-routing
+
+		if (WrappedMethods.loose_route())
+		{
+		    CoreMethods.route("DLGURI");
+
+		    if (WrappedMethods.is_method("BYE"))
+		    {
+			CoreMethods.setflag(FLT_ACC);		// do accounting ...
+			CoreMethods.setflag(FLT_ACCFAILED);	// ... even if the transaction fails
+		    }
+		    else if (WrappedMethods.is_method("ACK"))
+		    {
+			// ACK is forwarded statelessy
+			CoreMethods.route("NATMANAGE");
+		    }
+		    else if (WrappedMethods.is_method("NOTIFY"))
+		    {
+			// Add Record-Route for in-dialog NOTIFY as per RFC 6665.
+			WrappedMethods.record_route();
+		    }
+
+		    CoreMethods.route("RELAY");
+		}
+		else
+		{
+/* // this block would not work -- 'uri' and 'myself' aren't implemented yet //
+                        if (is_method("SUBSCRIBE") && uri == myself) {
+                                # in-dialog subscribe requests
+                                route(PRESENCE);
+                                exit;
+                        }
+*/
+			if (WrappedMethods.is_method("ACK"))
+			{
+			    if (WrappedMethods.t_check_trans())
+			    {
+                                // no loose-route, but stateful ACK;
+                                // must be an ACK after a 487
+                                // or e.g. 404 from upstream server
+                                WrappedMethods.t_relay();
+			    }
+			    else
+			    {
+				// ACK without matching transaction ... ignore and discard
+				return 1;
+			    }	
+			}
+			WrappedMethods.sl_send_reply("404", "Not here");
+		}
+
+	    }
+
+
+	    return 1;
+	}
+
+	public int Route_AUTH()
+	{
+	    return 1;
+	}
+
+	public int Route_SIPOUT()
+	{
+	    return 1;
+	}
+
+	public int Route_PRESENCE()
+	{
+	    return 1;
+	}
+
+	public int Route_PSTN()
+	{
+	    return 1;
+	}
+
+	public int Route_LOCATION()
+	{
+	    return 1;
+	}
+
+	public int Route_RELAY()
+	{
+	    // enable additional event routes for forwarded requests
+	    //  - serial forking, RTP relaying handling, a.s.o.
+    	    if (WrappedMethods.is_method("INVITE|SUBSCRIBE"))
+	    {
+////                WrappedMethods.t_on_branch("MANAGE_BRANCH");
+////                WrappedMethods.t_on_reply("MANAGE_REPLY");
+    	    }
+	    
+	    if (WrappedMethods.is_method("INVITE"))
+	    {
+////                WrappedMethods.t_on_failure("MANAGE_FAILURE");
+    	    }
+
+    	    if (!WrappedMethods.t_relay())
+	    {
+                WrappedMethods.sl_reply_error();
+	    }
+
+	    return 1;
+	}
+
+	public int Route_REGISTRAR()
+	{
+	    if (WrappedMethods.is_method("REGISTER"))
+	    {
+		if (CoreMethods.isflagset(FLT_NATS))
+		{
+		    CoreMethods.setflag(FLB_NATB);
+		    // uncomment next line to do SIP NAT pinging
+		    // CoreMethods.setflag(FLB_NATSIPPING);
+		}
+
+		if (!WrappedMethods.save("location"))
+		{
+		    WrappedMethods.sl_reply_error();
+		}
+	    }
+
+	    return 1;
+	}
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/app_java/kamailio_java_folder/java-untested/WrappedMethods.java b/modules/app_java/kamailio_java_folder/java-untested/WrappedMethods.java
new file mode 100644
index 0000000..b88cbd5
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/WrappedMethods.java
@@ -0,0 +1,87 @@
+import java.lang.*;
+import java.io.*;
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class WrappedMethods extends NativeMethods
+{
+	public static boolean is_method(String method)
+	{
+	    if (KamExec("is_method", method) == -1)
+		return false;
+	    else
+		return true;
+	}
+
+	public static boolean t_check_trans()
+	{
+	    if (KamExec("t_check_trans") == -1)
+		return false;
+	    else
+		return true;
+	}
+
+	public static boolean t_relay()
+	{
+	    if (KamExec("t_relay") == -1)
+		return false;
+	    else
+		return true;
+	}
+
+	public static void record_route()
+	{
+	    KamExec("record_route");
+	}
+
+	public static void append_hf(String txt)
+	{
+	    KamExec("append_hf", txt);
+	}
+
+	public static void append_hf(String txt, String hdr)
+	{
+	    KamExec("append_hf", txt, hdr);
+	}
+
+	public static void remove_hf(String hname)
+	{
+	    KamExec("remove_hf", hname);
+	}
+
+	public static void sl_send_reply(String replycode, String replymsg)
+	{
+	    KamExec("sl_send_reply", replycode, replymsg);
+	}
+
+	public static void sl_reply_error()
+	{
+	    KamExec("sl_reply_error");
+	}
+
+	public static boolean has_totag()
+	{
+	    if (KamExec("has_totag") == -1)
+                return false;
+            else
+                return true;
+        }
+
+	public static boolean loose_route()
+	{
+	    if (KamExec("loose_route") == -1)
+                return false;
+            else
+                return true;
+        }
+
+	public static boolean save(String location)
+	{
+	    if (KamExec("save", location) == -1)
+                return false;
+            else
+                return true;
+        }
+
+}
diff --git a/modules/app_java/kamailio_java_folder/java-untested/build.xml b/modules/app_java/kamailio_java_folder/java-untested/build.xml
new file mode 100644
index 0000000..02117ed
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/build.xml
@@ -0,0 +1,46 @@
+<project name="Kamailio Examples" default="all">
+
+    <target name="all" description="Do the entire build" depends="clean,siprouter_compile,kamailio.jar,main_compile" >
+	<echo>Building Kamailio examples</echo>
+    </target>
+
+    <target name="make.dirs" description="Make a dir">
+	<mkdir dir="build"/>
+    </target>
+
+    <target name="kamailio.jar" description="make jar file" depends="siprouter_compile">
+	<jar destfile="kamailio.jar">
+    	    <fileset dir="build" includes="**">
+        	<include name="**/*.class"/>
+                <exclude name="**/CVS"/>
+                <exclude name="**/.svn"/>
+                <exclude name="**/.git"/>
+            </fileset>
+        </jar>
+    </target>
+
+    <target name="siprouter_compile" description="compile java"  depends="make.dirs">
+	<javac destdir="build" includeantruntime="false">
+    	    <src path="siprouter_src/"/>
+        </javac>
+    </target>
+
+    <target name="main_compile" description="compile java">
+	<javac destdir="." includeantruntime="false" includes="**.java">
+    	    <src path="."/>
+	    <classpath>
+		<pathelement path="."/>
+		<pathelement location="kamailio.jar"/>
+	    </classpath>
+        </javac>
+    </target>
+
+
+
+    <target name="clean" description="Clean up">
+        <delete dir="build"/>
+	<delete file="kamailio.jar"/>
+	<delete file="Kamailio.class"/>
+    </target>
+
+</project>
diff --git a/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/CoreMethods.java b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/CoreMethods.java
new file mode 100644
index 0000000..42800f2
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/CoreMethods.java
@@ -0,0 +1,34 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public class CoreMethods
+{
+	    public static native int seturi(String ruri);
+	    public static native int rewriteuri(String ruri);			// alias to seturi
+
+	    public static native int add_local_rport();
+
+	    public static native int append_branch();
+	    public static native int append_branch(String branch);
+
+	    public static native int drop();
+
+	    public static native int force_rport();
+	    public static native int add_rport();				// alias to force_rport
+
+	    public static native int force_send_socket(String srchost, int srcport);
+
+	    public static native int forward();
+	    public static native int forward(String ruri, int port);
+
+	    public static native boolean isflagset(int flag);
+	    public static native void setflag(int flag);
+	    public static native void resetflag(int flag);
+
+	    public static native int revert_uri();
+
+	    public static native int route(String target);
+
+}
+
diff --git a/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/IPPair.java b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/IPPair.java
new file mode 100644
index 0000000..f7eae1b
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/IPPair.java
@@ -0,0 +1,15 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public class IPPair
+{ 
+    public final String ip;
+    public final int port; 
+    
+    public IPPair(String ip, int port)
+    { 
+	this.ip = ip; 
+	this.port = port;
+    }
+}
diff --git a/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeInterface.java b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeInterface.java
new file mode 100644
index 0000000..e93343f
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeInterface.java
@@ -0,0 +1,46 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public interface NativeInterface
+{
+    public abstract class Ranks
+    {
+	public static final int PROC_MAIN 		= 0;			// Main ser process
+	public static final int PROC_TIMER		= -1;			// Timer attendant process
+	public static final int PROC_RPC		= -2;			// RPC type process
+	public static final int PROC_FIFO		= PROC_RPC;		// FIFO attendant process
+	public static final int PROC_TCP_MAIN		= -4;			// TCP main process
+	public static final int PROC_UNIXSOCK		= -5;			// Unix socket server
+	public static final int PROC_ATTENDANT		= -10;			// main "attendant process
+	public static final int PROC_INIT		= -127;			/* special rank, the context is the main ser process, but this is 
+										    guaranteed to be executed before any rocess is forked, so it 
+										    can be used to setup shared variables that depend on some
+										    after mod_init available information (e.g. total number of processes).
+										    @warning child_init(PROC_MAIN) is again called in the same process (main)
+										    (before tcp), so make sure you don't init things twice, bot in PROC_MAIN and PROC_INT
+								*/
+	public static final int PROC_NOCHLDINIT		= -128;			// no child init functions will be called if this rank is used in fork_process()
+	public static final int PROC_SIPINIT		= 1;			// First SIP worker - some modules do special processing in this child, like loading db data
+	public static final int PROC_SIPRPC		= 127;			/* Used to init RPC worker as SIP commands handler. 
+										    Don't do any special processing in the child init with this rank - just bare child initialization
+										*/
+	public static final int PROC_MIN		= PROC_NOCHLDINIT;	// Minimum process rank
+    }
+
+    public abstract class LogParams
+    {
+	public static final int	L_ALERT			= -5;
+	public static final int L_BUG			= -4;
+	public static final int L_CRIT2			= -3;			// like L_CRIT, but adds prefix
+	public static final int L_CRIT			= -2;			// no prefix added
+	public static final int L_ERR			= -1;
+	public static final int L_WARN			= 0;
+	public static final int L_NOTICE		= 1;
+	public static final int L_INFO			= 2;
+	public static final int L_DBG			= 3;
+
+	public static final int DEFAULT_FACILITY	= 0;
+    }
+}
+
diff --git a/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeMethods.java b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeMethods.java
new file mode 100644
index 0000000..ba2ef1a
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/NativeMethods.java
@@ -0,0 +1,22 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class NativeMethods
+{
+	    public static native void LM_GEN1(int logLevel, String s);
+	    public static native void LM_GEN2(int logFacility, int logLevel, String s);
+	    public static native void LM_ALERT(String s);
+	    public static native void LM_CRIT(String s);
+	    public static native void LM_WARN(String s);
+	    public static native void LM_NOTICE(String s);
+	    public static native void LM_ERR(String s);
+	    public static native void LM_INFO(String s);
+	    public static native void LM_DBG(String s);
+
+
+	    protected final int mop = 0x0;				// 'message object pointer' (pointer to an original c pointer of 'struct sip_msg')
+
+	    public static native int KamExec(String fname, String... params);
+}
+
diff --git a/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/SipMsg.java b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/SipMsg.java
new file mode 100644
index 0000000..e544905
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java-untested/siprouter_src/SipMsg.java
@@ -0,0 +1,43 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class SipMsg
+{
+	/* Constructor. Do not remove !!! */
+	public SipMsg()
+	{
+	}
+
+	public int id;					// message id, unique/process
+	public int pid;					// process id
+	public String eoh;				// pointer to the end of header (if found) or null
+	public String unparsed;				// here we stopped parsing
+	public String buf;				// scratch pad, holds a modified message, via, etc. point into it
+	public int len;					// message len (orig)
+
+
+	public String new_uri;				// changed first line uri, when you change this
+	public String dst_uri;				// Destination URI, must be forwarded to this URI if dst_url lenght != 0
+	public int parsed_uri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+        public int parsed_orig_ruri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+
+	public String add_to_branch_s;			// whatever whoever want to append to branch comes here
+	public int add_to_branch_len;
+	public int hash_index;				// index to TM hash table; stored in core to avoid unnecessary calculations
+	public int msg_flags;				/* flags used by core. Allows to set various flags on the message; may be used for 
+							    simple inter-module communication or remembering processing state reached */
+	public String set_global_address;
+	public String set_global_port;
+
+
+	public static native SipMsg ParseSipMsg();
+
+	public static native String getMsgType();
+	public static native String getStatus();
+	public static native String getRURI();
+	public static native IPPair getSrcAddress();
+	public static native IPPair getDstAddress();
+	public static native String getBuffer();
+}
+
diff --git a/modules/app_java/kamailio_java_folder/java/Kamailio.java b/modules/app_java/kamailio_java_folder/java/Kamailio.java
new file mode 100644
index 0000000..e029517
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java/Kamailio.java
@@ -0,0 +1,130 @@
+
+import java.lang.*;
+import java.io.*; 
+
+import org.siprouter.*;
+import org.siprouter.NativeInterface.*;
+
+public class Kamailio extends NativeMethods
+{
+	static
+	{
+	    System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+	}
+
+	/* Constructor. Do not remove !!! */
+	public Kamailio()
+	{
+	}
+
+
+	public int child_init(int rank)
+	{
+	    switch (rank)
+	    {
+		case Ranks.PROC_MAIN:
+		    LM_INFO("We're at PROC_MAIN\n");
+		    break;
+		case Ranks.PROC_TIMER:
+		    LM_INFO("We're at PROC_TIMER\n");
+		    break;
+		case Ranks.PROC_RPC:
+		    LM_INFO("We're at PROC_RPC/PROC_FIFO\n");
+		    break;
+		case Ranks.PROC_TCP_MAIN:
+		    LM_INFO("We're at PROC_TCP_MAIN\n");
+		    break;
+		case Ranks.PROC_UNIXSOCK:
+		    LM_INFO("We're at PROC_UNIXSOCK\n");
+		    break;
+		case Ranks.PROC_ATTENDANT:
+		    LM_INFO("We're at PROC_ATTENDANT\n");
+		    break;
+		case Ranks.PROC_INIT:
+		    LM_INFO("We're at PROC_INIT\n");
+		    break;
+		case Ranks.PROC_NOCHLDINIT:
+		    LM_INFO("We're at PROC_NOCHLDINIT/PROC_MIN\n");
+		    break;
+		case Ranks.PROC_SIPINIT:
+		    LM_INFO("We're at PROC_SIPINIT\n");
+		    break;
+		case Ranks.PROC_SIPRPC:
+		    LM_INFO("We're at PROC_SIPRPC\n");
+		    break;
+	    }
+
+	    return 1;
+	}
+
+	public int TestMethod()
+	{
+
+	    LM_INFO(String.format("Msg Type: %s\n", SipMsg.getMsgType()));
+
+	    IPPair src = SipMsg.getSrcAddress();
+	    if (src != null)
+	    {
+		LM_INFO(String.format("src address=%s, src port=%d\n", src.ip, src.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair src is null!");
+	    }
+
+	    IPPair dst = SipMsg.getDstAddress();
+	    if (dst != null)
+	    {
+		LM_INFO(String.format("dst address=%s, dst port=%d\n", dst.ip, dst.port));
+	    }
+	    else
+	    {
+		LM_ERR("IPPair dst is null!");
+	    }
+
+	    LM_INFO(String.format("buffer:\n%s\n", SipMsg.getBuffer().trim()));
+
+	    SipMsg msg = SipMsg.ParseSipMsg();
+	    if (msg != null)
+	    {
+		LM_INFO("msg:\n");
+		LM_INFO(String.format("\tid=%d\n", msg.id));
+		LM_INFO(String.format("\tpid=%d\n", msg.pid));
+		LM_INFO(String.format("\teoh='%s'\n", msg.eoh));
+		LM_INFO(String.format("\tunparsed='%s'\n", msg.unparsed));
+		LM_INFO(String.format("\tbuf='%s'\n", msg.buf));
+		LM_INFO(String.format("\tlen=%d\n", msg.len));
+		LM_INFO(String.format("\tnew_uri='%s'\n", msg.new_uri));
+		LM_INFO(String.format("\tdst_uri='%s'\n", msg.dst_uri));
+		LM_INFO(String.format("\tparsed_uri_ok=%d\n", msg.parsed_uri_ok));
+		LM_INFO(String.format("\tparsed_orig_ruri_ok=%d\n", msg.parsed_orig_ruri_ok));
+		LM_INFO(String.format("\tadd_to_branch_s='%s'\n", msg.add_to_branch_s));
+		LM_INFO(String.format("\tadd_to_branch_len=%d\n", msg.add_to_branch_len));
+		LM_INFO(String.format("\thash_index=%d\n", msg.hash_index));
+		LM_INFO(String.format("\tmsg_flags=%d\n", msg.msg_flags));
+		LM_INFO(String.format("\tset_global_address='%s'\n", msg.set_global_address));
+		LM_INFO(String.format("\tset_global_port='%s'\n", msg.set_global_port));
+	    }
+	    else
+	    {
+		LM_ERR("SipMsg msg is null!\n");
+	    }
+
+	    return 1;
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/app_java/kamailio_java_folder/java/build.xml b/modules/app_java/kamailio_java_folder/java/build.xml
new file mode 100644
index 0000000..02117ed
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java/build.xml
@@ -0,0 +1,46 @@
+<project name="Kamailio Examples" default="all">
+
+    <target name="all" description="Do the entire build" depends="clean,siprouter_compile,kamailio.jar,main_compile" >
+	<echo>Building Kamailio examples</echo>
+    </target>
+
+    <target name="make.dirs" description="Make a dir">
+	<mkdir dir="build"/>
+    </target>
+
+    <target name="kamailio.jar" description="make jar file" depends="siprouter_compile">
+	<jar destfile="kamailio.jar">
+    	    <fileset dir="build" includes="**">
+        	<include name="**/*.class"/>
+                <exclude name="**/CVS"/>
+                <exclude name="**/.svn"/>
+                <exclude name="**/.git"/>
+            </fileset>
+        </jar>
+    </target>
+
+    <target name="siprouter_compile" description="compile java"  depends="make.dirs">
+	<javac destdir="build" includeantruntime="false">
+    	    <src path="siprouter_src/"/>
+        </javac>
+    </target>
+
+    <target name="main_compile" description="compile java">
+	<javac destdir="." includeantruntime="false" includes="**.java">
+    	    <src path="."/>
+	    <classpath>
+		<pathelement path="."/>
+		<pathelement location="kamailio.jar"/>
+	    </classpath>
+        </javac>
+    </target>
+
+
+
+    <target name="clean" description="Clean up">
+        <delete dir="build"/>
+	<delete file="kamailio.jar"/>
+	<delete file="Kamailio.class"/>
+    </target>
+
+</project>
diff --git a/modules/app_java/kamailio_java_folder/java/siprouter_src/IPPair.java b/modules/app_java/kamailio_java_folder/java/siprouter_src/IPPair.java
new file mode 100644
index 0000000..f7eae1b
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java/siprouter_src/IPPair.java
@@ -0,0 +1,15 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public class IPPair
+{ 
+    public final String ip;
+    public final int port; 
+    
+    public IPPair(String ip, int port)
+    { 
+	this.ip = ip; 
+	this.port = port;
+    }
+}
diff --git a/modules/app_java/kamailio_java_folder/java/siprouter_src/NativeInterface.java b/modules/app_java/kamailio_java_folder/java/siprouter_src/NativeInterface.java
new file mode 100644
index 0000000..e93343f
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java/siprouter_src/NativeInterface.java
@@ -0,0 +1,46 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public interface NativeInterface
+{
+    public abstract class Ranks
+    {
+	public static final int PROC_MAIN 		= 0;			// Main ser process
+	public static final int PROC_TIMER		= -1;			// Timer attendant process
+	public static final int PROC_RPC		= -2;			// RPC type process
+	public static final int PROC_FIFO		= PROC_RPC;		// FIFO attendant process
+	public static final int PROC_TCP_MAIN		= -4;			// TCP main process
+	public static final int PROC_UNIXSOCK		= -5;			// Unix socket server
+	public static final int PROC_ATTENDANT		= -10;			// main "attendant process
+	public static final int PROC_INIT		= -127;			/* special rank, the context is the main ser process, but this is 
+										    guaranteed to be executed before any rocess is forked, so it 
+										    can be used to setup shared variables that depend on some
+										    after mod_init available information (e.g. total number of processes).
+										    @warning child_init(PROC_MAIN) is again called in the same process (main)
+										    (before tcp), so make sure you don't init things twice, bot in PROC_MAIN and PROC_INT
+								*/
+	public static final int PROC_NOCHLDINIT		= -128;			// no child init functions will be called if this rank is used in fork_process()
+	public static final int PROC_SIPINIT		= 1;			// First SIP worker - some modules do special processing in this child, like loading db data
+	public static final int PROC_SIPRPC		= 127;			/* Used to init RPC worker as SIP commands handler. 
+										    Don't do any special processing in the child init with this rank - just bare child initialization
+										*/
+	public static final int PROC_MIN		= PROC_NOCHLDINIT;	// Minimum process rank
+    }
+
+    public abstract class LogParams
+    {
+	public static final int	L_ALERT			= -5;
+	public static final int L_BUG			= -4;
+	public static final int L_CRIT2			= -3;			// like L_CRIT, but adds prefix
+	public static final int L_CRIT			= -2;			// no prefix added
+	public static final int L_ERR			= -1;
+	public static final int L_WARN			= 0;
+	public static final int L_NOTICE		= 1;
+	public static final int L_INFO			= 2;
+	public static final int L_DBG			= 3;
+
+	public static final int DEFAULT_FACILITY	= 0;
+    }
+}
+
diff --git a/modules/app_java/kamailio_java_folder/java/siprouter_src/NativeMethods.java b/modules/app_java/kamailio_java_folder/java/siprouter_src/NativeMethods.java
new file mode 100644
index 0000000..f0d35ca
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java/siprouter_src/NativeMethods.java
@@ -0,0 +1,23 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class NativeMethods
+{
+	    public static native void LM_GEN1(int logLevel, String s);
+	    public static native void LM_GEN2(int logFacility, int logLevel, String s);
+	    public static native void LM_ALERT(String s);
+	    public static native void LM_CRIT(String s);
+	    public static native void LM_WARN(String s);
+	    public static native void LM_NOTICE(String s);
+	    public static native void LM_ERR(String s);
+	    public static native void LM_INFO(String s);
+	    public static native void LM_DBG(String s);
+
+
+	    protected final int mop = 0x0;				// 'message object pointer' (pointer to an original c pointer of 'struct sip_msg')
+
+	    public static native int KamExec(String fname, String... params);
+
+}
+
diff --git a/modules/app_java/kamailio_java_folder/java/siprouter_src/SipMsg.java b/modules/app_java/kamailio_java_folder/java/siprouter_src/SipMsg.java
new file mode 100644
index 0000000..e544905
--- /dev/null
+++ b/modules/app_java/kamailio_java_folder/java/siprouter_src/SipMsg.java
@@ -0,0 +1,43 @@
+
+package org.siprouter;
+import java.lang.*;
+
+public abstract class SipMsg
+{
+	/* Constructor. Do not remove !!! */
+	public SipMsg()
+	{
+	}
+
+	public int id;					// message id, unique/process
+	public int pid;					// process id
+	public String eoh;				// pointer to the end of header (if found) or null
+	public String unparsed;				// here we stopped parsing
+	public String buf;				// scratch pad, holds a modified message, via, etc. point into it
+	public int len;					// message len (orig)
+
+
+	public String new_uri;				// changed first line uri, when you change this
+	public String dst_uri;				// Destination URI, must be forwarded to this URI if dst_url lenght != 0
+	public int parsed_uri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+        public int parsed_orig_ruri_ok;			// 1 if parsed_orig_uri is valid, 0 if not, set if to 0 if you modify the uri (e.g change new_uri)
+
+	public String add_to_branch_s;			// whatever whoever want to append to branch comes here
+	public int add_to_branch_len;
+	public int hash_index;				// index to TM hash table; stored in core to avoid unnecessary calculations
+	public int msg_flags;				/* flags used by core. Allows to set various flags on the message; may be used for 
+							    simple inter-module communication or remembering processing state reached */
+	public String set_global_address;
+	public String set_global_port;
+
+
+	public static native SipMsg ParseSipMsg();
+
+	public static native String getMsgType();
+	public static native String getStatus();
+	public static native String getRURI();
+	public static native IPPair getSrcAddress();
+	public static native IPPair getDstAddress();
+	public static native String getBuffer();
+}
+
diff --git a/modules/app_java/utils.c b/modules/app_java/utils.c
new file mode 100644
index 0000000..72ee59a
--- /dev/null
+++ b/modules/app_java/utils.c
@@ -0,0 +1,89 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+#include "java_sig_parser.h"
+
+
+char **split(char *str, char *sep)
+{
+    char **buf = NULL;
+    char *token = NULL;
+    char *saveptr = NULL;
+    int i;
+
+    buf = (char **)pkg_malloc(sizeof(char *));
+    if (!buf)
+    {
+	LM_ERR("pkg_malloc() has failed. Not enough memory!\n");
+	return NULL;
+    }
+    memset(&buf, 0, sizeof(char *));
+
+    if (str == NULL)
+	return buf;
+
+    if (strncmp(str, sep, strlen(sep)) <= 0)
+    {
+	// string doesn't contains a separator
+	buf[0] = strdup(str);
+	return buf;
+    }
+
+    token = strdup(str);
+    for (i=0; token != NULL; token = saveptr, i++)
+    {
+        token = strtok_r(token, (const char *)sep, &saveptr);
+
+        if (token == NULL || !strcmp(token, ""))
+            break;
+
+	buf = (char **)pkg_realloc(buf, (i+1) * sizeof(char *));
+	if (!buf)
+	{
+	    LM_ERR("pkg_realloc() has failed. Not enough memory!\n");
+	    return NULL;
+	}
+        buf[i] = strdup(token);
+    }
+    buf[i] = NULL;
+
+    free(token);
+
+    return buf;
+}
+
diff --git a/modules/app_java/utils.h b/modules/app_java/utils.h
new file mode 100644
index 0000000..3f87391
--- /dev/null
+++ b/modules/app_java/utils.h
@@ -0,0 +1,34 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+char **split(char *, char *);
+
+#endif
diff --git a/modules/app_lua/README b/modules/app_lua/README
index d12b846..5768778 100644
--- a/modules/app_lua/README
+++ b/modules/app_lua/README
@@ -27,6 +27,7 @@ Daniel-Constantin Mierla
 
               3.1. load (string)
               3.2. register (string)
+              3.3. reload (boolean)
 
         4. Functions
 
@@ -35,16 +36,22 @@ Daniel-Constantin Mierla
               4.3. lua_run(function, params)
               4.4. lua_runstring(script)
 
-        5. Example of usage
+        5. Exported RPC Commands
+
+              5.1. app_lua.list
+              5.2. app_lua.reload
+
+        6. Example of usage
 
    List of Examples
 
    1.1. Set load parameter
    1.2. Set register parameter
-   1.3. lua_dofile usage
-   1.4. lua_dostring usage
-   1.5. lua_run usage
-   1.6. lua_runstring usage
+   1.3. Set reload parameter
+   1.4. lua_dofile usage
+   1.5. lua_dostring usage
+   1.6. lua_run usage
+   1.7. lua_runstring usage
 
 Chapter 1. Admin Guide
 
@@ -60,6 +67,7 @@ Chapter 1. Admin Guide
 
         3.1. load (string)
         3.2. register (string)
+        3.3. reload (boolean)
 
    4. Functions
 
@@ -68,7 +76,12 @@ Chapter 1. Admin Guide
         4.3. lua_run(function, params)
         4.4. lua_runstring(script)
 
-   5. Example of usage
+   5. Exported RPC Commands
+
+        5.1. app_lua.list
+        5.2. app_lua.reload
+
+   6. Example of usage
 
 1. Overview
 
@@ -109,6 +122,7 @@ Chapter 1. Admin Guide
 
    3.1. load (string)
    3.2. register (string)
+   3.3. reload (boolean)
 
 3.1. load (string)
 
@@ -167,6 +181,18 @@ modparam("app_lua", "load", "/usr/local/etc/kamailio/lua/myscript.lua")
 modparam("app_lua", "register", "sl")
 ...
 
+3.3. reload (boolean)
+
+   If reload is 1 enables the ability to reload the scripts using the RPC
+   app_lua.reload command.
+
+   Default value is "0 (off)".
+
+   Example 1.3. Set reload parameter
+...
+modparam("app_lua", "reload", 1)
+...
+
 4. Functions
 
    4.1. lua_dofile(path)
@@ -179,7 +205,7 @@ modparam("app_lua", "register", "sl")
    Execute the Lua script stored in 'path'. The parameter can be a string
    with pseudo-variables evaluated at runtime.
 
-   Example 1.3. lua_dofile usage
+   Example 1.4. lua_dofile usage
 ...
 lua_dofile("/usr/local/etc/kamailio/lua/myscript.lua");
 ...
@@ -189,7 +215,7 @@ lua_dofile("/usr/local/etc/kamailio/lua/myscript.lua");
    Execute the Lua script stored in parameter. The parameter can be a
    string with pseudo-variables.
 
-   Example 1.4. lua_dostring usage
+   Example 1.5. lua_dostring usage
 ...
 if(!lua_dostring("sr.log([[err]], [[----------- Hello World from $fU\n]])"))
 {
@@ -204,7 +230,7 @@ if(!lua_dostring("sr.log([[err]], [[----------- Hello World from $fU\n]])"))
    loaded at startup via parameter 'load'. Parameters can be strings with
    pseudo-variables that are evaluated at runtime.
 
-   Example 1.5. lua_run usage
+   Example 1.6. lua_run usage
 ...
 if(!lua_run("sr_append_fu_to_reply"))
 {
@@ -220,7 +246,7 @@ lua_run("lua_funcx", "$rU", "2");
    string with pseudo-variables. The script is executed in Lua context
    specific to loaded Lua files at startup.
 
-   Example 1.6. lua_runstring usage
+   Example 1.7. lua_runstring usage
 ...
 if(!lua_runstring("sr.log([[err]], [[----------- Hello World from $fU\n]])"))
 {
@@ -228,7 +254,37 @@ if(!lua_runstring("sr.log([[err]], [[----------- Hello World from $fU\n]])"))
 }
 ...
 
-5. Example of usage
+5. Exported RPC Commands
+
+   5.1. app_lua.list
+   5.2. app_lua.reload
+
+5.1. app_lua.list
+
+   Lists the id and path for every script loaded by the load parameter.
+
+   Name: app_lua.list
+
+   Parameters: none
+
+   Example:
+                kamcmd app_lua.lists
+
+5.2. app_lua.reload
+
+   Marks the need to reload the selected script. The actual reload is done
+   by every working process when the next call to lua_run function is
+   executed. If no parameter is added all the scripts are selected to be
+   reloaded.
+
+   Name: app_lua.reload
+
+   Parameters: id
+
+   Example:
+                kamcmd app_lua.reload 0
+
+6. Example of usage
 
    Create your Lua script and stored on file system, say:
    '/usr/local/etc/kamailio/lua/myscript.lua'.
diff --git a/modules/app_lua/app_lua_api.c b/modules/app_lua/app_lua_api.c
index 9d5e662..78a98e4 100644
--- a/modules/app_lua/app_lua_api.c
+++ b/modules/app_lua/app_lua_api.c
@@ -30,6 +30,7 @@
 #include "../../dprint.h"
 #include "../../ut.h"
 #include "../../mem/mem.h"
+#include "../../locking.h"
 #include "../../data_lump.h"
 #include "../../data_lump_rpl.h"
 #include "../../lib/kcore/cmpapi.h"
@@ -41,13 +42,22 @@
 
 #define SRVERSION "1.0"
 
-
+/**
+ * reload enabled param
+ * default: 0 (off)
+ */
+static unsigned int _app_lua_sr_reload = 0;
 /**
  *
  */
 static sr_lua_env_t _sr_L_env;
 
 /**
+ *
+ */
+static int *_app_lua_sv = NULL;
+
+/**
  * @return the static Lua env
  */
 sr_lua_env_t *sr_lua_env_get(void)
@@ -58,16 +68,65 @@ sr_lua_env_t *sr_lua_env_get(void)
 /**
  *
  */
-typedef struct _sr_lua_load
-{
-	char *script;
-	struct _sr_lua_load *next;
-} sr_lua_load_t;
-
+static sr_lua_load_t *_sr_lua_load_list = NULL;
 /**
- *
+ * set of locks to manage the shared variable.
  */
-static sr_lua_load_t *_sr_lua_load_list = NULL;
+static gen_lock_set_t *sr_lua_locks = NULL;
+static sr_lua_script_ver_t *sr_lua_script_ver = NULL;
+
+
+int lua_sr_alloc_script_ver(void)
+{
+	int size = _sr_L_env.nload;
+	
+	sr_lua_script_ver = (sr_lua_script_ver_t *) shm_malloc(sizeof(sr_lua_script_ver_t));
+	if(sr_lua_script_ver==NULL)
+	{
+		LM_ERR("cannot allocate shm memory\n");
+		return -1;
+	}
+
+	sr_lua_script_ver->version = (unsigned int *) shm_malloc(sizeof(unsigned int)*size);
+	if(sr_lua_script_ver->version==NULL)
+	{
+		LM_ERR("cannot allocate shm memory\n");
+		goto error;
+	}
+	memset(sr_lua_script_ver->version, 0, sizeof(unsigned int)*size);
+	sr_lua_script_ver->len = size;
+
+	if((sr_lua_locks=lock_set_alloc(size))==0)
+	{
+		LM_CRIT("failed to alloc lock set\n");
+		goto error;
+	}
+	if(lock_set_init(sr_lua_locks)==0 )
+	{
+		LM_CRIT("failed to init lock set\n");
+		goto error;
+	}
+
+	return 0;
+error:
+	if(sr_lua_script_ver!=NULL)
+	{
+		if(sr_lua_script_ver->version!=NULL)
+		{
+			shm_free(sr_lua_script_ver->version);
+			sr_lua_script_ver->version = NULL;
+		}
+		shm_free(sr_lua_script_ver);
+		sr_lua_script_ver = NULL;
+	}
+	if(sr_lua_locks!=NULL)
+	{
+		lock_set_destroy( sr_lua_locks );
+		lock_set_dealloc( sr_lua_locks );
+		sr_lua_locks = NULL;
+	}
+	return -1;
+}
 
 /**
  *
@@ -84,8 +143,13 @@ int sr_lua_load_script(char *script)
 	}
 	memset(li, 0, sizeof(sr_lua_load_t));
 	li->script = script;
+	li->version = 0;
 	li->next = _sr_lua_load_list;
 	_sr_lua_load_list = li;
+	_sr_L_env.nload += 1;
+	LM_DBG("loaded script:[%s].\n", script);
+	LM_DBG("Now there are %d scripts loaded\n", _sr_L_env.nload);
+
 	return 0;
 }
 
@@ -103,6 +167,19 @@ int sr_lua_register_module(char *mname)
 /**
  *
  */
+int sr_lua_reload_module(unsigned int reload)
+{
+	LM_DBG("reload:%d\n", reload);
+	if(reload!=0) {
+		_app_lua_sr_reload = 1;
+		LM_DBG("reload param activated!\n");
+	}
+	return 0;
+}
+
+/**
+ *
+ */
 void lua_sr_openlibs(lua_State *L)
 {
 	lua_sr_core_openlibs(L);
@@ -114,10 +191,19 @@ void lua_sr_openlibs(lua_State *L)
  */
 int lua_sr_init_mod(void)
 {
+	/* allocate shm */
+	if(lua_sr_alloc_script_ver()<0)
+	{
+		LM_CRIT("failed to alloc shm for version\n");
+		return -1;
+	}
+
 	memset(&_sr_L_env, 0, sizeof(sr_lua_env_t));
 	if(lua_sr_exp_init_mod()<0)
 		return -1;
+
 	return 0;
+
 }
 
 /**
@@ -258,6 +344,139 @@ void lua_sr_destroy(void)
 		_sr_L_env.LL = NULL;
 	}
 	memset(&_sr_L_env, 0, sizeof(sr_lua_env_t));
+
+	if(sr_lua_script_ver!=NULL)
+	{
+		shm_free(sr_lua_script_ver->version);
+		shm_free(sr_lua_script_ver);
+	}
+
+	if (sr_lua_locks!=NULL)
+	{
+		lock_set_destroy( sr_lua_locks );
+		lock_set_dealloc( sr_lua_locks );
+		sr_lua_locks = 0;
+	}
+
+	if(_app_lua_sv!=NULL) {
+		pkg_free(_app_lua_sv);
+		_app_lua_sv = 0;
+	}
+}
+
+/**
+ *
+ */
+int lua_sr_list_script(sr_lua_load_t **list)
+{
+	*list = _sr_lua_load_list;
+	return 0;
+}
+
+/**
+ * Mark script in pos to be reloaded
+ * pos -1: reload all scritps
+ */
+int lua_sr_reload_script(int pos)
+{
+	int i, len = sr_lua_script_ver->len;
+	if(_sr_lua_load_list!= NULL)
+	{
+		if (!sr_lua_script_ver)
+		{
+			LM_CRIT("shm for version not allocated\n");
+			return -1;
+		}
+		if (_app_lua_sr_reload==0)
+		{
+			LM_ERR("reload is not activated\n");
+			return -3;
+		}
+		if (pos<0)
+		{
+			// let's mark all the scripts to be reloaded
+			for (i=0;i<len;i++)
+			{
+				lock_set_get(sr_lua_locks, i);
+				sr_lua_script_ver->version[i] += 1;
+				lock_set_release(sr_lua_locks, i);
+			}
+		}
+		else
+		{
+			if (pos>=0 && pos<len)
+			{
+				lock_set_get(sr_lua_locks, pos);
+				sr_lua_script_ver->version[pos] += 1;
+				lock_set_release(sr_lua_locks, pos);
+				LM_DBG("pos: %d set to reloaded\n", pos);
+			}
+			else
+			{
+				LM_ERR("pos out of range\n");
+				return -2;
+			}
+		}
+		return 0;
+	}
+	LM_ERR("No script loaded\n");
+	return -1;
+}
+
+/**
+ * Checks if loaded version matches the shared
+ * counter. If not equal reloads the script.
+ */
+int sr_lua_reload_script(void)
+{
+	sr_lua_load_t *li = _sr_lua_load_list;
+	int ret, i;
+	char *txt;
+	int sv_len = sr_lua_script_ver->len;
+
+	if(li==NULL)
+	{
+		LM_DBG("No script loaded\n");
+		return 0;
+	}
+
+	if(_app_lua_sv==NULL) {
+		_app_lua_sv = (int *) pkg_malloc(sizeof(int)*sv_len);
+		if(_app_lua_sv==NULL)
+		{
+			LM_ERR("no more pkg memory\n");
+			return -1;
+		}
+	}
+
+	for(i=0;i<sv_len;i++)
+	{
+		lock_set_get(sr_lua_locks, i);
+		_app_lua_sv[i] = sr_lua_script_ver->version[i];
+		lock_set_release(sr_lua_locks, i);
+
+		if(li->version!=_app_lua_sv[i])
+		{
+			LM_DBG("loaded version:%d needed: %d Let's reload <%s>\n",
+				li->version, _app_lua_sv[i], li->script);
+			ret = luaL_dofile(_sr_L_env.LL, (const char*)li->script);
+			if(ret!=0)
+			{
+				LM_ERR("failed to load Lua script: %s (err: %d)\n",
+						li->script, ret);
+				txt = (char*)lua_tostring(_sr_L_env.LL, -1);
+				LM_ERR("error from Lua: %s\n", (txt)?txt:"unknown");
+				lua_pop(_sr_L_env.LL, 1);
+				return -1;
+			}
+			li->version = _app_lua_sv[i];
+			LM_DBG("<%s> set to version %d\n", li->script, li->version);
+		}
+		else LM_DBG("No need to reload [%s] is version %d\n",
+			li->script, li->version);
+		li = li->next;
+	}
+	return 1;
 }
 
 /**
@@ -406,7 +625,16 @@ int app_lua_run(struct sip_msg *msg, char *func, char *p1, char *p2,
 		LM_ERR("lua loading state not initialized (call: %s)\n", func);
 		return -1;
 	}
-
+	if(_app_lua_sr_reload!=0)
+	{
+		/* check the script version loaded */
+		if(!sr_lua_reload_script())
+		{
+			LM_ERR("lua reload failed\n");
+			return -1;
+		}
+	}
+	else LM_DBG("reload deactivated\n");
 	LM_DBG("executing Lua function: [[%s]]\n", func);
 	LM_DBG("lua top index is: %d\n", lua_gettop(_sr_L_env.LL));
 	lua_getglobal(_sr_L_env.LL, func);
diff --git a/modules/app_lua/app_lua_api.h b/modules/app_lua/app_lua_api.h
index 3d1bff7..9ba8794 100644
--- a/modules/app_lua/app_lua_api.h
+++ b/modules/app_lua/app_lua_api.h
@@ -30,14 +30,32 @@
 
 #include "../../parser/msg_parser.h"
 
+/**
+ * version variable stores a version counter for each script loaded.
+ * This counter will be updated via RPC.
+ */
+typedef struct _sr_lua_script_ver
+{
+	unsigned int *version;
+	unsigned int len; /* length of version array */
+} sr_lua_script_ver_t;
+
 typedef struct _sr_lua_env
 {
 	lua_State *L;
 	lua_State *LL;
 	struct sip_msg *msg;
 	unsigned int flags;
+	unsigned int nload; /* number of scripts loaded */
 } sr_lua_env_t;
 
+typedef struct _sr_lua_load
+{
+	char *script;
+	int version; /* child loaded version */
+	struct _sr_lua_load *next;
+} sr_lua_load_t;
+
 sr_lua_env_t *sr_lua_env_get(void);
 
 int lua_sr_initialized(void);
@@ -45,9 +63,13 @@ int lua_sr_init_mod(void);
 int lua_sr_init_child(void);
 void lua_sr_destroy(void);
 int lua_sr_init_probe(void);
+int lua_sr_reload_script(int pos);
+int lua_sr_list_script(sr_lua_load_t **list);
 
 int sr_lua_load_script(char *script);
+int sr_lua_reload_script(void);
 int sr_lua_register_module(char *mname);
+int sr_lua_reload_module(unsigned int reload);
 
 int app_lua_dostring(struct sip_msg *msg, char *script);
 int app_lua_dofile(struct sip_msg *msg, char *script);
diff --git a/modules/app_lua/app_lua_mod.c b/modules/app_lua/app_lua_mod.c
index 19a0c52..da39bce 100644
--- a/modules/app_lua/app_lua_mod.c
+++ b/modules/app_lua/app_lua_mod.c
@@ -29,6 +29,8 @@
 #include "../../dprint.h"
 #include "../../ut.h"
 #include "../../mod_fix.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
 
 #include "app_lua_api.h"
 
@@ -41,6 +43,8 @@ static int  mod_init(void);
 static void mod_destroy(void);
 static int  child_init(int rank);
 
+static int app_lua_init_rpc(void);
+
 static int w_app_lua_dostring(struct sip_msg *msg, char *script, char *extra);
 static int w_app_lua_dofile(struct sip_msg *msg, char *script, char *extra);
 static int w_app_lua_runstring(struct sip_msg *msg, char *script, char *extra);
@@ -59,10 +63,12 @@ static int fixup_lua_run(void** param, int param_no);
 
 int app_lua_load_param(modparam_t type, void *val);
 int app_lua_register_param(modparam_t type, void *val);
+int app_lua_reload_param(modparam_t type, void *val);
 
 static param_export_t params[]={
 	{"load",     STR_PARAM|USE_FUNC_PARAM, (void*)app_lua_load_param},
 	{"register", STR_PARAM|USE_FUNC_PARAM, (void*)app_lua_register_param},
+	{"reload",   INT_PARAM|USE_FUNC_PARAM, (void*)app_lua_reload_param},
 	{0, 0, 0}
 };
 
@@ -86,7 +92,7 @@ static cmd_export_t cmds[]={
 
 struct module_exports exports = {
 	"app_lua",
-	RTLD_NOW | RTLD_GLOBAL, /* dlopen flags */
+	DEFAULT_DLFLAGS, /* dlopen flags */
 	cmds,
 	params,
 	0,
@@ -99,7 +105,11 @@ struct module_exports exports = {
 	child_init      /* per child init function */
 };
 
-
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+	*dlflags = RTLD_NOW | RTLD_GLOBAL;
+	return 0;
+}
 
 /**
  * init module function
@@ -108,6 +118,12 @@ static int mod_init(void)
 {
 	if(lua_sr_init_mod()<0)
 		return -1;
+
+	if(app_lua_init_rpc()<0)  
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
 	return 0;
 }
 
@@ -324,8 +340,82 @@ int app_lua_register_param(modparam_t type, void *val)
 	return sr_lua_register_module((char*)val);
 }
 
+int app_lua_reload_param(modparam_t type, void *val)
+{
+	return sr_lua_reload_module((unsigned int)(long) (int *)val);
+}
+
 static int fixup_lua_run(void** param, int param_no)
 {
 	return fixup_spve_null(param, 1);
 }
 
+/*** RPC implementation ***/
+
+static const char* app_lua_rpc_reload_doc[2] = {
+	"Reload lua script",
+	0
+};
+
+static const char* app_lua_rpc_list_doc[2] = {
+	"list lua scripts",
+	0
+};
+
+static void app_lua_rpc_reload(rpc_t* rpc, void* ctx)
+{
+	int pos = -1;
+
+	rpc->scan(ctx, "*d", &pos);
+	LM_DBG("selected index: %d\n", pos);
+	if(lua_sr_reload_script(pos)<0)
+		rpc->fault(ctx, 500, "Reload Failed");
+	return;
+}
+
+static void app_lua_rpc_list(rpc_t* rpc, void* ctx)
+{
+	int i;
+	sr_lua_load_t *list = NULL, *li;
+	if(lua_sr_list_script(&list)<0)
+	{
+		LM_ERR("Can't get loaded scripts\n");
+		return;
+	}
+	if(list)
+	{
+		li = list;
+		i = 0;
+		while(li)
+		{
+			rpc->printf(ctx, "%d: [%s]", i, li->script);
+			li = li->next;
+			i += 1;
+		}
+	}
+	else {
+		rpc->printf(ctx,"No scripts loaded");
+	}
+	return;
+}
+
+rpc_export_t app_lua_rpc_cmds[] = {
+	{"app_lua.reload", app_lua_rpc_reload,
+		app_lua_rpc_reload_doc, 0},
+	{"app_lua.list", app_lua_rpc_list,
+		app_lua_rpc_list_doc, 0},
+	{0, 0, 0, 0}
+};
+
+/**
+ * register RPC commands
+ */
+static int app_lua_init_rpc(void)
+{
+	if (rpc_register_array(app_lua_rpc_cmds)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/modules/app_lua/app_lua_sr.c b/modules/app_lua/app_lua_sr.c
index c01db86..14ea838 100644
--- a/modules/app_lua/app_lua_sr.c
+++ b/modules/app_lua/app_lua_sr.c
@@ -39,6 +39,7 @@
 #include "../../dset.h"
 #include "../../parser/parse_uri.h"
 #include "../../lib/kcore/cmpapi.h"
+#include "../../xavp.h"
 
 #include "app_lua_api.h"
 #include "app_lua_sr.h"
@@ -1130,6 +1131,283 @@ static const luaL_reg _sr_pv_Map [] = {
 	{NULL, NULL}
 };
 
+
+/**
+ * creates and push a table to the lua stack with
+ * the elements of the list
+ */
+static int lua_sr_push_str_list_table(lua_State *L, struct str_list *list) {
+	lua_Number i = 1;
+	struct str_list *k = list;
+
+	lua_newtable(L);
+	while(k!=NULL){
+		lua_pushnumber(L, i);
+		lua_pushlstring(L, k->s.s, k->s.len);
+		lua_settable(L, -3);
+		i++;
+		k = k->next;
+	}
+	return 1;
+}
+
+static int lua_sr_push_xavp_table(lua_State *L, sr_xavp_t *xavp);
+
+/**
+ * creates and push a table for the key name in xavp
+ */
+static void lua_sr_push_xavp_name_table(lua_State *L, sr_xavp_t *xavp, str name) {
+	lua_Number i = 1;
+	lua_Number elem = 1;
+	sr_xavp_t *avp = xavp;
+
+	while(avp!=NULL&&!STR_EQ(avp->name,name))
+	{
+		avp = avp->next;
+	}
+	lua_newtable(L);
+
+	while(avp!=NULL){
+		lua_pushnumber(L, elem);
+		switch(avp->val.type) {
+			case SR_XTYPE_NULL:
+				lua_pushnil(L);
+			break;
+			case SR_XTYPE_INT:
+				i = avp->val.v.i;
+				lua_pushnumber(L, i);
+			break;
+			case SR_XTYPE_STR:
+				lua_pushlstring(L, avp->val.v.s.s, avp->val.v.s.len);
+			break;
+			case SR_XTYPE_TIME:
+			case SR_XTYPE_LONG:
+			case SR_XTYPE_LLONG:
+			case SR_XTYPE_DATA:
+				lua_pushnil(L);
+				LM_WARN("XAVP type:%d value not supported\n", avp->val.type);
+			break;
+			case SR_XTYPE_XAVP:
+				if(!lua_sr_push_xavp_table(L,avp->val.v.xavp)){
+					LM_ERR("xavp:%.*s subtable error. Nil value added\n", avp->name.len, avp->name.s);
+					lua_pushnil(L);
+				}
+			break;
+			default:
+				LM_ERR("xavp:%.*s unknown type: %d. Nil value added\n",
+					avp->name.len, avp->name.s, avp->val.type);
+				lua_pushnil(L);
+			break;
+		}
+		lua_rawset(L, -3);
+		elem = elem + 1;
+		avp = xavp_get_next(avp);
+	}
+	lua_setfield(L, -2, name.s);
+}
+
+/**
+ * creates and push a table to the lua stack with
+ * the elements of the xavp
+ */
+static int lua_sr_push_xavp_table(lua_State *L, sr_xavp_t *xavp) {
+	sr_xavp_t *avp = NULL;
+	struct str_list *keys;
+	struct str_list *k;
+
+	if(xavp->val.type!=SR_XTYPE_XAVP){
+		LM_ERR("%s not xavp?\n", xavp->name.s);
+		return 0;
+	}
+	avp = xavp->val.v.xavp;
+	keys = xavp_get_list_key_names(xavp);
+
+	lua_newtable(L);
+	if(keys!=NULL)
+	{
+		do
+		{
+			lua_sr_push_xavp_name_table(L, avp, keys->s);
+			k = keys;
+			keys = keys->next;
+			pkg_free(k);
+		}while(keys!=NULL);
+	}
+
+	return 1;
+}
+
+ /**
+ * creates and push a table to the lua stack with
+ * only the firsts elements of the xavp
+ */
+static int lua_sr_push_xavp_table_simple(lua_State *L, sr_xavp_t *xavp) {
+	lua_Number i = 1;
+	sr_xavp_t *avp = NULL;
+
+	if(xavp->val.type!=SR_XTYPE_XAVP){
+		LM_ERR("%s not xavp?\n", xavp->name.s);
+		return 0;
+	}
+	avp = xavp->val.v.xavp;
+
+	lua_newtable(L);
+	while(avp!=NULL){
+		switch(avp->val.type) {
+			case SR_XTYPE_NULL:
+				lua_pushnil(L);
+				lua_setfield(L, -2, avp->name.s);
+			break;
+			case SR_XTYPE_INT:
+				i = avp->val.v.i;
+				lua_pushnumber(L, i);
+				lua_setfield(L, -2, avp->name.s);
+			break;
+			case SR_XTYPE_STR:
+				lua_pushlstring(L, avp->val.v.s.s, avp->val.v.s.len);
+				lua_setfield(L, -2, avp->name.s);
+			break;
+			case SR_XTYPE_TIME:
+			case SR_XTYPE_LONG:
+			case SR_XTYPE_LLONG:
+			case SR_XTYPE_DATA:
+				lua_pushnil(L);
+				lua_setfield(L, -2, avp->name.s);
+				LM_WARN("XAVP type:%d value not supported\n", avp->val.type);
+			break;
+			case SR_XTYPE_XAVP:
+				if(!lua_sr_push_xavp_table(L,avp->val.v.xavp)){
+					LM_ERR("xavp:%.*s subtable error. Nil value added\n", avp->name.len, avp->name.s);
+					lua_pushnil(L);
+				}
+				lua_setfield(L, -2, avp->name.s);
+			break;
+		}
+		avp = avp->next;
+	}
+	return 1;
+}
+
+/**
+ * puts a table with content of a xavp
+ */
+static int lua_sr_xavp_get(lua_State *L)
+{
+	str xavp_name;
+	int indx = 0;
+	sr_lua_env_t *env_L;
+	sr_xavp_t *avp;
+	int num_param = 0;
+	int param = -1;
+	int simple_flag = 0;
+
+	env_L = sr_lua_env_get();
+	num_param = lua_gettop(L);
+	if(num_param<2 && num_param>3)
+	{
+		LM_ERR("wrong number of parameters [%d]\n", num_param);
+		return 0;
+	}
+
+	if(num_param==3)
+	{
+		if(!lua_isnumber(L, param))
+		{
+			LM_ERR("invalid int parameter\n");
+			return 0;
+		}
+		simple_flag = lua_tointeger(L, param);
+		param = param - 1;
+	}
+
+	if(!lua_isnumber(L, param))
+	{
+		LM_ERR("invalid int parameter\n");
+		return 0;
+	}
+	indx = lua_tointeger(L, param);
+	param = param - 1;
+
+	xavp_name.s = (char*)lua_tostring(L, param);
+	if(xavp_name.s==NULL || env_L->msg==NULL)
+		return 0;
+	xavp_name.len = strlen(xavp_name.s);
+
+	avp = xavp_get_by_index(&xavp_name, indx, NULL);
+	if(avp==NULL){
+		LM_ERR("can't get xavp:%.*s index:%d\n", xavp_name.len, xavp_name.s, indx);
+		lua_pushnil(L);
+		return 1;
+	}
+
+	if (simple_flag != 0)
+	{
+		lua_sr_push_xavp_table_simple(L, avp);
+	}
+	else
+	{
+		lua_sr_push_xavp_table(L, avp);
+	}
+	return 1;
+}
+
+/**
+ * puts a table with the list of keys of the xavp
+ */
+static int lua_sr_xavp_get_keys (lua_State *L)
+{
+	str xavp_name;
+	int indx = 0;
+	sr_lua_env_t *env_L;
+	sr_xavp_t *avp;
+	struct str_list *keys, *k;
+
+	env_L = sr_lua_env_get();
+
+	if(lua_gettop(L)<2)
+	{
+		LM_ERR("to few parameters [%d]\n",lua_gettop(L));
+		return 0;
+	}
+
+	if(!lua_isnumber(L, -1))
+	{
+		LM_ERR("invalid int parameter\n");
+		return 0;
+	}
+	indx = lua_tointeger(L, -1);
+
+	xavp_name.s = (char*)lua_tostring(L, -2);
+	if(xavp_name.s==NULL || env_L->msg==NULL)
+		return 0;
+	xavp_name.len = strlen(xavp_name.s);
+
+	avp = xavp_get_by_index(&xavp_name, indx, NULL);
+	if(avp==NULL){
+		LM_ERR("can't get xavp:%.*s index:%d\n", xavp_name.len, xavp_name.s, indx);
+		lua_pushnil(L);
+		return 1;
+	}
+	keys = xavp_get_list_key_names(avp);
+	lua_sr_push_str_list_table(L, keys);
+	// free list
+	while(keys!=NULL){
+		k = keys;
+		keys = k->next;
+		pkg_free(k);
+	}
+	return 1;
+}
+
+/**
+ *
+ */
+static const luaL_reg _sr_xavp_Map [] = {
+	{"get", lua_sr_xavp_get},
+	{"get_keys",  lua_sr_xavp_get_keys},
+	{NULL, NULL}
+};
+
 /**
  *
  */
@@ -1138,6 +1416,5 @@ void lua_sr_core_openlibs(lua_State *L)
 	luaL_openlib(L, "sr",      _sr_core_Map, 0);
 	luaL_openlib(L, "sr.hdr",  _sr_hdr_Map,  0);
 	luaL_openlib(L, "sr.pv",   _sr_pv_Map,   0);
+	luaL_openlib(L, "sr.xavp", _sr_xavp_Map, 0);
 }
-
-
diff --git a/modules/app_lua/doc/app_lua_admin.xml b/modules/app_lua/doc/app_lua_admin.xml
index 96e5771..02adb36 100644
--- a/modules/app_lua/doc/app_lua_admin.xml
+++ b/modules/app_lua/doc/app_lua_admin.xml
@@ -11,9 +11,9 @@
 <!-- Module User's Guide -->
 
 <chapter>
-    
+
     <title>&adminguide;</title>
-    
+
     <section>
 	<title>Overview</title>
 	<para>
@@ -80,7 +80,7 @@
     </section>
     <section>
 	<title>Parameters</title>
-	<section>
+	<section id="app_lua.p.load">
 	    <title><varname>load</varname> (string)</title>
 	    <para>
 			Set the path to the Lua script to be loaded at startup. Then you
@@ -102,7 +102,7 @@ modparam("app_lua", "load", "/usr/local/etc/kamailio/lua/myscript.lua")
 	    </example>
 	</section>
 
-	<section>
+	<section id="app_lua.p.register">
 	    <title><varname>register</varname> (string)</title>
 	    <para>
 			Use this function to register optional SIP Router submodules
@@ -249,11 +249,32 @@ modparam("app_lua", "register", "sl")
 	    </example>
 	</section>
 
+	<section id="app_lua.p.reload">
+	    <title><varname>reload</varname> (boolean)</title>
+	    <para>
+			If reload is 1 enables the ability to reload the
+			scripts using the RPC app_lua.reload command.
+	    </para>
+	    <para>
+		<emphasis>
+		    Default value is <quote>0 (off)</quote>.
+		</emphasis>
+	    </para>
+	    <example>
+		<title>Set <varname>reload</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("app_lua", "reload", 1)
+...
+</programlisting>
+	    </example>
+	</section>
+
 	</section>
-	
+
     <section>
 	<title>Functions</title>
- 	<section>
+ 	<section id="app_lua.f.lua_dotfile">
 	    <title>
 		<function moreinfo="none">lua_dofile(path)</function>
 	    </title>
@@ -270,8 +291,8 @@ lua_dofile("/usr/local/etc/kamailio/lua/myscript.lua");
 </programlisting>
 	    </example>
 	</section>
-	
- 	<section>
+
+ 	<section id="app_lua.f.lua_dostring">
 	    <title>
 		<function moreinfo="none">lua_dostring(script)</function>
 	    </title>
@@ -292,7 +313,7 @@ if(!lua_dostring("sr.log([[err]], [[----------- Hello World from $fU\n]])"))
 	    </example>
 	</section>
 
-	<section>
+	<section id="app_lua.f.lua_run">
 	    <title>
 		<function moreinfo="none">lua_run(function, params)</function>
 	    </title>
@@ -317,7 +338,7 @@ lua_run("lua_funcx", "$rU", "2");
 	    </example>
 	</section>
 
-	<section>
+	<section id="app_lua.f.lua_runstring">
 	    <title>
 		<function moreinfo="none">lua_runstring(script)</function>
 	    </title>
@@ -338,9 +359,53 @@ if(!lua_runstring("sr.log([[err]], [[----------- Hello World from $fU\n]])"))
 </programlisting>
 	    </example>
 	</section>
-	
+
+    </section>
+
+    <section>
+        <title>Exported RPC Commands</title>
+        <section id="app_lua.r.list">
+            <title>
+            <function moreinfo="none">app_lua.list</function>
+            </title>
+            <para>
+            Lists the id and path for every script loaded by
+            the load parameter.
+            </para>
+            <para>
+            Name: <emphasis>app_lua.list</emphasis>
+            </para>
+            <para>Parameters: <emphasis>none</emphasis></para>
+            <para>
+            Example:
+            </para>
+            <programlisting  format="linespecific">
+                &sercmd; app_lua.lists
+            </programlisting>
+        </section>
+        <section id="app_lua.r.reload">
+            <title>
+            <function moreinfo="none">app_lua.reload</function>
+            </title>
+            <para>
+            Marks the need to reload the selected script.
+            The actual reload is done by every working process when the next
+            call to lua_run function is executed.
+            If no parameter is added all the scripts are selected to be reloaded.
+            </para>
+            <para>
+            Name: <emphasis>app_lua.reload</emphasis>
+            </para>
+            <para>Parameters: <emphasis>id</emphasis></para>
+            <para>
+            Example:
+            </para>
+            <programlisting  format="linespecific">
+                &sercmd; app_lua.reload 0
+            </programlisting>
+        </section>
     </section>
-	
+
     <section>
 	<title>Example of usage</title>
     <para>
diff --git a/modules/app_perl/README b/modules/app_perl/README
index 186056b..ce1a530 100644
--- a/modules/app_perl/README
+++ b/modules/app_perl/README
@@ -8,7 +8,7 @@ Edited by
 
 Bastian Friedrich
 
-   Copyright © 2007 Collax GmbH
+   Copyright � 2007 Collax GmbH
      __________________________________________________________________
 
    Table of Contents
@@ -27,12 +27,18 @@ Bastian Friedrich
 
               5.1. filename (string)
               5.2. modpath (string)
+              5.3. reset_cycles (int)
 
         6. Functions
 
               6.1. perl_exec_simple(func, [param])
               6.2. perl_exec(func, [param])
 
+        7. RPC Commands
+
+              7.1. app_perl.set_reset_cycles
+              7.2. app_perl.get_reset_cycles
+
    2. Kamailio Perl API
 
         1. Kamailio
@@ -187,8 +193,11 @@ Bastian Friedrich
 
    1.1. Set filename parameter
    1.2. Set modpath parameter
-   1.3. perl_exec_simple() usage
-   1.4. perl_exec() usage
+   1.3. Set reset_cycles parameter
+   1.4. perl_exec_simple() usage
+   1.5. perl_exec() usage
+   1.6. app_perl.set_reset_cycles usage
+   1.7. app_perl.get_reset_cycles usage
 
 Chapter 1. Admin Guide
 
@@ -206,12 +215,18 @@ Chapter 1. Admin Guide
 
         5.1. filename (string)
         5.2. modpath (string)
+        5.3. reset_cycles (int)
 
    6. Functions
 
         6.1. perl_exec_simple(func, [param])
         6.2. perl_exec(func, [param])
 
+   7. RPC Commands
+
+        7.1. app_perl.set_reset_cycles
+        7.2. app_perl.get_reset_cycles
+
 1. Overview
 
    The time needed when writing a new Kamailio module unfortunately is
@@ -312,39 +327,60 @@ if (perl_exec("ldap_alias")) {
      * IPC::Shareable perl module from CPAN
 
    Although SuSE delivers a lot of perl modules, others may have to be
-   fetched from CPAN. Consider using the program “cpan2rpm” - which, in
+   fetched from CPAN. Consider using the program "cpan2rpm" - which, in
    turn, is available on CPAN. It creates RPM files from CPAN.
 
 5. Parameters
 
    5.1. filename (string)
    5.2. modpath (string)
+   5.3. reset_cycles (int)
 
 5.1. filename (string)
 
    This is the file name of your script. This may be set once only, but it
-   may include an arbitary number of functions and “use” as many Perl
+   may include an arbitary number of functions and "use" as many Perl
    module as necessary.
 
-   May not be empty!
+   Must not be empty!
 
    Example 1.1. Set filename parameter
 ...
-modparam("perl", "filename", "/home/test/kamailio/myperl.pl")
+modparam("app_perl", "filename", "/home/test/kamailio/myperl.pl")
 ...
 
 5.2. modpath (string)
 
    The path to the Perl modules included (Kamailio.pm et.al). It is not
    absolutely crucial to set this path, as you may install the Modules in
-   Perl's standard path, or update the “%INC” variable from within your
+   Perl's standard path, or update the "%INC" variable from within your
    script. Using this module parameter is the standard behavior, though.
-   Multiple paths may be specified by separating them with a “:”
+   Multiple paths may be specified by separating them with a ":"
    character. The maximum is 10 paths.
 
    Example 1.2. Set modpath parameter
 ...
-modparam("perl", "modpath", "/usr/local/lib/kamailio/perl/")
+modparam("app_perl", "modpath", "/usr/local/lib/kamailio/perl/")
+...
+
+5.3. reset_cycles (int)
+
+   The number of execution cycles after which the embedded perl
+   interpreter is reset. Sometimes is hard to track the scope of variables
+   in all used perl modules and that can result in leaks of system memory.
+   Resetting the interpreter cleans the memory space.
+
+   When the interpreter is reset, the perl script is loaded again. Note
+   that not all Kamailio processes will reset the interpreter at the same
+   time. Each will do it when it has executed the script for the number of
+   reset_cycles. Also, be aware that the reset of the interpreter is
+   taking a bit of time (in the order of tens of mili-seconds).
+
+   Default value is 0 - never reset the interpreter.
+
+   Example 1.3. Set reset_cycles parameter
+...
+modparam("app_perl", "reset_cycles", 100000)
 ...
 
 6. Functions
@@ -352,7 +388,7 @@ modparam("perl", "modpath", "/usr/local/lib/kamailio/perl/")
    6.1. perl_exec_simple(func, [param])
    6.2. perl_exec(func, [param])
 
-6.1.  perl_exec_simple(func, [param])
+6.1. perl_exec_simple(func, [param])
 
    Calls a perl function without passing it the current SIP message. May
    be used for very simple simple requests that do not have to fiddle with
@@ -365,14 +401,14 @@ modparam("perl", "modpath", "/usr/local/lib/kamailio/perl/")
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE and BRANCH_ROUTE.
 
-   Example 1.3. perl_exec_simple() usage
+   Example 1.4. perl_exec_simple() usage
 ...
 if (method=="INVITE") {
         perl_exec_simple("dosomething", "on invite messages");
 };
 ...
 
-6.2.  perl_exec(func, [param])
+6.2. perl_exec(func, [param])
 
    Calls a perl function with passing it the current SIP message. The SIP
    message is reflected by a Perl module that gives you access to the
@@ -384,13 +420,37 @@ if (method=="INVITE") {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE and BRANCH_ROUTE.
 
-   Example 1.4. perl_exec() usage
+   Example 1.5. perl_exec() usage
 ...
 if (perl_exec("ldapalias")) {
         ...
 };
 ...
 
+7. RPC Commands
+
+   7.1. app_perl.set_reset_cycles
+   7.2. app_perl.get_reset_cycles
+
+7.1. app_perl.set_reset_cycles
+
+   Set the value of the reset_cycle. The command has one integer
+   parameter.
+
+   Example 1.6. app_perl.set_reset_cycles usage
+...
+kamcmd app_perl.set_reset_cycles 20000
+...
+
+7.2. app_perl.get_reset_cycles
+
+   Return the value of the reset_cycle.
+
+   Example 1.7. app_perl.get_reset_cycles usage
+...
+kamcmd app_perl.get_reset_cycles
+...
+
 Chapter 2. Kamailio Perl API
 
    Table of Contents
@@ -602,7 +662,7 @@ Kamailio::log(L_INFO, "foobar");
 
    my $ruri = $m->getRURI();
 
-   getRURI returns a string. See “getParsedRURI()” below how to receive a
+   getRURI returns a string. See "getParsedRURI()" below how to receive a
    parsed structure.
 
    This function is valid in request messages only.
@@ -1445,11 +1505,11 @@ Chapter 3. Perl samples
         1.1.9. phonenumbers.pl
         1.1.10. pseudovars.pl
 
-   There are a number of example scripts in the “samples/”. They are
+   There are a number of example scripts in the "samples/". They are
    documented well. Read them, it will explain a lot to you :)
 
    If you want to use any of these scripts directly in your
-   implementation, you can use Perl's “require” mechanism to import them
+   implementation, you can use Perl's "require" mechanism to import them
    (just remember that you need to use quotes when require'ing .pl files).
 
 1.1. Script descriptions
@@ -1486,7 +1546,7 @@ Chapter 3. Perl samples
    functions from within perl, and the different types of functions you
    can offer for Kamailio access.
 
-   “exportedfuncs” simply demonstrates that you can use the moduleFunction
+   "exportedfuncs" simply demonstrates that you can use the moduleFunction
    method to call functions offered by other modules. The results are
    equivalent to calling these functions from your config file. In the
    demonstrated case, telephone calls with a destination number beginning
@@ -1496,13 +1556,13 @@ Chapter 3. Perl samples
    Please note that the moduleFunction method is not fully available in
    Kamailio 1.2. See the method's documentation for details.
 
-   “paramfunc” shows that you can pass arbitrary strings to perl
+   "paramfunc" shows that you can pass arbitrary strings to perl
    functions. Do with them whatever you want :)
 
-   “autotest” demonstrates that unknown functions in Kamailio::Message
+   "autotest" demonstrates that unknown functions in Kamailio::Message
    objects are automatically transformed into calls to module functions.
 
-   The “diefunc”s show that dying perl scripts - by "manual" dying, or
+   The "diefunc"s show that dying perl scripts - by "manual" dying, or
    because of script errors - are handled by the Kamailio package. The
    error message is logged through Kamailio's logging mechanism. Please
    note that this only works correctly if you do NOT overwrite the default
@@ -1514,22 +1574,22 @@ Chapter 3. Perl samples
    processing SIP messages. This sample script demonstrates access to
    header names and values within two sample functions.
 
-   “headernames” extracts all header names and logs their names.
+   "headernames" extracts all header names and logs their names.
 
-   “someheaders” logs the contents of the two headers, “To” and
-   “WWW-Contact”. As you can see, headers that occur more than once are
+   "someheaders" logs the contents of the two headers, "To" and
+   "WWW-Contact". As you can see, headers that occur more than once are
    retrieved as an array, which may be accessed by Perl's array accessing
    methods.
 
 1.1.6. logging.pl
 
    For debugging purposes, you probably want to write messages to the
-   syslog. The “logdemo” shows three ways to access the Kamailio log
+   syslog. The "logdemo" shows three ways to access the Kamailio log
    function: it is available through the Kamailio class as well as through
    the Kamailio::Message class.
 
    Remember that you can use exported functions from other modules. You
-   may thus as well use the “xlog” module and it's xlog function.
+   may thus as well use the "xlog" module and it's xlog function.
 
    The L_INFO, L_DBG, L_ERR, L_CRIT... constants are available through the
    Kamailio::Constants package.
@@ -1558,7 +1618,7 @@ Chapter 3. Perl samples
 
 1.1.10. pseudovars.pl
 
-   This script demonstrates the Perl module's “pseudoVar” method. It may
+   This script demonstrates the Perl module's "pseudoVar" method. It may
    be used to retrieve the values of current pseudo variables.
 
    You might notice that there is no particular function for setting
@@ -1574,48 +1634,48 @@ Chapter 4. Frequently Asked Questions
 
    4.1.
 
-       Are there known bugs in the Perl module?
-
-       The Perl module does have a few shortcomings that may be regarded as
-       bugs.
-         * Missing module functions. Not all functions of other modules are
-           available for Perl access. The reason for this is a design property
-           of Kamailio. Making available more functions is work in progress.
-         * Perl and threads. Perl itself is, when compiled with the correct
-           parameters, thread safe; unfortunately, not all Perl modules are.
-           The DBI modules, especially (but not restricted to) DBI::ODBC are
-           known NOT to be thread safe.
-           Using DBI::ODBC -- and possibly other non-thread-safe Perl
-           extensions -- may result in erroneous behavior of Kamailio,
-           including (but not restricted to) server crashes and wrong routing.
+   Are there known bugs in the Perl module?
+
+   The Perl module does have a few shortcomings that may be regarded as
+   bugs.
+     * Missing module functions. Not all functions of other modules are
+       available for Perl access. The reason for this is a design property
+       of Kamailio. Making available more functions is work in progress.
+     * Perl and threads. Perl itself is, when compiled with the correct
+       parameters, thread safe; unfortunately, not all Perl modules are.
+       The DBI modules, especially (but not restricted to) DBI::ODBC are
+       known NOT to be thread safe.
+       Using DBI::ODBC -- and possibly other non-thread-safe Perl
+       extensions -- may result in erroneous behavior of Kamailio,
+       including (but not restricted to) server crashes and wrong routing.
 
    4.2.
 
-       Where can I find more about Kamailio?
+   Where can I find more about Kamailio?
 
-       Take a look at http://www.kamailio.org/.
+   Take a look at http://www.kamailio.org/.
 
    4.3.
 
-       Where can I post a question about this module?
+   Where can I post a question about this module?
 
-       First at all check if your question was already answered on one of our
-       mailing lists:
-         * User Mailing List -
-           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
-         * Developer Mailing List -
-           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+   First at all check if your question was already answered on one of our
+   mailing lists:
+     * User Mailing List -
+       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+     * Developer Mailing List -
+       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
 
-       E-mails regarding any stable Kamailio release should be sent to
-       <sr-users at lists.sip-router.org> and e-mails regarding development
-       versions should be sent to <sr-dev at lists.sip-router.org>.
+   E-mails regarding any stable Kamailio release should be sent to
+   <sr-users at lists.sip-router.org> and e-mails regarding development
+   versions should be sent to <sr-dev at lists.sip-router.org>.
 
-       If you want to keep the mail private, send it to
-       <sr-users at lists.sip-router.org>.
+   If you want to keep the mail private, send it to
+   <sr-users at lists.sip-router.org>.
 
    4.4.
 
-       How can I report a bug?
+   How can I report a bug?
 
-       Please follow the guidelines provided at:
-       http://sip-router.org/tracker.
+   Please follow the guidelines provided at:
+   http://sip-router.org/tracker.
diff --git a/modules/app_perl/app_perl_mod.c b/modules/app_perl/app_perl_mod.c
index eb303ca..3948bbe 100644
--- a/modules/app_perl/app_perl_mod.c
+++ b/modules/app_perl/app_perl_mod.c
@@ -31,13 +31,18 @@
 #include <stdlib.h>
 #include <string.h>
 #include <dlfcn.h>
+#include <sys/time.h>
 
 #include "../../sr_module.h"
 #include "../../mem/mem.h"
+#include "../../mem/shm_mem.h"
 #include "../../lib/kmi/mi.h"
 #include "../../modules/rr/api.h"
 #include "../../modules/sl/sl.h"
 
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
+
 /* lock_ops.h defines union semun, perl does not need to redefine it */
 #ifdef USE_SYSV_SEM
 # define HAS_UNION_SEMUN
@@ -61,17 +66,26 @@ char *modpath = NULL;
  * memory leaks, the variable thus is not documented! */
 int unsafemodfnc = 0;
 
+/* number of execution cycles after which perl interpreter is reset */
+int _ap_reset_cycles_init = 0;
+int _ap_exec_cycles = 0;
+int *_ap_reset_cycles = 0;
+
 /* Reference to the running Perl interpreter instance */
 PerlInterpreter *my_perl = NULL;
 
 /** SL API structure */
 sl_api_t slb;
 
+static int ap_init_rpc(void);
+
 /*
  * Module destroy function prototype
  */
 static void destroy(void);
 
+/* environment pointer needed to init perl interpreter */
+extern char **environ;
 
 /*
  * Module initialization function prototype
@@ -113,6 +127,7 @@ static param_export_t params[] = {
 	{"filename", STR_PARAM, &filename},
 	{"modpath", STR_PARAM, &modpath},
 	{"unsafemodfnc", INT_PARAM, &unsafemodfnc},
+	{"reset_cycles", INT_PARAM, &_ap_reset_cycles_init},
 	{ 0, 0, 0 }
 };
 
@@ -273,7 +288,8 @@ int unload_perl(PerlInterpreter *p) {
  * Reinitializes the interpreter. Works, but execution for _all_
  * children is difficult.
  */
-int perl_reload(struct sip_msg *m, char *a, char *b) {
+int perl_reload(void)
+{
 
 	PerlInterpreter *new_perl;
 
@@ -289,9 +305,9 @@ int perl_reload(struct sip_msg *m, char *a, char *b) {
 #warning This binary will be unsupported.
 		PL_exit_flags |= PERL_EXIT_EXPECTED;
 #endif
-		return 1;
-	} else {
 		return 0;
+	} else {
+		return -1;
 	}
 
 }
@@ -303,10 +319,10 @@ int perl_reload(struct sip_msg *m, char *a, char *b) {
  */
 struct mi_root* perl_mi_reload(struct mi_root *cmd_tree, void *param)
 {
-	if (perl_reload(NULL, NULL, NULL)) {
-		return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
-	} else {
+	if (perl_reload()<0) {
 		return init_mi_tree( 500, "Perl reload failed", 18);
+	} else {
+		return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
 	}
 
 }
@@ -318,7 +334,11 @@ struct mi_root* perl_mi_reload(struct mi_root *cmd_tree, void *param)
  */
 static int mod_init(void) {
 
-	int ret = 0;
+	int argc = 1;
+	char *argt[] = { MOD_NAME, NULL };
+	char **argv;
+	struct timeval t1;
+	struct timeval t2;
 
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
 	{
@@ -326,6 +346,12 @@ static int mod_init(void) {
 		return -1;
 	}
 
+	if(ap_init_rpc()<0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+
 	if (!filename) {
 		LM_ERR("insufficient module parameters. Module not loaded.\n");
 		return -1;
@@ -337,21 +363,39 @@ static int mod_init(void) {
 		return -1;
 	}
 
-	PERL_SYS_INIT3(NULL, NULL, &environ);
+	_ap_reset_cycles = shm_malloc(sizeof(int));
+	if(_ap_reset_cycles == NULL) {
+		LM_ERR("no more shared memory\n");
+		return -1;
+	}
+	*_ap_reset_cycles = _ap_reset_cycles_init;
+
+	argv = argt;
+	PERL_SYS_INIT3(&argc, &argv, &environ);
+
+	gettimeofday(&t1, NULL);
+	my_perl = parser_init();
+	gettimeofday(&t2, NULL);
+
+	if (my_perl==NULL)
+		goto error;
+
+	LM_INFO("perl interpreter has been initialized (%d.%06d => %d.%06d)\n",
+				(int)t1.tv_sec, (int)t1.tv_usec,
+				(int)t2.tv_sec, (int)t2.tv_usec);
 
-	if ((my_perl = parser_init())) {
-		ret = 0;
 #ifdef PERL_EXIT_DESTRUCT_END
-		PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+	PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
 #else
-		PL_exit_flags |= PERL_EXIT_EXPECTED;
+	PL_exit_flags |= PERL_EXIT_EXPECTED;
 #endif
+	return 0;
 
-	} else {
-		ret = -1;
-	}
-
-	return ret;
+error:
+	if(_ap_reset_cycles!=NULL)
+		shm_free(_ap_reset_cycles);
+	_ap_reset_cycles = NULL;
+	return -1;
 }
 
 /*
@@ -360,9 +404,136 @@ static int mod_init(void) {
  */
 static void destroy(void)
 {
+	if(_ap_reset_cycles!=NULL)
+		shm_free(_ap_reset_cycles);
+	_ap_reset_cycles = NULL;
+
 	if(my_perl==NULL)
 		return;
 	unload_perl(my_perl);
 	PERL_SYS_TERM();
 	my_perl = NULL;
 }
+
+
+/**
+ * count executions and rest interpreter
+ *
+ */
+int app_perl_reset_interpreter(void)
+{
+	struct timeval t1;
+	struct timeval t2;
+
+	if(*_ap_reset_cycles==0)
+		return 0;
+
+	_ap_exec_cycles++;
+	LM_DBG("perl interpreter exec cycle [%d/%d]\n",
+				_ap_exec_cycles, *_ap_reset_cycles);
+
+	if(_ap_exec_cycles<=*_ap_reset_cycles)
+		return 0;
+
+	gettimeofday(&t1, NULL);
+	if (perl_reload()<0) {
+		LM_ERR("perl interpreter cannot be reset [%d/%d]\n",
+				_ap_exec_cycles, *_ap_reset_cycles);
+		return -1;
+	}
+	gettimeofday(&t2, NULL);
+
+	LM_INFO("perl interpreter has been reset [%d/%d] (%d.%06d => %d.%06d)\n",
+				_ap_exec_cycles, *_ap_reset_cycles,
+				(int)t1.tv_sec, (int)t1.tv_usec,
+				(int)t2.tv_sec, (int)t2.tv_usec);
+	_ap_exec_cycles = 0;
+
+	return 0;
+}
+
+/*** RPC implementation ***/
+
+static const char* app_perl_rpc_set_reset_cycles_doc[3] = {
+	"Set the value for reset_cycles",
+	"Has one parmeter with int value",
+	0
+};
+
+
+/*
+ * RPC command to set the value for reset_cycles
+ */
+static void app_perl_rpc_set_reset_cycles(rpc_t* rpc, void* ctx)
+{
+	int rsv;
+
+	if(rpc->scan(ctx, "d", &rsv)<1)
+	{
+		rpc->fault(ctx, 500, "Invalid Parameters");
+		return;
+	}
+	if(rsv<=0)
+		rsv = 0;
+
+	LM_DBG("new reset cycle value is %d\n", rsv);
+
+	*_ap_reset_cycles = rsv;
+
+	return;
+}
+
+static const char* app_perl_rpc_get_reset_cycles_doc[2] = {
+	"Get the value for reset_cycles",
+	0
+};
+
+
+/*
+ * RPC command to set the value for reset_cycles
+ */
+static void app_perl_rpc_get_reset_cycles(rpc_t* rpc, void* ctx)
+{
+	int rsv;
+	void* th;
+
+	rsv = *_ap_reset_cycles;
+
+	/* add entry node */
+	if (rpc->add(ctx, "{", &th) < 0)
+	{
+		rpc->fault(ctx, 500, "Internal error root reply");
+		return;
+	}
+
+	if(rpc->struct_add(th, "d", "reset_cycles", rsv)<0)
+	{
+		rpc->fault(ctx, 500, "Internal error adding reset cycles");
+		return;
+	}
+	LM_DBG("reset cycle value is %d\n", rsv);
+
+	return;
+}
+
+
+rpc_export_t app_perl_rpc_cmds[] = {
+	{"app_perl.set_reset_cycles", app_perl_rpc_set_reset_cycles,
+		app_perl_rpc_set_reset_cycles_doc,   0},
+	{"app_perl.get_reset_cycles", app_perl_rpc_get_reset_cycles,
+		app_perl_rpc_get_reset_cycles_doc,   0},
+	{0, 0, 0, 0}
+};
+
+/**
+ * register RPC commands
+ */
+static int ap_init_rpc(void)
+{
+	if (rpc_register_array(app_perl_rpc_cmds)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/modules/app_perl/doc/app_perl_admin.xml b/modules/app_perl/doc/app_perl_admin.xml
index 14371b5..1b377b5 100644
--- a/modules/app_perl/doc/app_perl_admin.xml
+++ b/modules/app_perl/doc/app_perl_admin.xml
@@ -152,7 +152,7 @@ if (perl_exec("ldap_alias")) {
 
 	<section>
 		<title>Parameters</title>
-		<section>
+		<section id="app_perl.p.filename">
 			<title><varname>filename</varname> (string)</title>
 			<para>
 			This is the file name of your script. This may be set once only, but it may include an arbitary
@@ -160,20 +160,20 @@ if (perl_exec("ldap_alias")) {
 			</para>
 			<para>
 			<emphasis>
-				May not be empty!
+				Must not be empty!
 			</emphasis>
 			</para>
 			<example>
 			<title>Set <varname>filename</varname> parameter</title>
 			<programlisting format="linespecific">
 ...
-modparam("perl", "filename", "/home/test/kamailio/myperl.pl")
+modparam("app_perl", "filename", "/home/test/kamailio/myperl.pl")
 ...
 </programlisting>
 			</example>
 		</section>
 
-		<section>
+		<section id="app_perl.p.modpath">
 			<title><varname>modpath</varname> (string)</title>
 			<para>
 			The path to the Perl modules included (Kamailio.pm et.al). It is not absolutely
@@ -187,7 +187,35 @@ modparam("perl", "filename", "/home/test/kamailio/myperl.pl")
 			<title>Set <varname>modpath</varname> parameter</title>
 			<programlisting format="linespecific">
 ...
-modparam("perl", "modpath", "/usr/local/lib/kamailio/perl/")
+modparam("app_perl", "modpath", "/usr/local/lib/kamailio/perl/")
+...
+</programlisting>
+			</example>
+		</section>
+
+		<section id="app_perl.p.reset_cycles">
+			<title><varname>reset_cycles</varname> (int)</title>
+			<para>
+			The number of execution cycles after which the embedded perl interpreter
+			is reset. Sometimes is hard to track the scope of variables in all used
+			perl modules and that can result in leaks of system memory. Resetting the
+			interpreter cleans the memory space.
+			</para>
+			<para>
+			When the interpreter is reset, the perl script is loaded again. Note that
+			not all &kamailio; processes will reset the interpreter at the same time.
+			Each will do it when it has executed the script for the number of
+			reset_cycles. Also, be aware that the reset of the interpreter is taking
+			a bit of time (in the order of tens of mili-seconds).
+			</para>
+			<para>
+			Default value is <emphasis>0</emphasis> - never reset the interpreter.
+			</para>
+			<example>
+			<title>Set <varname>reset_cycles</varname> parameter</title>
+			<programlisting format="linespecific">
+...
+modparam("app_perl", "reset_cycles", 100000)
 ...
 </programlisting>
 			</example>
@@ -196,7 +224,7 @@ modparam("perl", "modpath", "/usr/local/lib/kamailio/perl/")
 
 	<section>
 		<title>Functions</title>
-		<section>
+		<section id="app_perl.f.perl_exec_simple">
 			<title>
 			<function moreinfo="none">perl_exec_simple(func, [param])</function>
 			</title>
@@ -224,7 +252,7 @@ if (method=="INVITE") {
 			</example>
 		</section>
 
-		<section>
+		<section id="app_perl.f.perl_exec">
 			<title>
 			<function moreinfo="none">perl_exec(func, [param])</function>
 			</title>
@@ -253,5 +281,42 @@ if (perl_exec("ldapalias")) {
 		</section>
 	</section>
 
+	<section>
+		<title>RPC Commands</title>
+		<section id="app_perl.r.set_reset_cycles">
+			<title>
+			<function moreinfo="none">app_perl.set_reset_cycles</function>
+			</title>
+			<para>
+				Set the value of the reset_cycle. The command has one integer
+				parameter.
+			</para>
+			<example>
+			<title><function>app_perl.set_reset_cycles</function> usage</title>
+			<programlisting format="linespecific">
+...
+kamcmd app_perl.set_reset_cycles 20000
+...
+</programlisting>
+			</example>
+		</section>
+		<section id="app_perl.r.get_reset_cycles">
+			<title>
+			<function moreinfo="none">app_perl.get_reset_cycles</function>
+			</title>
+			<para>
+				Return the value of the reset_cycle.
+			</para>
+			<example>
+			<title><function>app_perl.get_reset_cycles</function> usage</title>
+			<programlisting format="linespecific">
+...
+kamcmd app_perl.get_reset_cycles
+...
+</programlisting>
+			</example>
+		</section>
+	</section>
+
 </chapter>
 
diff --git a/modules/app_perl/perlfunc.c b/modules/app_perl/perlfunc.c
index 06d3314..e67c81f 100644
--- a/modules/app_perl/perlfunc.c
+++ b/modules/app_perl/perlfunc.c
@@ -58,6 +58,7 @@ int perl_checkfnc(char *fnc) {
 
 int perl_exec_simple(char* fnc, char* args[], int flags) {
 
+	app_perl_reset_interpreter();
 	if (perl_checkfnc(fnc)) {
 		LM_DBG("running perl function \"%s\"", fnc);
 
@@ -94,6 +95,8 @@ int perl_exec2(struct sip_msg* _msg, char* fnc, char* mystr) {
 	SV *m;
 	str reason;
 
+	app_perl_reset_interpreter();
+
 	dSP;
 
 	if (!perl_checkfnc(fnc)) {
diff --git a/modules/app_perl/perlfunc.h b/modules/app_perl/perlfunc.h
index 2d380b9..9f40ce8 100644
--- a/modules/app_perl/perlfunc.h
+++ b/modules/app_perl/perlfunc.h
@@ -42,4 +42,6 @@ int perl_exec_simple2(struct sip_msg* _msg, char* fnc, char* str2);
 int perl_exec1(struct sip_msg* _msg, char* fnc, char *foobar);
 int perl_exec2(struct sip_msg* _msg, char* fnc, char* mystr);
 
+int app_perl_reset_interpreter(void);
+
 #endif /* PERL_FUNC_H */
diff --git a/modules/auth/README b/modules/auth/README
index 3727c5a..76d2992 100644
--- a/modules/auth/README
+++ b/modules/auth/README
@@ -1,4 +1,3 @@
-
 The Auth Module
 
 Jan Janak
@@ -17,7 +16,7 @@ Daniel-Constantin Mierla
    <miconda at gmail.com>
 
    Copyright � 2002, 2003 FhG FOKUS
-     _________________________________________________________________
+     __________________________________________________________________
 
    Table of Contents
 
@@ -27,35 +26,35 @@ Daniel-Constantin Mierla
         2. Dependencies
         3. Parameters
 
-              3.1. auth_checks_register, auth_checks_no_dlg, and
-                      auth_checks_in_dlg (flags) 
-
-              3.2. qop (string)
-              3.3. nonce_count (boolean)
-              3.4. one_time_nonce (boolean)
-              3.5. nid_pool_no (integer)
-              3.6. nc_array_size (integer)
-              3.7. nc_array_order (integer)
-              3.8. otn_in_flight_no (integer)
-              3.9. otn_in_flight_order (integer)
-              3.10. secret (string)
-              3.11. nonce_expire (integer)
-              3.12. nonce_auth_max_drift (integer)
-              3.13. force_stateless_reply (boolean)
-              3.14. realm_prefix (string)
-              3.15. use_domain (boolean)
+              3.1. auth_checks_register (flags)
+              3.2. auth_checks_no_dlg (flags)
+              3.3. auth_checks_in_dlg (flags)
+              3.4. qop (string)
+              3.5. nonce_count (boolean)
+              3.6. one_time_nonce (boolean)
+              3.7. nid_pool_no (integer)
+              3.8. nc_array_size (integer)
+              3.9. nc_array_order (integer)
+              3.10. otn_in_flight_no (integer)
+              3.11. otn_in_flight_order (integer)
+              3.12. secret (string)
+              3.13. nonce_expire (integer)
+              3.14. nonce_auth_max_drift (integer)
+              3.15. force_stateless_reply (boolean)
+              3.16. realm_prefix (string)
+              3.17. use_domain (boolean)
 
         4. Functions
 
               4.1. consume_credentials()
               4.2. has_credentials(realm)
-              4.3. www_challenge(realm, flags) 
-              4.4. proxy_challenge(realm, flags) 
-              4.5. auth_challenge(realm, flags) 
-              4.6. pv_www_authenticate(realm, passwd, flags [, method]) 
-              4.7. pv_proxy_authenticate(realm, passwd, flags) 
-              4.8. pv_auth_check(realm, passwd, flags, checks) 
-              4.9. auth_get_www_authenticate(realm, flags, pvdest) 
+              4.3. www_challenge(realm, flags)
+              4.4. proxy_challenge(realm, flags)
+              4.5. auth_challenge(realm, flags)
+              4.6. pv_www_authenticate(realm, passwd, flags [, method])
+              4.7. pv_proxy_authenticate(realm, passwd, flags)
+              4.8. pv_auth_check(realm, passwd, flags, checks)
+              4.9. auth_get_www_authenticate(realm, flags, pvdest)
 
    List of Examples
 
@@ -92,49 +91,49 @@ Chapter 1. Admin Guide
    2. Dependencies
    3. Parameters
 
-        3.1. auth_checks_register, auth_checks_no_dlg, and
-                auth_checks_in_dlg (flags) 
-
-        3.2. qop (string)
-        3.3. nonce_count (boolean)
-        3.4. one_time_nonce (boolean)
-        3.5. nid_pool_no (integer)
-        3.6. nc_array_size (integer)
-        3.7. nc_array_order (integer)
-        3.8. otn_in_flight_no (integer)
-        3.9. otn_in_flight_order (integer)
-        3.10. secret (string)
-        3.11. nonce_expire (integer)
-        3.12. nonce_auth_max_drift (integer)
-        3.13. force_stateless_reply (boolean)
-        3.14. realm_prefix (string)
-        3.15. use_domain (boolean)
+        3.1. auth_checks_register (flags)
+        3.2. auth_checks_no_dlg (flags)
+        3.3. auth_checks_in_dlg (flags)
+        3.4. qop (string)
+        3.5. nonce_count (boolean)
+        3.6. one_time_nonce (boolean)
+        3.7. nid_pool_no (integer)
+        3.8. nc_array_size (integer)
+        3.9. nc_array_order (integer)
+        3.10. otn_in_flight_no (integer)
+        3.11. otn_in_flight_order (integer)
+        3.12. secret (string)
+        3.13. nonce_expire (integer)
+        3.14. nonce_auth_max_drift (integer)
+        3.15. force_stateless_reply (boolean)
+        3.16. realm_prefix (string)
+        3.17. use_domain (boolean)
 
    4. Functions
 
         4.1. consume_credentials()
         4.2. has_credentials(realm)
-        4.3. www_challenge(realm, flags) 
-        4.4. proxy_challenge(realm, flags) 
-        4.5. auth_challenge(realm, flags) 
-        4.6. pv_www_authenticate(realm, passwd, flags [, method]) 
-        4.7. pv_proxy_authenticate(realm, passwd, flags) 
-        4.8. pv_auth_check(realm, passwd, flags, checks) 
-        4.9. auth_get_www_authenticate(realm, flags, pvdest) 
+        4.3. www_challenge(realm, flags)
+        4.4. proxy_challenge(realm, flags)
+        4.5. auth_challenge(realm, flags)
+        4.6. pv_www_authenticate(realm, passwd, flags [, method])
+        4.7. pv_proxy_authenticate(realm, passwd, flags)
+        4.8. pv_auth_check(realm, passwd, flags, checks)
+        4.9. auth_get_www_authenticate(realm, flags, pvdest)
 
 1. Overview
 
-   This  is  a  generic  module that itself doesn't provide all functions
+   This is a generic module that itself doesn't provide all functions
    necessary for authentication but provides functions that are needed by
-   all  other  authentication  related  modules (so called authentication
+   all other authentication related modules (so called authentication
    backends).
 
-   We  decided  to  divide  the  authentication code into several modules
-   because  there  are  now  more  than  one backends (currently database
-   authentication  and  radius  are  supported). This allows us to create
-   separate  packages  so  users  can  install and load only the required
-   functionality.  This  also allows us to avoid unnecessary dependencies
-   in the binary packages.
+   We decided to divide the authentication code into several modules
+   because there are now more than one backends (currently database
+   authentication and radius are supported). This allows us to create
+   separate packages so users can install and load only the required
+   functionality. This also allows us to avoid unnecessary dependencies in
+   the binary packages.
 
 2. Dependencies
 
@@ -142,57 +141,64 @@ Chapter 1. Admin Guide
 
 3. Parameters
 
-   3.1. auth_checks_register, auth_checks_no_dlg, and auth_checks_in_dlg
-          (flags) 
-
-   3.2. qop (string)
-   3.3. nonce_count (boolean)
-   3.4. one_time_nonce (boolean)
-   3.5. nid_pool_no (integer)
-   3.6. nc_array_size (integer)
-   3.7. nc_array_order (integer)
-   3.8. otn_in_flight_no (integer)
-   3.9. otn_in_flight_order (integer)
-   3.10. secret (string)
-   3.11. nonce_expire (integer)
-   3.12. nonce_auth_max_drift (integer)
-   3.13. force_stateless_reply (boolean)
-   3.14. realm_prefix (string)
-   3.15. use_domain (boolean)
-
-3.1.  auth_checks_register, auth_checks_no_dlg, and auth_checks_in_dlg
-(flags)
-
-   These  three module parameters control which optional integrity checks
-   will  be  performed on the SIP message carrying digest response during
-   digest  authentication.  auth_check_register controls integrity checks
-   to  be  performed  on  REGISTER  messages, auth_checks_no_dlg controls
-   which optional integrity checks will be performed on SIP requests that
-   have  no  To  header  field  or no To tag (in other words the requests
-   either  establishing  or outside dialogs). auth_checks_in_dlg controls
-   which  integrity  checks  will  be  performed  on  SIP requests within
-   dialogs,  such  as  BYE  or re-INVITE. The default value for all three
-   parameters is 0 (old behaviour, no extra checks). The set of integrity
-   checks  that can be performed on REGISTERs is typically different from
-   sets  of  integrity checks that can be performed for other SIP request
-   types, hence we have three independent module parameters.
-
-   Without  the  extra checks the nonce will protect only against expired
-   values.  Some reply attacks are still possible in the expire "window".
-   A possible workaround is to always force qop authentication and always
-   check  the  uri from the authorization header, but this would not work
-   if an upstream proxy rewrites the uri and it will also not work with a
-   lot of UA implementations.
+   3.1. auth_checks_register (flags)
+   3.2. auth_checks_no_dlg (flags)
+   3.3. auth_checks_in_dlg (flags)
+   3.4. qop (string)
+   3.5. nonce_count (boolean)
+   3.6. one_time_nonce (boolean)
+   3.7. nid_pool_no (integer)
+   3.8. nc_array_size (integer)
+   3.9. nc_array_order (integer)
+   3.10. otn_in_flight_no (integer)
+   3.11. otn_in_flight_order (integer)
+   3.12. secret (string)
+   3.13. nonce_expire (integer)
+   3.14. nonce_auth_max_drift (integer)
+   3.15. force_stateless_reply (boolean)
+   3.16. realm_prefix (string)
+   3.17. use_domain (boolean)
+
+3.1. auth_checks_register (flags)
+
+   See description of parameter auth_checks_in_dlg.
+
+3.2. auth_checks_no_dlg (flags)
+
+   See description of parameter auth_checks_in_dlg.
+
+3.3. auth_checks_in_dlg (flags)
+
+   These three module parameters control which optional integrity checks
+   will be performed on the SIP message carrying digest response during
+   digest authentication. auth_check_register controls integrity checks to
+   be performed on REGISTER messages, auth_checks_no_dlg controls which
+   optional integrity checks will be performed on SIP requests that have
+   no To header field or no To tag (in other words the requests either
+   establishing or outside dialogs). auth_checks_in_dlg controls which
+   integrity checks will be performed on SIP requests within dialogs, such
+   as BYE or re-INVITE. The default value for all three parameters is 0
+   (old behaviour, no extra checks). The set of integrity checks that can
+   be performed on REGISTERs is typically different from sets of integrity
+   checks that can be performed for other SIP request types, hence we have
+   three independent module parameters.
+
+   Without the extra checks the nonce will protect only against expired
+   values. Some reply attacks are still possible in the expire "window". A
+   possible workaround is to always force qop authentication and always
+   check the uri from the authorization header, but this would not work if
+   an upstream proxy rewrites the uri and it will also not work with a lot
+   of UA implementations.
 
    In this case the nonce value will be used only to hold the expire time
    (see nonce_expire) and an MD5 over it and some secret (the MD5 is used
    to make sure that nobody tampers with the nonce expire time).
 
-   When  the  extra  checks are enabled, the nonce will include and extra
-   MD5  over  the selected part/parts of the message (see below) and some
-   other  secret.  This will be used to check if the selected part of the
-   message  is  the  same  when  an  UA  tries  to  reuse the nonce, thus
-   protecting or severely limiting reply attacks.
+   When the extra checks are enabled, the nonce will include and extra MD5
+   over the selected part/parts of the message (see below) and some other
+   secret. This will be used to check if the selected part of the message
+   is the same when an UA tries to reuse the nonce, thus protecting or
+   severely limiting reply attacks.
 
    The possible flag values for all three parameters are:
      * 1 for checking if the message uri changed (uses the whole uri)
@@ -200,27 +206,27 @@ Chapter 1. Admin Guide
      * 4 for checking the from tag
      * 8 for checking the source ip (see nonce.h).
 
-   For  example  setting  auth_checks_register  to  3  would check if the
-   callid  or the request uri changed from the REGISTER message for which
-   the  original  nonce  was generated (this would allow nonce reuse only
-   within  the  same  UA and for the expire time). Note that enabling the
-   extra  checks  will  limit  nonce  caching  by  UAs,  requiring  extra
-   challenges and roundtrips, but will provide much better protection.
+   For example setting auth_checks_register to 3 would check if the callid
+   or the request uri changed from the REGISTER message for which the
+   original nonce was generated (this would allow nonce reuse only within
+   the same UA and for the expire time). Note that enabling the extra
+   checks will limit nonce caching by UAs, requiring extra challenges and
+   roundtrips, but will provide much better protection.
 
 Warning
 
-   Do    not    enable   the   from   tag   check   (4)   for   REGISTERs
+   Do not enable the from tag check (4) for REGISTERs
    (auth_checks_register) and out-of-dialog messages (auth_checks_no_dlg)
-   unless  you  are sure that all your user agents do not change the from
+   unless you are sure that all your user agents do not change the from
    tag when challenged. Some user agents will also change the callid when
-   the  challenged request is not in-dialog, so avoid enabling the callid
-   check   (2)   for   messages   that   are   not   part   of  a  dialog
+   the challenged request is not in-dialog, so avoid enabling the callid
+   check (2) for messages that are not part of a dialog
    (auth_checks_no_dlg). In some rare case this will also have to be done
    for REGISTERs.
 
    When the secret parameter is set and the extra checks are enabled, the
-   first  half of the secret will be used for the expire time MD5 and the
-   other  half  for  the  extra  checks MD5, so make sure you have a long
+   first half of the secret will be used for the expire time MD5 and the
+   other half for the extra checks MD5, so make sure you have a long
    secret (32 chars or longer are recommended).
 
    Example 1.1. Setting the auth_checks_register module parameter
@@ -246,15 +252,15 @@ modparam("auth", "auth_checks_in_dlg", 15)
 
 ...
 
-3.2. qop (string)
+3.4. qop (string)
 
-   If  set,  enable qop for challenges: each challenge will include a qop
-   parameter.  This  is  the  recommended way, but some older non rfc3261
-   compliant  UAs  might get confused and might not authenticate properly
-   if qop is enabled.
+   If set, enable qop for challenges: each challenge will include a qop
+   parameter. This is the recommended way, but some older non rfc3261
+   compliant UAs might get confused and might not authenticate properly if
+   qop is enabled.
 
-   Enabling  qop  together  with  nonce_count will provide extra-security
-   (protection  against  replay attacks) while still allowing credentials
+   Enabling qop together with nonce_count will provide extra-security
+   (protection against replay attacks) while still allowing credentials
    caching at the UA side and thus not compromising performance.
 
    The possible values are: "auth", "auth-int" and "" (unset).
@@ -268,48 +274,48 @@ modparam("auth", "auth_checks_in_dlg", 15)
 modparam("auth", "qop", "auth")   # set qop=auth
 ...
 
-3.3. nonce_count (boolean)
+3.5. nonce_count (boolean)
 
    If enabled the received nc value is remembered and checked against the
-   older  value  (for a successful authentication the received nc must be
-   greater  then  the  previously  received  one,  see  rfc2617  for more
-   details).  This  will  provide protection against replay attacks while
+   older value (for a successful authentication the received nc must be
+   greater then the previously received one, see rfc2617 for more
+   details). This will provide protection against replay attacks while
    still allowing credentials caching at the UA side.
 
    It depends on qop being enabled (if qop is not enabled, the challenges
-   won't  include  qop and so the UA will probably not include the qop or
-   nc parameters in its response).
+   won't include qop and so the UA will probably not include the qop or nc
+   parameters in its response).
 
    If a response doesn't include qop or nc (for example obsolete UAs that
-   don't  support  them)  the  response  will be checked according to the
-   other   enabled  nonce  checks,  in  this  order:  one_time_nonce  and
-   auth_check_*.  If  a response includes nc only the normal nonce_expire
-   checks  and  the  nonce_count  checks will be performed, all the other
-   checks will be ignored.
-
-   The  nonce_count  checks  work by tracking a limited number of nonces.
-   The maximum number of tracked nonces is set using the nc_array_size or
-   nc_array_order  parameters.  If this number is exceeded, older entries
-   will  be  overwritten.  As  long  as the maximum rate of challengeable
-   messages  per  average  response time is lower then nc_array_size, the
-   nonce_count  checks  should  work  flawlessly. For optimum performance
-   (maximum   reuse   of  cache  credentials)  nc_array_size  divided  by
-   nid_pool_no  should  be  lower then the message rate multiplied by the
+   don't support them) the response will be checked according to the other
+   enabled nonce checks, in this order: one_time_nonce and auth_check_*.
+   If a response includes nc only the normal nonce_expire checks and the
+   nonce_count checks will be performed, all the other checks will be
+   ignored.
+
+   The nonce_count checks work by tracking a limited number of nonces. The
+   maximum number of tracked nonces is set using the nc_array_size or
+   nc_array_order parameters. If this number is exceeded, older entries
+   will be overwritten. As long as the maximum rate of challengeable
+   messages per average response time is lower then nc_array_size, the
+   nonce_count checks should work flawlessly. For optimum performance
+   (maximum reuse of cache credentials) nc_array_size divided by
+   nid_pool_no should be lower then the message rate multiplied by the
    desired nonce_expire.
 
    The maximum accepted nc value is 255. If nc becomes greater then this,
    the nonce will be considered stale and the UA will be re-challenged.
 
-   Note:   nonce_count  should  be  enabled  only  in  stateful  mode  (a
-   transaction  should  be  created  prior to the authentication check to
-   absorb  possible  retransmissions  and  all the replies should be sent
-   statefuly,  using  t_reply()).  If  nonce_count and the authentication
+   Note: nonce_count should be enabled only in stateful mode (a
+   transaction should be created prior to the authentication check to
+   absorb possible retransmissions and all the replies should be sent
+   statefuly, using t_reply()). If nonce_count and the authentication
    checks are used in the stateless mode then all retransmissions will be
    challenged.
 
    The default value is 0 (off).
 
-   See    also:    qop,   nc_array_size,   nc_array_order,   nid_pool_no,
+   See also: qop, nc_array_size, nc_array_order, nid_pool_no,
    nonce_expire. one_time_nonce.
 
    Example 1.3. nonce_count example
@@ -364,42 +370,42 @@ route{
         }
 ...
 
-3.4. one_time_nonce (boolean)
+3.6. one_time_nonce (boolean)
 
-   If  set to 1 nonce reuse is disabled: each nonce is allowed only once,
-   in  the  first  reponse  to  a  challenge.  All  the  messages will be
-   challenged,  even  retransmissions.  Stateful  mode should be used, to
-   catch   retransmissions   before   the  authentication  checks  (using
-   t_newtran()  before  the  authentication  checks  and  sending all the
+   If set to 1 nonce reuse is disabled: each nonce is allowed only once,
+   in the first reponse to a challenge. All the messages will be
+   challenged, even retransmissions. Stateful mode should be used, to
+   catch retransmissions before the authentication checks (using
+   t_newtran() before the authentication checks and sending all the
    replies with t_reply()).
 
-   one_time_nonce  provides  enhanced  replay  protections at the cost of
-   invalidating  UA  side  credentials caching, challenging every message
-   (and  thus  generating  extra  messages  and  extra  round-trips)  and
-   requiring  stateful  mode.  In  general  qop and nonce_count should be
-   prefered  (if  possible)  with  fallback  to auth_checks_*. Due to the
-   disadvantages  listed above, one_time_nonce should be used only if the
-   extra  checks provided by auth_checks_register, auth_checks_no_dlg and
+   one_time_nonce provides enhanced replay protections at the cost of
+   invalidating UA side credentials caching, challenging every message
+   (and thus generating extra messages and extra round-trips) and
+   requiring stateful mode. In general qop and nonce_count should be
+   prefered (if possible) with fallback to auth_checks_*. Due to the
+   disadvantages listed above, one_time_nonce should be used only if the
+   extra checks provided by auth_checks_register, auth_checks_no_dlg and
    auth_checks_in_dlg are deemed insufficient for a specific setup.
 
-   Compared  to nonce_count, one_time_nonce provides the same protection,
-   but  at  a  higher message cost. The only advantages are that it works
-   with  user agents that do not support qop and nc and that it uses less
+   Compared to nonce_count, one_time_nonce provides the same protection,
+   but at a higher message cost. The only advantages are that it works
+   with user agents that do not support qop and nc and that it uses less
    memory for the same supported number of maximum in-flight nonces (by a
    factor of 8). one_time_nonce can be used as fallback from nonce_count,
-   when  the UA doesn't support nc (it happens automatically when both of
+   when the UA doesn't support nc (it happens automatically when both of
    them are enabled).
 
    Like nonce_count, one_time_nonce works by tracking a limited number of
-   nonces.  The  maximum  number  of  tracked  nonces  is  set  using the
-   otn_in_flight_no  or otn_in_flight_order parameters. If this number is
-   exceeded,  older  entries  will be overwritten. As long as the maximum
+   nonces. The maximum number of tracked nonces is set using the
+   otn_in_flight_no or otn_in_flight_order parameters. If this number is
+   exceeded, older entries will be overwritten. As long as the maximum
    rate of challengeable messages per average response time is lower then
    otn_in_flight_no, the one_time_nonce checks should work flawlessly.
 
    The default value is 0 (off).
 
-   See   also:  otn_in_flight_no,  otn_in_flight_order,  nid_pool_no  and
+   See also: otn_in_flight_no, otn_in_flight_order, nid_pool_no and
    nonce_count.
 
    Example 1.4. one_time_nonce example
@@ -408,35 +414,35 @@ modparam("auth", "one_time_nonce", 1)
 # Note: stateful mode should be used, see the nonce_count example
 ...
 
-3.5. nid_pool_no (integer)
+3.7. nid_pool_no (integer)
 
-   Controls   the   number   of   partitions   for  the  nonce_count  and
+   Controls the number of partitions for the nonce_count and
    one_time_nonce arrays (it's common to both of them to reduce the nonce
    size).
 
-   Instead  of  using single arrays for keeping nonce state, these arrays
-   can  be  divided into more partitions. Each ser process is assigned to
-   one  of these partitions, allowing for higher concurrency on multi-CPU
-   machines.  Besides  increasing performance, increasing nid_pool_no has
-   also  a  negative  effect:  it  could  decrease  the maximum supported
-   in-flight  nonces  in certain conditions. In the worst case, when only
-   one  ser  process  receives  most  of  the traffic (e.g. very busy tcp
+   Instead of using single arrays for keeping nonce state, these arrays
+   can be divided into more partitions. Each ser process is assigned to
+   one of these partitions, allowing for higher concurrency on multi-CPU
+   machines. Besides increasing performance, increasing nid_pool_no has
+   also a negative effect: it could decrease the maximum supported
+   in-flight nonces in certain conditions. In the worst case, when only
+   one ser process receives most of the traffic (e.g. very busy tcp
    connection between two proxies), the in-flight nonces could be limited
-   to  the  array size (nc_array_size for nonce_count or otn_in_flight_no
-   for  one_time_nonce)  divided  by the partitions number (nid_pool_no).
-   However  for  normal  traffic, when the process receiving a message is
+   to the array size (nc_array_size for nonce_count or otn_in_flight_no
+   for one_time_nonce) divided by the partitions number (nid_pool_no).
+   However for normal traffic, when the process receiving a message is
    either random or chosen in a round-robin fashion the maximum in-flight
-   nonces  number  will  be  very  little  influenced by nid_pool_no (the
-   messages  will  be  close  to  equally  distributed to processes using
+   nonces number will be very little influenced by nid_pool_no (the
+   messages will be close to equally distributed to processes using
    different partitions).
 
-   nid_pool_no  value  should  be  one  of: 1, 2, 4, 8, 16, 32 or 64 (the
-   maximum  value  is 64 and all values should be of the form 2^k or else
+   nid_pool_no value should be one of: 1, 2, 4, 8, 16, 32 or 64 (the
+   maximum value is 64 and all values should be of the form 2^k or else
    they will be rounded down to 2^k).
 
    The default value is 1.
 
-   See    also:    nonce_count,    one_time_nonce,    nc_array_size   and
+   See also: nonce_count, one_time_nonce, nc_array_size and
    otn_in_flight_no.
 
    Example 1.5. nid_pool_no example
@@ -444,21 +450,20 @@ modparam("auth", "one_time_nonce", 1)
 modparam("auth", "nid_pool_no", 4)
 ...
 
-3.6. nc_array_size (integer)
+3.8. nc_array_size (integer)
 
-   Maximum  number of in-flight nonces for nonce_count. It represents the
-   maximum  nonces  for  which  state  will  be kept. When this number is
-   exceeded,  state  for the older nonces will be discarded to make space
+   Maximum number of in-flight nonces for nonce_count. It represents the
+   maximum nonces for which state will be kept. When this number is
+   exceeded, state for the older nonces will be discarded to make space
    for new ones (see nonce_count for more details).
 
-   The  value  should  be of the form 2^k. If it's not it will be rounded
-   down  to  2^k  (for example a value of 1000000 will be rounded down to
+   The value should be of the form 2^k. If it's not it will be rounded
+   down to 2^k (for example a value of 1000000 will be rounded down to
    2^19=524288). nc_array_order can be used to directly specify the power
    of 2 (e.g. nc_array_order set to 20 is equivalent to nc_array_size set
    to 1048576).
 
-   The  memory  used  to  keep  the  nonce state will be nc_array_size in
-   bytes.
+   The memory used to keep the nonce state will be nc_array_size in bytes.
 
    The default value is 1048576 (1M in-flight nonces, using 1Mb memory).
 
@@ -469,10 +474,10 @@ modparam("auth", "nid_pool_no", 4)
 modparam("auth", "nc_array_size", 4194304)   # 4Mb
 ...
 
-3.7. nc_array_order (integer)
+3.9. nc_array_order (integer)
 
-   Equivalent  to  nc_array_size,  but instead of directly specifying the
-   size,   its   value   is  the  power  at  which  2  should  be  raised
+   Equivalent to nc_array_size, but instead of directly specifying the
+   size, its value is the power at which 2 should be raised
    (log2(nc_array_size)).
 
    nc_array_size = 2^nc_array_order. For more details see nc_array_size.
@@ -486,25 +491,24 @@ modparam("auth", "nc_array_size", 4194304)   # 4Mb
 modparam("auth", "nc_array_order", 22)   # 4Mb
 ...
 
-3.8. otn_in_flight_no (integer)
+3.10. otn_in_flight_no (integer)
 
-   Maximum  number  of in-flight nonces for one_time_nonce. It represents
-   the  maximum number of nonces remembered for the one-time-nonce check.
-   When  this  number is exceeded, information about older nonces will be
-   discarded  and  overwritten  with  information about the new generated
-   ones (see one_time_nonce for more details).
+   Maximum number of in-flight nonces for one_time_nonce. It represents
+   the maximum number of nonces remembered for the one-time-nonce check.
+   When this number is exceeded, information about older nonces will be
+   discarded and overwritten with information about the new generated ones
+   (see one_time_nonce for more details).
 
-   The  value  should  be of the form 2^k. If it's not it will be rounded
-   down  to  2^k  (for example a value of 1000000 will be rounded down to
-   2^19=524288).  otn_in_flight_no  can  be  used to directly specify the
-   power  of  2  (e.g.  otn_in_flight_order  set  to  19 is equivalent to
+   The value should be of the form 2^k. If it's not it will be rounded
+   down to 2^k (for example a value of 1000000 will be rounded down to
+   2^19=524288). otn_in_flight_no can be used to directly specify the
+   power of 2 (e.g. otn_in_flight_order set to 19 is equivalent to
    otn_in_fligh_number set to 524288).
 
-   The   memory   used   to  keep  the  nonce  information  will  be  the
+   The memory used to keep the nonce information will be the
    otn_in_flight_no divided by 8 (only 1 bit of state is kept per nonce).
 
-   The  default  value  is  1048576  (1M  in-flight  nonces,  using 128Kb
-   memory).
+   The default value is 1048576 (1M in-flight nonces, using 128Kb memory).
 
    See also: one_time_nonce and nid_pool_no.
 
@@ -513,13 +517,13 @@ modparam("auth", "nc_array_order", 22)   # 4Mb
 modparam("auth", "otn_in_flight_no", 8388608)   # 8 Mb (1Mb memory)
 ...
 
-3.9. otn_in_flight_order (integer)
+3.11. otn_in_flight_order (integer)
 
    Equivalent to otn_in_flight_no, but instead of directly specifying the
-   size,   its   value   is  the  power  at  which  2  should  be  raised
+   size, its value is the power at which 2 should be raised
    (log2(otn_in_flight_no)).
 
-   otn_in_flight_no   =   2^otn_in_flight_order.  For  more  details  see
+   otn_in_flight_no = 2^otn_in_flight_order. For more details see
    otn_in_flight_order.
 
    The default value is 20 (1M in-flight nonces, using 128Kb memory).
@@ -531,18 +535,18 @@ modparam("auth", "otn_in_flight_no", 8388608)   # 8 Mb (1Mb memory)
 modparam("auth", "otn_in_flight_order", 23)   # 8 Mb (1Mb memory)
 ...
 
-3.10. secret (string)
+3.12. secret (string)
 
-   Secret  phrase used to calculate the nonce value used to challenge the
+   Secret phrase used to calculate the nonce value used to challenge the
    client for authentication.
 
-   If  you  use  multiple servers in your installation, and would like to
-   authenticate  on  the second server against the nonce generated at the
+   If you use multiple servers in your installation, and would like to
+   authenticate on the second server against the nonce generated at the
    first one its necessary to explicitly set the secret to the same value
-   on  all servers. However, as the use of a shared (and fixed) secret as
-   nonce  is insecure, it is much better is to stay with the default. Any
-   clients  should  send  the  authenticated  request  to the server that
-   issued the challenge.
+   on all servers. However, as the use of a shared (and fixed) secret as
+   nonce is insecure, it is much better is to stay with the default. Any
+   clients should send the authenticated request to the server that issued
+   the challenge.
 
    Default value is randomly generated string.
 
@@ -551,14 +555,14 @@ modparam("auth", "otn_in_flight_order", 23)   # 8 Mb (1Mb memory)
 modparam("auth", "secret", "johndoessecretphrase")
 ...
 
-3.11. nonce_expire (integer)
+3.13. nonce_expire (integer)
 
    Nonces have limited lifetime. After a given period of time nonces will
-   be  considered invalid. This is to protect replay attacks. Credentials
-   containing  a  stale  nonce will be not authorized, but the user agent
-   will  be  challenged again. This time the challenge will contain stale
-   parameter  which  will  indicate to the client that it doesn't have to
-   disturb  user  by asking for username and password, it can recalculate
+   be considered invalid. This is to protect replay attacks. Credentials
+   containing a stale nonce will be not authorized, but the user agent
+   will be challenged again. This time the challenge will contain stale
+   parameter which will indicate to the client that it doesn't have to
+   disturb user by asking for username and password, it can recalculate
    credentials using existing username and password.
 
    The value is in seconds and default value is 300 seconds.
@@ -568,19 +572,18 @@ modparam("auth", "secret", "johndoessecretphrase")
 modparam("auth", "nonce_expire", 600)   # Set nonce_expire to 600s
 ...
 
-3.12. nonce_auth_max_drift (integer)
+3.14. nonce_auth_max_drift (integer)
 
-   Maximum  difference  in  seconds between a nonce creation time and the
+   Maximum difference in seconds between a nonce creation time and the
    current time, if the nonce creation time appears to be in the future.
 
    In some cases, like shortly after a system time backward adjustment or
-   when   the   current   proxy  is  part  of  a  cluster  which  is  not
+   when the current proxy is part of a cluster which is not
    time-synchronized, it's possible to receive a nonce with creation time
-   in  the  future.  In  this  case  if  the  difference  is greater then
-   nonce_auth_max_drift   seconds,   consider   the   nonce   stale   and
-   re-challenge  (otherwise  after  a  dramatic time change backwards, it
-   might  happen  that some previously generated nonces will be valid for
-   too much time).
+   in the future. In this case if the difference is greater then
+   nonce_auth_max_drift seconds, consider the nonce stale and re-challenge
+   (otherwise after a dramatic time change backwards, it might happen that
+   some previously generated nonces will be valid for too much time).
 
    The default value is 3 seconds
 
@@ -591,11 +594,11 @@ modparam("auth", "nonce_expire", 600)   # Set nonce_expire to 600s
 modparam("auth", "nonce_auth_max_drift", 1)   # set max drift to 1 s
 ...
 
-3.13. force_stateless_reply (boolean)
+3.15. force_stateless_reply (boolean)
 
-   If  set  to  1,  www_challenge()  and proxy_challenge() functions send
-   reply  statelessly no matter if transaction exists or not. If set to 0
-   (default),   reply  is  sent  statefully  if  transaction  exists  and
+   If set to 1, www_challenge() and proxy_challenge() functions send reply
+   statelessly no matter if transaction exists or not. If set to 0
+   (default), reply is sent statefully if transaction exists and
    stelelessly otherwise.
 
    Example 1.13. force_stateless_reply example
@@ -603,13 +606,13 @@ modparam("auth", "nonce_auth_max_drift", 1)   # set max drift to 1 s
 modparam("auth", "force_stateless_reply", 1)
 ...
 
-3.14. realm_prefix (string)
+3.16. realm_prefix (string)
 
-   Prefix  to be automatically strip from realm. As an alternative to SRV
-   records  (not  all SIP clients support SRV lookup), a subdomain of the
-   master  domain  can be defined for SIP purposes (like sip.mydomain.net
-   pointing  to  same  IP address as the SRV record for mydomain.net). By
-   ignoring  the realm_prefix "sip.", at authentication, sip.mydomain.net
+   Prefix to be automatically strip from realm. As an alternative to SRV
+   records (not all SIP clients support SRV lookup), a subdomain of the
+   master domain can be defined for SIP purposes (like sip.mydomain.net
+   pointing to same IP address as the SRV record for mydomain.net). By
+   ignoring the realm_prefix "sip.", at authentication, sip.mydomain.net
    will be equivalent to mydomain.net .
 
    Default value is empty string.
@@ -617,9 +620,9 @@ modparam("auth", "force_stateless_reply", 1)
    Example 1.14. realm_prefix parameter example
 modparam("auth", "realm_prefix", "sip.")
 
-3.15. use_domain (boolean)
+3.17. use_domain (boolean)
 
-   If  set  to  1, pv_auth_check() uses domain parts of the URIs to check
+   If set to 1, pv_auth_check() uses domain parts of the URIs to check
    user identity.
 
    Example 1.15. force_stateless_reply example
@@ -631,24 +634,23 @@ modparam("auth", "use_domain", 1)
 
    4.1. consume_credentials()
    4.2. has_credentials(realm)
-   4.3. www_challenge(realm, flags) 
-   4.4. proxy_challenge(realm, flags) 
-   4.5. auth_challenge(realm, flags) 
-   4.6. pv_www_authenticate(realm, passwd, flags [, method]) 
-   4.7. pv_proxy_authenticate(realm, passwd, flags) 
-   4.8. pv_auth_check(realm, passwd, flags, checks) 
-   4.9. auth_get_www_authenticate(realm, flags, pvdest) 
+   4.3. www_challenge(realm, flags)
+   4.4. proxy_challenge(realm, flags)
+   4.5. auth_challenge(realm, flags)
+   4.6. pv_www_authenticate(realm, passwd, flags [, method])
+   4.7. pv_proxy_authenticate(realm, passwd, flags)
+   4.8. pv_auth_check(realm, passwd, flags, checks)
+   4.9. auth_get_www_authenticate(realm, flags, pvdest)
 
 4.1. consume_credentials()
 
-   This  function  removes  previously authorized credential headers from
-   the  message  being  processed  by  the  server.  That  means that the
-   downstream  message  will  not  contain credentials there were used by
-   this  server.  This ensures that the proxy will not reveal information
-   about  credentials  used  to  downstream elements and also the message
-   will  be  a  little  bit  shorter.  The  function must be called after
-   www_authorize,        proxy_authorize,       www_authenticate       or
-   proxy_authenticate.
+   This function removes previously authorized credential headers from the
+   message being processed by the server. That means that the downstream
+   message will not contain credentials there were used by this server.
+   This ensures that the proxy will not reveal information about
+   credentials used to downstream elements and also the message will be a
+   little bit shorter. The function must be called after www_authorize,
+   proxy_authorize, www_authenticate or proxy_authenticate.
 
    Example 1.16. consume_credentials example
 ...
@@ -659,8 +661,8 @@ if (www_authenticate("realm", "subscriber")) {
 
 4.2. has_credentials(realm)
 
-   This  function  returns  true  of  the  request  has  Autorization  or
-   Proxy-Authorization  header  with provided realm. The parameter can be
+   This function returns true of the request has Autorization or
+   Proxy-Authorization header with provided realm. The parameter can be
    string with pseudo-variables.
 
    Example 1.17. consume_credentials example
@@ -670,31 +672,31 @@ if (has_credentials("myrealm")) {
 }
 ...
 
-4.3.  www_challenge(realm, flags)
+4.3. www_challenge(realm, flags)
 
    The function challenges a user agent. It will generate a WWW-Authorize
-   header  field  containing  a  digest challenge, it will put the header
-   field  into  a  response  generated  from  the  request  the server is
+   header field containing a digest challenge, it will put the header
+   field into a response generated from the request the server is
    processing and send the reply. Upon reception of such a reply the user
-   agent  should  compute  credentials  and  retry  the request. For more
-   information  regarding  digest  authentication see RFC2617. See module
+   agent should compute credentials and retry the request. For more
+   information regarding digest authentication see RFC2617. See module
    parameter force_stateless_reply regarding sending of the reply.
 
    Meaning of the parameters is as follows:
-     * realm  -  Realm  is  a  opaque  string  that the user agent should
-       present to the user so he can decide what username and password to
-       use. Usually this is domain of the host the server is running on.
-       It  must not be empty string "". In case of REGISTER requests, the
-       To  header  field domain (e.g., variable $td) can be used (because
-       this  header  field represents the user being registered), for all
-       other  messages  From  header  field  domain  can  be  used (e.g.,
-       variable $fd).
+     * realm - Realm is a opaque string that the user agent should present
+       to the user so he can decide what username and password to use.
+       Usually this is domain of the host the server is running on.
+       It must not be empty string "". In case of REGISTER requests, the
+       To header field domain (e.g., variable $td) can be used (because
+       this header field represents the user being registered), for all
+       other messages From header field domain can be used (e.g., variable
+       $fd).
        The string may contain pseudo variables.
      * flags - Value of this parameter can be a bitmask of following:
           + 1 - build challenge header with qop=auth
           + 2 - build challenge header with qop=auth-int
-          + 4   -   do   not  send  '500  Internal  Server  Error'  reply
-            automatically  in  failure  cases  (error code is returned to
+          + 4 - do not send '500 Internal Server Error' reply
+            automatically in failure cases (error code is returned to
             config)
           + 16 - build challenge header with stale=true
 
@@ -707,17 +709,17 @@ if (!www_authenticate("$td", "subscriber")) {
 }
 ...
 
-4.4.  proxy_challenge(realm, flags)
+4.4. proxy_challenge(realm, flags)
 
-   The   function   challenges   a   user   agent.  It  will  generate  a
-   Proxy-Authorize  header  field  containing a digest challenge, it will
-   put  the  header  field into a response generated from the request the
-   server  is  processing  and  send  the reply. Upon reception of such a
-   reply the user agent should compute credentials and retry the request.
-   For  more information regarding digest authentication see RFC2617. See
-   module parameter force_stateless_reply regarding sending of the reply.
+   The function challenges a user agent. It will generate a
+   Proxy-Authorize header field containing a digest challenge, it will put
+   the header field into a response generated from the request the server
+   is processing and send the reply. Upon reception of such a reply the
+   user agent should compute credentials and retry the request. For more
+   information regarding digest authentication see RFC2617. See module
+   parameter force_stateless_reply regarding sending of the reply.
 
-   Meaning   of   the   parameters   is   the   same   as   for  function
+   Meaning of the parameters is the same as for function
    www_challenge(realm, flags)
 
    This function can be used from REQUEST_ROUTE.
@@ -729,15 +731,15 @@ if (!proxy_authenticate("$fd", "subscriber")) {
 };
 ...
 
-4.5.  auth_challenge(realm, flags)
+4.5. auth_challenge(realm, flags)
 
-   The  function  challenges a user agent for authentication. It combines
-   the   functions  www_challenge()  and  proxy_challenge(),  by  calling
-   internally  the first one for REGISTER requests and the second one for
+   The function challenges a user agent for authentication. It combines
+   the functions www_challenge() and proxy_challenge(), by calling
+   internally the first one for REGISTER requests and the second one for
    the rest of other request types.
 
-   Meaning    of    the    parameters    the   same   as   for   function
-   www_challenge(realm, flags)
+   Meaning of the parameters the same as for function www_challenge(realm,
+   flags)
 
    This function can be used from REQUEST_ROUTE.
 
@@ -748,52 +750,49 @@ if (!auth_check("$fd", "subscriber", "1")) {
 };
 ...
 
-4.6.  pv_www_authenticate(realm, passwd, flags [, method])
+4.6. pv_www_authenticate(realm, passwd, flags [, method])
 
-   The  function  verifies  credentials  according  to  RFC2617.  If  the
-   credentials  are  verified successfully then the function will succeed
-   and  mark  the  credentials  as  authorized (marked credentials can be
-   later  used  by  some  other functions). If the function was unable to
-   verify  the  credentials  for  some  reason  then it will fail and the
-   script should call www_challenge which will challenge the user again.
+   The function verifies credentials according to RFC2617. If the
+   credentials are verified successfully then the function will succeed
+   and mark the credentials as authorized (marked credentials can be later
+   used by some other functions). If the function was unable to verify the
+   credentials for some reason then it will fail and the script should
+   call www_challenge which will challenge the user again.
 
    Negative codes may be interpreted as follows:
-     * -1  (generic error) - some generic error occurred and no reply was
+     * -1 (generic error) - some generic error occurred and no reply was
        sent out;
      * -2 (invalid password) - wrong password;
      * -3 (invalid user) - authentication user does not exist.
      * -4 (nonce expired) - the nonce has expired
-     * -5  (no  credentials)  - request does not contain an Authorization
+     * -5 (no credentials) - request does not contain an Authorization
        header with the correct realm.
-     * -6   (nonce   reused)  -  the  nonce  has  already  been  used  to
-       authenticate a previous request
+     * -6 (nonce reused) - the nonce has already been used to authenticate
+       a previous request
 
    Meaning of the parameters is as follows:
-     * realm  -  Realm  is  a  opaque  string  that the user agent should
-       present to the user so he can decide what username and password to
-       use. Usually this is domain of the host the server is running on.
-       It  must  not  be empty string "". In case of REGISTER requests To
+     * realm - Realm is a opaque string that the user agent should present
+       to the user so he can decide what username and password to use.
+       Usually this is domain of the host the server is running on.
+       It must not be empty string "". In case of REGISTER requests To
        header field domain (e.g., varibale $td) can be used (because this
-       header  field  represents  a user being registered), for all other
-       messages  From  header  field  domain  can be used (e.g., varibale
-       $fd).
+       header field represents a user being registered), for all other
+       messages From header field domain can be used (e.g., varibale $fd).
        The string may contain pseudo variables.
-     * passwd  -  the password to be used for authentication. Can contain
+     * passwd - the password to be used for authentication. Can contain
        config variables. The Username is taken from Auth header.
      * flags - the value of this parameter can be a bitmask of following:
           + 1 - the value of password parameter is HA1 format
           + 2 - build challenge header with no qop and add it to avp
           + 4 - build challenge header with qop=auth and add it to avp
-          + 8  -  build  challenge header with qop=auth-int and add it to
-            avp
+          + 8 - build challenge header with qop=auth-int and add it to avp
           + 16 - build challenge header with stale=true
-     * method  - the method to be used for authentication. This parameter
-       is   optional   and  if  not  set  is  the  first  "word"  on  the
-       request-line.
+     * method - the method to be used for authentication. This parameter
+       is optional and if not set is the first "word" on the request-line.
 
-   When  challenge  header  is built and stored in avp, append_to_reply()
-   and  the  sl reply functions can be used to send appropriate SIP reply
-   to challenge for authentication.
+   When challenge header is built and stored in avp, append_to_reply() and
+   the sl reply functions can be used to send appropriate SIP reply to
+   challenge for authentication.
 
    This function can be used from REQUEST_ROUTE.
 
@@ -804,19 +803,18 @@ if (!pv_www_authenticate("$td", "123abc", "0")) {
 };
 ...
 
-4.7.  pv_proxy_authenticate(realm, passwd, flags)
+4.7. pv_proxy_authenticate(realm, passwd, flags)
 
-   The  function  verifies  credentials  according  to  RFC2617.  If  the
-   credentials  are  verified successfully then the function will succeed
-   and  mark  the  credentials  as  authorized (marked credentials can be
-   later  used  by  some  other functions). If the function was unable to
-   verify  the  credentials  for  some  reason  then it will fail and the
-   script  should  call  proxy_challenge  which  will  challenge the user
-   again.  For  more  about  the  negative  return  codes,  see the above
-   function.
+   The function verifies credentials according to RFC2617. If the
+   credentials are verified successfully then the function will succeed
+   and mark the credentials as authorized (marked credentials can be later
+   used by some other functions). If the function was unable to verify the
+   credentials for some reason then it will fail and the script should
+   call proxy_challenge which will challenge the user again. For more
+   about the negative return codes, see the above function.
 
-   Meaning of the parameters is the same as for
-   pv_www_authenticate(realm, passwd, flags)
+   Meaning of the parameters is the same as for pv_www_authenticate(realm,
+   passwd, flags)
 
    This function can be used from REQUEST_ROUTE.
 
@@ -828,20 +826,20 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
 };
 ...
 
-4.8.  pv_auth_check(realm, passwd, flags, checks)
+4.8. pv_auth_check(realm, passwd, flags, checks)
 
-   The  function  combines the functionalities of pv_www_authenticate and
-   pv_proxy_authenticate,  first  being exectuted if the SIP request is a
+   The function combines the functionalities of pv_www_authenticate and
+   pv_proxy_authenticate, first being exectuted if the SIP request is a
    REGISTER, the second for the rest.
 
-   Meaning   of   the   first   three  parameters  is  the  same  as  for
+   Meaning of the first three parameters is the same as for
    pv_www_authenticate(realm, passwd, flags).
 
    Parameter checks can be used to control the behaviour of the function.
-   If  it is 1, then the function will check to see if the authentication
-   username  matches  either  To  or  From  header  username, a matter of
-   whether  it  is  for a REGISTER request or not. The parameter may be a
-   pseudo variable.
+   If it is 1, then the function will check to see if the authentication
+   username matches either To or From header username, a matter of whether
+   it is for a REGISTER request or not. The parameter may be a pseudo
+   variable.
 
    This function can be used from REQUEST_ROUTE.
 
@@ -853,12 +851,12 @@ if (!pv_auth_check("$fd", "$avp(password)", "0", "1")) {
 };
 ...
 
-4.9.  auth_get_www_authenticate(realm, flags, pvdest)
+4.9. auth_get_www_authenticate(realm, flags, pvdest)
 
-   Build  WWW-Authentication  header  and  set  the  resulting  value  in
-   'pvdest' pseudo-variable parameter.
+   Build WWW-Authentication header and set the resulting value in 'pvdest'
+   pseudo-variable parameter.
 
-   Meaning  of  the  realm  and  flags  parameters  is  the  same  as for
+   Meaning of the realm and flags parameters is the same as for
    pv_www_authenticate(realm, passwd, flags)
 
    This function can be used from ANY_ROUTE.
diff --git a/modules/auth/doc/auth_functions.xml b/modules/auth/doc/auth_functions.xml
index 4140f8c..0ab616a 100644
--- a/modules/auth/doc/auth_functions.xml
+++ b/modules/auth/doc/auth_functions.xml
@@ -6,7 +6,7 @@
 
     <title>Functions</title>
     
-    <section id="consume_credentials">
+    <section id="auth.f.consume_credentials">
 	<title><function>consume_credentials()</function></title>
 	<para>
 	    This function removes previously authorized credential headers from the
@@ -31,7 +31,7 @@ if (www_authenticate("realm", "subscriber")) {
 	    </programlisting>
 	</example>
     </section>
-    <section id="has_credentials">
+    <section id="auth.f.has_credentials">
 	<title><function>has_credentials(realm)</function></title>
 	<para>
 		This function returns true of the request has Autorization or
@@ -49,7 +49,7 @@ if (has_credentials("myrealm")) {
 	    </programlisting>
 	</example>
     </section>
-	<section id="www_challenge">
+	<section id="auth.f.www_challenge">
 		<title>
 			<function moreinfo="none">www_challenge(realm, flags)</function>
 		</title>
@@ -122,7 +122,7 @@ if (!www_authenticate("$td", "subscriber")) {
 		</example>
 	</section>
 
-	<section id="proxy_challenge">
+	<section id="auth.f.proxy_challenge">
 		<title>
 			<function moreinfo="none">proxy_challenge(realm, flags)</function>
 		</title>
@@ -152,7 +152,7 @@ if (!proxy_authenticate("$fd", "subscriber")) {
 		</example>
 	</section>
 
-	<section id="auth_challenge">
+	<section id="auth.f.auth_challenge">
 		<title>
 			<function moreinfo="none">auth_challenge(realm, flags)</function>
 		</title>
@@ -179,7 +179,7 @@ if (!auth_check("$fd", "subscriber", "1")) {
 		</example>
 	</section>
 
-	<section id="pv_www_authenticate">
+	<section id="auth.f.pv_www_authenticate">
 		<title>
 		<function moreinfo="none">pv_www_authenticate(realm, passwd, flags [, method])</function>
 		</title>
@@ -297,7 +297,7 @@ if (!pv_www_authenticate("$td", "123abc", "0")) {
 		</example>
 	</section>
 
-	<section id="pv_proxy_authenticate">
+	<section id="auth.f.pv_proxy_authenticate">
 		<title>
 			<function moreinfo="none">pv_proxy_authenticate(realm, passwd, flags)</function>
 		</title>
@@ -331,7 +331,7 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
 		</example>
 	</section>
 
-	<section id="pv_auth_check">
+	<section id="auth.f.pv_auth_check">
 		<title>
 			<function moreinfo="none">pv_auth_check(realm, passwd, flags, checks)</function>
 		</title>
@@ -368,7 +368,7 @@ if (!pv_auth_check("$fd", "$avp(password)", "0", "1")) {
 		</example>
 	</section>
 
-	<section id="auth_get_www_authenticate">
+	<section id="auth.f.auth_get_www_authenticate">
 		<title>
 			<function moreinfo="none">auth_get_www_authenticate(realm, flags, pvdest)</function>
 		</title>
diff --git a/modules/auth/doc/auth_params.xml b/modules/auth/doc/auth_params.xml
index 973f14e..3450ec1 100644
--- a/modules/auth/doc/auth_params.xml
+++ b/modules/auth/doc/auth_params.xml
@@ -6,14 +6,24 @@
 
     <title>Parameters</title>
     
-    <section id="auth.auth_checks">
-	<title>
-	  <varname>auth_checks_register</varname>,
-	  <varname>auth_checks_no_dlg</varname>, and
-	  <varname>auth_checks_in_dlg</varname> (flags)
-	</title>
-	<para>
-	These three module parameters control which optional integrity
+    <section id="auth.p.auth_checks_register">
+	<title><varname>auth_checks_register</varname> (flags)</title>
+	<para>
+		See description of parameter <varname>auth_checks_in_dlg</varname>.
+	</para>
+	</section>
+
+    <section id="auth.p.auth_checks_no_dlg">
+	<title><varname>auth_checks_no_dlg</varname> (flags)</title>
+	<para>
+		See description of parameter <varname>auth_checks_in_dlg</varname>.
+	</para>
+	</section>
+
+    <section id="auth.p.auth_checks_in_dlg">
+		<title><varname>auth_checks_in_dlg</varname> (flags)</title>
+	<para>
+		These three module parameters control which optional integrity
         checks will be performed on the SIP message carrying digest response
         during digest authentication. <varname>auth_check_register</varname>
         controls integrity checks to be performed on REGISTER messages,
@@ -125,7 +135,7 @@ modparam("auth", "auth_checks_in_dlg", 15)
 	</example>
     </section>
 
-    <section id="qop">
+    <section id="auth.p.qop">
 	<title><varname>qop</varname> (string)</title>
 	<para>
 		If set, enable <emphasis>qop</emphasis> for challenges: each challenge
@@ -161,7 +171,7 @@ modparam("auth", "qop", "auth")   # set qop=auth
 	</example>
     </section>
 
-    <section id="nonce_count">
+    <section id="auth.p.nonce_count">
 	<title><varname>nonce_count</varname> (boolean)</title>
 	<para>
 		If enabled the received <emphasis>nc</emphasis> value is remembered 
@@ -285,7 +295,7 @@ route{
 	</example>
     </section>
 
-	<section id="one_time_nonce">
+	<section id="auth.p.one_time_nonce">
 	<title><varname>one_time_nonce</varname> (boolean)</title>
 	<para>
 		If set to 1 nonce reuse is disabled: each nonce is allowed only once,
@@ -352,7 +362,7 @@ modparam("auth", "one_time_nonce", 1)
 	</example>
 	</section>
 
-    <section id="nid_pool_no">
+    <section id="auth.p.nid_pool_no">
 	<title><varname>nid_pool_no</varname> (integer)</title>
 	<para>
 		Controls the number of partitions for the 
@@ -404,7 +414,7 @@ modparam("auth", "nid_pool_no", 4)
 	</example>
     </section>
 
-    <section id="nc_array_size">
+    <section id="auth.p.nc_array_size">
 	<title><varname>nc_array_size</varname> (integer)</title>
 	<para>
 		Maximum number of in-flight nonces for <varname>nonce_count</varname>.
@@ -443,7 +453,7 @@ modparam("auth", "nc_array_size", 4194304)   # 4Mb
 	</example>
     </section>
 
-    <section id="nc_array_order">
+    <section id="auth.p.nc_array_order">
 	<title><varname>nc_array_order</varname> (integer)</title>
 	<para>
 		Equivalent to <varname>nc_array_size</varname>, but instead of 
@@ -473,7 +483,7 @@ modparam("auth", "nc_array_order", 22)   # 4Mb
 	</example>
     </section>
 
-    <section id="otn_in_flight_no">
+    <section id="auth.p.otn_in_flight_no">
 	<title><varname>otn_in_flight_no</varname> (integer)</title>
 	<para>
 		Maximum number of in-flight nonces for 
@@ -515,7 +525,7 @@ modparam("auth", "otn_in_flight_no", 8388608)   # 8 Mb (1Mb memory)
 	</example>
     </section>
 
-    <section id="otn_in_flight_order">
+    <section id="auth.p.otn_in_flight_order">
 	<title><varname>otn_in_flight_order</varname> (integer)</title>
 	<para>
 		Equivalent to <varname>otn_in_flight_no</varname>, but instead of
@@ -546,7 +556,7 @@ modparam("auth", "otn_in_flight_order", 23)   # 8 Mb (1Mb memory)
 	</example>
     </section>
 
-    <section id="auth.secret">
+    <section id="auth.p.secret">
 	<title><varname>secret</varname> (string)</title>
 	<para>Secret phrase used to calculate the nonce value used to challenge
 	the client for authentication.</para>
@@ -571,7 +581,7 @@ modparam("auth", "secret", "johndoessecretphrase")
 	</example>
     </section>
 
-    <section id="nonce_expire">
+    <section id="auth.p.nonce_expire">
 	<title><varname>nonce_expire</varname> (integer)</title>
 	<para>
 	    Nonces have limited lifetime. After a given period of time nonces
@@ -596,7 +606,7 @@ modparam("auth", "nonce_expire", 600)   # Set nonce_expire to 600s
 	</example>
     </section>
 
-	<section id="nonce_auth_max_drift">
+	<section id="auth.p.nonce_auth_max_drift">
 	<title><varname>nonce_auth_max_drift</varname> (integer)</title>
 	<para>
 		Maximum difference in seconds between a nonce creation time and the
@@ -628,7 +638,7 @@ modparam("auth", "nonce_auth_max_drift", 1)   # set max drift to 1 s
 	</example>
     </section>
 
-	<section id="force_stateless_reply">
+	<section id="auth.p.force_stateless_reply">
 	<title><varname>force_stateless_reply</varname> (boolean)</title>
 	<para>
 		If set to 1, <function>www_challenge()</function> and
@@ -647,7 +657,7 @@ modparam("auth", "force_stateless_reply", 1)
 	</example>
 	</section>
 
-	<section id="realm_prefix">
+	<section id="auth.p.realm_prefix">
 		<title><varname>realm_prefix</varname> (string)</title>
 		<para>
 			Prefix to be automatically strip from realm. As an alternative to
@@ -669,7 +679,7 @@ modparam("auth", "realm_prefix", "sip.")
 		</example>
 	</section>
 
-	<section id="auth.use_domain">
+	<section id="auth.p.use_domain">
 	<title><varname>use_domain</varname> (boolean)</title>
 	<para>
 		If set to 1, <function>pv_auth_check()</function> uses
diff --git a/modules/auth_db/README b/modules/auth_db/README
index 7bcc6f4..4076d19 100644
--- a/modules/auth_db/README
+++ b/modules/auth_db/README
@@ -320,8 +320,16 @@ modparam("auth_db", "version_table", 0)
    Negative codes may be interpreted as follows:
      * -1 (generic error) - some generic error occurred and no reply was
        sent out;
-     * -2 (invalid password) - valid user, but wrong password;
+     * -2 (invalid password) - wrong password;
      * -3 (invalid user) - authentication user does not exist.
+     * -4 (nonce expired) - the nonce has expired
+     * -5 (no credentials) - request does not contain an Authorization
+       header with the correct realm.
+     * -6 (nonce reused) - the nonce has already been used to authenticate
+       a previous request
+     * -8 (authuser mismatch) - depending on the method, th From/To/RURI
+       user does not match the authentication user (see auth_check()
+       function).
 
    Meaning of the parameters is as follows:
      * realm - Realm is a opaque string that the user agent should present
@@ -402,6 +410,8 @@ if (!proxy_authorize("$fd", "subscriber)) {
    authentication username matches From/To header username, and
    Request-URI in case of PUBLISH.
 
+   Negative return codes have the same meaning as for www_authenticate().
+
    Meaning of the parameters is as follows:
      * realm - Realm is a opaque string that the user agent should present
        to the user so he can decide what username and password to use.
diff --git a/modules/auth_db/doc/auth_db_admin.xml b/modules/auth_db/doc/auth_db_admin.xml
index 999c3cf..246d532 100644
--- a/modules/auth_db/doc/auth_db_admin.xml
+++ b/modules/auth_db/doc/auth_db_admin.xml
@@ -327,13 +327,27 @@ modparam("auth_db", "version_table", 0)
 			occurred and no reply was sent out;
 			</para></listitem>
 			<listitem><para>
-			<emphasis>-2 (invalid password)</emphasis> - valid user, but 
-			wrong password;
+			<emphasis>-2 (invalid password)</emphasis> - wrong password;
 			</para></listitem>
 			<listitem><para>
 			<emphasis>-3 (invalid user)</emphasis> - authentication user does
 			not exist.
 			</para></listitem>
+			<listitem><para>
+			<emphasis>-4 (nonce expired)</emphasis> - the nonce has expired
+			</para></listitem>
+			<listitem><para>
+			<emphasis>-5 (no credentials)</emphasis> - request does not contain
+			an Authorization header with the correct realm.
+			</para></listitem>
+			<listitem><para>
+			<emphasis>-6 (nonce reused)</emphasis> - the nonce has already been
+			used to authenticate a previous request
+			</para></listitem>
+			<listitem><para>
+			<emphasis>-8 (authuser mismatch)</emphasis> - depending on the method, th
+			From/To/RURI user does not match the authentication user (see auth_check() function).
+			</para></listitem>
 		</itemizedlist>
 		<para>Meaning of the parameters is as follows:</para>
 		<itemizedlist>
@@ -479,6 +493,8 @@ if (!proxy_authorize("$fd", "subscriber)) {
 		the function checks if authentication username matches From/To header
 		username, and Request-URI in case of PUBLISH.
 		</para>
+		<para>Negative return codes have the same meaning as for
+			www_authenticate().</para>
 		<para>Meaning of the parameters is as follows:</para>
 		<itemizedlist>
 		<listitem>
diff --git a/modules/auth_ephemeral/Makefile b/modules/auth_ephemeral/Makefile
new file mode 100644
index 0000000..eedbe86
--- /dev/null
+++ b/modules/auth_ephemeral/Makefile
@@ -0,0 +1,41 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=auth_ephemeral.so
+
+ifeq ($(CROSS_COMPILE),)
+SSL_BUILDER=$(shell \
+	if pkg-config --exists libssl; then \
+		echo 'pkg-config libssl'; \
+	fi)
+endif
+
+ifneq ($(SSL_BUILDER),)
+	DEFS += $(shell $(SSL_BUILDER) --cflags)
+	LIBS += $(shell $(SSL_BUILDER) --libs)
+else
+	DEFS += -I$(LOCALBASE)/ssl/include
+	LIBS += -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib \
+			-L$(LOCALBASE)/lib64 -L$(LOCALBASE)/ssl/lib64 \
+			-lssl -lcrypto
+	# NOTE: depending on the way in which libssl was compiled you might
+	#       have to add -lz -lkrb5   (zlib and kerberos5).
+	#       E.g.: make TLS_HOOKS=1 TLS_EXTRA_LIBS="-lz -lkrb5"
+endif
+
+LIBS+= $(TLS_EXTRA_LIBS)
+
+# Static linking, if you'd like to use TLS and AUTH_EPHEMERAL at the same time
+#
+#LIBS+= /usr/lib/libcurl.a /usr/lib/libssl.a /usr/lib/libcrypto.a -lkrb5 -lidn -lz -lgssapi_krb5 -lrt
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+
+include ../../Makefile.modules
diff --git a/modules/auth_ephemeral/README b/modules/auth_ephemeral/README
new file mode 100644
index 0000000..139d112
--- /dev/null
+++ b/modules/auth_ephemeral/README
@@ -0,0 +1,497 @@
+Auth_ephemeral Module
+
+Peter Dunkley
+
+   Crocodile RCS Ltd
+   <peter.dunkley at crocodile-rcs.com>
+
+   Copyright © 2013 Crocodile RCS Ltd
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+
+              1.1. How ephemeral credentials work
+
+                    1.1.1. Request
+                    1.1.2. Response
+
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. secret (string)
+              3.2. username_format (integer)
+
+        4. Functions
+
+              4.1. autheph_proxy(realm)
+              4.2. autheph_www(realm[, method])
+              4.3. autheph_check(realm)
+              4.4. autheph_authenticate(username, password)
+              4.5. autheph_check_from([username])
+              4.6. autheph_check_to([username])
+              4.7. autheph_check_timestamp(username)
+
+        5. MI Commands
+
+              5.1. autheph.add_secret
+              5.2. autheph.dump_secrets
+              5.3. autheph.rm_secret
+
+   List of Examples
+
+   1.1. Request example
+   1.2. Response example
+   1.3. secret parameter usage
+   1.4. username_format parameter usage
+   1.5. autheph_proxy usage
+   1.6. autheph_www usage
+   1.7. autheph_check usage
+   1.8. autheph_authenticate usage
+   1.9. autheph_check_from usage
+   1.10. autheph_check_to usage
+   1.11. autheph_check_timestamp usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+
+        1.1. How ephemeral credentials work
+
+              1.1.1. Request
+              1.1.2. Response
+
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. secret (string)
+        3.2. username_format (integer)
+
+   4. Functions
+
+        4.1. autheph_proxy(realm)
+        4.2. autheph_www(realm[, method])
+        4.3. autheph_check(realm)
+        4.4. autheph_authenticate(username, password)
+        4.5. autheph_check_from([username])
+        4.6. autheph_check_to([username])
+        4.7. autheph_check_timestamp(username)
+
+   5. MI Commands
+
+        5.1. autheph.add_secret
+        5.2. autheph.dump_secrets
+        5.3. autheph.rm_secret
+
+1. Overview
+
+   1.1. How ephemeral credentials work
+
+        1.1.1. Request
+        1.1.2. Response
+
+   This module contains all authentication related functions that can work
+   with ephemeral credentials. This module can be used together with the
+   auth module for digest authentication. Use this module if you want to
+   use ephemeral credentials instead of ordinary usernames and passwords.
+
+1.1. How ephemeral credentials work
+
+   Ephemeral credentials are generated by a web-service and enforced on
+   Kamailio. This use of ephemeral credentials ensures that access to
+   Kamailio is controlled even if the credentials cannot be kept secret,
+   as can be the case in WebRTC where the credentials may be specified in
+   Javascript.
+
+   The only interaction needed between the web-service and Kamailio is to
+   share a secret key.
+
+   Credentials will typically be requested from the web-service using an
+   HTTP POST and provided in a HTTP response with a content-type of
+   "application/json". To prevent unauthorised use the HTTP requests can
+   be ACLd by various means.
+
+   This mechanism is based on draft-uberti-rtcweb-turn-rest.
+
+1.1.1. Request
+
+   The request to the web-service should contain the following parameters:
+     * service - specifies the desired service (msrp, sip, etc)
+     * username - an optional user identifier for the service (as would
+       normally be found in the username parameter of an Authorization: or
+       Proxy-Authorization: header)
+     * key - an optional API key used for authentication
+
+   Example 1.1. Request example
+POST /?service=sip&username=foo at bar.com
+
+1.1.2. Response
+
+   The response should include the following parameters:
+     * username - the username to use, which is a colon-delimited
+       combination of the expiration timestamp and the username parameter
+       from the request (if specified). When used with this module the
+       timestamp must be a UNIX timestamp.
+     * password - the password to use; this value is computed from the
+       secret key and the returned username value, by performing
+       base64(hmac-sha1(secret key, returned username)).
+     * ttl - the duration for which the username and password are valid,
+       in seconds.
+     * uris - an array of URIs indicating servers that the username and
+       password are valid for.
+
+   Example 1.2. Response example
+{
+  "username" : "1234567890:foo at bar.com",
+  "password" : "asdfghjklauio=",
+  "ttl" : 86400,
+  "uris" : [
+    "sip:1.2.3.4;transport=ws",
+    "sip:5.6.7.8;transport=ws"
+  ]
+}
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The module must be loaded before this module:
+     * auth (optional).
+
+2.2. External Libraries or Applications
+
+   The following libraries must be installed before running Kamailio with
+   this module loaded:
+     * OpenSSL.
+
+3. Parameters
+
+   3.1. secret (string)
+   3.2. username_format (integer)
+
+3.1. secret (string)
+
+   The shared secret to use for generating credentials. This parameter can
+   be set multiple times - this enables the secret used for new
+   credentials to be changed without causing existing credentials to stop
+   working. The last secret set is the first that will be tried.
+
+   Example 1.3. secret parameter usage
+...
+modparam("auth_ephemeral", "secret", "kamailio_rules")
+...
+
+3.2. username_format (integer)
+
+   The format of the username in the web-service response.
+
+     * 0 (deprecated - pre IETF draft format) - <username parameter from
+       the request>:<timestamp>
+     * 1 (default - IETF draft format) - <timestamp>:<username parameter
+       from the request>
+
+   Example 1.4. username_format parameter usage
+...
+modparam("auth_ephemeral", "username_format", 0)
+...
+
+4. Functions
+
+   4.1. autheph_proxy(realm)
+   4.2. autheph_www(realm[, method])
+   4.3. autheph_check(realm)
+   4.4. autheph_authenticate(username, password)
+   4.5. autheph_check_from([username])
+   4.6. autheph_check_to([username])
+   4.7. autheph_check_timestamp(username)
+
+4.1.  autheph_proxy(realm)
+
+   This function performs proxy authentication.
+
+Note
+
+   This function can only be used when the auth module is loaded before
+   this module.
+
+   The meaning of the parameters are as follows:
+     * realm - realm is an opaque string that the user agent should
+       present to the user so that he can decide what username and
+       password to use. Usually this is domain of the host the server is
+       running on.
+       It must not be an empty string “”. Apart from a static string, a
+       typical value is the From-URI domain (i.e., $fd).
+       The string may contain pseudo variables.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.5. autheph_proxy usage
+...
+if (!autheph_proxy("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+
+4.2.  autheph_www(realm[, method])
+
+   This function performs WWW digest authentication.
+
+Note
+
+   This function can only be used when the auth module is loaded before
+   this module.
+
+   The meaning of the parameters are as follows:
+     * realm - realm is an opaque string that the user agent should
+       present to the user so that he can decide what username and
+       password to use. Usually this is domain of the host the server is
+       running on.
+       It must not be an empty string “”. Apart from a static string, a
+       typical value is the From-URI domain (i.e., $fd).
+       The string may contain pseudo variables.
+     * method - the method to be used for authentication. This parameter
+       is optional and if not set the first "word" on the request-line is
+       used.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.6. autheph_www usage
+...
+if (!autheph_www("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+
+4.3.  autheph_check(realm)
+
+   This function combines the functionalities of autheph_www and
+   autheph_proxy, the first being exectuted if the SIP request is a
+   REGISTER, the second for the rest.
+
+Note
+
+   This function can only be used when the auth module is loaded before
+   this module.
+
+   The meaning of the parameters are as follows:
+     * realm - realm is an opaque string that the user agent should
+       present to the user so that he can decide what username and
+       password to use. Usually this is domain of the host the server is
+       running on.
+       It must not be an empty string “”. Apart from a static string, a
+       typical value is the From-URI domain (i.e., $fd).
+       The string may contain pseudo variables.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.7. autheph_check usage
+...
+if (!autheph_check("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+
+4.4.  autheph_authenticate(username, password)
+
+   This function performs non-digest ephemeral authentication. This may be
+   used when digest authentication cannot. For example, during WebSocket
+   handshake the username may be part of the requested URI and the
+   password presented in a Cookie: header.
+
+Note
+
+   This function may be used without loading the auth module.
+
+   The meaning of the parameters are as follows:
+     * username - the username returned in the response from the
+       web-service.
+     * password - the password returned in the response from the
+       web-service.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.8. autheph_authenticate usage
+...
+if (!autheph_authenticate("$var(username)", "$var(password)")) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+
+4.5.  autheph_check_from([username])
+
+   This function checks that the username (or username and domain) in the
+   From: URI matches the credentials.
+
+   When used without the username parameter it compares the From: URI with
+   the credentials used to authenticate the request (in the Authorization:
+   or Proxy-Authorization: headers).
+
+   The username parameter can be used to check the From: when individual
+   SIP requests are not authenticated (for example, when they are over
+   WebSockets and the connection was authenticated during the handshake).
+   In this scenario the username should be cached (perhaps in a
+   hash-table) at the point the authentication occurs.
+
+Note
+
+   This function must have the optional username parameter specified to
+   use it without loading the auth module before this module.
+
+   The meaning of the parameters are as follows:
+     * username (optional) - the username returned in the response from
+       the web-service.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.9. autheph_check_from usage
+...
+if (!autheph_check_from()) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+
+4.6.  autheph_check_to([username])
+
+   This function checks that the username (or username and domain) in the
+   To: URI matches the credentials.
+
+   When used without the username parameter it compares the To: URI with
+   the credentials used to authenticate the request (in the Authorization:
+   or Proxy-Authorization: headers).
+
+   The username parameter can be used to check the From: when individual
+   SIP requests are not authenticated (for example, when they are over
+   WebSockets and the connection was authenticated during the handshake).
+   In this scenario the username should be cached (perhaps in a
+   hash-table) at the point the authentication occurs.
+
+Note
+
+   This function must have the optional username parameter specified to
+   use it without loading the auth module before this module.
+
+   The meaning of the parameters are as follows:
+     * username (optional) - the username returned in the response from
+       the web-service.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.10. autheph_check_to usage
+...
+if (!autheph_check_to()) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+
+4.7.  autheph_check_timestamp(username)
+
+   This function checks that the timestamp in the username parameter has
+   not expired. The autheph_(check|proxy|www) functions all do this
+   automatically, but in a scenario when individual SIP requests are not
+   authenticated (for example, when they are over WebSockets and the
+   connection was authenticated during the handshake) you may want to
+   re-check for each new out-of-dialog request. In this scenario the
+   username should be cached (perhaps in a hash-table) at the point
+   authentication occurs.
+
+Note
+
+   This function may be used without loading the auth module.
+
+   The meaning of the parameters are as follows:
+     * username - the username returned in the response from the
+       web-service.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.11. autheph_check_timestamp usage
+...
+if (!autheph_check_timestamp("$var(username)")) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+
+5. MI Commands
+
+   5.1. autheph.add_secret
+   5.2. autheph.dump_secrets
+   5.3. autheph.rm_secret
+
+5.1. autheph.add_secret
+
+   Add a secret to the head of the shared secret list. The secret will be
+   the first one tried during future authentication attempts. This MI
+   command allows you to update the shared secret list without having to
+   restart Kamailio.
+
+Note
+
+   If you want your new shared secret list to persist across restarts you
+   must add it to your Kamailio configuration file.
+
+   Name: autheph.add_secret
+
+   Parameters:
+     * secret
+
+   MI FIFO Command Format:
+                        :autheph.add_secret:fifo_reply
+                        kamailio_rules
+                        _empty_line_
+
+5.2. autheph.dump_secrets
+
+   Dump the set of shared secrets.
+
+   Name: autheph.dump_secrets
+
+   Parameters:
+     * none
+
+   MI FIFO Command Format:
+                        :autheph.dump_secrets:fifo_reply
+                        _empty_line_
+
+5.3. autheph.rm_secret
+
+   Remove the secret with the specified integer ID. This MI command allows
+   you to update the shared secret list without having to restart
+   Kamailio.
+
+Note
+
+   If you want your new shared secret list to persist across restarts you
+   must add it to your Kamailio configuration file.
+
+   Name: autheph.rm_secret
+
+   Parameters:
+     * ID - the ID of the secret to remove
+
+   MI FIFO Command Format:
+                        :autheph.rm_secret:fifo_reply
+                        0
+                        _empty_line_
diff --git a/modules/auth_ephemeral/autheph_mod.c b/modules/auth_ephemeral/autheph_mod.c
new file mode 100644
index 0000000..8e72fba
--- /dev/null
+++ b/modules/auth_ephemeral/autheph_mod.c
@@ -0,0 +1,449 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "../../dprint.h"
+#include "../../locking.h"
+#include "../../mod_fix.h"
+#include "../../sr_module.h"
+#include "../../str.h"
+#include "../../lib/kmi/mi.h"
+#include "../../modules/auth/api.h"
+
+#include "autheph_mod.h"
+#include "authorize.h"
+#include "checks.h"
+
+MODULE_VERSION
+
+static int mod_init(void);
+static void destroy(void);
+
+static int secret_param(modparam_t _type, void *_val);
+struct secret *secret_list = NULL;
+static struct mi_root *mi_dump_secrets(struct mi_root *cmd, void *param);
+static struct mi_root *mi_add_secret(struct mi_root *cmd, void *param);
+static struct mi_root *mi_rm_secret(struct mi_root *cmd, void *param);
+gen_lock_t *autheph_secret_lock = NULL;
+
+autheph_username_format_t autheph_username_format = AUTHEPH_USERNAME_IETF;
+
+auth_api_s_t eph_auth_api;
+
+static cmd_export_t cmds[]=
+{
+	{ "autheph_check", (cmd_function) autheph_check,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_www", (cmd_function) autheph_www,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_www", (cmd_function) autheph_www2,
+	  2, fixup_var_str_12, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_proxy", (cmd_function) autheph_proxy,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_authenticate", (cmd_function) autheph_authenticate,
+	  2, fixup_var_str_12, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_check_from", (cmd_function) autheph_check_from0,
+	  0, 0, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_check_from", (cmd_function) autheph_check_from1,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_check_to", (cmd_function) autheph_check_to0,
+	  0, 0, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_check_to", (cmd_function) autheph_check_to1,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_check_timestamp", (cmd_function) autheph_check_timestamp,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]=
+{
+	{ "secret",		STR_PARAM|USE_FUNC_PARAM,
+	  (void *) secret_param },
+	{ "username_format",	INT_PARAM,
+	  &autheph_username_format },
+	{0, 0, 0}
+};
+
+static mi_export_t mi_cmds[] =
+{
+	{ "autheph.add_secret",		mi_add_secret,	0, 0, 0 },
+	{ "autheph.dump_secrets",	mi_dump_secrets,0, 0, 0 },
+	{ "autheph.rm_secret",		mi_rm_secret,	0, 0, 0 },
+
+	{ 0, 0, 0, 0, 0 }
+};
+
+struct module_exports exports=
+{
+	"auth_ephemeral", 
+	DEFAULT_DLFLAGS,	/* dlopen flags */
+	cmds,			/* Exported functions */
+	params,			/* Exported parameters */
+	0,			/* exported statistics */
+	mi_cmds,		/* exported MI functions */
+	0,			/* exported pseudo-variables */
+	0,			/* extra processes */
+	mod_init,		/* module initialization function */
+	0,			/* response function */
+	destroy,		/* destroy function */
+	0			/* child initialization function */
+};
+
+static int mod_init(void)
+{
+	bind_auth_s_t bind_auth;
+
+	if (register_mi_mod(exports.name, mi_cmds) != 0)
+	{
+		LM_ERR("registering MI commands\n");
+		return -1;
+	}
+
+	if (secret_list == NULL)
+	{
+		LM_ERR("secret modparam not set\n");
+		return -1;
+	}
+
+	switch(autheph_username_format)
+	{
+	case AUTHEPH_USERNAME_NON_IETF:
+		LM_WARN("the %d value for the username_format modparam is "
+			"deprecated. You should update the web-service that "
+			"generates credentials to use the format specified in "
+			"draft-uberti-rtcweb-turn-rest.\n",
+			autheph_username_format);
+		/* Fall-thru */
+	case AUTHEPH_USERNAME_IETF:
+		break;
+
+	default:
+		LM_ERR("bad value for username_format modparam: %d\n",
+			autheph_username_format);
+		return -1;
+	}
+
+	bind_auth = (bind_auth_s_t) find_export("bind_auth_s", 0, 0);
+	if (bind_auth)
+	{
+		if (bind_auth(&eph_auth_api) < 0)
+		{
+			LM_ERR("unable to bind to auth module\n");
+			return -1;
+		}
+	}
+	else
+	{
+		memset(&eph_auth_api, 0, sizeof(auth_api_s_t));
+		LM_INFO("auth module not loaded - digest authentication and "
+			"check functions will not be available\n");
+	}
+
+	return 0;
+}
+
+static void destroy(void)
+{
+	struct secret *secret_struct;
+
+	if (secret_list != NULL)
+	{
+		SECRET_UNLOCK;
+		SECRET_LOCK;
+		while (secret_list != NULL)
+		{
+			secret_struct = secret_list;
+			secret_list = secret_struct->next;
+
+			if (secret_struct->secret_key.s != NULL)
+			{
+				shm_free(secret_struct->secret_key.s);
+			}
+			shm_free(secret_struct);
+		}
+		SECRET_UNLOCK;
+	}
+
+	if (autheph_secret_lock != NULL)
+	{
+		lock_destroy(autheph_secret_lock);
+		lock_dealloc((void *) autheph_secret_lock);
+	}
+}
+
+static inline int add_secret(str _secret_key)
+{
+	struct secret *secret_struct;
+
+	if (autheph_secret_lock == NULL)
+	{
+		autheph_secret_lock = lock_alloc();
+		if (autheph_secret_lock == NULL)
+		{
+			LM_ERR("allocating lock\n");
+			return -1;
+		}
+		if (lock_init(autheph_secret_lock) == 0)
+		{
+			LM_ERR("initialising lock\n");
+			return -1;
+		}
+	}
+
+	secret_struct = (struct secret *) shm_malloc(sizeof(struct secret));
+	if (secret_struct == NULL)
+	{
+		LM_ERR("unable to allocate shared memory\n");
+		return -1;
+	}
+
+	memset(secret_struct, 0, sizeof (struct secret));
+	secret_struct->secret_key = _secret_key;
+	SECRET_LOCK;
+	if (secret_list != NULL)
+	{
+		secret_list->prev = secret_struct;
+	}
+	secret_struct->next = secret_list;
+	secret_list = secret_struct;
+	SECRET_UNLOCK;
+
+	return 0;
+}
+
+static inline int rm_secret(int _id)
+{
+	int pos = 0;
+	struct secret *secret_struct;
+
+	if (secret_list == NULL)
+	{
+		LM_ERR("secret list empty\n");
+		return -1;
+	}
+
+	SECRET_LOCK;
+	secret_struct = secret_list;
+	while (pos <= _id && secret_struct != NULL)
+	{
+		if (pos == _id)
+		{
+			if (secret_struct->prev != NULL)
+			{
+				secret_struct->prev->next = secret_struct->next;
+			}
+			if (secret_struct->next != NULL)
+			{
+				secret_struct->next->prev = secret_struct->prev;
+			}
+			if (pos == 0)
+			{
+				secret_list = secret_struct->next;
+			}
+			SECRET_UNLOCK;
+			shm_free(secret_struct->secret_key.s);
+			shm_free(secret_struct);
+			return 0;
+		}
+
+		pos++;
+		secret_struct = secret_struct->next;
+
+	}
+	SECRET_UNLOCK;
+
+	LM_ERR("ID %d not found\n", _id);
+	return -1;
+}
+
+static int secret_param(modparam_t _type, void *_val)
+{
+	str sval;
+
+	if (_val == NULL)
+	{
+		LM_ERR("bad parameter\n");
+		return -1;
+	}
+
+	LM_INFO("adding %s to secret list\n", (char *) _val);
+
+	sval.len = strlen((char *) _val);
+	sval.s = (char *) shm_malloc(sizeof(char) * sval.len);
+	if (sval.s == NULL)
+	{
+		LM_ERR("unable to allocate shared memory\n");
+		return -1;
+	}
+	memcpy(sval.s, (char *) _val, sval.len);
+
+	return add_secret(sval);
+}
+
+static str str_status_too_many_params = str_init("Too many parameters");
+static str str_status_empty_param = str_init("Not enough parameters");
+static str str_status_no_memory = str_init("Unable to allocate shared memory");
+static str str_status_string_error = str_init("Error converting string to int");
+static str str_status_adding_secret = str_init("Error adding secret");
+static str str_status_removing_secret = str_init("Error removing secret");
+
+static struct mi_root *mi_dump_secrets(struct mi_root *cmd, void *param)
+{
+	int pos = 0;
+	struct secret *secret_struct = secret_list;
+	struct mi_root *rpl_tree;
+
+	if (cmd->node.kids != NULL)
+	{
+		LM_WARN("too many parameters\n");
+		return init_mi_tree(400, str_status_too_many_params.s,
+					str_status_too_many_params.len);
+	}
+
+	rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+	if (rpl_tree == NULL)
+		return 0;
+
+	SECRET_LOCK;
+	while (secret_struct != NULL)
+	{
+		if (addf_mi_node_child(&rpl_tree->node, 0, 0, 0,
+					"ID %d: %.*s", pos++,
+					secret_struct->secret_key.len,
+					secret_struct->secret_key.s) == 0)
+		{
+			free_mi_tree(rpl_tree);
+			SECRET_UNLOCK;
+			return 0;
+		}
+		secret_struct = secret_struct->next;
+	}
+	SECRET_UNLOCK;
+
+	return rpl_tree;
+}
+
+static struct mi_root *mi_add_secret(struct mi_root *cmd, void *param)
+{
+	str sval;
+	struct mi_node *node = NULL;
+
+	node = cmd->node.kids;
+	if (node == NULL)
+	{
+		LM_WARN("no secret parameter\n");
+		return init_mi_tree(400, str_status_empty_param.s,
+						str_status_empty_param.len);
+	}
+
+	if (node->value.s == NULL || node->value.len == 0)
+	{
+		LM_WARN("empty secret parameter\n");
+		return init_mi_tree(400, str_status_empty_param.s,
+					str_status_empty_param.len);
+	}
+
+	if (node->next != NULL)
+	{
+		LM_WARN("too many parameters\n");
+		return init_mi_tree(400, str_status_too_many_params.s,
+					str_status_too_many_params.len);
+	}
+
+	sval.len = node->value.len;
+	sval.s = shm_malloc(sizeof(char) * sval.len);
+	if (sval.s == NULL)
+	{
+		LM_ERR("Unable to allocate shared memory\n");
+		return init_mi_tree(400, str_status_no_memory.s,
+					str_status_no_memory.len);
+	}
+	memcpy(sval.s, node->value.s, sval.len);
+
+	if (add_secret(sval) == 0)
+	{
+		return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+	}
+	else
+	{
+		LM_ERR("Adding secret\n");
+		return init_mi_tree(400, str_status_adding_secret.s,
+					str_status_adding_secret.len);
+	}
+}
+
+static struct mi_root *mi_rm_secret(struct mi_root *cmd, void *param)
+{
+	unsigned int id;
+	struct mi_node *node = NULL;
+
+	node = cmd->node.kids;
+	if (node == NULL)
+	{
+		LM_WARN("no id parameter\n");
+		return init_mi_tree(400, str_status_empty_param.s,
+						str_status_empty_param.len);
+	}
+
+	if (node->value.s == NULL || node->value.len == 0)
+	{
+		LM_WARN("empty id parameter\n");
+		return init_mi_tree(400, str_status_empty_param.s,
+					str_status_empty_param.len);
+	}
+
+	if (str2int(&node->value, &id) < 0)
+	{
+		LM_ERR("converting string to int\n");
+		return init_mi_tree(400, str_status_string_error.s,
+					str_status_string_error.len);
+	}
+
+	if (node->next != NULL)
+	{
+		LM_WARN("too many parameters\n");
+		return init_mi_tree(400, str_status_too_many_params.s,
+					str_status_too_many_params.len);
+	}
+
+	if (rm_secret(id) == 0)
+	{
+		return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+	}
+	else
+	{
+		LM_ERR("Removing secret\n");
+		return init_mi_tree(400, str_status_removing_secret.s,
+					str_status_removing_secret.len);
+	}
+
+	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+}
diff --git a/modules/auth_ephemeral/autheph_mod.h b/modules/auth_ephemeral/autheph_mod.h
new file mode 100644
index 0000000..62bc808
--- /dev/null
+++ b/modules/auth_ephemeral/autheph_mod.h
@@ -0,0 +1,50 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef AUTHEPH_MOD_H
+#define AUTHEPH_MOD_H
+
+#include "../../locking.h"
+#include "../../str.h"
+#include "../../modules/auth/api.h"
+
+struct secret
+{
+	str secret_key;
+	struct secret *prev;
+	struct secret *next;
+};
+extern struct secret *secret_list;
+
+typedef enum {
+	AUTHEPH_USERNAME_NON_IETF	= 0,
+	AUTHEPH_USERNAME_IETF		= 1,
+} autheph_username_format_t;
+extern autheph_username_format_t autheph_username_format;
+
+extern auth_api_s_t eph_auth_api;
+
+extern gen_lock_t *autheph_secret_lock;
+#define SECRET_LOCK	lock_get(autheph_secret_lock)
+#define SECRET_UNLOCK	lock_release(autheph_secret_lock)
+
+#endif /* AUTHEPH_MOD_H */
diff --git a/modules/auth_ephemeral/authorize.c b/modules/auth_ephemeral/authorize.c
new file mode 100644
index 0000000..a09a9f8
--- /dev/null
+++ b/modules/auth_ephemeral/authorize.c
@@ -0,0 +1,479 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include "../../basex.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../str.h"
+#include "../../ut.h"
+#include "../../parser/digest/digest.h"
+#include "../../parser/hf.h"
+#include "../../mod_fix.h"
+
+#include "autheph_mod.h"
+#include "authorize.h"
+
+static inline int get_pass(str *_username, str *_secret, str *_password)
+{
+	unsigned int hmac_len = SHA_DIGEST_LENGTH;
+	unsigned char hmac_sha1[hmac_len];
+
+	if (HMAC(EVP_sha1(), _secret->s, _secret->len,
+			(unsigned char *) _username->s,
+			_username->len, hmac_sha1, &hmac_len) == NULL)
+	{
+		LM_ERR("HMAC-SHA1 failed\n");
+		return -1;
+	}
+
+	_password->len = base64_enc(hmac_sha1, hmac_len,
+					(unsigned char *) _password->s,
+					base64_enc_len(hmac_len));
+	LM_DBG("calculated password: %.*s\n", _password->len, _password->s);
+
+	return 0;
+}
+
+static inline int get_ha1(struct username *_username, str *_domain,
+				str *_secret, char *_ha1)
+{
+	char password[base64_enc_len(SHA_DIGEST_LENGTH)];
+	str spassword;
+
+	spassword.s = (char *) password;
+	spassword.len = 0;
+
+	if (get_pass(&_username->whole, _secret, &spassword) < 0)
+	{
+		LM_ERR("calculating password\n");
+		return -1;
+	}
+
+	eph_auth_api.calc_HA1(HA_MD5, &_username->whole, _domain, &spassword,
+				0, 0, _ha1);
+	LM_DBG("calculated HA1: %s\n", _ha1);
+
+	return 0;
+}
+
+static inline int do_auth(struct sip_msg *_m, struct hdr_field *_h, str *_realm,
+			str *_method, str *_secret)
+{
+	int ret;
+	char ha1[256];
+	auth_body_t *cred = (auth_body_t*) _h->parsed;
+
+	LM_DBG("secret: %.*s\n", _secret->len, _secret->s);
+
+	if (get_ha1(&cred->digest.username, _realm, _secret, ha1) < 0)
+	{
+		LM_ERR("calculating HA1\n");
+		return AUTH_ERROR;
+	}
+
+	ret = eph_auth_api.check_response(&cred->digest, _method, ha1);
+	if (ret == AUTHENTICATED)
+	{
+		if (eph_auth_api.post_auth(_m, _h) != AUTHENTICATED)
+		{
+			return AUTH_ERROR;
+		}
+	}
+	else if (ret == NOT_AUTHENTICATED)
+	{
+		return AUTH_INVALID_PASSWORD;
+	}
+	else
+	{
+		ret = AUTH_ERROR;
+	}
+
+	return AUTH_OK;
+}
+
+int autheph_verify_timestamp(str *_username)
+{
+	int pos = 0, cur_time = (int) time(NULL);
+	unsigned int expires;
+	str time_str = {0, 0};
+
+	while (pos < _username->len && _username->s[pos] != ':')
+		pos++;
+
+	if (autheph_username_format == AUTHEPH_USERNAME_NON_IETF)
+	{
+		if (pos < _username->len - 1)
+		{
+			time_str.s = _username->s + pos + 1;
+			time_str.len = _username->len - pos - 1;
+		}
+		else
+		{
+			time_str.s = _username->s;
+			time_str.len = _username->len;
+		}
+	}
+	else
+	{
+		time_str.s = _username->s;
+		if (pos < _username->len - 1)
+		{
+			time_str.len = pos;
+		}
+		else
+		{
+			time_str.len = _username->len;
+		}
+	}
+
+	LM_DBG("username timestamp: %.*s\n", time_str.len, time_str.s);
+	if (str2int(&time_str, &expires) < 0)
+	{
+		LM_ERR("unable to convert timestamp to int\n");
+		return -1;
+	}
+
+	LM_DBG("current time: %d\n", cur_time);
+	if (cur_time > expires)
+	{
+		LM_WARN("username has expired\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static inline int digest_authenticate(struct sip_msg *_m, str *_realm,
+				hdr_types_t _hftype, str *_method)
+{
+	struct hdr_field* h;
+	int ret;
+	struct secret *secret_struct;
+	str username;
+
+	LM_DBG("realm: %.*s\n", _realm->len, _realm->s);
+	LM_DBG("method: %.*s\n", _method->len, _method->s);
+
+	ret = eph_auth_api.pre_auth(_m, _realm, _hftype, &h, NULL);
+	switch(ret)
+	{
+	case NONCE_REUSED:
+		LM_DBG("nonce reused\n");
+		return AUTH_NONCE_REUSED;
+	case STALE_NONCE:
+		LM_DBG("stale nonce\n");
+		return AUTH_STALE_NONCE;
+	case NO_CREDENTIALS:
+		LM_DBG("no credentials\n");
+		return AUTH_NO_CREDENTIALS;
+	case ERROR:
+	case BAD_CREDENTIALS:
+		LM_DBG("error or bad credentials\n");
+		return AUTH_ERROR;
+	case CREATE_CHALLENGE:
+		LM_ERR("CREATE_CHALLENGE is not a valid state\n");
+		return AUTH_ERROR;
+	case DO_RESYNCHRONIZATION:
+		LM_ERR("DO_RESYNCHRONIZATION is not a valid state\n");
+		return AUTH_ERROR;
+	case NOT_AUTHENTICATED:
+		LM_DBG("not authenticated\n");
+		return AUTH_ERROR;
+	case DO_AUTHENTICATION:
+		break;
+	case AUTHENTICATED:
+		return AUTH_OK;
+	}
+
+	username = ((auth_body_t *) h->parsed)->digest.username.whole;
+	LM_DBG("username: %.*s\n", username.len, username.s);
+
+	if (autheph_verify_timestamp(&username) < 0)
+	{
+		LM_ERR("invalid timestamp in username\n");
+		return AUTH_ERROR;
+	}
+
+	SECRET_LOCK;
+	secret_struct = secret_list;
+	while (secret_struct != NULL)
+	{
+		ret = do_auth(_m, h, _realm, _method,
+				&secret_struct->secret_key);
+		if (ret == AUTH_OK)
+		{
+			break;
+		}
+		secret_struct = secret_struct->next;
+	}
+	SECRET_UNLOCK;
+
+	return ret;
+}
+
+int autheph_check(struct sip_msg *_m, char *_realm)
+{
+	str srealm;
+
+	if (eph_auth_api.pre_auth == NULL)
+	{
+		LM_ERR("autheph_check() cannot be used without the auth "
+			"module\n");
+		return AUTH_ERROR;
+	}
+
+	if (_m->REQ_METHOD == METHOD_ACK || _m->REQ_METHOD == METHOD_CANCEL)
+	{
+		return AUTH_OK;
+	}
+
+	if(_m == NULL || _realm == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len == 0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	if (_m->REQ_METHOD == METHOD_REGISTER)
+	{
+		return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T,
+					&_m->first_line.u.request.method);
+	}
+	else
+	{
+		return digest_authenticate(_m, &srealm, HDR_PROXYAUTH_T,
+					&_m->first_line.u.request.method);
+	}
+}
+
+int autheph_www(struct sip_msg *_m, char *_realm)
+{
+	str srealm;
+
+	if (eph_auth_api.pre_auth == NULL)
+	{
+		LM_ERR("autheph_www() cannot be used without the auth "
+			"module\n");
+		return AUTH_ERROR;
+	}
+
+	if (_m->REQ_METHOD == METHOD_ACK || _m->REQ_METHOD == METHOD_CANCEL)
+	{
+		return AUTH_OK;
+	}
+
+	if(_m == NULL || _realm == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len == 0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T,
+					&_m->first_line.u.request.method);
+}
+
+int autheph_www2(struct sip_msg *_m, char *_realm, char *_method)
+{
+	str srealm;
+	str smethod;
+
+	if (eph_auth_api.pre_auth == NULL)
+	{
+		LM_ERR("autheph_www() cannot be used without the auth "
+			"module\n");
+		return AUTH_ERROR;
+	}
+
+	if (_m->REQ_METHOD == METHOD_ACK || _m->REQ_METHOD == METHOD_CANCEL)
+	{
+		return AUTH_OK;
+	}
+
+	if(_m == NULL || _realm == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len == 0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&smethod, _m, (fparam_t*)_method) < 0)
+	{
+		LM_ERR("failed to get method value\n");
+		return AUTH_ERROR;
+	}
+
+	if (smethod.len == 0)
+	{
+		LM_ERR("invalid method value - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T, &smethod);
+}
+
+int autheph_proxy(struct sip_msg *_m, char *_realm)
+{
+	str srealm;
+
+	if (eph_auth_api.pre_auth == NULL)
+	{
+		LM_ERR("autheph_proxy() cannot be used without the auth "
+			"module\n");
+		return AUTH_ERROR;
+	}
+
+	if (_m->REQ_METHOD == METHOD_ACK || _m->REQ_METHOD == METHOD_CANCEL)
+	{
+		return AUTH_OK;
+	}
+
+	if(_m == NULL || _realm == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len == 0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	return digest_authenticate(_m, &srealm, HDR_PROXYAUTH_T,
+					&_m->first_line.u.request.method);
+}
+
+int autheph_authenticate(struct sip_msg *_m, char *_username, char *_password)
+{
+	str susername, spassword;
+	char generated_password[base64_enc_len(SHA_DIGEST_LENGTH)];
+	str sgenerated_password;
+	struct secret *secret_struct;
+
+	if (_m == NULL || _username == NULL || _password == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&susername, _m, (fparam_t*)_username) < 0)
+	{
+		LM_ERR("failed to get username value\n");
+		return AUTH_ERROR;
+	}
+
+	if (susername.len == 0)
+	{
+		LM_ERR("invalid username parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&spassword, _m, (fparam_t*)_password) < 0)
+	{
+		LM_ERR("failed to get password value\n");
+		return AUTH_ERROR;
+	}
+
+	if (spassword.len == 0)
+	{
+		LM_ERR("invalid password parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	if (autheph_verify_timestamp(&susername) < 0)
+	{
+		LM_ERR("invalid timestamp in username\n");
+		return AUTH_ERROR;
+	}
+
+	LM_DBG("username: %.*s\n", susername.len, susername.s);
+	LM_DBG("password: %.*s\n", spassword.len, spassword.s);
+
+	sgenerated_password.s = generated_password;
+	SECRET_LOCK;
+	secret_struct = secret_list;
+	while (secret_struct != NULL)
+	{
+		LM_DBG("trying secret: %.*s\n",
+			secret_struct->secret_key.len,
+			secret_struct->secret_key.s);
+		if (get_pass(&susername, &secret_struct->secret_key,
+				&sgenerated_password) == 0)
+		{
+			LM_DBG("generated password: %.*s\n",
+				sgenerated_password.len, sgenerated_password.s);
+			if (strncmp(spassword.s, sgenerated_password.s,
+					spassword.len) == 0)
+			{
+				SECRET_UNLOCK;
+				return AUTH_OK;
+			}
+		}
+		secret_struct = secret_struct->next;
+	}
+	SECRET_UNLOCK;
+
+	return AUTH_ERROR;
+}
diff --git a/modules/auth_ephemeral/authorize.h b/modules/auth_ephemeral/authorize.h
new file mode 100644
index 0000000..8ce9331
--- /dev/null
+++ b/modules/auth_ephemeral/authorize.h
@@ -0,0 +1,37 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef AUTHORIZE_H
+#define AUTHORIZE_H
+
+#include "../../str.h"
+#include "../../parser/msg_parser.h"
+
+int autheph_verify_timestamp(str *_username);
+
+int autheph_check(struct sip_msg *_m, char *_realm);
+int autheph_www(struct sip_msg *_m, char *_realm);
+int autheph_www2(struct sip_msg *_m, char *_realm, char *_method);
+int autheph_proxy(struct sip_msg *_m, char *_realm);
+int autheph_authenticate(struct sip_msg *_m, char *_username, char *_password);
+
+#endif /* AUTHORIZE_H */
diff --git a/modules/auth_ephemeral/checks.c b/modules/auth_ephemeral/checks.c
new file mode 100644
index 0000000..447e997
--- /dev/null
+++ b/modules/auth_ephemeral/checks.c
@@ -0,0 +1,282 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../str.h"
+#include "../../ut.h"
+#include "../../parser/digest/digest.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_uri.h"
+#include "../../mod_fix.h"
+
+#include "autheph_mod.h"
+#include "authorize.h"
+#include "checks.h"
+
+static inline int check_username(str *_username, struct sip_uri *_uri)
+{
+	str uname, domain = {0, 0};
+	int pos = 0;
+
+	if (_username == NULL || _username->len == 0)
+	{
+		LM_ERR("invalid username\n");
+		return CHECK_ERROR;
+	}
+
+	while (pos < _username->len && _username->s[pos] != ':')
+		pos++;
+
+	if (pos < _username->len - 1)
+	{
+		if (autheph_username_format == AUTHEPH_USERNAME_NON_IETF)
+		{
+			uname.s = _username->s;
+			uname.len = pos;
+		}
+		else
+		{
+			uname.s = _username->s + pos + 1;
+			uname.len = _username->len - pos - 1;
+		}
+	}
+	else
+	{
+		return CHECK_NO_USER;
+	}
+
+	pos = 0;
+	while (pos < uname.len && uname.s[pos] != '@')
+		pos++;
+
+	if (pos < uname.len - 1)
+	{
+		domain.s = uname.s + pos + 1;
+		domain.len = uname.len - pos - 1;
+		uname.len = pos;
+	}
+
+	if (uname.len == _uri->user.len
+		&& strncmp(uname.s, _uri->user.s, uname.len) == 0)
+	{
+		if (domain.len == 0)
+		{
+			return CHECK_OK;
+		}
+		else if (domain.len == _uri->host.len
+			&& strncmp(domain.s, _uri->host.s, domain.len) == 0)
+		{
+			return CHECK_OK;
+		}
+	}
+
+	return CHECK_ERROR;
+}
+
+static inline int check_from(struct sip_msg *_m, str *_username)
+{
+	if (parse_from_header(_m) < 0)
+	{
+		LM_ERR("parsing From: header\n");
+		return CHECK_ERROR;
+	}
+
+	if (parse_from_uri(_m) == NULL)
+	{
+		LM_ERR("parsing From: URI\n");
+		return CHECK_ERROR;
+	}
+
+	return check_username(_username, &get_from(_m)->parsed_uri);
+}
+
+static inline int get_cred(struct sip_msg *_m, str *_username)
+{
+	struct hdr_field *h;
+
+	get_authorized_cred(_m->authorization, &h);
+	if (!h)
+	{
+		get_authorized_cred(_m->proxy_auth, &h);
+		if (!h)
+		{
+			LM_ERR("No authorized credentials found\n");
+			return -1;
+		}
+	}
+
+	*_username = ((auth_body_t *) h->parsed)->digest.username.whole;
+	return 0;
+}
+
+int autheph_check_from0(struct sip_msg *_m)
+{
+	str username = {0, 0};
+
+	if (eph_auth_api.pre_auth == NULL)
+	{
+		LM_ERR("autheph_check_from() with no username parameter "
+			"cannot be used without the auth module\n");
+		return CHECK_ERROR;
+	}
+
+	if (_m == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return CHECK_ERROR;
+	}
+
+	if (get_cred(_m, &username) < 0)
+	{
+		LM_ERR("call autheph_(check|proxy|www) before calling "
+			" check_from() with no username parameter\n");
+		return CHECK_ERROR;
+	}
+
+	return check_from(_m, &username);
+}
+
+int autheph_check_from1(struct sip_msg *_m, char *_username)
+{
+	str susername;
+
+	if (_m == NULL || _username == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return CHECK_ERROR;
+	}
+
+	if (get_str_fparam(&susername, _m, (fparam_t*)_username) < 0)
+	{
+		LM_ERR("failed to get username value\n");
+		return CHECK_ERROR;
+	}
+
+	if (susername.len == 0)
+	{
+		LM_ERR("invalid username parameter - empty value\n");
+		return CHECK_ERROR;
+	}
+
+
+	return check_from(_m, &susername);
+}
+
+static inline int check_to(struct sip_msg *_m, str *_username)
+{
+	if (!_m->to && ((parse_headers(_m, HDR_TO_F, 0) == -1) || (!_m->to)))
+	{
+		LM_ERR("parsing To: header\n");
+		return CHECK_ERROR;
+	}
+
+	if (parse_to_uri(_m) == NULL)
+	{
+		LM_ERR("parsing To: URI\n");
+		return CHECK_ERROR;
+	}
+
+	return check_username(_username, &get_to(_m)->parsed_uri);
+}
+
+int autheph_check_to0(struct sip_msg *_m)
+{
+	str username = {0, 0};
+
+	if (eph_auth_api.pre_auth == NULL)
+	{
+		LM_ERR("autheph_check_to() with no username parameter "
+			"cannot be used without the auth module\n");
+		return CHECK_ERROR;
+	}
+
+	if (_m == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return CHECK_ERROR;
+	}
+
+	if (get_cred(_m, &username) < 0)
+	{
+		LM_ERR("call autheph_(check|proxy|www) before calling "
+			" check_to() with no username parameter\n");
+		return CHECK_ERROR;
+	}
+
+	return check_to(_m, &username);
+}
+
+int autheph_check_to1(struct sip_msg *_m, char *_username)
+{
+	str susername;
+
+	if (_m == NULL || _username == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return CHECK_ERROR;
+	}
+
+	if (get_str_fparam(&susername, _m, (fparam_t*)_username) < 0)
+	{
+		LM_ERR("failed to get username value\n");
+		return CHECK_ERROR;
+	}
+
+	if (susername.len == 0)
+	{
+		LM_ERR("invalid username parameter - empty value\n");
+		return CHECK_ERROR;
+	}
+
+	return check_to(_m, &susername);
+}
+
+int autheph_check_timestamp(struct sip_msg *_m, char *_username)
+{
+	str susername;
+
+	if (_m == NULL || _username == NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return CHECK_ERROR;
+	}
+
+	if (get_str_fparam(&susername, _m, (fparam_t*)_username) < 0)
+	{
+		LM_ERR("failed to get username value\n");
+		return CHECK_ERROR;
+	}
+
+	if (susername.len == 0)
+	{
+		LM_ERR("invalid username parameter - empty value\n");
+		return CHECK_ERROR;
+	}
+
+	if (autheph_verify_timestamp(&susername) < 0)
+	{
+		return CHECK_ERROR;
+	}
+
+	return CHECK_OK;
+}
diff --git a/modules/auth_ephemeral/checks.h b/modules/auth_ephemeral/checks.h
new file mode 100644
index 0000000..27cb7fe
--- /dev/null
+++ b/modules/auth_ephemeral/checks.h
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef CHECKS_H
+#define CHECKS_H
+
+#include "../../parser/msg_parser.h"
+
+int autheph_check_from0(struct sip_msg *_m);
+int autheph_check_from1(struct sip_msg *_m, char *_username);
+int autheph_check_to0(struct sip_msg *_m);
+int autheph_check_to1(struct sip_msg *_m, char *_username);
+int autheph_check_timestamp(struct sip_msg *_m, char *_username);
+
+typedef enum {
+	CHECK_NO_USER	= -2,
+	CHECK_ERROR	= -1,
+	CHECK_OK	= 1
+} autheph_check_result_t;
+
+#endif /* CHECKS_H */
diff --git a/modules/auth_ephemeral/doc/Makefile b/modules/auth_ephemeral/doc/Makefile
new file mode 100644
index 0000000..cfd51c2
--- /dev/null
+++ b/modules/auth_ephemeral/doc/Makefile
@@ -0,0 +1,4 @@
+docs = auth_ephemeral.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/auth_ephemeral/doc/auth_ephemeral.xml b/modules/auth_ephemeral/doc/auth_ephemeral.xml
new file mode 100644
index 0000000..097228a
--- /dev/null
+++ b/modules/auth_ephemeral/doc/auth_ephemeral.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>Auth_ephemeral Module</title>
+	<authorgroup>
+		<author>
+		<firstname>Peter</firstname>
+		<surname>Dunkley</surname>
+		<affiliation><orgname>Crocodile RCS Ltd</orgname></affiliation>
+		<email>peter.dunkley at crocodile-rcs.com</email>
+		</author>
+	</authorgroup>
+	<copyright>
+		<year>2013</year>
+		<holder>Crocodile RCS Ltd</holder>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+
+	<xi:include href="auth_ephemeral_admin.xml"/>
+</book>
diff --git a/modules/auth_ephemeral/doc/auth_ephemeral_admin.xml b/modules/auth_ephemeral/doc/auth_ephemeral_admin.xml
new file mode 100644
index 0000000..315781b
--- /dev/null
+++ b/modules/auth_ephemeral/doc/auth_ephemeral_admin.xml
@@ -0,0 +1,574 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Auth_ephemeral Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+	This module contains all authentication related functions that can work
+	with ephemeral credentials. This module can be used together with the
+	<emphasis>auth</emphasis> module for digest authentication. Use this
+	module if you want to use ephemeral credentials instead of ordinary
+	usernames and passwords.
+	</para>
+
+	<section>
+	<title>How ephemeral credentials work</title>
+	<para>
+	Ephemeral credentials are generated by a web-service and enforced on
+	Kamailio. This use of ephemeral credentials ensures that access to
+	Kamailio is controlled even if the credentials cannot be kept secret,
+	as can be the case in WebRTC where the credentials may be specified in
+	Javascript.
+	</para>
+	<para>
+	The only interaction needed between the web-service and Kamailio is to
+	share a secret key.
+	</para>
+	<para>
+	Credentials will typically be requested from the web-service using an
+	HTTP POST and provided in a HTTP response with a content-type of
+	"application/json". To prevent unauthorised use the HTTP
+	requests can be ACLd by various means.
+	</para>
+	<para>
+	This mechanism is based on draft-uberti-rtcweb-turn-rest.
+	</para>
+	<section>
+	<title>Request</title>
+	<para>
+	The request to the web-service should contain the following parameters:
+	<itemizedlist>
+	<listitem>
+	<para><emphasis>service</emphasis> - specifies the desired service
+	(msrp, sip, etc)</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>username</emphasis> - an optional user identifier for
+	the service (as would normally be found in the username parameter of an
+	Authorization: or Proxy-Authorization: header)</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>key</emphasis> - an optional API key used for
+	authentication</para>
+	</listitem>
+	</itemizedlist>
+	</para>
+	<example>
+	<title>Request example</title>
+	<programlisting format="linespecific">
+POST /?service=sip&username=foo at bar.com
+</programlisting>
+	</example>
+	</section>
+	<section>
+	<title>Response</title>
+	<para>
+	The response should include the following parameters:
+	<itemizedlist>
+	<listitem>
+	<para><emphasis>username</emphasis> - the username to use, which is a
+	colon-delimited combination of the expiration timestamp and the username
+	parameter from the request (if specified). When used with this module
+	the timestamp must be a UNIX timestamp.</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>password</emphasis> - the password to use; this value is
+	computed from the secret key and the returned username value, by
+	performing base64(hmac-sha1(secret key, returned username)).</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>ttl</emphasis> - the duration for which the username and
+	password are valid, in seconds.</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>uris</emphasis> - an array of URIs indicating servers
+	that the username and password are valid for.</para>
+	</listitem>
+	</itemizedlist>
+	</para>
+	<example>
+	<title>Response example</title>
+	<programlisting format="linespecific">
+{
+  "username" : "1234567890:foo at bar.com",
+  "password" : "asdfghjklauio=",
+  "ttl" : 86400,
+  "uris" : [
+    "sip:1.2.3.4;transport=ws",
+    "sip:5.6.7.8;transport=ws"
+  ]
+}
+</programlisting>
+	</example>
+	</section>
+	</section>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The module must be loaded before this module:
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>auth</emphasis> (optional).</para>
+		</listitem>
+		</itemizedlist>
+		</para>
+	</section>
+
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries must be installed before running
+		&kamailio; with this module loaded:
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>OpenSSL</emphasis>.</para>
+		</listitem>
+		</itemizedlist>
+		</para>
+	</section>
+	</section>
+
+	<section id="auth_eph.parameters">
+	<title>Parameters</title>
+	<section id="auth_eph.p.secret">
+		<title><varname>secret</varname> (string)</title>
+		<para>
+		The shared secret to use for generating credentials. This
+		parameter can be set multiple times - this enables the secret
+		used for new credentials to be changed without causing existing
+		credentials to stop working. The last secret set is the first
+		that will be tried.
+		</para>
+		<example>
+		<title><varname>secret</varname> parameter usage</title>
+		<programlisting format="linespecific">
+...
+modparam("auth_ephemeral", "secret", "kamailio_rules")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="auth_eph.p.username_format">
+		<title><varname>username_format</varname> (integer)</title>
+		<para>
+		The format of the username in the web-service response.
+		</para>
+		<para>
+		<itemizedlist>
+		<listitem>
+			<para>0 (deprecated - pre IETF draft format) -
+		<username parameter from the request>:<timestamp>
+			</para>
+		</listitem>
+		<listitem>
+			<para>1 (default - IETF draft format) -
+		<timestamp>:<username parameter from the request>
+			</para>
+		</listitem>
+		</itemizedlist>
+		</para>
+		<example>
+		<title><varname>username_format</varname> parameter
+		usage</title>
+		<programlisting format="linespecific">
+...
+modparam("auth_ephemeral", "username_format", 0)
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section id="auth_eph.functions">
+	<title>Functions</title>
+	<section id="auth_eph.f.autheph_proxy">
+		<title>
+			<function moreinfo="none">autheph_proxy(realm)</function>
+		</title>
+		<para>This function performs proxy authentication.</para>
+		<note><para>This function can only be used when the
+		<emphasis>auth</emphasis> module is loaded before this module.
+		</para></note>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>realm</emphasis> - realm is an opaque
+			string that the user agent should present to the user so
+			that he can decide what username and password to use.
+			Usually this is domain of the host the server is running
+			on.
+			</para>
+			<para>
+			It must not be an empty string <quote></quote>. Apart
+			from a static string, a typical value is the From-URI
+			domain (i.e., $fd).
+			</para>
+			<para>
+			The string may contain pseudo variables.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_proxy usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_proxy("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="auth_eph.f.autheph_www">
+		<title>
+			<function moreinfo="none">autheph_www(realm[, method])</function>
+		</title>
+		<para>This function performs WWW digest authentication.</para>
+		<note><para>This function can only be used when the
+		<emphasis>auth</emphasis> module is loaded before this module.
+		</para></note>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>realm</emphasis> - realm is an opaque
+			string that the user agent should present to the user so
+			that he can decide what username and password to use.
+			Usually this is domain of the host the server is running
+			on.
+			</para>
+			<para>
+			It must not be an empty string <quote></quote>. Apart
+			from a static string, a typical value is the From-URI
+			domain (i.e., $fd).
+			</para>
+			<para>
+			The string may contain pseudo variables.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>method</emphasis> - the method to be
+			used for authentication. This parameter is optional and
+			if not set the first "word" on the request-line is used.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_www usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_www("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="auth_eph.f.autheph_check">
+		<title>
+			<function moreinfo="none">autheph_check(realm)</function>
+		</title>
+		<para>This function combines the functionalities of
+		<function moreinfo="none">autheph_www</function> and
+		<function moreinfo="none">autheph_proxy</function>, the first
+		being exectuted if the SIP request is a REGISTER, the second for
+		the rest.</para>
+		<note><para>This function can only be used when the
+		<emphasis>auth</emphasis> module is loaded before this module.
+		</para></note>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>realm</emphasis> - realm is an opaque
+			string that the user agent should present to the user so
+			that he can decide what username and password to use.
+			Usually this is domain of the host the server is running
+			on.
+			</para>
+			<para>
+			It must not be an empty string <quote></quote>. Apart
+			from a static string, a typical value is the From-URI
+			domain (i.e., $fd).
+			</para>
+			<para>
+			The string may contain pseudo variables.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_check usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_check("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="auth_eph.f.autheph_authenticate">
+		<title>
+			<function moreinfo="none">autheph_authenticate(username, password)</function>
+		</title>
+		<para>This function performs non-digest ephemeral
+		authentication. This may be used when digest authentication
+		cannot. For example, during WebSocket handshake the username
+		may be part of the requested URI and the password presented in
+		a Cookie: header.</para>
+		<note><para>This function may be used without loading the
+		<emphasis>auth</emphasis> module.</para></note>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>username</emphasis> - the username
+			returned in the response from the web-service.</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>password</emphasis> - the password
+			returned in the response from the web-service.</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_authenticate usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_authenticate("$var(username)", "$var(password)")) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="auth_eph.f.autheph_check_from">
+		<title>
+			<function moreinfo="none">autheph_check_from([username])</function>
+		</title>
+		<para>This function checks that the username (or username and
+		domain) in the From: URI matches the credentials.</para>
+		<para>When used without the <emphasis>username</emphasis>
+		parameter it compares the From: URI with the credentials used
+		to authenticate the request (in the Authorization: or
+		Proxy-Authorization: headers).</para>
+		<para>The <emphasis>username</emphasis> parameter can be used
+		to check the From: when individual SIP requests are not
+		authenticated (for example, when they are over WebSockets and
+		the connection was authenticated during the handshake). In this
+		scenario the username should be cached (perhaps in a hash-table)
+		at the point the authentication occurs.</para>
+		<note><para>This function must have the optional
+		<emphasis>username</emphasis> parameter specified to use it
+		without loading the <emphasis>auth</emphasis> module before this
+		module.</para></note>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>username</emphasis> (optional) - the
+			username returned in the response from the
+			web-service.</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_check_from usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_check_from()) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="auth_eph.f.autheph_check_to">
+		<title>
+			<function moreinfo="none">autheph_check_to([username])</function>
+		</title>
+		<para>This function checks that the username (or username and
+		domain) in the To: URI matches the credentials.</para>
+		<para>When used without the <emphasis>username</emphasis>
+		parameter it compares the To: URI with the credentials used
+		to authenticate the request (in the Authorization: or
+		Proxy-Authorization: headers).</para>
+		<para>The <emphasis>username</emphasis> parameter can be used
+		to check the From: when individual SIP requests are not
+		authenticated (for example, when they are over WebSockets and
+		the connection was authenticated during the handshake). In this
+		scenario the username should be cached (perhaps in a hash-table)
+		at the point the authentication occurs.</para>
+		<note><para>This function must have the optional
+		<emphasis>username</emphasis> parameter specified to use it
+		without loading the <emphasis>auth</emphasis> module before this
+		module.</para></note>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>username</emphasis> (optional) - the
+			username returned in the response from the
+			web-service.</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_check_to usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_check_to()) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="auth_eph.f.autheph_check_timestamp">
+		<title>
+			<function moreinfo="none">autheph_check_timestamp(username)</function>
+		</title>
+		<para>This function checks that the timestamp in the
+		<emphasis>username</emphasis> parameter has not expired. The
+		<emphasis>autheph_(check|proxy|www)</emphasis> functions all do
+		this automatically, but in a scenario when individual SIP
+		requests are not authenticated (for example, when they are over
+		WebSockets and the connection was authenticated during the
+		handshake) you may want to re-check for each new out-of-dialog
+		request. In this scenario the username should be cached (perhaps
+		in a hash-table) at the point authentication occurs.</para>
+		<note><para>This function may be used without loading the
+		<emphasis>auth</emphasis> module.</para></note>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>username</emphasis> - the username
+			returned in the response from the web-service.</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_check_timestamp usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_check_timestamp("$var(username)")) {
+    sl_send_reply("403", "Forbidden");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>MI Commands</title>
+	<section id="auth_eph.m.autheph.add_secret">
+		<title><function moreinfo="none">autheph.add_secret</function></title>
+		<para>Add a secret to the head of the shared secret list. The
+		secret will be the first one tried during future authentication
+		attempts. This MI command allows you to update the shared secret
+		list without having to restart Kamailio.</para>
+		<note><para>If you want your new shared secret list to persist
+		across restarts you must add it to your Kamailio configuration
+		file.</para></note>
+		<para>Name: <emphasis>autheph.add_secret</emphasis></para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem>
+				<para>secret</para>
+			</listitem>
+		</itemizedlist>
+		<para>MI FIFO Command Format:</para>
+		<programlisting  format="linespecific">
+			:autheph.add_secret:fifo_reply
+			kamailio_rules
+			_empty_line_
+</programlisting>
+	</section>
+
+	<section id="auth_eph.m.autheph.dump_secrets">
+		<title><function moreinfo="none">autheph.dump_secrets</function></title>
+		<para>Dump the set of shared secrets.</para>
+		<para>Name: <emphasis>autheph.dump_secrets</emphasis></para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem>
+				<para><emphasis>none</emphasis></para>
+			</listitem>
+		</itemizedlist>
+		<para>MI FIFO Command Format:</para>
+		<programlisting  format="linespecific">
+			:autheph.dump_secrets:fifo_reply
+			_empty_line_
+</programlisting>
+	</section>
+
+	<section id="auth_eph.m.autheph.rm_secret">
+		<title><function moreinfo="none">autheph.rm_secret</function></title>
+		<para>Remove the secret with the specified integer ID.  This MI
+		command allows you to update the shared secret list without
+		having to restart Kamailio.</para>
+		<note><para>If you want your new shared secret list to persist
+		across restarts you must add it to your Kamailio configuration
+		file.</para></note>
+		<para>Name: <emphasis>autheph.rm_secret</emphasis></para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem>
+				<para>ID - the ID of the secret to remove</para>
+			</listitem>
+		</itemizedlist>
+		<para>MI FIFO Command Format:</para>
+		<programlisting  format="linespecific">
+			:autheph.rm_secret:fifo_reply
+			0
+			_empty_line_
+</programlisting>
+	</section>
+
+	</section>
+</chapter>
+
diff --git a/modules/avp/doc/avp_functions.xml b/modules/avp/doc/avp_functions.xml
index 01bdd7f..18e5459 100644
--- a/modules/avp/doc/avp_functions.xml
+++ b/modules/avp/doc/avp_functions.xml
@@ -14,7 +14,7 @@
 
     <title>Functions</title>
 
-    <section id="set_iattr">
+    <section id="avp.f.set_iattr">
 	<title><function>set_iattr(attribute,value)</function></title>
 	<para>
 	    Create an AVP of type integer.
@@ -44,7 +44,7 @@ set_iattr("fr_inv_timer", "60")
 	</example>
     </section>
     
-    <section id="flags2attr">
+    <section id="avp.f.flags2attr">
 	<title><function>flags2attr("$avp")</function></title>
 	<para>
 	    Store the current state of &kamailio; flags into the specified AVP.
@@ -59,7 +59,7 @@ flags2attr("$msg_flags")
 	</example>
     </section>
     
-    <section id="set_sattr">
+    <section id="avp.f.set_sattr">
 	<title><function>set_sattr(attribute,value)</function></title>
 	<para>
 	    Create an AVP of type string.
@@ -87,7 +87,7 @@ set_sattr("called_number", "1234")
 	</example>
     </section>
 
-    <section id="print_aattr">
+    <section id="avp.f.print_aattr">
 	<title><function>print_attr($attribute)</function></title>
 	<para>
 	    Print the value of an AVP to syslog.
@@ -101,7 +101,7 @@ set_sattr("called_number", "1234")
 	</itemizedlist>
     </section>
     
-    <section id="attr2uri">
+    <section id="avp.f.attr2uri">
 	<title><function>attr2uri($attribute[,uri-part])</function></title>
 	<para>
 		Rewrite the whole Request-URI of the message being processed with
@@ -130,7 +130,7 @@ set_sattr("called_number", "1234")
 	</itemizedlist>
     </section>
 
-	<section id="attr_exists">
+	<section id="avp.f.attr_exists">
 	<title><function>attr_exists(attribute)</function></title>
 	<para>
 	    Test for the existence of AVP with given name. The function returns
@@ -159,7 +159,7 @@ if (attr_exists("saved_ruri")) {
     </section>
 
     
-    <section id="attr_equals">
+    <section id="avp.f.attr_equals">
 	<title><function>attr_equals(attribute, value)</function></title>
 	<para>
 	    Test whether an AVP with given name and value exists. The function
@@ -181,7 +181,7 @@ if (attr_exists("saved_ruri")) {
 	</itemizedlist>
     </section>
     
-    <section id="attr_equals_xl">
+    <section id="avp.f.attr_equals_xl">
 	<title><function>attr_equals_xl(attribute, xl_format)</function></title>
 	<para>
 	    Test whether an AVP with given name and value exists. The function
@@ -217,7 +217,7 @@ if (attr_equals_xl("my_avp", "%ct")) {
 	</example>
     </section>
     
-	<section id="dump_attrs">
+	<section id="avp.f.dump_attrs">
 	<title><function>dump_attrs()</function></title>
 	<para>
 		Dumps all AVPs in user lists to the debug output (with level INFO).
@@ -225,7 +225,7 @@ if (attr_equals_xl("my_avp", "%ct")) {
 	<para>The function does not require any parameters.</para>
     </section>
     
-	<section id="xlset_attr">
+	<section id="avp.f.xlset_attr">
 	<title><function>xlset_attr($attribute, xl_format)</function></title>
 	<para>
 		Creates new AVP identified by <emphasis>attribute</emphasis> and assigns the result string of xprint formatting rules as its value.
@@ -263,7 +263,7 @@ if (attr_equals_xl("my_avp", "%ct")) {
     </section>
     
     
-	<section id="insert_attr_hf_1">
+	<section id="avp.f.insert_attr_hf_1">
 	<title><function>insert_attr_hf(name)</function></title>
 	<para>
 		Inserts new header into the request, which is beeing forwarded. The AVP name is the name of the header field.
@@ -284,7 +284,7 @@ if (attr_equals_xl("my_avp", "%ct")) {
     </itemizedlist>
 	</section>
 	
-	<section id="insert_attr_hf_2">
+	<section id="avp.f.insert_attr_hf_2">
 	<title><function>insert_attr_hf(header_name, $avp_name)</function></title>
 	<para>
 		Inserts new header into the request, which is beeing forwarded. 
@@ -318,7 +318,7 @@ insert_attr_hf("Route", "$my_route");
 	</example>
 	</section>
 	
-	<section id="append_attr_hf_1">
+	<section id="avp.f.append_attr_hf_1">
 	<title><function>append_attr_hf(name)</function></title>
 	<para>
 		Appends new header into the request, which is beeing forwarded. The AVP name is the name of the header field.
@@ -339,7 +339,7 @@ insert_attr_hf("Route", "$my_route");
     </itemizedlist>
 	</section>
 	
-	<section id="append_attr_hf_2">
+	<section id="avp.f.append_attr_hf_2">
 	<title><function>append_attr_hf(header_name, $avp_name)</function></title>
 	<para>
 		Appends new header into the request, which is beeing forwarded. 
@@ -364,7 +364,7 @@ insert_attr_hf("Route", "$my_route");
     </itemizedlist>
 	</section>
 	
-	<section id="replace_attr_hf_1">
+	<section id="avp.f.replace_attr_hf_1">
 	<title><function>replace_attr_hf(name)</function></title>
 	<para>
 		Replaces header in the request, which is beeing forwarded. The AVP name is the same as the name of the header field.
@@ -385,7 +385,7 @@ insert_attr_hf("Route", "$my_route");
     </itemizedlist>
 	</section>
 	
-	<section id="replace_attr_hf_2">
+	<section id="avp.f.replace_attr_hf_2">
 	<title><function>replace_attr_hf(header_name, $avp_name)</function></title>
 	<para>
 		Replaces header in the request, which is beeing forwarded. 
@@ -410,7 +410,7 @@ insert_attr_hf("Route", "$my_route");
     </itemizedlist>
 	</section>
 	
-	<section id="attr_to_reply_1">
+	<section id="avp.f.attr_to_reply_1">
 	<title><function>attr_to_reply(name)</function></title>
 	<para>
 		Appends new header into the reply at the request time processing. The AVP name is the name of the header field.
@@ -431,7 +431,7 @@ insert_attr_hf("Route", "$my_route");
     </itemizedlist>
 	</section>
 	
-	<section id="attr_to_reply_2">
+	<section id="avp.f.attr_to_reply_2">
 	<title><function>attr_to_reply(header_name, $avp_name)</function></title>
 	<para>
 		Appends new header into the reply at the request time processing. 
@@ -462,7 +462,7 @@ attr_to_reply("P-Hint-Route", "my_route");
 	</example>
 	</section>
 	
-	<section id="attr_destination">
+	<section id="avp.f.attr_destination">
 	<title><function>attr_destination($avp_name)</function></title>
 	<para>
 		Sets the destination of the forwarded request to the value of AVP, 
@@ -490,7 +490,7 @@ t_relay();
 	</example>
 	</section>
 	
-	<section id="xlset_destination">
+	<section id="avp.f.xlset_destination">
 	<title><function>xlset_destination(xl_format)</function></title>
 	<para>
 		Sets the destination of the forwarded request to the value of result of xprint formatted string. Either SIP URI or nameaddr format is allowed.
@@ -515,7 +515,7 @@ t_relay();
 	</example>
 	</section>
 	
-	<section id="subst_attr">
+	<section id="avp.f.subst_attr">
 	<title><function>subst_attr($avp_name, subst_re)</function></title>
 	<para>
 		The value of the AVP identified by <emphasis>$avp_name</emphasis>
@@ -546,7 +546,7 @@ subst_attr("$uri","/tel:[0-9]*/sip:\1 at foo.bar;user=phone/");
 	</example>
 	</section>
 	
-	<section id="del_attr">
+	<section id="avp.f.del_attr">
 	<title><function>del_attr($avp_name)</function></title>
 	<para>
 		The AVP identified by <emphasis>$avp_name</emphasis> name is deleted.
@@ -577,7 +577,7 @@ failure_route[1] {
 	</example>
 	</section>
 	
-	<section id="hdr_body2attrs">
+	<section id="avp.f.hdr_body2attrs">
 	<title><function>hdr_body2attrs(headername, prefix)</function></title>
 	<para>
 		Function parses a header body content scans for fld1=val1,fld2=val2,... and creates bunch of avps prefixfld1:= val1, prefixfld2:= val2, .... 
@@ -600,7 +600,7 @@ failure_route[1] {
     </itemizedlist>
 	</section>
 
-	<section id="hdr_body2attrs2">
+	<section id="avp.f.hdr_body2attrs2">
 	<title><function>hdr_body2attrs2(headername, prefix)</function></title>
 	<para>
 		Function parses a header body content scans for fld1=val1,val2;fld2=val3,... and creates bunch of avps prefixfld1#1:= val1, prefixfld1#2:= val2, prefixfld2:=val3 .... 
diff --git a/modules/avp/doc/avp_params.xml b/modules/avp/doc/avp_params.xml
index 6660824..6386e0c 100644
--- a/modules/avp/doc/avp_params.xml
+++ b/modules/avp/doc/avp_params.xml
@@ -8,7 +8,7 @@
 
     <title>Parameters</title>
 
-    <section id="xlbuf_size">
+    <section id="avp.p.xlbuf_size">
     <title><varname>xlbuf_size</varname> (integer)</title>
     <para>
 		Defines size of internal buffer for all xprint formatting calls. If you
diff --git a/modules/avpops/README b/modules/avpops/README
index df0bfe7..5e6d0c9 100644
--- a/modules/avpops/README
+++ b/modules/avpops/README
@@ -10,7 +10,7 @@ Ramona-Elena Modroiu
 
    <ramona at rosdev.ro>
 
-   Copyright � 2004, 2005 Voice Sistem SRL
+   Copyright © 2004, 2005 Voice Sistem SRL
      __________________________________________________________________
 
    Table of Contents
@@ -133,6 +133,9 @@ Chapter 1. Admin Guide
    AVPs and SIP messages and a function for testing/checking the value of
    an AVP.
 
+   If you just need a way to execute SQL statements in a Kamailio
+   configuration script, please consider use the sqlops module instead.
+
    AVPs are persistent per SIP transaction, being available in "route",
    "branch_route" and "failure_route". A tutorial providing more
    information (detailed explanations and commented examples) can be found
@@ -239,7 +242,7 @@ modparam("avpops","use_domain",1)
 
    Name of column containing the uuid (unique user id).
 
-   Default value is "uuid".
+   Default value is “uuid”.
 
    Example 1.5. Set uuid_column parameter
 ...
@@ -250,7 +253,7 @@ modparam("avpops","uuid_column","uuid")
 
    Name of column containing the username.
 
-   Default value is "username".
+   Default value is “username”.
 
    Example 1.6. Set username_column parameter
 ...
@@ -261,7 +264,7 @@ modparam("avpops","username_column","username")
 
    Name of column containing the domain name.
 
-   Default value is "domain".
+   Default value is “domain”.
 
    Example 1.7. Set domain_column parameter
 ...
@@ -272,7 +275,7 @@ modparam("avpops","domain_column","domain")
 
    Name of column containing the attribute name (AVP name).
 
-   Default value is "attribute".
+   Default value is “attribute”.
 
    Example 1.8. Set attribute_column parameter
 ...
@@ -283,7 +286,7 @@ modparam("avpops","attribute_column","attribute")
 
    Name of column containing the AVP value.
 
-   Default value is "value".
+   Default value is “value”.
 
    Example 1.9. Set value_column parameter
 ...
@@ -294,7 +297,7 @@ modparam("avpops","value_column","value")
 
    Name of integer column containing the AVP type.
 
-   Default value is "type".
+   Default value is “type”.
 
    Possible column values are
      * 0 - AVP with string name and string value
@@ -322,7 +325,7 @@ modparam("avpops","type_column","type")
           + 'value_type='('integer'|'string')
           + 'table='string
 
-   Default value is "NULL".
+   Default value is “NULL”.
 
    Example 1.11. Set db_scheme parameter
 ...
@@ -346,7 +349,7 @@ modparam("avpops","db_scheme",
    5.12. is_avp_set(name)
    5.13. avp_print()
 
-5.1. avp_db_load(source,name)
+5.1.  avp_db_load(source,name)
 
    Loads from DB into memory the AVPs corresponding to the given source.
    If given, it sets the script flags for loaded AVPs. It returns true if
@@ -384,7 +387,7 @@ avp_db_load("$uuid","$avp(s:404fwd)/fwd_table");
 avp_db_load("$ru","$avp(i1:123)/$some_scheme");
 ...
 
-5.2. avp_db_store(source,name)
+5.2.  avp_db_store(source,name)
 
    Stores to DB the AVPs corresponding to the given source.
 
@@ -400,7 +403,7 @@ avp_db_store("$tu","$avp(i:678)");
 avp_db_store("$ru/username","$avp(email)");
 ...
 
-5.3. avp_db_delete(source,name)
+5.3.  avp_db_delete(source,name)
 
    Deletes from DB the AVPs corresponding to the given source.
 
@@ -417,9 +420,11 @@ avp_db_delete("$ru/username","$avp(email)");
 avp_db_delete("$uuid","$avp(s:404fwd)/fwd_table");
 ...
 
-5.4. avp_db_query(query[,dest])
+5.4.  avp_db_query(query[,dest])
 
-   Make a database query and store the result in AVPs.
+   Make a database query and store the result in AVPs. This command is
+   deprecated, please use the more flexible and advanced sqlops module
+   instead.
 
    The meaning and usage of the parameters:
      * query - must be a valid SQL query. The parameter can contain
@@ -431,8 +436,8 @@ avp_db_delete("$uuid","$avp(s:404fwd)/fwd_table");
        used in the query makes you vulnerable to SQL injection, e.g. make
        it possible for an outside attacker to alter your database content.
      * dest - a list with AVP names where to store the result. The format
-       is "$avp(name1);$avp(name2);...". If this parameter is ommited, the
-       result is stored in "$avp(i:1);$avp(i:2);...". If the result gives
+       is “$avp(name1);$avp(name2);...”. If this parameter is ommited, the
+       result is stored in “$avp(i:1);$avp(i:2);...”. If the result gives
        many rows, then multiple AVPs with corresponding name will be
        added. The value type of the AVP (string or integer) will be
        derived from the type of the columns. Please note that only this
@@ -455,7 +460,7 @@ avp_db_query("select password, ha1 from subscriber where username='$tu'",
 avp_db_query("delete from subscriber");
 ...
 
-5.5. avp_delete(name)
+5.5.  avp_delete(name)
 
    Deletes from memory the AVPs with name or, if empty, all AVPs.
 
@@ -477,7 +482,7 @@ avp_delete("i");
 avp_delete("a3");
 ...
 
-5.6. avp_pushto(destination,name)
+5.6.  avp_pushto(destination,name)
 
    Pushes the value of AVP(s) into the SIP message.
 
@@ -507,7 +512,7 @@ avp_pushto("$du","$avp(i:679)");
 avp_pushto("$br","$avp(i:680)");
 ...
 
-5.7. avp_check(name,op_value)
+5.7.  avp_check(name,op_value)
 
    Checks the value of the AVP(s) against an operator and value.
 
@@ -544,12 +549,25 @@ avp_pushto("$br","$avp(i:680)");
 ...
 avp_check("$avp(i:678)", "lt/i:345/g");
 avp_check("$fd","eq/$td/I");
-avp_check("$avp(s:foo)","gt/$avp($bar)/g");
+avp_check("$avp(s:foo)","gt/$avp($var(bar))/g");
 avp_check("$avp(s:foo)","re/sip:.*@bar.net/g");
 avp_check("$avp(s:foo)","fm/$avp(fm_avp)/g");
 ...
 
-5.8. avp_copy(old_name,new_name)
+   NOTE: you can use a xavp variable ($xavp(key1[indx1]=>key2[indx2])) as
+   first or second parameter. If you want to check all the values of the
+   key2 you should use [*] at indx2. The [*] index is not allowed at
+   indx1.
+...
+avp_check("$xavp(op[0]=>lt[0])", "lt/i:345/g");
+avp_check("$xavp(op=>fd","eq/$td/I");
+avp_check("$xavp(op[1]=>foo[*])","gt/$avp($var(bar))/g");
+avp_check("$avp(s:foo)","re/$xavp(op[0]=>re[*]/g");
+$var(id)=2;
+avp_check("$xavp(op=>foo[*])","fm/$xavp(op=>fm[$var(id)])/g");
+...
+
+5.8.  avp_copy(old_name,new_name)
 
    Copy / move an avp under a new name.
 
@@ -570,7 +588,7 @@ avp_copy("$avp(i:678)", "$avp(s:345)/g");
 avp_copy("$avp(old)","$avp(new)/gd");
 ...
 
-5.9. avp_printf(dest, format)
+5.9.  avp_printf(dest, format)
 
    NOTE: since Kamailio 1.3.0 the function has been moved to core and it
    is an alias to pv_printf().
@@ -594,7 +612,7 @@ avp_copy("$avp(old)","$avp(new)/gd");
 avp_printf("$avp(i:20)", "This is a $rm request with call-id $hdr(call-id)");
 ...
 
-5.10. avp_subst(avps, subst)
+5.10.  avp_subst(avps, subst)
 
    Perl/sed-like subst applied to AVPs having string value.
 
@@ -636,7 +654,7 @@ avp_subst("$avp(i:678)/$avp(i:679)/g", "/(.*)@(.*)/\1@$rd/");
    after the first src_avp is processed, it will be added in avp list and
    next processing will use it.
 
-5.11. avp_op(name,op_value)
+5.11.  avp_op(name,op_value)
 
    Different integer operations with avps.
 
@@ -668,7 +686,7 @@ avp_op("$avp(i:678)", "add/i:345/g");
 avp_op("$avp(number)","sub/$avp(number2)/d");
 ...
 
-5.12. is_avp_set(name)
+5.12.  is_avp_set(name)
 
    Check if any AVP with name is set.
 
@@ -687,7 +705,7 @@ if(is_avp_set("$avp(i:678)"))
     log("AVP with integer id 678 exists\n");
 ...
 
-5.13. avp_print()
+5.13.  avp_print()
 
    Prints the list with all the AVPs from memory. This is only a
    helper/debug function.
diff --git a/modules/avpops/avpops.c b/modules/avpops/avpops.c
index 4de02a1..1f793d6 100644
--- a/modules/avpops/avpops.c
+++ b/modules/avpops/avpops.c
@@ -266,16 +266,16 @@ static int fixup_db_avp(void** param, int param_no, int allow_scheme)
 		} else {
 			/* is a variable $xxxxx */
 			s.len = strlen(s.s);
-			p = pv_parse_spec(&s, &sp->u.sval);
-			if (p==0 || sp->u.sval.type==PVT_NULL || sp->u.sval.type==PVT_EMPTY)
+			sp->u.sval = pv_cache_get(&s);
+			if (sp->u.sval==0 || sp->u.sval->type==PVT_NULL || sp->u.sval->type==PVT_EMPTY)
 			{
 				LM_ERR("bad param 1; "
 					"expected : $pseudo-variable or int/str value\n");
 				return E_UNSPEC;
 			}
 			
-			if(sp->u.sval.type==PVT_RURI || sp->u.sval.type==PVT_FROM
-					|| sp->u.sval.type==PVT_TO || sp->u.sval.type==PVT_OURI)
+			if(sp->u.sval->type==PVT_RURI || sp->u.sval->type==PVT_FROM
+					|| sp->u.sval->type==PVT_TO || sp->u.sval->type==PVT_OURI)
 			{
 				sp->opd = ((flags==0)?AVPOPS_FLAG_URI0:flags)|AVPOPS_VAL_PVAR;
 			} else {
@@ -396,7 +396,7 @@ static int fixup_delete_avp(void** param, int param_no)
 					" pseudo-variable in param \n");
 				return E_UNSPEC;
 			}
-			if (ap->u.sval.type!=PVT_AVP)
+			if (ap->u.sval->type!=PVT_AVP)
 			{
 				LM_ERR("bad param; expected : $avp(name)\n");
 				return E_UNSPEC;
@@ -500,7 +500,7 @@ static int fixup_copy_avp(void** param, int param_no)
 	}
 
 	/* attr name is mandatory */
-	if (ap->u.sval.type!=PVT_AVP)
+	if (ap->u.sval->type!=PVT_AVP)
 	{
 		LM_ERR("you must specify only AVP as parameter\n");
 		return E_UNSPEC;
@@ -566,7 +566,7 @@ static int fixup_pushto_avp(void** param, int param_no)
 			return E_OUT_OF_MEM;
 		}
 
-		switch(ap->u.sval.type) {
+		switch(ap->u.sval->type) {
 			case PVT_RURI:
 				ap->opd = AVPOPS_VAL_NONE|AVPOPS_USE_RURI;
 				if ( p && !(
@@ -623,7 +623,7 @@ static int fixup_pushto_avp(void** param, int param_no)
 			LM_ERR("unable to get pseudo-variable in param 2\n");
 			return E_OUT_OF_MEM;
 		}
-		if (ap->u.sval.type==PVT_NULL)
+		if (ap->u.sval->type==PVT_NULL)
 		{
 			LM_ERR("bad param 2; expected : $pseudo-variable ...\n");
 			pkg_free(ap);
@@ -669,7 +669,7 @@ static int fixup_check_avp(void** param, int param_no)
 			return E_OUT_OF_MEM;
 		}
 		/* attr name is mandatory */
-		if (ap->u.sval.type==PVT_NULL)
+		if (ap->u.sval->type==PVT_NULL)
 		{
 			LM_ERR("null pseudo-variable in param 1\n");
 			return E_UNSPEC;
@@ -683,28 +683,23 @@ static int fixup_check_avp(void** param, int param_no)
 		/* if REGEXP op -> compile the expresion */
 		if (ap->ops&AVPOPS_OP_RE)
 		{
-			if ( (ap->opd&AVPOPS_VAL_STR)==0 )
+			if ( (ap->opd&AVPOPS_VAL_STR)!=0 )
 			{
-				LM_ERR("regexp operation requires string value\n");
-				return E_UNSPEC;
-			}
-			re = pkg_malloc(sizeof(regex_t));
-			if (re==0)
-			{
-				LM_ERR("no more pkg mem\n");
-				return E_OUT_OF_MEM;
-			}
-			LM_DBG("compiling regexp <%.*s>\n", ap->u.s.len, ap->u.s.s);
-			if (regcomp(re, ap->u.s.s,
-						REG_EXTENDED|REG_ICASE|REG_NEWLINE))
-			{
-				pkg_free(re);
-				LM_ERR("bad re <%.*s>\n", ap->u.s.len, ap->u.s.s);
-				return E_BAD_RE;
+				re = (regex_t*) pkg_malloc(sizeof(regex_t));
+				if (re==0)
+				{
+					LM_ERR("no more pkg mem\n");
+					return E_OUT_OF_MEM;
+				}
+				LM_DBG("compiling regexp <%.*s>\n", ap->u.s.len, ap->u.s.s);
+				if (regcomp(re, ap->u.s.s,REG_EXTENDED|REG_ICASE|REG_NEWLINE))
+				{
+					pkg_free(re);
+					LM_ERR("bad re <%.*s>\n", ap->u.s.len, ap->u.s.s);
+					return E_BAD_RE;
+				}
+				ap->u.s.s = (char*)re;
 			}
-			/* free the string and link the regexp */
-			// pkg_free(ap->sval.p.s);
-			ap->u.s.s = (char*)re;
 		} else if (ap->ops&AVPOPS_OP_FM) {
 			if ( !( ap->opd&AVPOPS_VAL_PVAR ||
 			(!(ap->opd&AVPOPS_VAL_PVAR) && ap->opd&AVPOPS_VAL_STR) ) )
@@ -750,7 +745,7 @@ static int fixup_subst(void** param, int param_no)
 			LM_ERR("unable to get pseudo-variable in param 2 [%s]\n", s);
 			return E_OUT_OF_MEM;
 		}
-		if (ap->u.sval.type!=PVT_AVP)
+		if (ap->u.sval->type!=PVT_AVP)
 		{
 			LM_ERR("bad attribute name <%s>\n", (char*)*param);
 			pkg_free(av);
@@ -784,7 +779,7 @@ static int fixup_subst(void** param, int param_no)
 					return E_OUT_OF_MEM;
 				}
 			
-				if (ap->u.sval.type!=PVT_AVP)
+				if (ap->u.sval->type!=PVT_AVP)
 				{
 					LM_ERR("bad attribute name <%s>!\n", s);
 					pkg_free(av);
@@ -870,7 +865,7 @@ static int fixup_op_avp(void** param, int param_no)
 			LM_ERR("unable to get pseudo-variable in param 1\n");
 			return E_OUT_OF_MEM;
 		}
-		if (av[0]->u.sval.type!=PVT_AVP)
+		if (av[0]->u.sval->type!=PVT_AVP)
 		{
 			LM_ERR("bad attribute name <%s>\n", (char*)*param);
 			pkg_free(av);
@@ -889,7 +884,7 @@ static int fixup_op_avp(void** param, int param_no)
 			LM_ERR("unable to get pseudo-variable in param 1 (2)\n");
 			return E_OUT_OF_MEM;
 		}
-		if (ap->u.sval.type!=PVT_AVP)
+		if (ap->u.sval->type!=PVT_AVP)
 		{
 			LM_ERR("bad attribute name/alias <%s>!\n", s);
 			pkg_free(av);
@@ -935,7 +930,7 @@ static int fixup_is_avp_set(void** param, int param_no)
 			return E_OUT_OF_MEM;
 		}
 		
-		if (ap->u.sval.type!=PVT_AVP)
+		if (ap->u.sval->type!=PVT_AVP)
 		{
 			LM_ERR("bad attribute name <%s>\n", (char*)*param);
 			return E_UNSPEC;
diff --git a/modules/avpops/avpops_impl.c b/modules/avpops/avpops_impl.c
index fda6db1..ecf31b0 100644
--- a/modules/avpops/avpops_impl.c
+++ b/modules/avpops/avpops_impl.c
@@ -45,6 +45,7 @@
 #include "../../parser/parse_from.h"
 #include "../../parser/parse_uri.h"
 #include "../../mem/mem.h"
+#include "../../xavp.h"
 #include "avpops_impl.h"
 #include "avpops_db.h"
 
@@ -216,7 +217,7 @@ static int dbrow2avp(struct db_row *row, struct db_param *dbp, int_str attr,
 	/* added the avp */
 	db_flags |= AVP_IS_IN_DB;
 	/* set script flags */
-	db_flags |= dbp->a.u.sval.pvp.pvn.u.isname.type&0xff00;
+	db_flags |= dbp->a.u.sval->pvp.pvn.u.isname.type&0xff00;
 	return add_avp( (unsigned short)db_flags, avp_attr, avp_val);
 }
 
@@ -274,7 +275,7 @@ static int avpops_get_aname(struct sip_msg* msg, struct fis_param *ap,
 		return -1;
 	}
 
-	return pv_get_avp_name(msg, &ap->u.sval.pvp, avp_name, name_type);
+	return pv_get_avp_name(msg, &ap->u.sval->pvp, avp_name, name_type);
 }
 
 #define AVPOPS_ATTR_LEN	64
@@ -301,7 +302,7 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp,
 	/* get uuid from avp */
 	if (sp->opd&AVPOPS_VAL_PVAR)
 	{
-		if(pv_get_spec_value(msg, &(sp->u.sval), &xvalue)!=0)
+		if(pv_get_spec_value(msg, sp->u.sval, &xvalue)!=0)
 		{
 			LM_CRIT("failed to get PVAR value (%d/%d)\n", sp->opd, sp->ops);
 			goto error;
@@ -343,9 +344,9 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp,
 	/* is dynamic avp name ? */
 	if(dbp->a.type==AVPOPS_VAL_PVAR)
 	{
-		if(pv_has_dname(&(dbp->a.u.sval)))
+		if(pv_has_dname(dbp->a.u.sval))
 		{
-			if(pv_get_spec_name(msg, &(dbp->a.u.sval.pvp), &xvalue)!=0)
+			if(pv_get_spec_name(msg, &(dbp->a.u.sval->pvp), &xvalue)!=0)
 			{
 				LM_CRIT("failed to get value for P2\n");
 				goto error;
@@ -394,7 +395,7 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp,
 		memset(&avp_name, 0, sizeof(int_str));
 		if(dbp->a.type==AVPOPS_VAL_PVAR)
 		{
-			if(pv_has_dname(&dbp->a.u.sval))
+			if(pv_has_dname(dbp->a.u.sval))
 			{
 				if(xvalue.flags&PV_TYPE_INT)
 				{
@@ -404,8 +405,8 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp,
 					avp_type = AVP_NAME_STR;
 				}
 			} else {
-				avp_name = dbp->a.u.sval.pvp.pvn.u.isname.name;
-				avp_type = dbp->a.u.sval.pvp.pvn.u.isname.type;
+				avp_name = dbp->a.u.sval->pvp.pvn.u.isname.name;
+				avp_type = dbp->a.u.sval->pvp.pvn.u.isname.type;
 			}
 		}
 		//if ( dbrow2avp( &res->rows[i], dbp->a.opd, avp_name, sh_flg) < 0 )
@@ -442,7 +443,7 @@ int ops_dbdelete_avps (struct sip_msg* msg, struct fis_param *sp,
 	/* get uuid from avp */
 	if (sp->opd&AVPOPS_VAL_PVAR)
 	{
-		if(pv_get_spec_value(msg, &(sp->u.sval), &xvalue)!=0)
+		if(pv_get_spec_value(msg, sp->u.sval, &xvalue)!=0)
 		{
 			LM_CRIT("failed to get PVAR value (%d/%d)\n", sp->opd, sp->ops);
 			goto error;
@@ -484,9 +485,9 @@ int ops_dbdelete_avps (struct sip_msg* msg, struct fis_param *sp,
 	/* is dynamic avp name ? */
 	if(dbp->a.type==AVPOPS_VAL_PVAR)
 	{
-		if(pv_has_dname(&dbp->a.u.sval))
+		if(pv_has_dname(dbp->a.u.sval))
 		{
-			if(pv_get_spec_name(msg, &(dbp->a.u.sval.pvp), &xvalue)!=0)
+			if(pv_get_spec_name(msg, &(dbp->a.u.sval->pvp), &xvalue)!=0)
 			{
 				LM_CRIT("failed to get value for P2\n");
 				goto error;
@@ -562,7 +563,7 @@ int ops_dbstore_avps (struct sip_msg* msg, struct fis_param *sp,
 	/* get uuid from avp */
 	if (sp->opd&AVPOPS_VAL_PVAR)
 	{
-		if(pv_get_spec_value(msg, &(sp->u.sval), &xvalue)!=0)
+		if(pv_get_spec_value(msg, sp->u.sval, &xvalue)!=0)
 		{
 			LM_CRIT("failed to get PVAR value (%d/%d)\n", sp->opd, sp->ops);
 			goto error;
@@ -610,9 +611,9 @@ int ops_dbstore_avps (struct sip_msg* msg, struct fis_param *sp,
 	/* is dynamic avp name ? */
 	if(dbp->a.type==AVPOPS_VAL_PVAR)
 	{
-		if(pv_has_dname(&dbp->a.u.sval))
+		if(pv_has_dname(dbp->a.u.sval))
 		{
-			if(pv_get_spec_name(msg, &(dbp->a.u.sval.pvp), &xvalue)!=0)
+			if(pv_get_spec_name(msg, &(dbp->a.u.sval->pvp), &xvalue)!=0)
 			{
 				LM_CRIT("failed to get value for P2\n");
 				goto error;
@@ -647,14 +648,14 @@ int ops_dbstore_avps (struct sip_msg* msg, struct fis_param *sp,
 				goto error;
 			}
 		} else {
-			name_type = dbp->a.u.sval.pvp.pvn.u.isname.type;
-			avp_name = dbp->a.u.sval.pvp.pvn.u.isname.name;
+			name_type = dbp->a.u.sval->pvp.pvn.u.isname.type;
+			avp_name = dbp->a.u.sval->pvp.pvn.u.isname.name;
 		}
 	}
 
 	/* set the script flags */
 	if(dbp->a.type==AVPOPS_VAL_PVAR)
-		name_type |= dbp->a.u.sval.pvp.pvn.u.isname.type&0xff00;
+		name_type |= dbp->a.u.sval->pvp.pvn.u.isname.type&0xff00;
 	
 	/* set uuid/(username and domain) fields */
 
@@ -795,8 +796,8 @@ int ops_delete_avp(struct sip_msg* msg, struct fis_param *ap)
 			((ap->opd&AVPOPS_VAL_INT)&&((avp->flags&AVP_NAME_STR))==0) ||
 			((ap->opd&AVPOPS_VAL_STR)&&(avp->flags&AVP_NAME_STR)) )  )
 				continue;
-			if((ap->u.sval.pvp.pvn.u.isname.type&AVP_SCRIPT_MASK)!=0
-					&& ((ap->u.sval.pvp.pvn.u.isname.type&AVP_SCRIPT_MASK)
+			if((ap->u.sval->pvp.pvn.u.isname.type&AVP_SCRIPT_MASK)!=0
+					&& ((ap->u.sval->pvp.pvn.u.isname.type&AVP_SCRIPT_MASK)
 								&avp->flags)==0)
 				continue;
 			/* remove avp */
@@ -925,7 +926,7 @@ int ops_pushto_avp (struct sip_msg* msg, struct fis_param* dst,
 
 	avp = NULL;
 	flags = 0;
-	if(src->u.sval.type==PVT_AVP)
+	if(src->u.sval->type==PVT_AVP)
 	{
 		/* search for the avp */
 		if(avpops_get_aname(msg, src, &avp_name, &name_type)!=0)
@@ -941,7 +942,7 @@ int ops_pushto_avp (struct sip_msg* msg, struct fis_param* dst,
 		}
 		flags = avp->flags;
 	} else {
-		if(pv_get_spec_value(msg, &(src->u.sval), &xvalue)!=0)
+		if(pv_get_spec_value(msg, src->u.sval, &xvalue)!=0)
 		{
 			LM_ERR("cannot get src value\n");
 			goto error;
@@ -999,7 +1000,7 @@ int ops_pushto_avp (struct sip_msg* msg, struct fis_param* dst,
 				/* if is not the first modification, push the current uri as
 				 * branch */
 			    if (append_branch( msg, 0, 0, 0, Q_UNSPECIFIED,
-					       0, 0, 0, 0) != 1)
+					       0, 0, 0, 0, 0, 0) != 1)
 				{
 					LM_ERR("append_branch action failed\n");
 					goto error;
@@ -1026,7 +1027,7 @@ int ops_pushto_avp (struct sip_msg* msg, struct fis_param* dst,
 			ruri_mark_new(); /* re-use uri for serial forking */
 		} else if (dst->opd&AVPOPS_USE_BRANCH) {
 			if (append_branch( msg, &val, 0, 0, Q_UNSPECIFIED, 0,
-					   msg->force_send_socket, 0, 0) != 1)
+					   msg->force_send_socket, 0, 0, 0, 0) != 1)
 			{
 				LM_ERR("append_branch action failed\n");
 				goto error;
@@ -1051,14 +1052,108 @@ error:
 	return -1;
 }
 
+int get_xavp(struct sip_msg *msg, pv_xavp_name_t *xname,
+		sr_xavp_t **avp, int *flag)
+{
+	int idxf = 0;
+	int idx = 0;
+	int count;
+
+	if(xname==NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+
+	if(xname->index.type==PVT_EXTRA)
+	{
+		/* get the index */
+		if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0)
+		{
+			LM_ERR("invalid index\n");
+			return -1;
+		}
+		LM_DBG("key1 idx:%d idxf:%d\n", idx, idxf);
+		if(idxf==PV_IDX_ALL)
+			LM_ERR("idx:* at first key not implemented. Using idx:0\n");
+	}
+	/* fix the index */
+	if(idx<0)
+	{
+		count = xavp_count(&xname->name, NULL);
+		idx = count + idx;
+	}
+	*avp = xavp_get_by_index(&xname->name, idx, NULL);
+	if(*avp==NULL)
+		return -1;
+	if(xname->next==NULL)
+		return 0;
+
+	idx = 0;
+	idxf = 0;
+	if(xname->next->index.type==PVT_EXTRA)
+	{
+		/* get the index */
+		if(pv_get_spec_index(msg, &xname->next->index.pvp, &idx, &idxf)!=0)
+		{
+			LM_ERR("invalid index\n");
+			return -1;
+		}
+		LM_DBG("key2 idx:%d idxf:%d\n", idx, idxf);
+		*flag=idxf;
+	}
+	/* fix the index */
+	if(idx<0)
+	{
+		count = xavp_count(&xname->next->name, &(*avp)->val.v.xavp);
+		idx = count + idx;
+	}
+	*avp = xavp_get_by_index(&xname->next->name, idx, &(*avp)->val.v.xavp);
+	if(*avp==NULL)
+		return -1;
+	return 1;
+}
+
+int get_xavp_param(struct sip_msg* msg, pv_spec_p spec, sr_xavp_t **xavp,
+	int *flag)
+{
+	int res;
+	pv_xavp_name_t *xname = (pv_xavp_name_t*)spec->pvp.pvn.u.dname;
+	res = get_xavp(msg, xname, xavp, flag);
+	if(res<=0)
+	{
+		if(res==0)
+			LM_ERR("xavp has to have key2\n");
+		LM_DBG("no dst xavp found\n");
+		goto error;
+	}
+	return 1;
+error:
+	return -1;
+}
+
+int set_val_xavp(sr_xavp_t *xavp, int_str *avp_val, int *flag)
+{
+	if(xavp->val.type!=SR_XTYPE_INT&&xavp->val.type!=SR_XTYPE_STR)
+		return -1;
+	if(xavp->val.type==SR_XTYPE_INT)
+	{
+		avp_val->n = xavp->val.v.i;
+	} else {
+		*flag = AVP_VAL_STR;
+		avp_val->s = xavp->val.v.s;
+	}
+	return 1;
+}
+
 int ops_check_avp( struct sip_msg* msg, struct fis_param* src,
 													struct fis_param* val)
 {
 	struct search_state st1, st2;
 	unsigned short    name_type1;
 	unsigned short    name_type2;
-	struct usr_avp    *avp1;
-	struct usr_avp    *avp2;
+	struct usr_avp    *avp1 = NULL;
+	struct usr_avp    *avp2 = NULL;
 	regmatch_t        pmatch;
 	int_str           avp_name1;
 	int_str           avp_name2;
@@ -1069,9 +1164,15 @@ int ops_check_avp( struct sip_msg* msg, struct fis_param* src,
 	int            flags;
 	pv_value_t     xvalue;
 	char           backup;
+	regex_t	       re_temp;
+	regex_t	       *re;
+	sr_xavp_t         *xavp1 = NULL; // first parameter
+	sr_xavp_t         *xavp2 = NULL; // second parameter
+	int               xavp1_flags=0;
+	int               xavp2_flags=0;
 
 	/* look if the required avp(s) is/are present */
-	if(src->u.sval.type==PVT_AVP)
+	if(src->u.sval->type==PVT_AVP)
 	{
 		/* search for the avp */
 		if(avpops_get_aname(msg, src, &avp_name1, &name_type1)!=0)
@@ -1086,10 +1187,23 @@ int ops_check_avp( struct sip_msg* msg, struct fis_param* src,
 			goto error;
 		}
 		flags = avp1->flags;
+	} else if(src->u.sval->type==PVT_XAVP)
+	{
+		avp1 = 0;
+		flags = 0;
+		LM_DBG("xavp1 found!");
+		/* search for the xavp */
+		if(get_xavp_param(msg, src->u.sval, &xavp1, &xavp1_flags)<0)
+			goto error;
+		if(set_val_xavp(xavp1, &avp_val, &flags)<0)
+		{
+			LM_ERR("src value is not INT or STR\n");
+			goto next;
+		}
 	} else {
 		avp1 = 0;
 		flags = 0;
-		if(pv_get_spec_value(msg, &(src->u.sval), &xvalue)!=0)
+		if(pv_get_spec_value(msg, src->u.sval, &xvalue)!=0)
 		{
 			LM_ERR("cannot get src value\n");
 			goto error;
@@ -1121,7 +1235,7 @@ cycle1:
 	{
 		/* the 2nd operator is variable -> get avp value */
 		check_flags = 0;
-		if(val->u.sval.type==PVT_AVP)
+		if(val->u.sval->type==PVT_AVP)
 		{
 			/* search for the avp */
 			if(avpops_get_aname(msg, val, &avp_name2, &name_type2)!=0)
@@ -1136,9 +1250,19 @@ cycle1:
 				goto error;
 			}
 			check_flags = avp2->flags;
+		}
+		else if(val->u.sval->type==PVT_XAVP)
+		{
+			if(xavp2==NULL)
+				if(get_xavp_param(msg, val->u.sval, &xavp2, &xavp2_flags)<0)
+					goto error;
+			if(set_val_xavp(xavp2, &check_val, &check_flags)<0)
+			{
+				LM_ERR("dst value is not INT or STR\n");
+				goto next;
+			}
 		} else {
-			avp2 = 0;
-			if(pv_get_spec_value(msg, &(val->u.sval), &xvalue)!=0)
+			if(pv_get_spec_value(msg, val->u.sval, &xvalue)!=0)
 			{
 				LM_ERR("cannot get dst value\n");
 				goto error;
@@ -1160,7 +1284,6 @@ cycle1:
 			check_val.s = val->u.s;
 			check_flags = AVP_VAL_STR;
 		}
-		avp2 = 0;
 	}
 
 cycle2:
@@ -1228,14 +1351,24 @@ cycle2:
 			if (strncasecmp(avp_val.s.s,check_val.s.s,n)>=0)
 				return 1;
 		} else if (val->ops&AVPOPS_OP_RE) {
+			if (val->opd&AVPOPS_VAL_PVAR) {
+				LM_DBG("compiling regexp <%.*s>\n", check_val.s.len, check_val.s.s);
+				if (regcomp(&re_temp, check_val.s.s,REG_EXTENDED|REG_ICASE|REG_NEWLINE))
+				{
+					LM_ERR("bad re <%.*s>\n", check_val.s.len, check_val.s.s);
+					goto next;
+				}
+				re = &re_temp;
+			}
+			else re = (regex_t*)check_val.s.s;
 			backup  = avp_val.s.s[avp_val.s.len];
 			avp_val.s.s[avp_val.s.len] = '\0';
-			if (regexec((regex_t*)check_val.s.s, avp_val.s.s, 1, &pmatch,0)==0)
-			{
-				avp_val.s.s[avp_val.s.len] = backup;
-				return 1;
+			rt=regexec(re, avp_val.s.s, 1, &pmatch,0);
+			if (val->opd&AVPOPS_VAL_PVAR) {
+				regfree(re);
 			}
 			avp_val.s.s[avp_val.s.len] = backup;
+			if (rt==0) return 1;
 		} else if (val->ops&AVPOPS_OP_FM){
 			backup  = avp_val.s.s[avp_val.s.len];
 			avp_val.s.s[avp_val.s.len] = '\0';
@@ -1296,6 +1429,11 @@ next:
 	{
 		check_flags = avp2->flags;
 		goto cycle2;
+	} else if ((xavp2!=NULL) && (xavp2_flags&PV_IDX_ALL)
+		&& (xavp2=xavp_get_next(xavp2))!=NULL)
+	{
+		LM_DBG("xavp2->next\n");
+		goto cycle1;
 	/* cycle for the first value -> next avp */
 	} else {
 		if(avp1 && val->ops&AVPOPS_FLAG_ALL)
@@ -1304,6 +1442,21 @@ next:
 			if (avp1)
 				goto cycle1;
 		}
+		else if((xavp1!=NULL) && (xavp1_flags&PV_IDX_ALL))
+		{
+			xavp1=xavp_get_next(xavp1);
+			if (xavp1!=NULL)
+			{
+				LM_DBG("xavp1->next\n");
+				xavp2 = NULL;
+				if(set_val_xavp(xavp1, &avp_val, &flags)<0)
+				{
+					LM_ERR("src value is not INT or STR\n");
+					goto next;
+				}
+				goto cycle1;
+			}
+		}
 	}
 
 	LM_DBG("no match\n");
@@ -1526,7 +1679,7 @@ cycle1:
 	if (val->opd&AVPOPS_VAL_PVAR)
 	{
 		/* the 2nd operator is variable -> get value */
-		if(val->u.sval.type==PVT_AVP)
+		if(val->u.sval->type==PVT_AVP)
 		{
 			/* search for the avp */
 			if(avpops_get_aname(msg, val, &avp_name2, &name_type2)!=0)
@@ -1548,7 +1701,7 @@ cycle1:
 			}
 		} else {
 			avp2 = 0;
-			if(pv_get_spec_value(msg, &(val->u.sval), &xvalue)!=0)
+			if(pv_get_spec_value(msg, val->u.sval, &xvalue)!=0)
 			{
 				LM_ERR("cannot get dst value\n");
 				goto error;
@@ -1668,7 +1821,7 @@ int ops_is_avp_set(struct sip_msg* msg, struct fis_param *ap)
 	}
 
 	/* get avp index */
-	if(pv_get_spec_index(msg, &ap->u.sval.pvp, &index, &findex)!=0)
+	if(pv_get_spec_index(msg, &ap->u.sval->pvp, &index, &findex)!=0)
 	{
 		LM_ERR("failed to get AVP index\n");
 		return -1;
diff --git a/modules/avpops/avpops_impl.h b/modules/avpops/avpops_impl.h
index 6e38007..9e55222 100644
--- a/modules/avpops/avpops_impl.h
+++ b/modules/avpops/avpops_impl.h
@@ -104,7 +104,7 @@ struct fis_param
 	int     opd;       /* operand flags */
 	int     type;
 	union {
-		pv_spec_t sval;    /* values int or str */
+		pv_spec_t *sval;    /* values int or str */
 		int n;
 		str s;
 	} u;
diff --git a/modules/avpops/avpops_parse.c b/modules/avpops/avpops_parse.c
index 47bb984..3a16f18 100644
--- a/modules/avpops/avpops_parse.c
+++ b/modules/avpops/avpops_parse.c
@@ -69,7 +69,8 @@ struct fis_param *avpops_parse_pvar(char *in)
 	}
 	memset( ap, 0, sizeof(struct fis_param));
 	s.s = in; s.len = strlen(s.s);
-	if(pv_parse_spec(&s, &ap->u.sval)==0)
+	ap->u.sval = pv_cache_get(&s);
+	if(ap->u.sval==NULL)
 	{
 		pkg_free(ap);
 		return NULL;
@@ -87,7 +88,6 @@ int parse_avp_db(char *s, struct db_param *dbp, int allow_scheme)
 	str   tmp;
 	str   s0;
 	char  have_scheme;
-	char *p;
 	char *p0;
 	unsigned int flags;
 
@@ -129,12 +129,12 @@ int parse_avp_db(char *s, struct db_param *dbp, int allow_scheme)
 				goto error;
 			}
 		}
-		dbp->a.u.sval.pvp.pvn.u.isname.type |= (flags<<8)&0xff00;
+		dbp->a.u.sval->pvp.pvn.u.isname.type |= (flags<<8)&0xff00;
 		dbp->a.type = AVPOPS_VAL_NONE;
 	} else {
 		s0.s = s; s0.len = strlen(s0.s);
-		p = pv_parse_spec(&s0, &dbp->a.u.sval);
-		if (p==0 || *p!='\0' || dbp->a.u.sval.type!=PVT_AVP)
+		dbp->a.u.sval = pv_cache_get(&s0);
+		if (dbp->a.u.sval==0 || dbp->a.u.sval->type!=PVT_AVP)
 		{
 			LM_ERR("bad param - expected : $avp(name) or int/str value\n");
 			return E_UNSPEC;
@@ -147,22 +147,22 @@ int parse_avp_db(char *s, struct db_param *dbp, int allow_scheme)
 	if (dbp->a.type == AVPOPS_VAL_PVAR)
 	{
 		dbp->a.opd = AVPOPS_VAL_PVAR;
-		if(pv_has_sname(&dbp->a.u.sval))
+		if(pv_has_sname(dbp->a.u.sval))
 		{
 			dbp->sa.s=(char*)pkg_malloc(
-					dbp->a.u.sval.pvp.pvn.u.isname.name.s.len+1);
+					dbp->a.u.sval->pvp.pvn.u.isname.name.s.len+1);
 			if (dbp->sa.s==0)
 			{
 				LM_ERR("no more pkg mem\n");
 				goto error;
 			}
-			memcpy(dbp->sa.s, dbp->a.u.sval.pvp.pvn.u.isname.name.s.s,
-					dbp->a.u.sval.pvp.pvn.u.isname.name.s.len);
-			dbp->sa.len = dbp->a.u.sval.pvp.pvn.u.isname.name.s.len;
+			memcpy(dbp->sa.s, dbp->a.u.sval->pvp.pvn.u.isname.name.s.s,
+					dbp->a.u.sval->pvp.pvn.u.isname.name.s.len);
+			dbp->sa.len = dbp->a.u.sval->pvp.pvn.u.isname.name.s.len;
 			dbp->sa.s[dbp->sa.len] = 0;
 			dbp->a.opd = AVPOPS_VAL_PVAR|AVPOPS_VAL_STR;
-		} else if(pv_has_iname(&dbp->a.u.sval)) {
-			ul = (unsigned long)dbp->a.u.sval.pvp.pvn.u.isname.name.n;
+		} else if(pv_has_iname(dbp->a.u.sval)) {
+			ul = (unsigned long)dbp->a.u.sval->pvp.pvn.u.isname.name.n;
 			tmp.s = int2str( ul, &(tmp.len) );
 			dbp->sa.s = (char*)pkg_malloc( tmp.len + 1 );
 			if (dbp->sa.s==0)
@@ -514,7 +514,7 @@ struct fis_param* parse_check_value(char *s)
 			LM_ERR("unable to get pseudo-variable\n");
 			goto error;
 		}
-		if (vp->u.sval.type==PVT_NULL)
+		if (vp->u.sval->type==PVT_NULL)
 		{
 			LM_ERR("bad param; expected : $pseudo-variable or int/str value\n");
 			goto error;
@@ -620,7 +620,7 @@ struct fis_param* parse_op_value(char *s)
 			LM_ERR("unable to get pseudo-variable\n");
 			goto error;
 		}
-		if (vp->u.sval.type==PVT_NULL)
+		if (vp->u.sval->type==PVT_NULL)
 		{
 			LM_ERR("bad param; expected : $pseudo-variable or int/str value\n");
 			goto error;
diff --git a/modules/avpops/doc/avpops_admin.xml b/modules/avpops/doc/avpops_admin.xml
index dc3ab0c..482bb89 100644
--- a/modules/avpops/doc/avpops_admin.xml
+++ b/modules/avpops/doc/avpops_admin.xml
@@ -29,6 +29,11 @@
 		testing/checking the value of an AVP.
 		</para>
 		<para>
+		If you just need a way to execute SQL statements in a
+		&kamailio; configuration script, please consider use the
+		<emphasis>sqlops</emphasis> module instead.
+		</para>
+		<para>
 		AVPs are persistent per SIP transaction, being available in "route", 
 		"branch_route" and "failure_route". A tutorial providing more information (detailed
 		explanations and commented examples) can be found on the SIP-router web site.
@@ -132,7 +137,7 @@ $avp(i3:123) - the AVP identified by the integer 123 which has script flags 1
 	</section>
 	<section>
 		<title>Parameters</title>
-		<section>
+		<section id="avpops.p.db_url">
 			<title><varname>db_url</varname> (string)</title>
 			<para>
 			DB URL for database connection.
@@ -151,7 +156,7 @@ modparam("avpops","db_url","mysql://user:passwd@host/database")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.avp_table">
 			<title><varname>avp_table</varname> (string)</title>
 			<para>
 			DB table to be used.
@@ -171,7 +176,7 @@ modparam("avpops","avp_table","avptable")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.use_domain">
 			<title><varname>use_domain</varname> (integer)</title>
 			<para>
 				If the domain part of the URI should be used for 
@@ -191,7 +196,7 @@ modparam("avpops","use_domain",1)
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.uuid_column">
 			<title><varname>uuid_column</varname> (string)</title>
 			<para>
 				Name of column containing the uuid (unique user id).
@@ -209,7 +214,7 @@ modparam("avpops","uuid_column","uuid")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.username_column">
 			<title><varname>username_column</varname> (string)</title>
 			<para>
 				Name of column containing the username.
@@ -227,7 +232,7 @@ modparam("avpops","username_column","username")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.domain_column">
 			<title><varname>domain_column</varname> (string)</title>
 			<para>
 				Name of column containing the domain name.
@@ -245,7 +250,7 @@ modparam("avpops","domain_column","domain")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.attribute_column">
 			<title><varname>attribute_column</varname> (string)</title>
 			<para>
 				Name of column containing the attribute name (AVP name).
@@ -264,7 +269,7 @@ modparam("avpops","attribute_column","attribute")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.value_column">
 			<title><varname>value_column</varname> (string)</title>
 			<para>
 				Name of column containing the AVP value.
@@ -283,7 +288,7 @@ modparam("avpops","value_column","value")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.type_column">
 			<title><varname>type_column</varname> (string)</title>
 			<para>
 				Name of integer column containing the AVP type.
@@ -320,7 +325,7 @@ modparam("avpops","type_column","type")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.p.db_scheme">
 			<title><varname>db_scheme</varname> (string)</title>
 			<para>
 				Definition of a DB scheme to be used for non-standard
@@ -370,7 +375,7 @@ modparam("avpops","db_scheme",
 
 	<section>
 		<title>Functions</title>
-		<section>
+		<section id="avpops.f.avp_db_load">
 			<title>
 				<function moreinfo="none">avp_db_load(source,name)
 				</function>
@@ -440,7 +445,7 @@ avp_db_load("$ru","$avp(i1:123)/$some_scheme");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_db_store">
 			<title>
 				<function moreinfo="none">avp_db_store(source,name)</function>
 			</title>
@@ -467,7 +472,7 @@ avp_db_store("$ru/username","$avp(email)");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_db_delete">
 			<title>
 				<function moreinfo="none">avp_db_delete(source,name)</function>
 			</title>
@@ -494,12 +499,14 @@ avp_db_delete("$uuid","$avp(s:404fwd)/fwd_table");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_db_query">
 			<title>
 				<function moreinfo="none">avp_db_query(query[,dest])</function>
 			</title>
 			<para>
 			Make a database query and store the result in AVPs.
+			This command is deprecated, please use the more
+			flexible and advanced <emphasis>sqlops</emphasis> module instead.
 			</para>
 			<para>
 			The meaning and usage of the parameters:
@@ -560,7 +567,7 @@ avp_db_query("delete from subscriber");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_delete">
 			<title>
 				<function moreinfo="none">avp_delete(name)
 				</function>
@@ -605,7 +612,7 @@ avp_delete("a3");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_pushto">
 			<title>
 				<function moreinfo="none">avp_pushto(destination,name)
 				</function>
@@ -671,7 +678,7 @@ avp_pushto("$br","$avp(i:680)");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_check">
 			<title>
 				<function moreinfo="none">avp_check(name,op_value)
 				</function>
@@ -760,14 +767,29 @@ avp_pushto("$br","$avp(i:680)");
 ...
 avp_check("$avp(i:678)", "lt/i:345/g");
 avp_check("$fd","eq/$td/I");
-avp_check("$avp(s:foo)","gt/$avp($bar)/g");
+avp_check("$avp(s:foo)","gt/$avp($var(bar))/g");
 avp_check("$avp(s:foo)","re/sip:.*@bar.net/g");
 avp_check("$avp(s:foo)","fm/$avp(fm_avp)/g");
 ...
 				</programlisting>
+				<para>NOTE: you can use a xavp variable ($xavp(key1[indx1]=>key2[indx2]))
+				as first or second parameter.
+				If you want to check all the values of the key2 you should
+				use [*] at indx2. The [*] index is not allowed at indx1.
+				</para>
+				<programlisting format="linespecific">
+...
+avp_check("$xavp(op[0]=>lt[0])", "lt/i:345/g");
+avp_check("$xavp(op=>fd","eq/$td/I");
+avp_check("$xavp(op[1]=>foo[*])","gt/$avp($var(bar))/g");
+avp_check("$avp(s:foo)","re/$xavp(op[0]=>re[*]/g");
+$var(id)=2;
+avp_check("$xavp(op=>foo[*])","fm/$xavp(op=>fm[$var(id)])/g");
+...
+				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_copy">
 			<title>
 				<function moreinfo="none">avp_copy(old_name,new_name)
 				</function>
@@ -817,7 +839,7 @@ avp_copy("$avp(old)","$avp(new)/gd");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_printf">
 			<title>
 				<function moreinfo="none">avp_printf(dest, format)
 				</function>
@@ -866,7 +888,7 @@ avp_printf("$avp(i:20)", "This is a $rm request with call-id $hdr(call-id)");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_subst">
 			<title>
 				<function moreinfo="none">avp_subst(avps, subst)</function>
 			</title>
@@ -947,7 +969,7 @@ avp_subst("$avp(i:678)/$avp(i:679)/g", "/(.*)@(.*)/\1@$rd/");
 			processing will use it.
 			</para>
 		</section>
-		<section>
+		<section id="avpops.f.avp_op">
 			<title>
 				<function moreinfo="none">avp_op(name,op_value)
 				</function>
@@ -1024,7 +1046,7 @@ avp_op("$avp(number)","sub/$avp(number2)/d");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.is_avp_set">
 			<title>
 				<function moreinfo="none">is_avp_set(name)
 				</function>
@@ -1063,7 +1085,7 @@ if(is_avp_set("$avp(i:678)"))
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="avpops.f.avp_print">
 			<title>
 				<function moreinfo="none">avp_print()
 				</function>
diff --git a/modules/carrierroute/README b/modules/carrierroute/README
index d06b85c..67b230d 100644
--- a/modules/carrierroute/README
+++ b/modules/carrierroute/README
@@ -511,6 +511,11 @@ descavp)
    This is useful if you need some additional informations that belongs to
    each gw, like the destination or the number of channels.
 
+   The function pays special attention to the failurerouting cases, so
+   that any destination that has failed to provide a successful response
+   will not be reused in a subsequent call of cr_route. This situation can
+   appear when different route domains contain a set of common gateways.
+
    This function is only usable with rewrite_user and prefix_matching
    containing a valid string. This string needs to be numerical if the
    match_mode parameter is set to 10. It uses the standard CRC32 algorithm
@@ -1063,7 +1068,7 @@ Chapter 2. Module parameter for database access.
 
    URL to the database containing the data.
 
-   Default value is “mysql://openserro:openserro@localhost/openser”.
+   Default value is “mysql://kamailioro:kamailioro@localhost/kamailio”.
 
    Example 2.1. Set db_url parameter
 ...
diff --git a/modules/carrierroute/carrierroute.c b/modules/carrierroute/carrierroute.c
index 3200cb2..5aee64e 100644
--- a/modules/carrierroute/carrierroute.c
+++ b/modules/carrierroute/carrierroute.c
@@ -41,6 +41,7 @@
 #include "../../str.h"
 #include "../../mem/mem.h"
 #include "../../ut.h" /* for user2uid() */
+#include "../../rpc_lookup.h" /* for sercmd */
 #include "carrierroute.h"
 #include "cr_fixup.h"
 #include "cr_map.h"
@@ -51,6 +52,9 @@
 #include "config.h"
 #include <sys/stat.h>
 
+#define AVP_CR_URIS "_cr_uris"
+int_str cr_uris_avp; // contains all PSTN destinations
+
 MODULE_VERSION
 
 str carrierroute_db_url = str_init(DEFAULT_RODB_URL);
@@ -129,6 +133,8 @@ static mi_export_t mi_cmds[] = {
 	{ 0, 0, 0, 0, 0}
 };
 
+static rpc_export_t rpc_methods[];
+
 struct module_exports exports = {
 	"carrierroute",
 	DEFAULT_DLFLAGS, /* dlopen flags */
@@ -164,6 +170,11 @@ static int mod_init(void) {
 		return -1;
 	}
 
+	if(rpc_register_array(rpc_methods)!=0) {
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+
 	subscriber_table.len = strlen(subscriber_table.s);
 	subscriber_username_col.len = strlen(subscriber_username_col.s);
 	subscriber_domain_col.len = strlen(subscriber_domain_col.s);
@@ -241,6 +252,10 @@ static int mod_init(void) {
 	if(mode == CARRIERROUTE_MODE_DB){
 		carrierroute_db_close();
 	}
+
+	cr_uris_avp.s.s = AVP_CR_URIS;
+	cr_uris_avp.s.len = sizeof(AVP_CR_URIS) -1;
+
 	return 0;
 }
 
@@ -263,10 +278,37 @@ static int mi_child_init(void) {
 	return 0;
 }
 
-
 static void mod_destroy(void) {
 	if(mode == CARRIERROUTE_MODE_DB){
 		carrierroute_db_close();
 	}
 	destroy_route_data();
 }
+
+static const char *rpc_cr_reload_routes_doc[2] = {
+	"Reload routes", 0
+};
+
+static void rpc_cr_reload_routes(rpc_t *rpc, void *c) {
+
+	if(mode == CARRIERROUTE_MODE_DB){
+		if (carrierroute_dbh==NULL) {
+			carrierroute_dbh = carrierroute_dbf.init(&carrierroute_db_url);
+			if(carrierroute_dbh==0 ) {
+				LM_ERR("cannot initialize database connection\n");
+				return;
+			}
+		}
+	}
+
+	if ( (reload_route_data())!=0 ) {
+		LM_ERR("failed to load routing data\n");
+		return;
+	}
+}
+
+static rpc_export_t rpc_methods[] = {
+	{ "cr.reload_routes",  rpc_cr_reload_routes, rpc_cr_reload_routes_doc, 0},
+	{0, 0, 0, 0}
+};
+
diff --git a/modules/carrierroute/carrierroute.h b/modules/carrierroute/carrierroute.h
index adfedf0..53b6810 100644
--- a/modules/carrierroute/carrierroute.h
+++ b/modules/carrierroute/carrierroute.h
@@ -31,6 +31,7 @@
 #define CARRIERROUTE_H
 
 #include "../../str.h"
+#include "../../usr_avp.h"
 
 #define DICE_MAX 1000
 
@@ -53,4 +54,6 @@ extern const str CR_EMPTY_PREFIX;
 extern int mode;
 extern int cr_match_mode;
 
+extern int_str cr_uris_avp;
+
 #endif
diff --git a/modules/carrierroute/cr_func.c b/modules/carrierroute/cr_func.c
index 3cda514..cc31a1a 100644
--- a/modules/carrierroute/cr_func.c
+++ b/modules/carrierroute/cr_func.c
@@ -49,6 +49,8 @@
 #include "carrierroute.h"
 #include "config.h"
 
+#define MAX_DESTINATIONS 64
+
 enum hash_algorithm {
 	alg_crc32 = 1, /*!< hashing algorithm is CRC32 */
 	alg_crc32_nofallback, /*!< same algorithm as alg_crc32, with only a backup rule, but no fallback tree is chosen
@@ -269,6 +271,65 @@ static struct route_rule * get_rule_by_hash(const struct route_flags * rf,
 	return act_hash;
 }
 
+// debug functions for cr_uri_avp
+/*
+static void print_cr_uri_avp(){
+	struct search_state st;
+	int_str val;
+	int elem = 0;
+
+	if (!search_first_avp( AVP_VAL_STR | AVP_NAME_STR, cr_uris_avp, &val, &st)) {
+		LM_DBG("no AVPs - we are done!\n");
+		return;
+	}
+
+	LM_DBG("	cr_uri_avp[%d]=%.*s\n", elem++, val.s.len, val.s.s);
+
+	while (  search_next_avp(&st, &val) ) {
+		LM_DBG("	cr_uri_avp[%d]=%.*s\n", elem++, val.s.len, val.s.s);
+	}
+}
+*/
+
+static void build_used_uris_list(avp_value_t* used_dests, int* no_dests){
+	struct search_state st;
+	int_str val;
+	*no_dests = 0;
+
+	if (!search_first_avp( AVP_VAL_STR | AVP_NAME_STR, cr_uris_avp, &val, &st)) {
+		//LM_DBG("no AVPs - we are done!\n");
+		return;
+	}
+
+	used_dests[(*no_dests)++] = val;
+	//LM_DBG("	used_dests[%d]=%.*s \n", (*no_dests)-1, used_dests[(*no_dests)-1].s.len, used_dests[(*no_dests)-1].s.s);
+
+	while ( search_next_avp(&st, &val) ) {
+		if ( MAX_DESTINATIONS == *no_dests ) {
+			LM_ERR("Too many  AVPs - we are done!\n");
+			return;
+		}
+		used_dests[(*no_dests)++] = val;
+		//LM_DBG("	used_dests[%d]=%.*s \n", (*no_dests)-1, used_dests[(*no_dests)-1].s.len, used_dests[(*no_dests)-1].s.s);
+	}
+
+	//LM_DBG("sucessfully built used_uris list!\n");
+}
+
+int cr_uri_already_used(str dest , avp_value_t* used_dests, int no_dests){
+	int i;
+	for (i=0; i<no_dests; i++){
+		if ( (dest.len == used_dests[i].s.len) &&
+				(memcmp(dest.s, used_dests[i].s.s, dest.len)==0)){
+			LM_NOTICE("Candidate destination <%.*s> was previously used.\n", dest.len, dest.s);
+			return 1;
+		}
+
+	}
+	//LM_DBG("cr_uri_already_used: Candidate destination <%.*s> was NEVER USED.\n", dest.len, dest.s);
+	return 0;
+}
+
 
 /**
  * does the work for rewrite_on_rule, writes the new URI into dest
@@ -288,7 +349,6 @@ static int actually_rewrite(const struct route_rule *rs, str *dest,
 	char *p;
 	int_str avp_val;
 	int strip = 0;
-
 	str l_user;
 	
 	if( !rs || !dest || !msg || !user) {
@@ -406,6 +466,11 @@ static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest
 
 	switch (alg) {
 		case alg_crc32:
+		{
+			static avp_value_t used_dests[MAX_DESTINATIONS];
+			static int no_dests = 0;
+			avp_value_t cr_new_uri;
+
 			if(rf->dice_max == 0) {
 				LM_ERR("invalid dice_max value\n");
 				return -1;
@@ -414,15 +479,48 @@ static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest
 				LM_ERR("could not hash message with CRC32");
 				return -1;
 			}
+
 			/* This auto-magically takes the last rule if anything is broken.
 			 * Sometimes the hash result is zero. If the first rule is off
 			 * (has a probablility of zero) then it has also a dice_to of
 			 * zero and the message could not be routed at all if we use
 			 * '<' here. Thus the '<=' is necessary.
+			 *
+			 * cr_uri_already_used is a function that checks that the selected
+			 * rule has not been previously used as a failed destinatin
 			 */
+
 			for (rr = rf->rule_list;
-			        rr->next != NULL && rr->dice_to <= prob;
-		        rr = rr->next) {}
+				rr->next!= NULL && rr->dice_to <= prob ; rr = rr->next) {}
+
+			//LM_DBG("CR: candidate hashed destination is: <%.*s>\n", rr->host.len, rr->host.s);
+
+			if (is_route_type(FAILURE_ROUTE) && (mode == CARRIERROUTE_MODE_DB) ){
+				build_used_uris_list(used_dests, &no_dests);
+
+				if (cr_uri_already_used(rr->host, used_dests, no_dests) ) {
+					//LM_DBG("CR: selecting new destination !!! \n");
+					for (rr = rf->rule_list;
+								rr!= NULL && cr_uri_already_used(rr->host, used_dests, no_dests); rr = rr->next) {}
+					/* are there any destinations that were not already used? */
+					if (rr == NULL) {
+						LM_NOTICE("All gateways from this group were already used\n");
+						return -1;
+					}
+
+					/* this is a hack: we do not take probabilities into consideration if first destination
+					 * was previously tried */
+
+					do {
+						int rule_no = rand() % rf->rule_num;
+						//LM_DBG("CR: trying rule_no=%d \n", rule_no);
+						for (rr = rf->rule_list; (rule_no > 0) && (rr->next!=NULL) ; rule_no-- , rr = rr->next) {}
+					} while (cr_uri_already_used(rr->host, used_dests, no_dests));
+					LM_DBG("CR: candidate selected destination is: <%.*s>\n", rr->host.len, rr->host.s);
+				}
+			}
+			/*This should be regarded as an ELSE branch for the if above
+			 * ( status exists for mode == CARRIERROUTE_MODE_FILE */
 			if (!rr->status) {
 				if (!rr->backup) {
 					LM_ERR("all routes are off\n");
@@ -435,7 +533,24 @@ static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest
 					rr = rr->backup->rr;
 				}
 			}
+
+			//LM_DBG("CR: destination is: <%.*s>\n", rr->host.len, rr->host.s);
+			cr_new_uri.s = rr->host;
+			/* insert used destination into avp, in case corresponding request fails and
+			 * another destination has to be used; this new destination must not be one
+			 * that failed before
+			 */
+
+			if (mode == CARRIERROUTE_MODE_DB){
+				if ( add_avp( AVP_VAL_STR | AVP_NAME_STR, cr_uris_avp, cr_new_uri) < 0){
+					LM_ERR("set AVP failed\n");
+					return -1;
+				}
+				//print_cr_uri_avp();
+			}
+
 			break;
+		}
 		case alg_crc32_nofallback:
 			if ((prob = (hash_func(msg, hash_source, rf->max_targets))) < 0) {
 				LM_ERR("could not hash message with CRC32");
diff --git a/modules/carrierroute/doc/carrierroute_admin.xml b/modules/carrierroute/doc/carrierroute_admin.xml
index 978ed8f..11c1b6a 100644
--- a/modules/carrierroute/doc/carrierroute_admin.xml
+++ b/modules/carrierroute/doc/carrierroute_admin.xml
@@ -427,7 +427,13 @@ cr_tree_rewrite_uri(tree, domain)
         is stored in an AVP). This is useful if you need some additional
         informations that belongs to each gw, like the destination or the
         number of channels.
-        </para>
+		</para>
+		<para>
+		The function pays special attention to the failurerouting cases, so that
+		any destination that has failed to provide a successful response will not
+		be reused in a subsequent call of cr_route. This situation can appear when
+		different route domains contain a set of common gateways.
+		</para>
         <para>
         This function is only usable with rewrite_user and prefix_matching
         containing a valid string. This string needs to be numerical if the match_mode
diff --git a/modules/cdp/acctstatemachine.c b/modules/cdp/acctstatemachine.c
new file mode 100644
index 0000000..8537d0d
--- /dev/null
+++ b/modules/cdp/acctstatemachine.c
@@ -0,0 +1,254 @@
+/*
+ * acctstatemachine.c
+ *
+ *  Created on: 03 Apr 2013
+ *      Author: jaybeepee
+ */
+
+#include "acctstatemachine.h"
+#include "diameter_ims.h"
+#include "common.h"
+
+/**
+ * update Granted Service Unit timers based on CCR
+ */
+inline void update_gsu_request_timers(cdp_cc_acc_session_t* session, AAAMessage* msg) {
+	AAA_AVP *avp;
+
+	avp = AAAFindMatchingAVP(msg, 0, AVP_Event_Timestamp, 0, 0);
+	if (avp && avp->data.len == 4) {
+		session->last_reservation_request_time = ntohl(*((uint32_t*)avp->data.s))-EPOCH_UNIX_TO_EPOCH_NTP;
+	}
+}
+
+/**
+ * update Granted Service Unit timers based on CCA, for onw we assume on one MSCC per session and only TIME based supported
+ */
+inline void update_gsu_response_timers(cdp_cc_acc_session_t* session, AAAMessage* msg) {
+	AAA_AVP *avp;
+	AAA_AVP_LIST mscc_avp_list;
+	AAA_AVP_LIST y;
+	AAA_AVP *z;
+
+	avp = AAAFindMatchingAVP(msg, 0, AVP_Multiple_Services_Credit_Control, 0, 0);
+	mscc_avp_list = AAAUngroupAVPS(avp->data);
+	AAA_AVP *mscc_avp = mscc_avp_list.head;
+
+	while (mscc_avp != NULL ) {
+		LM_DBG("MSCC AVP code is [%i] and data length is [%i]", mscc_avp->code, mscc_avp->data.len);
+		switch (mscc_avp->code) {
+			case AVP_Granted_Service_Unit:
+				y = AAAUngroupAVPS(mscc_avp->data);
+				z = y.head;
+				while (z) {
+					switch (z->code) {
+					case AVP_CC_Time:
+						session->reserved_units = get_4bytes(z->data.s);
+						break;
+					default:
+						LM_DBG("ignoring AVP in GSU group with code:[%d]\n", z->code);
+					}
+					z = z->next;
+				}
+				break;
+			case AVP_Validity_Time:
+				session->reserved_units_validity_time = get_4bytes(mscc_avp->data.s);
+				break;
+			case AVP_Final_Unit_Indication:
+				y = AAAUngroupAVPS(mscc_avp->data);
+				z = y.head;
+				while (z) {
+					switch (z->code) {
+						case AVP_Final_Unit_Action:
+							session->fua = get_4bytes(z->data.s);
+							break;
+						default:
+							LM_DBG("ignoring AVP in FUI group with code:[%d]\n", z->code);
+					}
+					z = z->next;
+				}
+				break;
+		}
+		mscc_avp = mscc_avp->next;
+	}
+
+	AAAFreeAVPList(&mscc_avp_list);
+	AAAFreeAVPList(&y);
+}
+
+
+/**
+ * stateful client state machine
+ * \Note - should be called with a lock on the session and will unlock it - do not use it after!
+ * @param cc_acc - AAACCAccSession which uses this state machine
+ * @param ev   - Event
+ * @param msg  - AAAMessage
+ * @returns 0 if msg should be given to the upper layer 1 if not
+ */
+inline int cc_acc_client_stateful_sm_process(cdp_session_t* s, int event, AAAMessage* msg)
+{
+	cdp_cc_acc_session_t* x;
+	int ret = 0;
+	int rc;		//return code for responses
+	int record_type;
+
+	x = &(s->u.cc_acc);
+	LM_DBG("cc_acc_client_stateful_sm_process: processing CC App in state [%d] and event [%d]\n", x->state, event);
+
+	//first run session callbacks
+	if (s->cb) (s->cb)(event, s);
+	LM_DBG("finished callback of event %i\n", event);
+
+	switch (x->state) {
+		case ACC_CC_ST_IDLE:
+			switch (event) {
+				case ACC_CC_EV_SEND_REQ:		//were sending a message - CCR
+					//assert this is an initial request. we can't move from IDLE with anything else
+					record_type = get_accounting_record_type(msg);
+					switch (record_type) {
+						case 2 /*START RECORD*/:
+							LM_DBG("sending CCR START record on session\n");
+							s->application_id = msg->applicationId;
+							s->u.cc_acc.state = ACC_CC_ST_PENDING_I;
+							//update our reservation and its timers... if they exist in CCR
+							update_gsu_request_timers(x, msg);
+							break;
+						default:
+							LM_ERR("Sending CCR with no/incorrect accounting record type AVP. In state IDLE\n");
+							break;
+					}
+					break;
+
+				default:
+					LM_ERR("Recevied unknown event [%d] in state [%d]\n", event, x->state);
+					break;
+			}
+			break;
+		case ACC_CC_ST_OPEN:
+			switch (event) {
+				case ACC_CC_EV_SEND_REQ:		//were sending a message - CCR
+					//make sure it is either an update or a termination.
+					record_type = get_accounting_record_type(msg);
+					switch (record_type) {
+						case 3 /*UPDATE RECORD*/:
+							LM_DBG("sending CCR UPDATE record on session\n");
+							s->u.cc_acc.state = ACC_CC_ST_PENDING_U;
+							//update our reservation and its timers...
+							update_gsu_request_timers(x, msg);
+							break;
+						case 4: /*TERMINATE RECORD*/
+							LM_DBG("sending CCR TERMINATE record on session\n");
+							s->u.cc_acc.state = ACC_CC_ST_PENDING_T;
+							//update our reservation and its timers...
+							update_gsu_request_timers(x, msg);
+							break;
+						default:
+							LM_ERR("asked to send CCR with no/incorrect accounting record type AVP. In state IDLE\n");
+							break;
+					}
+					break;
+				case ACC_CC_EV_RSVN_WARNING:
+					//nothing we can do here, we have sent callback, client needs to send CCR Update
+					LM_DBG("Reservation close to expiring\n");
+					break;
+				default:
+					LM_ERR("Received unknown event [%d] in state [%d]\n", event, x->state);
+					break;
+			}
+			break;
+		case ACC_CC_ST_PENDING_I:
+			if (event == ACC_CC_EV_RECV_ANS && msg && !is_req(msg)) {
+				rc = get_result_code(msg);
+				if (rc >= 2000 && rc < 3000) {
+					event = ACC_CC_EV_RECV_ANS_SUCCESS;
+				} else {
+					event = ACC_CC_EV_RECV_ANS_UNSUCCESS;
+				}
+			}
+			switch (event) {
+				case ACC_CC_EV_RECV_ANS_SUCCESS:
+					x->state = ACC_CC_ST_OPEN;
+					LM_DBG("received success response for CCR START\n");
+					update_gsu_response_timers(x, msg);
+					break;
+				case ACC_CC_EV_RECV_ANS_UNSUCCESS:
+					//TODO: grant/terminate service callbacks to callback clients
+					LM_ERR("failed answer on CCR START\n");
+					x->state = ACC_CC_ST_DISCON;
+					break;
+				default:
+					LM_ERR("Received unknown event [%d] in state [%d]\n", event, x->state);
+					break;
+			}
+			break;
+		case ACC_CC_ST_PENDING_T:
+			if (event == ACC_CC_EV_RECV_ANS && msg && !is_req(msg)) {
+				rc = get_result_code(msg);
+				if (rc >= 2000 && rc < 3000) {
+					event = ACC_CC_EV_RECV_ANS_SUCCESS;
+				} else {
+					event = ACC_CC_EV_RECV_ANS_UNSUCCESS;
+				}
+			}
+			switch (event) {
+				case ACC_CC_EV_RECV_ANS_SUCCESS:
+					x->state = ACC_CC_ST_DISCON;
+//					update_gsu_response_timers(x, msg);
+				case ACC_CC_EV_RECV_ANS_UNSUCCESS:
+					x->state = ACC_CC_ST_DISCON;
+				default:
+					LM_DBG("Received event [%d] in state [%d] - cleaning up session regardless\n", event, x->state);
+					//have to leave session alone because our client app still has to be given this msg
+					x->discon_time = time(0);
+//					if (msg) AAAFreeMessage(&msg);
+//					cdp_session_cleanup(s, NULL);
+//					s = 0;
+			}
+			break;
+		case ACC_CC_ST_PENDING_U:
+			if (event == ACC_CC_EV_RECV_ANS && msg && !is_req(msg)) {
+				rc = get_result_code(msg);
+				if (rc >= 2000 && rc < 3000) {
+					event = ACC_CC_EV_RECV_ANS_SUCCESS;
+				} else {
+					event = ACC_CC_EV_RECV_ANS_UNSUCCESS;
+				}
+			}
+			switch (event) {
+				case ACC_CC_EV_RECV_ANS_SUCCESS:
+					x->state = ACC_CC_ST_OPEN;
+					LM_DBG("success CCA for UPDATE\n");
+					update_gsu_response_timers(x, msg);
+					break;
+				case ACC_CC_EV_RECV_ANS_UNSUCCESS:
+					//TODO: check whether we grant or terminate service to callback clients
+					x->state = ACC_CC_ST_DISCON;
+					LM_ERR("update failed... going back to IDLE/DISCON\n");
+					break;
+				default:
+					LM_ERR("Received unknown event [%d] in state [%d]\n", event, x->state);
+				break;
+			}
+			break;
+		case ACC_CC_ST_DISCON:
+			switch (event) {
+				case ACC_CC_EV_SESSION_STALE:
+					LM_DBG("stale session about to be cleared\n");
+					cdp_session_cleanup(s, msg);
+					s = 0;
+					break;
+				default:
+					LM_ERR("Received unknown event [%d] in state [%d]\n", event, x->state);
+					break;
+			}
+			break;
+	}
+
+	if (s) {
+		AAASessionsUnlock(s->hash);
+	}
+
+	return ret;
+}
+
+
diff --git a/modules/cdp/acctstatemachine.h b/modules/cdp/acctstatemachine.h
new file mode 100644
index 0000000..129aaa8
--- /dev/null
+++ b/modules/cdp/acctstatemachine.h
@@ -0,0 +1,19 @@
+/*
+ * acctstatemachine.h
+ *
+ *  Created on: 03 Apr 2013
+ *      Author: jaybeepee
+ */
+
+#ifndef ACCTSTATEMACHINE_H_
+#define ACCTSTATEMACHINE_H_
+
+#include "diameter_api.h"
+#include "session.h"
+#include "config.h"
+
+#define EPOCH_UNIX_TO_EPOCH_NTP 2208988800u // according to http://www.cis.udel.edu/~mills/y2k.html
+
+inline int cc_acc_client_stateful_sm_process(cdp_session_t* cc_acc, int event, AAAMessage* msg);
+
+#endif /* ACCTSTATEMACHINE_H_ */
diff --git a/modules/cdp/authstatemachine.c b/modules/cdp/authstatemachine.c
index e23af4b..42e9397 100644
--- a/modules/cdp/authstatemachine.c
+++ b/modules/cdp/authstatemachine.c
@@ -53,45 +53,13 @@
 #include "peermanager.h"
 #include "routing.h"
 #include "receiver.h"
+#include "common.h"
 
 char *auth_states[] = {"Idle", "Pending", "Open", "Discon"};
 char *auth_events[] = {};
 
 extern dp_config *config; // because i want to use tc for the expire times...
 
-int get_result_code(AAAMessage* msg) {
-    AAA_AVP *avp;
-    AAA_AVP_LIST list;
-    list.head = 0;
-    list.tail = 0;
-    int rc = -1;
-
-    if (!msg) goto error;
-
-    for (avp = msg->avpList.tail; avp; avp = avp->prev) {
-
-        if (avp->code == AVP_Result_Code) {
-            rc = get_4bytes(avp->data.s);
-            goto finish;
-        } else if (avp->code == AVP_Experimental_Result) {
-            list = AAAUngroupAVPS(avp->data);
-            for (avp = list.head; avp; avp = avp->next) {
-                if (avp->code == AVP_IMS_Experimental_Result_Code) {
-                    rc = get_4bytes(avp->data.s);
-                    AAAFreeAVPList(&list);
-                    goto finish;
-                }
-            }
-            AAAFreeAVPList(&list);
-        }
-    }
-finish:
-    return rc;
-error:
-    LM_ERR("get_result_code(): no AAAMessage or Result Code not found\n");
-    return -1;
-}
-
 /*
  * Alberto Diez changes the default behaviour on error is going to be to return the default state
  * that is  STATE_MAINTAINED
@@ -282,7 +250,7 @@ inline int auth_client_statefull_sm_process(cdp_session_t* s, int event, AAAMess
                 case AUTH_EV_SESSION_TIMEOUT:
                 case AUTH_EV_SERVICE_TERMINATED:
                 case AUTH_EV_SESSION_GRACE_TIMEOUT:
-                    Session_Cleanup(s, NULL);
+                    cdp_session_cleanup(s, NULL);
                     break;
 
                 default:
@@ -381,7 +349,7 @@ inline int auth_client_statefull_sm_process(cdp_session_t* s, int event, AAAMess
                     if (msg) AAAFreeMessage(&msg); // if might be needed in frequency
                     // If I register a ResponseHandler then i Free the STA there not here..
                     // but i dont have interest in that now..
-                    Session_Cleanup(s, NULL);
+                    cdp_session_cleanup(s, NULL);
                     s = 0;
                     rv = 1;
                     break;
@@ -438,14 +406,14 @@ inline void auth_server_statefull_sm_process(cdp_session_t* s, int event, AAAMes
                     break;
                 case AUTH_EV_SEND_STA:
                     x->state = AUTH_ST_IDLE;
-                    Session_Cleanup(s, msg);
+                    cdp_session_cleanup(s, msg);
                     s = 0;
                     break;
 
                     /* Just in case we have some lost sessions */
                 case AUTH_EV_SESSION_TIMEOUT:
                 case AUTH_EV_SESSION_GRACE_TIMEOUT:
-                    Session_Cleanup(s, msg);
+                	cdp_session_cleanup(s, msg);
                     s = 0;
                     break;
 
@@ -477,7 +445,7 @@ inline void auth_server_statefull_sm_process(cdp_session_t* s, int event, AAAMes
                     break;
                 case AUTH_EV_SEND_ANS_UNSUCCESS:
                     x->state = AUTH_ST_IDLE;
-                    Session_Cleanup(s, msg);
+                    cdp_session_cleanup(s, msg);
                     s = 0;
                     break;
                 case AUTH_EV_SEND_ASR:
@@ -487,13 +455,13 @@ inline void auth_server_statefull_sm_process(cdp_session_t* s, int event, AAAMes
                 case AUTH_EV_SESSION_GRACE_TIMEOUT:
                     x->state = AUTH_ST_IDLE;
                     LM_DBG("before session cleanup\n");
-                    Session_Cleanup(s, msg);
+                    cdp_session_cleanup(s, msg);
                     s = 0;
                     break;
                 case AUTH_EV_SEND_STA:
                     LM_ERR("SENDING STA!!!\n");
                     x->state = AUTH_ST_IDLE;
-                    Session_Cleanup(s, msg);
+                    cdp_session_cleanup(s, msg);
                     s = 0;
                     break;
                 default:
@@ -509,7 +477,7 @@ inline void auth_server_statefull_sm_process(cdp_session_t* s, int event, AAAMes
                 case AUTH_EV_RECV_ASA:
                 case AUTH_EV_RECV_ASA_SUCCESS:
                     x->state = AUTH_ST_IDLE;
-                    //Session_Cleanup(s,msg);
+                    //cdp_session_cleanup(s,msg);
                     break;
                 case AUTH_EV_RECV_ASA_UNSUCCESS:
                     Send_ASR(s, msg);
@@ -518,7 +486,7 @@ inline void auth_server_statefull_sm_process(cdp_session_t* s, int event, AAAMes
                     break;
                 case AUTH_EV_SEND_STA:
                     x->state = AUTH_ST_IDLE;
-                    Session_Cleanup(s, msg);
+                    cdp_session_cleanup(s, msg);
                     s = 0;
                     break;
                 default:
@@ -865,17 +833,3 @@ void Send_ASR(cdp_session_t* s, AAAMessage* msg) {
     } else
         LM_DBG("success sending ASR\n");
 }
-
-void Session_Cleanup(cdp_session_t* s, AAAMessage* msg) {
-    // Here we should drop the session ! and free everything related to it
-    // but the generic_data thing should be freed by the callback function registered
-    // when the auth session was created
-    AAASessionCallback_f *cb;
-    LM_INFO("cleaning up session %.*s\n", s->id.len, s->id.s);
-    if (s->cb) {
-        cb = s->cb;
-        (cb) (AUTH_EV_SERVICE_TERMINATED, s);
-    }
-
-    AAADropAuthSession(s);
-}
diff --git a/modules/cdp/authstatemachine.h b/modules/cdp/authstatemachine.h
index cb8453c..5fe3414 100644
--- a/modules/cdp/authstatemachine.h
+++ b/modules/cdp/authstatemachine.h
@@ -63,7 +63,5 @@ void Send_ASA(cdp_session_t* s, AAAMessage* msg);
 void Send_STR(cdp_session_t* s, AAAMessage* msg);
 void Send_ASR(cdp_session_t* s, AAAMessage* msg);
 
-void Session_Cleanup(cdp_session_t* s, AAAMessage* msg);
-
 #endif
 
diff --git a/modules/cdp/cdp_load.c b/modules/cdp/cdp_load.c
index 078b45a..3ac6015 100644
--- a/modules/cdp/cdp_load.c
+++ b/modules/cdp/cdp_load.c
@@ -69,7 +69,6 @@ int load_cdp( struct cdp_binds *cdpb)
 	FIND_EXP(AAACreateResponse);
 	FIND_EXP(AAAFreeMessage);
 
-
 	FIND_EXP(AAACreateAVP);
 	FIND_EXP(AAAAddAVPToMessage);
 	FIND_EXP(AAAAddAVPToList);
@@ -86,15 +85,12 @@ int load_cdp( struct cdp_binds *cdpb)
 	FIND_EXP(AAASendRecvMessage);
 	FIND_EXP(AAASendRecvMessageToPeer);
 
-
 	FIND_EXP(AAAAddRequestHandler);
 	FIND_EXP(AAAAddResponseHandler);
 
-
 	FIND_EXP(AAACreateTransaction);
 	FIND_EXP(AAADropTransaction);
 
-
 	FIND_EXP(AAACreateSession);
 	FIND_EXP(AAAMakeSession);
 	FIND_EXP(AAAGetSession);
@@ -108,5 +104,12 @@ int load_cdp( struct cdp_binds *cdpb)
 	FIND_EXP(AAADropAuthSession);
 	FIND_EXP(AAATerminateAuthSession);
 	
+	/* Credit Control Application API - RFC 4006 */
+	FIND_EXP(AAACreateCCAccSession);
+	FIND_EXP(AAAStartChargingCCAccSession);
+	FIND_EXP(AAAGetCCAccSession);
+	FIND_EXP(AAADropCCAccSession);
+	FIND_EXP(AAATerminateCCAccSession);
+
 	return 1;
 }
diff --git a/modules/cdp/cdp_load.h b/modules/cdp/cdp_load.h
index 207d3e1..5e01759 100644
--- a/modules/cdp/cdp_load.h
+++ b/modules/cdp/cdp_load.h
@@ -100,6 +100,12 @@ struct cdp_binds {
 	AAADropAuthSession_f		AAADropAuthSession;
 	AAATerminateAuthSession_f	AAATerminateAuthSession;
 
+	AAACreateCCAccSession_f 	AAACreateCCAccSession;
+	AAAStartChargingCCAccSession_f	AAAStartChargingCCAccSession;
+	AAAGetCCAccSession_f		AAAGetCCAccSession;
+	AAADropCCAccSession_f		AAADropCCAccSession;
+	AAATerminateCCAccSession_f	AAATerminateCCAccSession;
+
 };
 
 
diff --git a/modules/cdp/common.c b/modules/cdp/common.c
new file mode 100644
index 0000000..ff27a0a
--- /dev/null
+++ b/modules/cdp/common.c
@@ -0,0 +1,52 @@
+/*
+ * common.c
+ *
+ *  Created on: 10 Apr 2013
+ *      Author: jaybeepee
+ */
+
+#include "common.h"
+#include "diameter_ims_code_avp.h"
+
+int get_accounting_record_type(AAAMessage* msg) {
+	AAA_AVP* avp = AAAFindMatchingAVP(msg, 0, AVP_Accounting_Record_Type, 0, 0);
+	if (avp && avp->data.len == 4) {
+		//assert this is an initial request. we can't move from IDLE with anything else
+		return get_4bytes(avp->data.s);
+	}
+	return -1;
+}
+
+int get_result_code(AAAMessage* msg) {
+    AAA_AVP *avp;
+    AAA_AVP_LIST list;
+    list.head = 0;
+    list.tail = 0;
+    int rc = -1;
+
+    if (!msg) goto error;
+
+    for (avp = msg->avpList.tail; avp; avp = avp->prev) {
+
+        if (avp->code == AVP_Result_Code) {
+            rc = get_4bytes(avp->data.s);
+            goto finish;
+        } else if (avp->code == AVP_Experimental_Result) {
+            list = AAAUngroupAVPS(avp->data);
+            for (avp = list.head; avp; avp = avp->next) {
+                if (avp->code == AVP_IMS_Experimental_Result_Code) {
+                    rc = get_4bytes(avp->data.s);
+                    AAAFreeAVPList(&list);
+                    goto finish;
+                }
+            }
+            AAAFreeAVPList(&list);
+        }
+    }
+finish:
+    return rc;
+error:
+    LM_ERR("get_result_code(): no AAAMessage or Result Code not found\n");
+    return -1;
+}
+
diff --git a/modules/cdp/common.h b/modules/cdp/common.h
new file mode 100644
index 0000000..b00aaa2
--- /dev/null
+++ b/modules/cdp/common.h
@@ -0,0 +1,19 @@
+/*
+ * common.h
+ *
+ *  Created on: 10 Apr 2013
+ *      Author: jaybeepee
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include "diameter.h"
+#include "diameter_api.h"
+
+
+int get_result_code(AAAMessage* msg);
+int get_accounting_record_type(AAAMessage* msg);
+
+
+#endif /* COMMON_H_ */
diff --git a/modules/cdp/configexample/ConfigExample.xml b/modules/cdp/configexample/ConfigExample.xml
index fd43305..5f44bdc 100644
--- a/modules/cdp/configexample/ConfigExample.xml
+++ b/modules/cdp/configexample/ConfigExample.xml
@@ -110,4 +110,4 @@
 	<DefaultRoute FQDN="test7" metric="13"/>
 
 
-</DiameterPeer>
\ No newline at end of file
+</DiameterPeer>
diff --git a/modules/cdp/diameter_peer.c b/modules/cdp/diameter_peer.c
index 4c01bb4..6bb5da2 100644
--- a/modules/cdp/diameter_peer.c
+++ b/modules/cdp/diameter_peer.c
@@ -62,6 +62,7 @@
 #include "session.h"
 
 #include "../../pt.h"
+#include "../../cfg/cfg_struct.h"
 
 dp_config *config=0;		/**< Configuration for this diameter peer 	*/
 
@@ -304,6 +305,7 @@ int diameter_peer_start(int blocking)
 		if (pid==0) {
 			srandom(time(0)*k);
 			snprintf(pt[process_no].desc, MAX_PT_DESC,"cdp worker child=%d", k );
+			if (cfg_child_init()) return 0;
 			worker_process(k);
 			LM_CRIT("init_diameter_peer(): worker_process finished without exit!\n");
 			exit(-1);
@@ -330,6 +332,7 @@ int diameter_peer_start(int blocking)
 		srandom(time(0)*k);
 		snprintf(pt[process_no].desc, MAX_PT_DESC,
 				"cdp receiver peer unknown");
+		if (cfg_child_init()) return 0;
 		receiver_process(NULL);
 		LM_CRIT("init_diameter_peer(): receiver_process finished without exit!\n");
 		exit(-1);
@@ -349,6 +352,7 @@ int diameter_peer_start(int blocking)
 			srandom(time(0)*k);
 				snprintf(pt[process_no].desc, MAX_PT_DESC,
 					"cdp_receiver_peer=%.*s", p->fqdn.len,p->fqdn.s );
+			if (cfg_child_init()) return 0;
 			receiver_process(p);
 			LM_CRIT("init_diameter_peer(): receiver_process finished without exit!\n");
 			exit(-1);
@@ -367,6 +371,7 @@ int diameter_peer_start(int blocking)
 		return 0;
 	}
 	if (pid==0) {
+		if (cfg_child_init()) return 0;
 		acceptor_process(config);
 		LM_CRIT("init_diameter_peer(): acceptor_process finished without exit!\n");
 		exit(-1);
@@ -377,6 +382,7 @@ int diameter_peer_start(int blocking)
 	/* fork/become timer */
 	if (blocking) {
 		dp_add_pid(getpid());
+		if (cfg_child_init()) return 0;
 		timer_process(1);
 	}
 	else{
@@ -386,6 +392,7 @@ int diameter_peer_start(int blocking)
 			return 0;
 		}
 		if (pid==0) {
+			if (cfg_child_init()) return 0;
 			timer_process(0);
 			LM_CRIT("init_diameter_peer(): timer_process finished without exit!\n");
 			exit(-1);
@@ -417,8 +424,8 @@ void diameter_peer_destroy()
 		lock_release(shutdownx_lock);
 	}
 
-	/* wait for all childs to clean up nicely (acceptor, receiver, timer, workers) */
-	LM_INFO("destroy_diameter_peer(): Terminating all childs...\n");
+	/* wait for all children to clean up nicely (acceptor, receiver, timer, workers) */
+	LM_INFO("destroy_diameter_peer(): Terminating all children...\n");
 	while(pid_list->tail){
 		pid = dp_last_pid();
 		if (pid<=0||pid==getpid()){
diff --git a/modules/cdp/mod.c b/modules/cdp/mod.c
index c677ac1..0f12b4c 100644
--- a/modules/cdp/mod.c
+++ b/modules/cdp/mod.c
@@ -52,6 +52,8 @@
 #include "config.h"
 #include "cdp_load.h"
 
+#include "../../cfg/cfg_struct.h"
+
 MODULE_VERSION
 
 char* config_file="DiameterPeer.xml"; 	/**< default DiameterPeer configuration filename */
@@ -143,6 +145,12 @@ static cmd_export_t cdp_cmds[] = {
 	EXP_FUNC(AAADropAuthSession)
 	EXP_FUNC(AAATerminateAuthSession)
 
+	EXP_FUNC(AAACreateCCAccSession)
+	EXP_FUNC(AAAStartChargingCCAccSession)
+	EXP_FUNC(AAAGetCCAccSession)
+	EXP_FUNC(AAADropCCAccSession)
+	EXP_FUNC(AAATerminateCCAccSession)
+
 	{ 0, 0, 0, 0, 0 }
 };
 
@@ -213,6 +221,7 @@ static int cdp_init( void )
 		return 1;
 	}
 	register_procs(2+config->workers + 2 * config->peers_cnt);
+	cfg_register_child(2+config->workers + 2 * config->peers_cnt);
 	return 0;
 }
 
diff --git a/modules/cdp/peerstatemachine.c b/modules/cdp/peerstatemachine.c
index 807ae65..ecd8470 100644
--- a/modules/cdp/peerstatemachine.c
+++ b/modules/cdp/peerstatemachine.c
@@ -57,6 +57,7 @@
 #include "config.h"
 #include "worker.h"
 #include "authstatemachine.h"
+#include "acctstatemachine.h"
 
 extern dp_config *config;		/**< Configuration for this diameter peer 	*/
 
@@ -1100,6 +1101,15 @@ void Snd_Message(peer *p, AAAMessage *msg)
 	if (session){
 		LM_DBG("There is a session of type %d\n",session->type);
 		switch (session->type){
+			case ACCT_CC_CLIENT:
+				if (is_req(msg)) {
+					LM_DBG("this is a request for CC app\n");
+					cc_acc_client_stateful_sm_process(session, ACC_CC_EV_SEND_REQ, msg);
+					session = 0;
+				} else {
+					LM_DBG("this is a response to CC app\n");
+				}
+				break;
 			case AUTH_CLIENT_STATEFULL:
 				if (is_req(msg)) {
 					auth_client_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg);
@@ -1187,6 +1197,16 @@ void Rcv_Process(peer *p, AAAMessage *msg)
 
 	if (session){
 		switch (session->type){
+			case ACCT_CC_CLIENT:
+				if (is_req(msg)){
+					LM_WARN("unhandled receive request on Credit Control Acct session\n");
+					AAASessionsUnlock(session->hash);	//must be called because we dont call state machine here
+					session = 0; //we dont call SM here so we mustnt set to 0
+				} else {
+					cc_acc_client_stateful_sm_process(session, ACC_CC_EV_RECV_ANS, msg);
+					session = 0;
+				}
+				break;
 			case AUTH_CLIENT_STATEFULL:
 				if (is_req(msg)){
 					if (msg->commandCode==IMS_ASR)
diff --git a/modules/cdp/receiver.c b/modules/cdp/receiver.c
index 538b233..5762694 100644
--- a/modules/cdp/receiver.c
+++ b/modules/cdp/receiver.c
@@ -69,6 +69,8 @@
 
 #include "receiver.h"
 
+#include "../../cfg/cfg_struct.h"
+
 extern dp_config *config;		/**< Configuration for this diameter peer 	*/
 
 int dp_add_pid(pid_t pid);
@@ -643,6 +645,7 @@ int receive_loop(peer *original_peer)
 
 		while(!n){
 			if (shutdownx&&*shutdownx) break;
+			cfg_update();
 
 			log_serviced_peers();
 
diff --git a/modules/cdp/session.c b/modules/cdp/session.c
index 8da2ed7..77a1f45 100644
--- a/modules/cdp/session.c
+++ b/modules/cdp/session.c
@@ -51,7 +51,9 @@
 #include "diameter.h"
 #include "config.h"
 #include "authstatemachine.h"
+#include "acctstatemachine.h"
 #include "timer.h"
+#include "globals.h"
 
 extern dp_config *config;		/**< Configuration for this diameter peer 	*/
 
@@ -63,6 +65,8 @@ cdp_session_list_t *sessions;	/**< the session hash table					*/
 unsigned int *session_id1;		/**< counter for first part of the session id */
 unsigned int *session_id2;		/**< counter for second part of the session id */
 
+#define GRACE_DISCON_TIMEOUT	60	/**< 60 seconds for a DISCON acct session to hang around for before being cleaned up */
+
 
 /**
  * Lock a hash table row
@@ -111,6 +115,8 @@ void free_session(cdp_session_t *x)
 				break;
 			case AUTH_SERVER_STATEFULL:
 				break;
+			case ACCT_CC_CLIENT:
+				break;
 			default:
 				LM_ERR("free_session(): Unknown session type %d!\n",x->type);
 		}
@@ -383,11 +389,11 @@ void cdp_sessions_log()
 	int hash;
 	cdp_session_t *x;
 
-	LM_DBG("------- CDP Sessions ----------------\n");
+	LM_DBG(ANSI_MAGENTA"------- CDP Sessions ----------------\n"ANSI_GREEN);
 	for(hash=0;hash<sessions_hash_size;hash++){
 		AAASessionsLock(hash);
 		for(x = sessions[hash].head;x;x=x->next) {
-			LM_DBG(" %3u. [%.*s] AppId [%d] Type [%d]\n",
+			LM_DBG(ANSI_GRAY" %3u. [%.*s] AppId [%d] Type [%d]\n",
 					hash,
 					x->id.len,x->id.s,
 					x->application_id,
@@ -395,20 +401,29 @@ void cdp_sessions_log()
 			switch (x->type){
 				case AUTH_CLIENT_STATEFULL:
 				case AUTH_SERVER_STATEFULL:
-					LM_DBG("\tAuth State [%d] Timeout [%d] Lifetime [%d] Grace [%d] Generic [%p]\n",
+					LM_DBG(ANSI_GRAY"\tAuth State [%d] Timeout [%d] Lifetime [%d] Grace [%d] Generic [%p]\n",
 							x->u.auth.state,
 							(int)(x->u.auth.timeout-time(0)),
 							x->u.auth.lifetime?(int)(x->u.auth.lifetime-time(0)):-1,
 							(int)(x->u.auth.grace_period),
 							x->u.auth.generic_data);
 					break;
+				case ACCT_CC_CLIENT:
+					LM_DBG(ANSI_GRAY"\tCCAcct State [%d] Charging Active [%c (%d)s] Reserved Units(valid=%ds) [%d] Generic [%p]\n",
+							x->u.cc_acc.state,
+							(x->u.cc_acc.charging_start_time&&x->u.cc_acc.state!=ACC_CC_ST_DISCON)?'Y':'N',
+							x->u.cc_acc.charging_start_time?(int)((int)time(0) - (int)x->u.cc_acc.charging_start_time):-1,
+							x->u.cc_acc.reserved_units?(int)((int)x->u.cc_acc.last_reservation_request_time + x->u.cc_acc.reserved_units_validity_time) - (int)time(0):-1,
+							x->u.cc_acc.reserved_units,
+							x->u.cc_acc.generic_data);
+					break;
 				default:
 					break;
 			}
 		}
 		AAASessionsUnlock(hash);
 	}
-	LM_DBG("-------------------------------------\n");
+	LM_DBG(ANSI_MAGENTA"-------------------------------------\n"ANSI_GREEN);
 }
 
 int cdp_sessions_timer(time_t now, void* ptr)
@@ -420,6 +435,36 @@ int cdp_sessions_timer(time_t now, void* ptr)
 		for(x = sessions[hash].head;x;x=n) {
 			n = x->next;
 			switch (x->type){
+				case ACCT_CC_CLIENT:
+					if (x->u.cc_acc.type == ACC_CC_TYPE_SESSION) {
+						//check for old, stale sessions, we need to do something more elegant
+						//here to ensure that if a CCR start record is sent and the client never sends anything
+						//else that we catch it and clean up the session from within CDP, calling all callbacks, etc
+						if ((time(0) > (x->u.cc_acc.discon_time + GRACE_DISCON_TIMEOUT)) && (x->u.cc_acc.state==ACC_CC_ST_DISCON)) {
+							cc_acc_client_stateful_sm_process(x, ACC_CC_EV_SESSION_STALE, 0);
+						}
+						//check reservation timers - again here we are assuming CC-Time applications
+						int last_res_timestamp = x->u.cc_acc.last_reservation_request_time;
+						int res_valid_for = x->u.cc_acc.reserved_units_validity_time;
+						int last_reservation = x->u.cc_acc.reserved_units;
+						int buffer_time = 15; //15 seconds - TODO: add as config parameter
+						//we should check for reservation expiries if the state is open
+						if(x->u.cc_acc.state==ACC_CC_ST_OPEN){
+						    if (last_res_timestamp) {
+							    //we have obv already started reservations
+							    if ((last_res_timestamp + res_valid_for) < (time(0) + last_reservation + buffer_time)) {
+								    LM_DBG("reservation about to expire, sending callback\n");
+								    cc_acc_client_stateful_sm_process(x, ACC_CC_EV_RSVN_WARNING, 0);
+							    }
+
+						    }
+						}
+						/* TODO: if reservation has expired we need to tear down the session. Ideally 
+						 * the client application (module) should do this but for completeness we should
+						 * put a failsafe here too.
+						 */
+					}
+					break;
 				case AUTH_CLIENT_STATEFULL:
 					if (x->u.auth.timeout>=0 && x->u.auth.timeout<=now){
 						//Session timeout
@@ -544,6 +589,33 @@ AAASession* cdp_new_auth_session(str id,int is_client,int is_statefull)
 }
 
 /**
+ * Creates a Credit Control Accounting session for Client.
+ * It generates a new id and adds the session to the cdp list of sessions
+ * \note Returns with a lock on AAASession->hash. Unlock when done working with the result
+ * @returns the new AAASession or null on error
+ */
+AAASession* cdp_new_cc_acc_session(str id, int is_statefull)
+{
+	AAASession *s;
+	cdp_session_type_t type;
+
+	if (is_statefull) type = ACCT_CC_CLIENT;
+	else type = ACCT_CC_CLIENT; //for now everything will be supported through this SM (until we add IEC)
+
+	s = cdp_new_session(id,type);
+	if (s) {
+		if (is_statefull)
+			s->u.cc_acc.type = ACC_CC_TYPE_SESSION;
+		else
+			s->u.cc_acc.type = ACC_CC_TYPE_EVENT;
+
+//		s->u.cc_acc.timeout=time(0)+config->default_cc_acct_session_timeout;
+		cdp_add_session(s);
+	}
+	return s;
+}
+
+/**
  * Creates a Authorization Session for the Client.
  * It generates a new id and adds the session to the cdp list of sessions
  * \note Returns with a lock on AAASession->hash. Unlock when done working with the result
@@ -667,5 +739,112 @@ AAASession* AAACreateAccSession(void *generic_data)
  */
 void AAADropAccSession(AAASession *s)
 {
-	free_session(s);
+	AAADropSession(s);
+}
+
+/**
+ * Creates an Accounting Session (Credit control - RFC 4006) for the client
+ * It generates a new id and adds the session to the cdp list of sessions
+ * \note Returns with a lock on AAASession->hash. Unlock when done working with the result
+ * @returns the new AAASession or null on error
+ */
+AAASession* AAACreateCCAccSession(AAASessionCallback_f *cb, int is_session, void *generic_data)
+{
+	AAASession *s;
+	str id;
+
+	generate_session_id(&id, 0);
+
+	s = cdp_new_cc_acc_session(id, is_session);
+	if (s) {
+		if (generic_data) 
+			s->u.auth.generic_data = generic_data;
+		s->cb = cb;
+		if (s->cb)
+			(s->cb)(ACC_CC_EV_SESSION_CREATED, s);
+	}
+	return s;
+}
+
+/**
+ * Starts accounting on time-based CC App session (Credit control - RFC 4006) for the client
+  * @returns 0 on success, anything else on failure
+ */
+int AAAStartChargingCCAccSession(AAASession *s)
+{
+	if (s->type != ACCT_CC_CLIENT && s->u.cc_acc.type != ACC_CC_TYPE_SESSION) {
+		LM_ERR("Can't start charging on a credit-control session that is not session based\n");
+		return -1;
+	}
+
+	s->u.cc_acc.charging_start_time = time(0);
+	return 0;
+}
+/**
+ * Deallocates the memory taken by a Accounting Session (Credit Control - RFC 4006)
+ */
+void AAADropCCAccSession(AAASession *s)
+{
+	AAADropSession(s);
+}
+
+/**
+ * Looks for a CC Acc dession with a given id and returns it if found
+ * \note Returns with a lock on AAASession->hash. Unlock when done working with the result
+ * @returns the new AAASession or null on error
+ */
+AAASession* AAAGetCCAccSession(str id)
+{
+	AAASession *x=cdp_get_session(id);
+	if (x){
+		switch (x->type){
+			case ACCT_CC_CLIENT:
+				return x;
+			default:
+				AAASessionsUnlock(x->hash);
+				return 0;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Sends a Service terminated event to the session
+ */
+void AAATerminateCCAccSession(AAASession *s)
+{
+	if (s->type==ACCT_CC_CLIENT) {
+		//TODO: run state machine for terminate event
+	}
 }
+
+void cdp_session_cleanup(cdp_session_t* s, AAAMessage* msg) {
+    // Here we should drop the session ! and free everything related to it
+    // but the generic_data thing should be freed by the callback function registered
+    // when the auth session was created
+    AAASessionCallback_f *cb;
+
+    LM_DBG("cleaning up session %.*s\n", s->id.len, s->id.s);
+    switch (s->type) {
+    	case ACCT_CC_CLIENT:
+    		if (s->cb) {
+    			cb = s->cb;
+    			(cb)(ACC_CC_EV_SESSION_TERMINATED, s);
+    		}
+    		AAADropCCAccSession(s);
+    		break;
+    	case AUTH_CLIENT_STATEFULL:
+    	case AUTH_CLIENT_STATELESS:
+			if (s->cb) {
+				cb = s->cb;
+				(cb)(AUTH_EV_SERVICE_TERMINATED, s);
+			}
+			AAADropAuthSession(s);
+			break;
+    	default:
+    		LM_WARN("asked to cleanup unknown/unhandled session type [%d]\n", s->type);
+    		break;
+    }
+
+}
+
diff --git a/modules/cdp/session.h b/modules/cdp/session.h
index 177ea09..d422346 100644
--- a/modules/cdp/session.h
+++ b/modules/cdp/session.h
@@ -52,7 +52,7 @@
 #include "diameter.h"
 
 /** Function for callback on session events: timeout, etc. */
-typedef void (AAASessionCallback_f)(int event,void *session);
+typedef void (AAASessionCallback_f)(int event, void *session);
 
 /** Types of sessions */
 typedef enum {
@@ -63,9 +63,12 @@ typedef enum {
 	AUTH_CLIENT_STATEFULL	= 3,
 	AUTH_SERVER_STATEFULL	= 4,
 
-	ACCT_CLIENT				= 5,
-	ACCT_SERVER_STATELESS	= 6,
-	ACCT_SERVER_STATEFULL	= 7,
+	ACCT_CLIENT_STATELESS	= 5,
+	ACCT_CLIENT_STATEFUL	= 6,
+	ACCT_SERVER_STATELESS	= 7,
+	ACCT_SERVER_STATEFULL	= 8,
+
+	ACCT_CC_CLIENT			= 9,		/**< Credit Control Client - RFC (4006) */
 
 } cdp_session_type_t;
 
@@ -128,7 +131,6 @@ typedef enum {
 	ACC_ST_PENDING_L	= 6		/**< PendingL - sent accounting stop */
 } cdp_acc_state_t;
 
-
 /** Accounting events definition */
 typedef enum {
 	ACC_EV_START					= 101,	/**< Client or device "requests access" (SIP session establishment) */
@@ -140,32 +142,85 @@ typedef enum {
 	ACC_EV_STOP						= 107,	/**< User service terminated */
 	ACC_EV_INTERIM					= 108,	/**< Interim interval elapses */
 	ACC_EV_RCV_SUC_ACA_INTERIM		= 109,	/**< Successful accounting interim answer received */
-	ACC_EV_RCV_FAILED_ACA_INTERIM	=110,	/**< Failed accounting interim answer received */
+	ACC_EV_RCV_FAILED_ACA_INTERIM	= 110,	/**< Failed accounting interim answer received */
 	ACC_EV_RCV_SUC_ACA_EVENT		= 111,	/**< Successful accounting event answer received */
 	ACC_EV_RCV_FAILED_ACA_EVENT		= 112,	/**< Failed accounting event answer received */
 	ACC_EV_RCV_SUC_ACA_STOP			= 113,	/**< Successful accounting stop answer received */
 	ACC_EV_RCV_FAILED_ACA_STOP		= 114,	/**< Failed accounting stop answer received */
 } cdp_acc_event_t;
 
+/** Credit Control states - RFC 4006 */
+typedef enum {
+	ACC_CC_ST_IDLE		= 0, 	/**< Idle */
+	ACC_CC_ST_PENDING_I	= 1,	/**< Pending Initial Answer */
+	ACC_CC_ST_PENDING_U	= 2,	/**< Pending Interim/Update Answer */
+	ACC_CC_ST_PENDING_T	= 3,	/**< Pending Terminate Answer */
+	ACC_CC_ST_OPEN		= 4,	/**< Open */
+	ACC_CC_ST_DISCON	= 5,	/**< Disconnected, ie. end of session */
+} cdp_cc_acc_state_t;
+
+/** Credit Control events - RFC 4006 */
+typedef enum {
+	ACC_CC_EV_SESSION_START				= 0, 		/**< Client or device requests access to service */
+	ACC_CC_EV_SEND_REQ					= 1,		/**< Sent initial request on session CCR */
+	ACC_CC_EV_RECV_ANS					= 2,		/**< Received a response message */
+	ACC_CC_EV_RECV_ANS_SUCCESS 			= 3,		/**< CCA = success */
+	ACC_CC_EV_RECV_ANS_UNSUCCESS 		= 4,		/**< CCA = failure */
+	ACC_CC_EV_SESSION_CREATED 			= 5,		/**< used for callbacks - new CC session created */
+	ACC_CC_EV_SESSION_TIMEOUT			= 6,		/**< CC Session timeout */
+	ACC_CC_EV_RSVN_WARNING				= 7,		/**< Reservation is about to expire */
+	ACC_CC_EV_SESSION_TERMINATED		= 8,
+	ACC_CC_EV_SESSION_MODIFIED			= 9,
+	ACC_CC_EV_SESSION_STALE				= 10,		/**< Session is being removed from memory after stale expiry */
+} cdp_cc_acc_event_t;
+
+/** Credit Control Session types - RFC 4006 */
+typedef enum {
+	ACC_CC_TYPE_EVENT		= 0, 	/**< Immediate Event Charge (IEC - see TS32.299 6.3.2.1)*/
+	ACC_CC_TYPE_SESSION		= 1, 	/**< Session-based charging (SCUR/ECUR - see TS32.299 6.3.2.1)*/
+} cdp_cc_acc_type_t;
 
-/** Structure for accounting sessions */
-typedef struct _acc_session {
+/** Credit Control Failure Handling */
+typedef enum {
+	ACC_CC_CCFH_UNKNOWN				= 0,
+	ACC_CC_CCFH_CONTINUE 			= 1,
+	ACC_CC_CCFH_TERMINATE			= 2,
+	ACC_CC_CCFH_RETRY_AND_TERMINATE	= 3,
+} cdp_cc_acc_ccfh_t;
 
-	cdp_acc_state_t state;						/**< current state */
+/** Credit Control Final Unit Action */
+typedef enum {
+	ACC_CC_FUI_UNKNOWN				= 0,
+	ACC_CC_FUI_TERMINATE			= 1,
+} cdp_cc_acc_fua_t;
 
+/** Structure for accounting sessions */
+typedef struct _acc_session {
+	cdp_acc_state_t state;					/**< current state */
 	str dlgid;       						/**< application-level identifier, combines application session (e.g. SIP dialog) or event with diameter accounting session */
-
 	unsigned int acct_record_number; 		/**< number of last accounting record within this session */
 	time_t aii;	 							/**< expiration of Acct-Interim-Interval (seconds) */
 	time_t timeout;							/**< session timeout (seconds) */
-
-
 	void* generic_data;
-
 } cdp_acc_session_t;
 
+/** Structure for credit control accounting sessions (RFC 4006)*/
+typedef struct _cc_acc_session {
+	cdp_cc_acc_state_t state;				/**< current state */
+	time_t discon_time;						/**< the time we went into DISCON state. we use this to cleanup dead sessions*/
+	cdp_cc_acc_type_t type;					/**< type of CC, event or session (each have a different state machine - see RFC 4006 */
+	cdp_cc_acc_ccfh_t ccfh;					/**< credit control failure handling type set for this session */
+//	cdp_cc_acc_fua_t fua;					/**< final unit action */
+	int fua;								/**< TODO: clean this up */
+	unsigned int acct_record_number; 		/**< number of last accounting record within this session */
+	time_t timeout;							/**< session timeout (seconds) - this is to prevent idle sessions from 'hanging' around */
+	time_t charging_start_time;				/**< the time the session started to charge */
+	time_t last_reservation_request_time;	/**< the last time we requested reservation for the current granted units */
+	int reserved_units;						/**< current number of granted units */
+	int reserved_units_validity_time;		/**< number of seconds current granted units valid for */
 
-
+	void* generic_data;
+} cdp_cc_acc_session_t;
 
 /** Structure for session identification */
 typedef struct _cdp_session_t {
@@ -174,10 +229,11 @@ typedef struct _cdp_session_t {
 	unsigned int application_id;		/**< specific application id associated with this session */
 	unsigned int vendor_id;				/**< specific vendor id for this session */
 	cdp_session_type_t type;
-	str dest_host, dest_realm; /*the destination host and realm, used only for auth, for the moment*/
+	str dest_host, dest_realm; 			/*the destination host and realm, used only for auth, for the moment*/
 	union {
 		cdp_auth_session_t auth;
 		cdp_acc_session_t acc;
+		cdp_cc_acc_session_t cc_acc;
 		void *generic_data;
 	} u;
 
@@ -192,24 +248,24 @@ typedef struct _cdp_session_list_t {
 	cdp_session_t *head,*tail;		/**< first, last sessions in the list */
 } cdp_session_list_t;
 
-
-
 int cdp_sessions_init(int hash_size);
 int cdp_sessions_destroy();
 void cdp_sessions_log();
 int cdp_sessions_timer(time_t now, void* ptr);
 
+void cdp_session_cleanup(cdp_session_t* s, AAAMessage* msg);	/**< Session cleanup for all session types */
+
+
 cdp_session_t* cdp_get_session(str id);
 cdp_session_t* cdp_new_session(str id,cdp_session_type_t type); //this function is needed in the peerstatemachine
+
 void cdp_add_session(cdp_session_t *x);
 cdp_session_t* cdp_new_auth_session(str id,int is_client,int is_statefull);
-
+cdp_session_t* cdp_new_cc_acc_session(str id, int is_statefull);	//new redit control acct session
 
 /*           API Exported */
-
 typedef cdp_session_t AAASession;
 
-
 AAASession* AAACreateSession(void *generic_data);
 typedef AAASession* (*AAACreateSession_f)(void *generic_data);
 
@@ -228,9 +284,6 @@ typedef void (*AAASessionsUnlock_f) (unsigned int hash);
 void AAASessionsLock(unsigned int hash);
 typedef void (*AAASessionsLock_f) (unsigned int hash);
 
-
-
-
 AAASession* AAACreateClientAuthSession(int is_statefull,AAASessionCallback_f *cb,void *generic_data);
 typedef AAASession* (*AAACreateClientAuthSession_f)(int is_statefull,AAASessionCallback_f *cb,void *generic_data);
 
@@ -246,13 +299,22 @@ typedef void (*AAADropAuthSession_f)(AAASession *s);
 void AAATerminateAuthSession(AAASession *s);
 typedef void (*AAATerminateAuthSession_f)(AAASession *s);
 
-
-
+AAASession* AAAGetCCAccSession(str id);
+typedef AAASession* (*AAAGetCCAccSession_f)(str id);
 
 AAASession* AAACreateAccSession(void *generic_data);
 void AAADropAccSession(AAASession *s);
 
+AAASession* AAACreateCCAccSession(AAASessionCallback_f *cb, int is_session, void *generic_data);	/*create CreditControl accounting session*/
+typedef AAASession* (*AAACreateCCAccSession_f)(AAASessionCallback_f *cb, int is_session, void *generic_data);
+
+int AAAStartChargingCCAccSession(AAASession *s);
+typedef int (*AAAStartChargingCCAccSession_f)(AAASession *s);
 
+void AAADropCCAccSession(AAASession *s);		/*drop CreditControl accounting session*/
+typedef void (*AAADropCCAccSession_f)(AAASession *s);
 
+void AAATerminateCCAccSession(AAASession *s);
+typedef void (*AAATerminateCCAccSession_f)(AAASession *s);
 
 #endif
diff --git a/modules/cdp/tcp_accept.c b/modules/cdp/tcp_accept.c
index fdf3dd3..473f14b 100644
--- a/modules/cdp/tcp_accept.c
+++ b/modules/cdp/tcp_accept.c
@@ -63,6 +63,8 @@
 #include "tcp_accept.h"
 #include "receiver.h"
 
+#include "../../cfg/cfg_struct.h"
+
 /* defined in ../diameter_peer.c */
 int dp_add_pid(pid_t pid);
 
@@ -205,6 +207,8 @@ void accept_loop()
 	while(1){
 		if (shutdownx && *shutdownx) break;
 		
+		cfg_update();
+		
 		timeout.tv_sec=2;
 		timeout.tv_usec=0;	
 		FD_ZERO(&listen_set);
diff --git a/modules/cdp/timer.c b/modules/cdp/timer.c
index 0ac18c5..17be7de 100644
--- a/modules/cdp/timer.c
+++ b/modules/cdp/timer.c
@@ -53,6 +53,8 @@
 
 #include "timer.h"
 
+#include "../../cfg/cfg_struct.h"
+
 
 /* defined in ../diameter_peer.c */
 int dp_add_pid(pid_t pid);
@@ -83,6 +85,7 @@ void timer_loop()
 	while(1){
 		if (shutdownx && *shutdownx) break;
 		now = time(0);
+		cfg_update();
 	
 		do {
 			cb = 0;
diff --git a/modules/cdp/worker.c b/modules/cdp/worker.c
index b4d4fb9..45cffe6 100644
--- a/modules/cdp/worker.c
+++ b/modules/cdp/worker.c
@@ -57,6 +57,8 @@
 #include "worker.h"
 #include "diameter_api.h"
 
+#include "../../cfg/cfg_struct.h"
+
 /* defined in ../diameter_peer.c */
 int dp_add_pid(pid_t pid);
 void dp_del_pid(pid_t pid);
@@ -315,6 +317,7 @@ void worker_process(int id) {
     /* init the application level for this child */
     while (1) {
         if (shutdownx && (*shutdownx)) break;
+	cfg_update();
         t = take_task();
         if (!t.msg) {
             if (shutdownx && (*shutdownx)) break;
diff --git a/modules/cfgutils/README b/modules/cfgutils/README
index 1306601..48307f1 100644
--- a/modules/cfgutils/README
+++ b/modules/cfgutils/README
@@ -18,14 +18,18 @@ Jiri Kuthan
 
    <jiri at iptel.org>
 
+Olle E. Johansson
+
+   <oej at edvina.net>
+
 Edited by
 
 Daniel-Constantin Mierla
 
    <miconda at gmail.com>
 
-   Copyright � 2007, 2008, 2004 1und1 Internet AG, BASIS AudioNet GmbH,
-   Elena-Ramona Modroiu, FhG FOKUS
+   Copyright � 2013, 2007, 2008, 2004 Edvina AB, 1und1 Internet AG, BASIS
+   AudioNet GmbH, Elena-Ramona Modroiu, FhG FOKUS
      __________________________________________________________________
 
    Table of Contents
@@ -59,7 +63,9 @@ Daniel-Constantin Mierla
               4.14. is_gflag(flag)
               4.15. lock(key)
               4.16. unlock(key)
-              4.17. core_hash(string1, string2, size)
+              4.17. check_route_exists(route)
+              4.18. route_if_exists(route)
+              4.19. core_hash(string1, string2, size)
 
         5. MI Commands
 
@@ -99,17 +105,19 @@ Daniel-Constantin Mierla
    1.18. is_gflag() usage
    1.19. lock() usage
    1.20. unlock() usage
-   1.21. core_hash() usage
-   1.22. rand_set_prob usage
-   1.23. rand_reset_prob usage
-   1.24. rand_get_prob usage
-   1.25. check_config_hash usage
-   1.26. get_config_hash usage
-   1.27. set_gflag usage
-   1.28. reset_gflag usage
-   1.29. is_gflag usage
-   1.30. get_gflags usage
-   1.31. RANDOM pseudo-variable usage
+   1.21. check_route_exists() usage
+   1.22. route_if_exists() usage
+   1.23. core_hash() usage
+   1.24. rand_set_prob usage
+   1.25. rand_reset_prob usage
+   1.26. rand_get_prob usage
+   1.27. check_config_hash usage
+   1.28. get_config_hash usage
+   1.29. set_gflag usage
+   1.30. reset_gflag usage
+   1.31. is_gflag usage
+   1.32. get_gflags usage
+   1.33. RANDOM pseudo-variable usage
 
 Chapter 1. Admin Guide
 
@@ -142,7 +150,9 @@ Chapter 1. Admin Guide
         4.14. is_gflag(flag)
         4.15. lock(key)
         4.16. unlock(key)
-        4.17. core_hash(string1, string2, size)
+        4.17. check_route_exists(route)
+        4.18. route_if_exists(route)
+        4.19. core_hash(string1, string2, size)
 
    5. MI Commands
 
@@ -281,7 +291,9 @@ modparam("cfgutils", "lock_set_size", 4)
    4.14. is_gflag(flag)
    4.15. lock(key)
    4.16. unlock(key)
-   4.17. core_hash(string1, string2, size)
+   4.17. check_route_exists(route)
+   4.18. route_if_exists(route)
+   4.19. core_hash(string1, string2, size)
 
 4.1. rand_event()
 
@@ -509,7 +521,42 @@ lock("$rU");
 unlock("$rU");
 ...
 
-4.17. core_hash(string1, string2, size)
+4.17. check_route_exists(route)
+
+   Check if a route block exists
+
+   Parameters:
+
+   "name" of a route block in the config file, like "route[FROGJUMP]"
+
+   This function can be used from any route. You can only check for
+   route[] blocks, not reply, event or other routes.
+
+   Example 1.21. check_route_exists() usage
+...
+if(check_route_exists("FROGJUMP") {
+        $var(jumping_frogs) = 1;
+};
+...
+
+4.18. route_if_exists(route)
+
+   Execute a routing block only if it is defined. If it's not defined,
+   silently move to the next action in the configuration script.
+
+   Parameters:
+
+   "name" of a route block in the config file, like "route[FROGJUMP]"
+
+   This function can be used from any route. You can only execute it for
+   route[] blocks, not reply, event or other routes.
+
+   Example 1.22. route_if_exists() usage
+...
+route_if_exists("PRESENCE_SANTA_CLAUS");
+...
+
+4.19. core_hash(string1, string2, size)
 
    Exported function that enables the core_hash() function to be used from
    the configuration file.
@@ -526,7 +573,7 @@ unlock("$rU");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.21. core_hash() usage
+   Example 1.23. core_hash() usage
 ...
 core_hash("$ci", "", 4);
 ...
@@ -555,7 +602,7 @@ core_hash("$ci", "", 4);
 
    The parameter value must be a number from 0 to 100.
 
-   Example 1.22. rand_set_prob usage
+   Example 1.24. rand_set_prob usage
 ...
 $ kamctl fifo rand_set_prob 10
 ...
@@ -566,7 +613,7 @@ $ kamctl fifo rand_set_prob 10
 
    This command don't need a parameter.
 
-   Example 1.23. rand_reset_prob usage
+   Example 1.25. rand_reset_prob usage
 ...
 $ kamctl fifo rand_reset_prob
 ...
@@ -577,7 +624,7 @@ $ kamctl fifo rand_reset_prob
 
    The function return the actual probability value.
 
-   Example 1.24. rand_get_prob usage
+   Example 1.26. rand_get_prob usage
 ...
 $ kamctl fifo get_prob
 The actual probability is 50 percent.
@@ -591,7 +638,7 @@ The actual probability is 50 percent.
    there are not identical, 404 if no file for hashing has been configured
    and 500 on errors. Additional a short text message is printed.
 
-   Example 1.25. check_config_hash usage
+   Example 1.27. check_config_hash usage
 ...
 $ kamctl fifo check_config_hash
 The actual config file hash is identical to the stored one.
@@ -604,7 +651,7 @@ The actual config file hash is identical to the stored one.
    The function returns 200 OK and the hash value on success or 404 if no
    file for hashing has been configured.
 
-   Example 1.26. get_config_hash usage
+   Example 1.28. get_config_hash usage
 ...
 $ kamctl fifo get_config_hash
 1580a37104eb4de69ab9f31ce8d6e3e0
@@ -617,7 +664,7 @@ $ kamctl fifo get_config_hash
    The parameter value must be a bitmask in decimal or hexadecimal format.
    The bitmask has a 32 bit size.
 
-   Example 1.27. set_gflag usage
+   Example 1.29. set_gflag usage
 ...
 $ kamctl fifo set_gflag 1
 $ kamctl fifo set_gflag 0x3
@@ -630,7 +677,7 @@ $ kamctl fifo set_gflag 0x3
    The parameter value must be a bitmask in decimal or hexadecimal format.
    The bitmask has a 32 bit size.
 
-   Example 1.28. reset_gflag usage
+   Example 1.30. reset_gflag usage
 ...
 $ kamctl fifo reset_gflag 1
 $ kamctl fifo reset_gflag 0x3
@@ -646,7 +693,7 @@ $ kamctl fifo reset_gflag 0x3
    The function returns TRUE if all the flags from the set are set and
    FALSE if at least one is not set.
 
-   Example 1.29. is_gflag usage
+   Example 1.31. is_gflag usage
 ...
 $ kamctl fifo set_gflag 1024
 $ kamctl fifo is_gflag 1024
@@ -669,7 +716,7 @@ TRUE
    Return the bitmap with all flags. The function gets no parameters and
    returns the bitmap in hexadecimal and decimal format.
 
-   Example 1.30. get_gflags usage
+   Example 1.32. get_gflags usage
 ...
 $ kamctl fifo get_gflags
 0x3039
@@ -684,7 +731,7 @@ $ kamctl fifo get_gflags
 
    Returns a random value from the [0 - 2^31) range.
 
-   Example 1.31. RANDOM pseudo-variable usage
+   Example 1.33. RANDOM pseudo-variable usage
 ...
 if (rand_event()) {
   $avp(i:10) = ($RANDOM / 16777216); # 2^24
diff --git a/modules/cfgutils/cfgutils.c b/modules/cfgutils/cfgutils.c
index 37c106a..8416e9c 100644
--- a/modules/cfgutils/cfgutils.c
+++ b/modules/cfgutils/cfgutils.c
@@ -1,6 +1,7 @@
 /*
  * $Id$
  *
+ * Copyright (C) 2012 Edvina AB
  * Copyright (C) 2007 1&1 Internet AG
  * Copyright (C) 2007 BASIS AudioNet GmbH
  * Copyright (C) 2004 FhG
@@ -70,6 +71,7 @@
 #include "../../globals.h"
 #include "../../hashes.h"
 #include "../../locking.h"
+#include "../../route.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -91,6 +93,8 @@ static int dbg_pkg_status(struct sip_msg*, char*,char*);
 static int dbg_shm_status(struct sip_msg*, char*,char*);
 static int dbg_pkg_summary(struct sip_msg*, char*,char*);
 static int dbg_shm_summary(struct sip_msg*, char*,char*);
+static int route_exists(struct sip_msg*, char*);
+static int check_route_exists(struct sip_msg*, char*);
 
 static int set_gflag(struct sip_msg*, char *, char *);
 static int reset_gflag(struct sip_msg*, char *, char *);
@@ -127,7 +131,7 @@ static int mod_init(void);
 static void mod_destroy(void);
 
 static int initial_prob = 10;
-static int *probability;
+static int *probability = NULL;
 
 static char config_hash[MD5_LEN];
 static char* hash_file = NULL;
@@ -178,6 +182,10 @@ static cmd_export_t cmds[]={
 		ANY_ROUTE},
 	{"core_hash",    (cmd_function)w_core_hash, 3,   fixup_core_hash, 0,
 		ANY_ROUTE},
+	{"check_route_exists",    (cmd_function)check_route_exists, 1,   0, 0,
+		ANY_ROUTE},
+	{"route_if_exists",    (cmd_function)route_exists, 1,   0, 0,
+		ANY_ROUTE},
 	{"bind_cfgutils", (cmd_function)bind_cfgutils,  0,
 		0, 0, 0},
 	{0, 0, 0, 0, 0, 0}
@@ -737,6 +745,32 @@ static int cfg_unlock(struct sip_msg *msg, char *key, char *s2)
 	return cfg_lock_wrapper(msg, (gparam_p)key, 1);
 }
 
+/*! Check if a route block exists - only request routes
+ */
+static int check_route_exists(struct sip_msg *msg, char *route)
+{
+	if (route_lookup(&main_rt, route))
+		return 1;
+	return 0;
+}
+
+/*! Run a request route block if it exists
+ */
+static int route_exists(struct sip_msg *msg, char *route)
+{
+	struct run_act_ctx ctx;
+	int newroute, backup_rt;
+
+	if (!(newroute = route_lookup(&main_rt, route))) {
+		return 0;
+	}
+	backup_rt = get_route_type();
+	set_route_type(REQUEST_ROUTE);
+	init_run_actions_ctx(&ctx);
+	run_top_route(main_rt.rlist[newroute], msg, 0);
+	set_route_type(backup_rt);
+	return 0;
+}
 
 static int mod_init(void)
 {
diff --git a/modules/cfgutils/doc/cfgutils.xml b/modules/cfgutils/doc/cfgutils.xml
index 4ad9cb5..ec45314 100644
--- a/modules/cfgutils/doc/cfgutils.xml
+++ b/modules/cfgutils/doc/cfgutils.xml
@@ -37,6 +37,11 @@
 		<surname>Kuthan</surname>
 		<email>jiri at iptel.org</email>
 		</author>
+		<author>
+		<firstname>Olle E.</firstname>
+		<surname>Johansson</surname>
+		<email>oej at edvina.net</email>
+		</author>
 		<editor>
 		<firstname>Daniel-Constantin</firstname>
 		<surname>Mierla</surname>
@@ -44,9 +49,11 @@
 		</editor>
 	</authorgroup>
 	<copyright>
+		<year>2013</year>
 		<year>2007</year>
 		<year>2008</year>
 		<year>2004</year>
+		<holder>Edvina AB</holder>
 		<holder>1und1 Internet AG</holder>
 		<holder>BASIS AudioNet GmbH</holder>
 		<holder>Elena-Ramona Modroiu</holder>
diff --git a/modules/cfgutils/doc/cfgutils_admin.xml b/modules/cfgutils/doc/cfgutils_admin.xml
index d83c3c1..bc50a85 100644
--- a/modules/cfgutils/doc/cfgutils_admin.xml
+++ b/modules/cfgutils/doc/cfgutils_admin.xml
@@ -92,7 +92,7 @@
     </section>
     <section>
 	<title>Parameters</title>
-	<section>
+	<section id="cfgutils.p.initial_propability">
 		<title><varname>initial_probability</varname> (string)</title>
 		<para>
 		The initial value of the probability.
@@ -111,7 +111,7 @@ modparam("cfgutils", "initial_probability", 15)
 	    </example>
 	</section>
 
-	<section>
+	<section id="cfgutils.p.hash_file">
 		<title><varname>hash_file</varname> (string)</title>
 		<para>
 		The config file name for that a hash value should be calculated on startup.
@@ -130,7 +130,7 @@ modparam("cfgutils", "hash_file", "/etc/kamailio/&kamailioconfig;")
 	    </example>
 	</section>
 
-		<section>
+		<section id="cfgutils.p.initial_gflags">
 		<title><varname>initial_gflags</varname> (integer)</title>
 		<para>
 		The initial value of global flags bitmap.
@@ -145,7 +145,7 @@ modparam("cfgutils", "initial_gflags", 15)
 		</programlisting>
 		</example>
 	</section>
-		<section>
+		<section id="cfgutils.p.lock_set_size">
 		<title><varname>lock_set_size</varname> (integer)</title>
 		<para>
 		Size of lock set - the value is used as power of two to compute the
@@ -165,7 +165,7 @@ modparam("cfgutils", "lock_set_size", 4)
 
     <section>
 	<title>Functions</title>
-	<section>
+	<section  id="cfgutils.f.rand_event">
 		<title><function moreinfo="none">rand_event()</function></title>
 		<para>
 			Return true or false, depending on a random value and a
@@ -186,7 +186,7 @@ if (rand_event()) {
 		</example>
 	</section>
 	
-	<section>
+	<section id="cfgutils.f.rand_set_prob">
 	    <title><function moreinfo="none">rand_set_prob(probabiltiy)</function></title>
 	    <para>
 		Set the <quote>probability</quote> of the decision.
@@ -204,7 +204,7 @@ rand_set_prob("4");
 	    </example>
 	</section>
 
-	<section>
+	<section id="cfgutils.f.rand_reset_prob">
 	    <title><function moreinfo="none">rand_reset_prob()</function></title>
 	    <para>
 		Reset the probability back to the inital value.
@@ -219,7 +219,7 @@ rand_reset_prob();
 	    </example>
 	</section>
 
-	<section>
+	<section id="cfgutils.f.rand_get_prob">
 	    <title><function moreinfo="none">rand_get_prob()</function></title>
 	    <para>
 		Return the current probability setting, e.g. for logging purposes.
@@ -233,7 +233,7 @@ rand_get_prob();
 </programlisting>
 	    </example>
 	</section>
-	<section>
+	<section id="cfgutils.f.sleep">
 		<title>
 			<function moreinfo="none">sleep(time)</function>
 		</title>
@@ -261,7 +261,7 @@ sleep("1");
 		</example>
 	</section>
 	
-	<section>
+	<section id="cfgutils.f.usleep">
 		<title>
 			<function moreinfo="none">usleep(time)</function>
 		</title>
@@ -291,7 +291,7 @@ usleep("5000");
 		</example>
 	</section>
 	
-	<section>
+	<section id="cfgutils.f.abort">
 		<title>
 			<function moreinfo="none">abort()</function>
 		</title>
@@ -313,7 +313,7 @@ abort();
 		</example>
 	</section>
 	
-	<section>
+	<section id="cfgutils.f.pkg_status">
 		<title>
 			<function moreinfo="none">pkg_status()</function>
 		</title>
@@ -337,7 +337,7 @@ pkg_status();
 		</example>
 	</section>
 	
-	<section>
+	<section id="cfgutils.f.pkg_summary">
 		<title>
 			<function moreinfo="none">pkg_summary()</function>
 		</title>
@@ -361,7 +361,7 @@ pkg_summary();
 		</example>
 	</section>
 	
-	<section>
+	<section id="cfgutils.f.shm_status">
 		<title>
 			<function moreinfo="none">shm_status()</function>
 		</title>
@@ -385,7 +385,7 @@ shm_status();
 		</example>
 	</section>
 
-	<section>
+	<section  id="cfgutils.f.shm_summary">
 		<title>
 			<function moreinfo="none">shm_summary()</function>
 		</title>
@@ -409,7 +409,7 @@ shm_summary();
 		</example>
 	</section>
 	
-	<section>
+	<section id="cfgutils.f.set_gflag">
 		<title><function moreinfo="none">set_gflag(flag)</function></title>
 		<para>
 		Set the bit at the position <quote>flag</quote> in global flags.
@@ -431,7 +431,7 @@ set_gflag("4");
 		</example>
 	</section>
 
-	<section>
+	<section id="cfgutils.f.reset_gflag">
 		<title><function moreinfo="none">reset_gflag(flag)</function></title>
 		<para>
 		Reset the bit at the position <quote>flag</quote> in global flags.
@@ -453,7 +453,7 @@ reset_gflag("4");
 		</example>
 	</section>
 
-	<section>
+	<section id="cfgutils.f.is_gflag">
 		<title><function moreinfo="none">is_gflag(flag)</function></title>
 		<para>
 		Check if bit at the position <quote>flag</quote> in global flags is
@@ -480,7 +480,7 @@ if(is_gflag("4"))
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="cfgutils.f.lock">
 		<title><function moreinfo="none">lock(key)</function></title>
 		<para>
 		Lock the key. Can be used to syncronize operations in config file,
@@ -505,7 +505,7 @@ lock("$rU");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="cfgutils.f.unlock">
 		<title><function moreinfo="none">unlock(key)</function></title>
 		<para>
 		Unlock the key.
@@ -526,7 +526,54 @@ unlock("$rU");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="cfgutils.f.check_route_exists">
+		<title><function moreinfo="none">check_route_exists(route)</function></title>
+		<para>
+		Check if a route block exists
+		</para>
+		<para>Parameters:</para>
+		<para>
+		<quote>name</quote> of a route block in the config file, like <quote>route[FROGJUMP]</quote>
+		</para>
+		<para>
+		This function can be used from any route. You can only check for
+		route[] blocks, not reply, event or other routes.
+		</para>
+		<example>
+		<title><function moreinfo="none">check_route_exists()</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(check_route_exists("FROGJUMP") {
+	$var(jumping_frogs) = 1;
+};
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="cfgutils.f.route_if_exists">
+		<title><function moreinfo="none">route_if_exists(route)</function></title>
+		<para>
+		Execute a routing block only if it is defined. If it's not defined, silently
+		move to the next action in the configuration script.
+		</para>
+		<para>Parameters:</para>
+		<para>
+		<quote>name</quote> of a route block in the config file, like <quote>route[FROGJUMP]</quote>
+		</para>
+		<para>
+		This function can be used from any route. You can only execute it for
+		route[] blocks, not reply, event or other routes.
+		</para>
+		<example>
+		<title><function moreinfo="none">route_if_exists()</function> usage</title>
+		<programlisting format="linespecific">
+...
+route_if_exists("PRESENCE_SANTA_CLAUS");
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="cfgutils.f.core_hash">
 		<title><function moreinfo="none">core_hash(string1, string2, size)</function></title>
 		<para>
 		Exported function that enables the core_hash() function to be used
@@ -572,7 +619,7 @@ core_hash("$ci", "", 4);
 			should be changed as in the functions available in the routing
 			script.
 		</para>
-		<section>
+		<section id="cfgutils.m.rand_set_prob">
 			<title><function moreinfo="none">rand_set_prop</function></title>
 			<para>
 				Set the probability value to the given parameter.
@@ -591,7 +638,7 @@ $ &ctltool; fifo rand_set_prob 10
 			</example>
 			
 		</section>
-		<section>
+		<section id="cfgutils.m.rand_reset_prob">
 			<title><function moreinfo="none">rand_reset_prob</function></title>
 			<para>
 				Reset the probability value to the inital start value.
@@ -609,7 +656,7 @@ $ &ctltool; fifo rand_reset_prob
 </programlisting>
 			</example>
 		</section>
-		<section>
+		<section  id="cfgutils.m.rand_get_prob">
 			<title><function moreinfo="none">rand_get_prob</function></title>
 			<para>
 				Return the actual probability setting.
@@ -627,7 +674,7 @@ The actual probability is 50 percent.
 </programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="cfgutils.m.check_config_hash">
 			<title><function moreinfo="none">check_config_hash</function></title>
 			<para>
 				Check if the actual config file hash is identical to the stored one.
@@ -647,7 +694,7 @@ The actual config file hash is identical to the stored one.
 </programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="cfgutils.m.get_config_hash">
 			<title><function moreinfo="none">get_config_hash</function></title>
 			<para>
 				Return the stored config file hash.
@@ -666,7 +713,7 @@ $ &ctltool; fifo get_config_hash
 </programlisting>
 			</example>
 		</section>
-				<section>
+		<section  id="cfgutils.m.set_gflag">
 			<title><function moreinfo="none">set_gflag</function></title>
 			<para>
 			Set the value of some flags (specified by bitmask) to 1.
@@ -686,7 +733,7 @@ $ &ctltool; fifo set_gflag 0x3
 			</example>
 
 		</section>
-		<section>
+		<section  id="cfgutils.m.reset_gflag">
 			<title><function moreinfo="none">reset_gflag</function></title>
 			<para>
 			Reset the value of some flags to 0.
@@ -706,7 +753,7 @@ $ &ctltool; fifo reset_gflag 0x3
 </programlisting>
 			</example>
 		</section>
-		<section>
+		<section  id="cfgutils.m.is_gflag">
 			<title><function moreinfo="none">is_gflag</function></title>
 			<para>
 			Returns true if the all the flags from the bitmask are set.
@@ -741,7 +788,7 @@ TRUE
 </programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="cfgutils.m.get_gflags">
 			<title><function moreinfo="none">get_gflags</function></title>
 			<para>
 			Return the bitmap with all flags. The function gets no 
diff --git a/modules/cnxcc/Makefile b/modules/cnxcc/Makefile
new file mode 100644
index 0000000..be6c1f1
--- /dev/null
+++ b/modules/cnxcc/Makefile
@@ -0,0 +1,17 @@
+# $Id$
+#
+# example module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=cnxcc.so
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+include ../../Makefile.modules
diff --git a/modules/cnxcc/README b/modules/cnxcc/README
new file mode 100644
index 0000000..da1e5f6
--- /dev/null
+++ b/modules/cnxcc/README
@@ -0,0 +1,362 @@
+cnxcc Module
+
+Carlos Ruiz Diaz
+
+   ConexionGroup S.A.
+
+   Copyright © 2013 Carlos Ruiz Diaz, carlos.ruizdiaz at gmail.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Modules
+
+        3. Parameters
+
+              3.1. dlg_flag (integer)
+              3.2. credit_check_period (integer)
+
+        4. Functions
+
+              4.1. cnxcc_set_max_credit()
+              4.2. cnxcc_set_max_time()
+              4.3. cnxcc_update_max_time()
+              4.4. cnxcc_set_max_channel()
+              4.5. cnxcc_terminate_all()
+
+        5. Exported RPC Commands
+
+              5.1. cnxcc.active_clients
+              5.2. cnxcc.check_client
+              5.3. cnxcc.kill_call
+
+        6. Events
+        7. Web Interface
+        8. Sample
+
+   List of Examples
+
+   1.1. dlg_flag
+   1.2. credit_check_period
+   1.3. cnxcc_set_max_credit()
+   1.4. cnxcc_set_max_time()
+   1.5. cnxcc_update_max_time()
+   1.6. cnxcc_set_max_channels()
+   1.7. cnxcc_set_max_time()
+   1.8. kamailio-cnxcc.cfg
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Modules
+
+   3. Parameters
+
+        3.1. dlg_flag (integer)
+        3.2. credit_check_period (integer)
+
+   4. Functions
+
+        4.1. cnxcc_set_max_credit()
+        4.2. cnxcc_set_max_time()
+        4.3. cnxcc_update_max_time()
+        4.4. cnxcc_set_max_channel()
+        4.5. cnxcc_terminate_all()
+
+   5. Exported RPC Commands
+
+        5.1. cnxcc.active_clients
+        5.2. cnxcc.check_client
+        5.3. cnxcc.kill_call
+
+   6. Events
+   7. Web Interface
+   8. Sample
+
+1. Overview
+
+   This module was designed to act as a mechanism to limit call duration
+   based on credit information parameters. After getting the credit
+   information of the call being set up, you can instruct the module to
+   start monitoring the consumed credit to shutdown a single call or a
+   group of calls in case of credit exhaustion.
+
+   Every call is associated to an unique client/customer identifier. If a
+   credit event occurs, all calls hooked to this identifier are
+   automatically shutdown.
+
+   Cnxcc is dialog-aware so there's no need to explicitly
+   allocate/deallocate the monitoring. Only a single function call inside
+   the script is needed upon reception of the INVITE.
+
+   The credit discount rate is proportional to the number of calls grouped
+   inside an identifier. Once the setup of the first call is done, the
+   information remains while the call is active. If the customer starts a
+   new call with the same routing criteria, it will land in the same
+   monitoring bag and it will consume the same pool of credit in rates
+   that are equal to the cost per second of both calls.
+
+   If your accounting program does not maintain the state of the call in
+   real time, this module can provide you that ability.
+
+   Cnxcc can also provide more common means of monitoring, i.e., by time
+   limit or by maximum simultaneous calls.
+
+2. Dependencies
+
+   2.1. Modules
+
+2.1. Modules
+
+   The following module must be loaded before this module:
+     * dialog
+
+3. Parameters
+
+   3.1. dlg_flag (integer)
+   3.2. credit_check_period (integer)
+
+3.1.  dlg_flag (integer)
+
+   Flag to indicate if the dialog must be monitored or not. Messages are
+   flagged with this value if we call one of the monitoring functions.
+
+   Example 1.1. dlg_flag
+...
+modparam("cnxcc", "dlg_flag", 29)
+...
+
+3.2. credit_check_period (integer)
+
+   Indicates how often the credit checking function should be called. It
+   is directly related to the precison of the module. The maximum
+   precision is 1, which means that every call is checked every one
+   second.
+
+   Values greater than 1 leads to precision lost but less CPU consumption.
+
+   Example 1.2. credit_check_period
+...
+modparam("cnxcc", "credit_check_period", 1)
+...
+
+4. Functions
+
+   4.1. cnxcc_set_max_credit()
+   4.2. cnxcc_set_max_time()
+   4.3. cnxcc_update_max_time()
+   4.4. cnxcc_set_max_channel()
+   4.5. cnxcc_terminate_all()
+
+4.1.  cnxcc_set_max_credit()
+
+   Specifies the initial pulse, final pulse, max credit and cost per
+   second of a call. The discount is calculated in pulses (30/6, 1/1, etc)
+   and sustracted from the pool of credit.
+
+   Return code:
+     * 1 - successful
+     * -1 - failed, error logged
+     * -2 - failed, credit value is less than initial pulse value
+
+   Example 1.3. cnxcc_set_max_credit()
+...
+$var(customer) = "john-doe-123-premium";
+$var(credit) = "100";
+$var(cps)   = "2.00";         # cost per second
+$var(initial_p)   = "030";    # intial pulse
+$var(final_p)   = "006";      # final pulse
+
+cnxcc_set_max_credit("$var(customer)", "$var(credit)", "$var(cps)", "$var(initia
+l_p)", "$var(final_p)");
+...
+
+4.2.  cnxcc_set_max_time()
+
+   Specifies the amount of time the call should last at most.
+
+   Return code:
+     * 1 - successful
+     * -1 - failed, error logged
+
+   Example 1.4. cnxcc_set_max_time()
+...
+$var(customer) = "john-doe-123-basic";
+$var(max_time) = 120;
+
+cnxcc_set_max_time("$var(customer)", "$var(max_time)");
+...
+
+4.3.  cnxcc_update_max_time()
+
+   Updates max-time of an established and monitored call. This can be used
+   to grant minimum values and to update them every short periods on time
+   as a mean to prevent frauds and/or to mimic requested/granted units of
+   time of Credit Control Application behavior.
+
+   Return code:
+     * 1 - successful
+     * -1 - failed, error logged
+
+   Example 1.5. cnxcc_update_max_time()
+...
+        $var(update_time)  = 5;
+        $var(client)       = "john-doe-123-basic";
+
+        if (!cnxcc_update_max_time("$var(client)",
+                                  "$var(update_time)")) {
+                xlog("Error updating max-time");
+                return;
+        }
+
+...
+
+4.4.  cnxcc_set_max_channel()
+
+   Specifies a limit for the number of simultaneous calls
+
+   Return code:
+     * 1 - successful
+     * -1 - failed, error logged
+     * -2 - failed, calls established plus calls being established result
+       in more than the limit you specified
+     * -3 - failed, number of calls established is more than the limit you
+       specified
+
+   Example 1.6. cnxcc_set_max_channels()
+...
+$var(customer)  = "john-doe-123-basic";
+$var(max_chan)  = 2;
+$var(retcode)   = cnxcc_set_max_channels("$var(customer)", "$var(max_chan)");
+
+if ($var(retcode) == -1) {
+        xlog("Error setting up credit control");
+        return;
+}
+
+if ($var(retcode) < -1) {
+        xlog("Too many channels for customer");
+        sl_send_reply(403, "Forbidden");
+
+        if (!cnxcc_terminate_all("$var(customer)")) {
+                xlog("Error terminating customer's calls");
+        }
+
+        exit;
+}
+
+...
+
+4.5.  cnxcc_terminate_all()
+
+   Terminates all calls of the specified customer/profile
+
+   Return code:
+     * 1 - successful
+     * -1 - failed, error logged
+
+   Example 1.7. cnxcc_set_max_time()
+...
+$var(customer)  = "john-doe-123-basic";
+
+if (!cnxcc_terminate_all("$var(customer)")) {
+        xlog("Error terminating customer's calls");
+}
+...
+
+5. Exported RPC Commands
+
+   5.1. cnxcc.active_clients
+   5.2. cnxcc.check_client
+   5.3. cnxcc.kill_call
+
+5.1. cnxcc.active_clients
+
+   Retrieves all calls grouped by their identifiers.
+
+   Parameters: none
+
+   Example:
+            kamcmd cnxcc.active_clients
+
+5.2. cnxcc.check_client
+
+   Retrives all calls from a particular identifier.
+
+   Parameters: client/customer identifier
+
+   Example:
+            kamcmd cnxcc.check_client john-doe-123-premium
+
+5.3. cnxcc.kill_call
+
+   Kills an active call using its call ID.
+
+   Parameters: Call-ID
+
+   Example:
+            kamcmd cnxcc.kill_call qumojlaahitafih at carlosrdcnx-laptop.site
+
+6. Events
+
+   When a call is forced to end an event route is automatically invoked.
+   This route is suited with a fake OPTIONS message containing the call
+   ID, ftag and ttag of the original call so it can be located somehow in
+   the accounting database.
+
+   Example:
+...
+event_route[cnxcc:call-shutdown]
+{
+        xlog("L_INFO", "[$ci]: call killed");
+
+        # perform some kind of notification, database update, email sending, etc
+.
+}
+...
+
+7. Web Interface
+
+   The module contains a web management interface completely optional.
+   With it, you can review your calls in real time and hang them up if
+   necessary.
+
+   Link: https://github.com/caruizdiaz/cnxcc-web
+
+8. Sample
+
+   Example 1.8. kamailio-cnxcc.cfg
+...
+route[CNXCC]
+{
+        $var(client)              = "test-client-0-123-01";
+        $var(credit)              = "50";
+        $var(cost_per_sec)        = "0.5";
+        $var(i_pulse)             = "30";
+        $var(f_pulse)             = "6";
+
+        if (!cnxcc_set_max_credit("$var(client)",
+                          "$var(credit)",
+                          "$var(cost_per_sec)",
+                          "$var(i_pulse)",
+                          "$var(f_pulse)")) {
+                 xlog("Error setting up credit control");
+        }
+}
+
+event_route[cnxcc:call-shutdown]
+{
+        xlog("L_INFO", "[$ci]: call killed");
+
+
+}
+...
diff --git a/modules/cnxcc/cnxcc.c b/modules/cnxcc/cnxcc.c
new file mode 100644
index 0000000..e869af4
--- /dev/null
+++ b/modules/cnxcc/cnxcc.c
@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "cnxcc.h"
+
+inline void get_datetime(str *dest)
+{
+	timestamp2isodt(dest, get_current_timestamp());
+}
+
+inline unsigned int get_current_timestamp()
+{
+	return time(NULL);
+}
+
+inline int timestamp2isodt(str *dest, unsigned int timestamp)
+{
+	time_t  		tim;
+	struct tm 		*tmPtr;
+
+	tim 		= timestamp;
+	tmPtr 		= localtime(&tim);
+
+	strftime( dest->s, DATETIME_SIZE, "%Y-%m-%d %H:%M:%S", tmPtr);
+	dest->len	= DATETIME_LENGTH;
+
+	return 0;
+}
+
+double str2double(str *string)
+{
+	char buffer[string->len + 1];
+
+	buffer[string->len]	= '\0';
+	memcpy(buffer, string->s, string->len);
+
+	return atof(buffer);
+}
diff --git a/modules/cnxcc/cnxcc.h b/modules/cnxcc/cnxcc.h
new file mode 100644
index 0000000..9454e16
--- /dev/null
+++ b/modules/cnxcc/cnxcc.h
@@ -0,0 +1,39 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _CNXCC_H
+#define _CNXCC_H
+
+#include "../../str.h"
+
+#define DATETIME_SIZE		sizeof("0001-01-01 00:00:00")
+#define DATETIME_LENGTH		DATETIME_SIZE - 1
+
+
+inline void get_datetime(str *dest);
+inline unsigned int get_current_timestamp();
+inline int timestamp2isodt(str *dest, unsigned int timestamp);
+double str2double(str *string);
+
+#endif /* _CNXCC_H */
diff --git a/modules/cnxcc/cnxcc_check.c b/modules/cnxcc/cnxcc_check.c
new file mode 100644
index 0000000..eb58899
--- /dev/null
+++ b/modules/cnxcc/cnxcc_check.c
@@ -0,0 +1,193 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdio.h>
+
+#include "../../locking.h"
+#include "../../lock_ops.h"
+
+#include "cnxcc_mod.h"
+#include "cnxcc.h"
+#include "cnxcc_check.h"
+
+extern data_t _data;
+
+void check_calls_by_money(unsigned int ticks, void *param)
+{
+	struct str_hash_entry *h_entry 	= NULL,
+						  *tmp		= NULL;
+	call_t *tmp_call				= NULL;
+	int i;
+
+	lock_get(&_data.money.lock);
+
+	if (_data.money.credit_data_by_client->table)
+		for(i = 0; i < _data.money.credit_data_by_client->size; i++)
+			clist_foreach_safe(&_data.money.credit_data_by_client->table[i], h_entry, tmp, next)
+			{
+				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
+				call_t *call				= NULL;
+				double total_consumed_money	= 0;
+
+				if (i > SAFE_ITERATION_THRESHOLD)
+				{
+					LM_ERR("Too many iterations for this loop: %d", i);
+					break;
+				}
+
+				lock_get(&credit_data->lock);
+
+				clist_foreach_safe(credit_data->call_list, call, tmp_call, next)
+				{
+					int consumed_time = 0;
+
+					if (!call->confirmed)
+						continue;
+
+					consumed_time 				= get_current_timestamp() - call->start_timestamp;
+
+					if (consumed_time > call->money_based.initial_pulse)
+					{
+						call->consumed_amount = (call->money_based.cost_per_second * call->money_based.initial_pulse)
+												+
+												call->money_based.cost_per_second *
+												( (consumed_time - call->money_based.initial_pulse) / call->money_based.final_pulse + 1 ) *
+												call->money_based.final_pulse;
+					}
+
+					total_consumed_money	+= call->consumed_amount;
+
+					if (call->consumed_amount > call->max_amount)
+					{
+						LM_ALERT("[%.*s] call has exhausted its credit. Breaking the loop\n", call->sip_data.callid.len, call->sip_data.callid.s);
+						break;
+					}
+
+					LM_DBG("CID [%.*s], start_timestamp [%d], seconds alive [%d], consumed credit [%f]\n",
+																			call->sip_data.callid.len, call->sip_data.callid.s,
+																			call->start_timestamp,
+																			consumed_time,
+																			call->consumed_amount
+																			);
+				}
+
+				if (credit_data->concurrent_calls == 0)
+				{
+					lock_release(&credit_data->lock);
+					continue;
+				}
+
+				credit_data->consumed_amount	= credit_data->ended_calls_consumed_amount + total_consumed_money;
+
+				LM_DBG("Client [%.*s] | Ended-Calls-Credit-Spent: %f  TotalCredit/MaxCredit: %f/%f\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
+																									credit_data->ended_calls_consumed_amount,
+																									credit_data->consumed_amount,
+																									credit_data->max_amount);
+
+				if (credit_data->consumed_amount >= credit_data->max_amount)
+				{
+					terminate_all_calls(credit_data);
+					lock_release(&credit_data->lock);
+					break;
+				}
+
+				lock_release(&credit_data->lock);
+			}
+
+	lock_release(&_data.money.lock);
+}
+
+void check_calls_by_time(unsigned int ticks, void *param)
+{
+	struct str_hash_entry *h_entry 	= NULL,
+						  *tmp		= NULL;
+	call_t *tmp_call				= NULL;
+	int i;
+
+	lock_get(&_data.time.lock);
+
+	if (_data.time.credit_data_by_client->table)
+		for(i = 0; i < _data.time.credit_data_by_client->size; i++)
+			clist_foreach_safe(&_data.time.credit_data_by_client->table[i], h_entry, tmp, next)
+			{
+				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
+				call_t *call				= NULL;
+				int total_consumed_secs		= 0;
+
+				lock_get(&credit_data->lock);
+
+				if (i > SAFE_ITERATION_THRESHOLD)
+				{
+					LM_ERR("Too many iterations for this loop: %d", i);
+					break;
+				}
+
+				LM_DBG("Iterating through calls of client [%.*s]\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s);
+
+				clist_foreach_safe(credit_data->call_list, call, tmp_call, next)
+				{
+					if (!call->confirmed)
+						continue;
+
+					call->consumed_amount		= get_current_timestamp() - call->start_timestamp;
+					total_consumed_secs			+= call->consumed_amount;
+
+					if (call->consumed_amount > call->max_amount)
+					{
+						LM_ALERT("[%.*s] call has exhausted its time. Breaking the loop\n", call->sip_data.callid.len, call->sip_data.callid.s);
+						break;
+					}
+
+					LM_DBG("CID [%.*s], start_timestamp [%d], seconds alive [%d]\n",
+																			call->sip_data.callid.len, call->sip_data.callid.s,
+																			call->start_timestamp,
+																			(int) call->consumed_amount
+																			);
+				}
+
+				if (credit_data->concurrent_calls == 0)
+				{
+					lock_release(&credit_data->lock);
+					continue;
+				}
+
+				credit_data->consumed_amount	= credit_data->ended_calls_consumed_amount + total_consumed_secs;
+
+				LM_DBG("Client [%.*s] | Ended-Calls-Time: %d  TotalTime/MaxTime: %d/%d\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
+																									(int) credit_data->ended_calls_consumed_amount,
+																									(int) credit_data->consumed_amount,
+																									(int) credit_data->max_amount);
+
+				if (credit_data->consumed_amount >= credit_data->max_amount)
+				{
+					terminate_all_calls(credit_data);
+					lock_release(&credit_data->lock);
+					break;
+				}
+
+				lock_release(&credit_data->lock);
+			}
+
+	lock_release(&_data.time.lock);
+}
diff --git a/modules/cnxcc/cnxcc_check.h b/modules/cnxcc/cnxcc_check.h
new file mode 100644
index 0000000..afb8654
--- /dev/null
+++ b/modules/cnxcc/cnxcc_check.h
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef CNXCC_CHECK_H_
+#define CNXCC_CHECK_H_
+
+#define SAFE_ITERATION_THRESHOLD 5000
+
+void check_calls_by_time(unsigned int ticks, void *param);
+void check_calls_by_money(unsigned int ticks, void *param);
+
+#endif /* CNXCC_CHECK_H_ */
diff --git a/modules/cnxcc/cnxcc_mod.c b/modules/cnxcc/cnxcc_mod.c
new file mode 100644
index 0000000..808df1f
--- /dev/null
+++ b/modules/cnxcc/cnxcc_mod.c
@@ -0,0 +1,1960 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../error.h"
+#include "../../mem/mem.h"
+#include "../../shm_init.h"
+#include "../../mem/shm_mem.h"
+#include "../../pvar.h"
+#include "../../locking.h"
+#include "../../lock_ops.h"
+#include "../../str_hash.h"
+#include "../../timer_proc.h"
+#include "../../modules/tm/tm_load.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/parse_cseq.h"
+#include "../../parser/contact/parse_contact.h"
+#include "../../parser/contact/contact.h"
+#include "../../parser/parse_rr.h"
+#include "../../mod_fix.h"
+#include "../dialog/dlg_load.h"
+#include "../dialog/dlg_hash.h"
+#include "../../mi/mi_types.h"
+#include "../../lib/kcore/faked_msg.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
+
+#include "cnxcc_mod.h"
+#include "cnxcc.h"
+#include "cnxcc_sip_msg_faker.h"
+#include "cnxcc_check.h"
+#include "cnxcc_rpc.h"
+#include "cnxcc_select.h"
+
+MODULE_VERSION
+
+#define HT_SIZE						229
+#define MODULE_NAME					"cnxcc"
+#define NUMBER_OF_TIMERS			2
+
+#define TRUE						1
+#define FALSE						0
+
+data_t _data;
+struct dlg_binds _dlgbinds;
+
+static int fixup_par(void** param, int param_no);
+
+/*
+ *  module core functions
+ */
+static int mod_init(void);
+static int child_init(int);
+static int init_hashtable(struct str_hash_table *ht);
+
+/*
+ * Memory management functions
+ */
+static int shm_str_hash_alloc(struct str_hash_table *ht, int size);
+static void free_credit_data_hash_entry(struct str_hash_entry *e);
+
+/*
+ * PV management functions
+ */
+static int pv_parse_calls_param(pv_spec_p sp, str *in);
+static int pv_get_calls(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+//static int get_str_pv(struct sip_msg* msg, str *pv_name, str *pvvalue);
+
+/*
+ * Billing management functions
+ */
+static int set_max_time(struct sip_msg* msg, char* number, char* str2);
+static int update_max_time(struct sip_msg* msg, char* number, char* str2);
+static int set_max_credit(struct sip_msg* msg, char *str_pv_client, char *str_pv_credit, char *str_pv_cps, char *str_pv_inip, char *str_pv_finp);
+static int set_max_channels(struct sip_msg* msg, char* str_pv_client, char* str_pv_max_chan);
+static int get_channel_count(struct sip_msg* msg, char* str_pv_client, char* str_pv_max_chan);
+static int terminate_all(struct sip_msg* msg, char* str_pv_client);
+
+static void start_billing(str *callid, str tags[2]);
+static void setup_billing(str *callid, unsigned int h_entry, unsigned int h_id);
+static void stop_billing(str *callid);
+static int add_call_by_cid(str *cid, call_t *call, credit_type_t type);
+static credit_data_t *get_or_create_credit_data_entry(str *client_id, credit_type_t type);
+static call_t *alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs);
+static call_t *alloc_new_call_by_money(credit_data_t *credit_data, struct sip_msg *msg, double credit, double cost_per_second, int initial_pulse, int final_pulse);
+static void notify_call_termination(str *callid, str *from_tag, str *to_tag);
+static void free_call(call_t *call);
+static int has_to_tag(struct sip_msg *msg);
+
+/*
+ * MI interface
+ */
+static struct mi_root *mi_credit_control_stats(struct mi_root *tree, void *param);
+
+/*
+ * Dialog management callback functions
+ */
+static void dialog_terminated_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params);
+static void dialog_confirmed_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params);
+static void dialog_created_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params);
+
+static pv_export_t mod_pvs[] =
+{
+	{ {"cnxcc", sizeof("cnxcc")-1 }, PVT_OTHER, pv_get_calls, 0,
+		                pv_parse_calls_param, 0, 0, 0 },
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static cmd_export_t cmds[] =
+{
+	{"cnxcc_set_max_time",   (cmd_function) set_max_time, 2, fixup_pvar_pvar, fixup_free_pvar_pvar, ANY_ROUTE},
+	{"cnxcc_update_max_time",   (cmd_function) update_max_time, 2, fixup_pvar_pvar, fixup_free_pvar_pvar, ANY_ROUTE},
+	{"cnxcc_set_max_credit",   (cmd_function) set_max_credit, 5, fixup_par, NULL, ANY_ROUTE},
+	{"cnxcc_set_max_channels",   (cmd_function) set_max_channels, 2, fixup_pvar_pvar, NULL, ANY_ROUTE},
+	{"cnxcc_get_channel_count",   (cmd_function) get_channel_count, 2, fixup_pvar_pvar, NULL, ANY_ROUTE},
+	{"cnxcc_terminate_all",   (cmd_function) terminate_all, 1, fixup_pvar_null, NULL, ANY_ROUTE},
+
+	{0,0,0,0,0,0}
+};
+
+static param_export_t params[] =
+{
+	{"dlg_flag",  				INT_PARAM,			&_data.ctrl_flag	},
+	{"credit_check_period",  	INT_PARAM,			&_data.check_period	},
+	{ 0, 0, 0 }
+};
+
+static const char* rpc_active_clients_doc[2] =
+{
+	"List of clients with active calls",
+	0
+};
+
+static const char* rpc_check_client_stats_doc[2] =
+{
+	"Check specific client calls",
+	0
+};
+
+static const char* rpc_kill_call_doc[2] =
+{
+	"Kill call using its call ID",
+	0
+};
+
+rpc_export_t ul_rpc[] =
+{
+    {"cnxcc.active_clients",	rpc_active_clients,	rpc_active_clients_doc,	0},
+    {"cnxcc.check_client",		rpc_check_client_stats,	rpc_check_client_stats_doc,	0},
+    {"cnxcc.kill_call",			rpc_kill_call,	rpc_kill_call_doc,	0},
+    {0, 0, 0, 0}
+};
+
+/* selects declaration */
+select_row_t sel_declaration[] = {
+        { NULL, SEL_PARAM_STR, STR_STATIC_INIT("cnxcc"), sel_root, SEL_PARAM_EXPECTED},
+        { sel_root, SEL_PARAM_STR, STR_STATIC_INIT("channels"), sel_channels, SEL_PARAM_EXPECTED|CONSUME_NEXT_STR|FIXUP_CALL},
+        { sel_channels, SEL_PARAM_STR, STR_STATIC_INIT("count"), sel_channels_count, 0},
+
+        { NULL, SEL_PARAM_STR, STR_NULL, NULL, 0}
+};
+
+/** module exports */
+struct module_exports exports =
+{
+	MODULE_NAME,
+	DEFAULT_DLFLAGS, 	/* dlopen flags */
+	cmds,
+	params,
+	0,          		/* exported statistics */
+	0, 		    		/* exported MI functions */
+	mod_pvs,  			/* exported pseudo-variables */
+	0,          		/* extra processes */
+	mod_init,   		/* module initialization function */
+	0,
+	0,
+	child_init          /* per-child init function */
+};
+
+static int fixup_par(void** param, int param_no)
+{
+	str var;
+
+	var.s	= (char *) *param;
+	var.len = strlen(var.s);
+
+	if (fixup_pvar_null(param, 1))
+	{
+		LM_ERR("Invalid PV [%.*s] as parameter\n", var.len, var.s);
+		return E_CFG;
+	}
+/*
+	if (((pv_spec_t*)(*param))->setf == NULL)
+	{
+		LM_ERR("[%.*s] has to be writable\n", var.len, var.s);
+		return E_CFG;
+	} */
+
+	return 0;
+}
+
+static int mod_init(void)
+{
+	LM_INFO("Loading " MODULE_NAME " module\n");
+
+	_data.cs_route_number = route_get(&event_rt, "cnxcc:call-shutdown");
+
+	if (_data.cs_route_number < 0)
+		LM_INFO("No cnxcc:call-shutdown event route found");
+
+	if (_data.cs_route_number > 0 && event_rt.rlist[_data.cs_route_number] == NULL)
+	{
+		LM_INFO("cnxcc:call-shutdown route is empty");
+		_data.cs_route_number	= -1;
+	}
+
+	if (_data.check_period <= 0)
+	{
+		LM_INFO("credit_check_period cannot be less than 1 second");
+		return -1;
+	}
+
+	_data.time.credit_data_by_client	= shm_malloc(sizeof(struct str_hash_table));
+	_data.time.call_data_by_cid 		= shm_malloc(sizeof(struct str_hash_table));
+	_data.money.credit_data_by_client	= shm_malloc(sizeof(struct str_hash_table));
+	_data.money.call_data_by_cid 		= shm_malloc(sizeof(struct str_hash_table));
+	_data.channel.credit_data_by_client	= shm_malloc(sizeof(struct str_hash_table));
+	_data.channel.call_data_by_cid 		= shm_malloc(sizeof(struct str_hash_table));
+
+	_data.stats							= (stats_t *) shm_malloc(sizeof(stats_t));
+
+	if (!_data.stats)
+	{
+		LM_ERR("Error allocating shared memory stats\n");
+		return -1;
+	}
+
+	_data.stats->active		= 0;
+	_data.stats->dropped	= 0;
+	_data.stats->total		= 0;
+
+	if (init_hashtable(_data.time.credit_data_by_client) != 0)
+		return -1;
+
+	if (init_hashtable(_data.time.call_data_by_cid) != 0)
+		return -1;
+
+	if (init_hashtable(_data.money.credit_data_by_client) != 0)
+		return -1;
+
+	if (init_hashtable(_data.money.call_data_by_cid) != 0)
+		return -1;
+
+	if (init_hashtable(_data.channel.credit_data_by_client) != 0)
+		return -1;
+
+	if (init_hashtable(_data.channel.call_data_by_cid) != 0)
+		return -1;
+
+	lock_init(&_data.lock);
+	lock_init(&_data.time.lock);
+	lock_init(&_data.money.lock);
+	lock_init(&_data.channel.lock);
+
+	register_mi_cmd(mi_credit_control_stats, "cnxcc_stats", NULL, NULL, 0);
+
+	/*
+	 * One for time based monitoring
+	 * One for money based monitoring
+	 */
+	register_dummy_timers(NUMBER_OF_TIMERS);
+
+	if (rpc_register_array(ul_rpc) != 0)
+	{
+		LM_ERR("Failed registering RPC commands\n");
+		return -1;
+	}
+
+	if (load_dlg_api(&_dlgbinds) != 0)
+	{
+		LM_ERR("Error loading dialog API\n");
+	    return -1;
+	}
+
+	_dlgbinds.register_dlgcb(NULL, DLGCB_CREATED, dialog_created_callback, NULL, NULL);
+
+	 register_select_table(sel_declaration);
+
+	return 0;
+}
+
+static int child_init(int rank)
+{
+	if (rank != PROC_MAIN)
+		return 0;
+
+
+	if(fork_dummy_timer(PROC_TIMER, "CNXCC TB TIMER", 1,
+			check_calls_by_money, NULL, _data.check_period) < 0)
+	{
+		LM_ERR("failed to register TB TIMER routine as process\n");
+		return -1;
+	}
+
+	if(fork_dummy_timer(PROC_TIMER, "CNXCC MB TIMER", 1,
+								check_calls_by_time, NULL, _data.check_period) < 0)
+	{
+		LM_ERR("failed to register MB TIMER routine as process\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int init_hashtable(struct str_hash_table *ht)
+{
+	if (shm_str_hash_alloc(ht, HT_SIZE) != 0)
+	{
+		LM_ERR("Error allocating shared memory hashtable\n");
+		return -1;
+	}
+
+	str_hash_init(ht);
+
+	return 0;
+}
+
+static void dialog_created_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
+{
+	struct sip_msg *msg	= NULL;
+
+	msg	= params->direction == SIP_REPLY ? params->rpl : params->req;
+
+	if (msg == NULL)
+	{
+		LM_ERR("Error getting direction of SIP msg\n");
+		return;
+	}
+
+	if (isflagset(msg, _data.ctrl_flag) == -1)
+	{
+		LM_DBG("Flag is not set for this message. Ignoring\n");
+		return;
+	}
+
+	LM_DBG("Dialog created for CID [%.*s]", cell->callid.len, cell->callid.s);
+
+	_dlgbinds.register_dlgcb(cell, DLGCB_CONFIRMED, dialog_confirmed_callback, NULL, NULL);
+	_dlgbinds.register_dlgcb(cell, DLGCB_TERMINATED|DLGCB_FAILED|DLGCB_EXPIRED, dialog_terminated_callback, NULL, NULL);
+
+	setup_billing(&cell->callid, cell->h_entry, cell->h_id);
+}
+
+static void dialog_confirmed_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
+{
+	LM_DBG("Dialog confirmed for CID [%.*s]", cell->callid.len, cell->callid.s);
+
+	start_billing(&cell->callid, cell->tag);
+}
+
+static void dialog_terminated_callback(struct dlg_cell *cell, int type, struct dlg_cb_params *params)
+{
+	LM_DBG("Dialog terminated for CID [%.*s]", cell->callid.len, cell->callid.s);
+
+	stop_billing(&cell->callid);
+}
+
+static void notify_call_termination(str *callid, str *from_tag, str *to_tag)
+{
+	struct run_act_ctx ra_ctx;
+	struct sip_msg *msg;
+
+	if (_data.cs_route_number < 0)
+		return;
+
+	if (faked_msg_init_with_dlg_info(callid, from_tag, to_tag,  &msg) != 0)
+	{
+		LM_ERR("[%.*s]: error generating faked sip message\n", callid->len, callid->s);
+		return;
+	}
+
+	init_run_actions_ctx(&ra_ctx);
+	//run_top_route(event_rt.rlist[_data.cs_route_number], msg, &ra_ctx);
+
+	if (run_actions(&ra_ctx, event_rt.rlist[_data.cs_route_number], msg) < 0)
+		LM_ERR("Error executing cnxcc:call-shutdown route");
+}
+
+int try_get_credit_data_entry(str *client_id, credit_data_t **credit_data)
+{
+	struct str_hash_entry *cd_entry	= NULL;
+	hash_tables_t *hts				= NULL;
+	*credit_data					= NULL;
+
+	/* by money */
+	hts					= &_data.money;
+	lock_get(&hts->lock);
+
+	cd_entry			= str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
+
+	if (cd_entry != NULL)
+	{
+		*credit_data	= cd_entry->u.p;
+		lock_release(&hts->lock);
+		return 0;
+	}
+
+	lock_release(&hts->lock);
+
+	/* by time */
+	hts					= &_data.time;
+	lock_get(&hts->lock);
+
+	cd_entry			= str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
+
+	if (cd_entry != NULL)
+	{
+		*credit_data	= cd_entry->u.p;
+		lock_release(&hts->lock);
+		return 0;
+	}
+
+	lock_release(&hts->lock);
+
+	/* by channel */
+	hts					= &_data.channel;
+	lock_get(&hts->lock);
+
+	cd_entry			= str_hash_get(hts->credit_data_by_client, client_id->s, client_id->len);
+
+	if (cd_entry != NULL)
+	{
+		*credit_data	= cd_entry->u.p;
+		lock_release(&hts->lock);
+		return 0;
+	}
+
+	lock_release(&hts->lock);
+
+	return -1;
+}
+
+int try_get_call_entry(str *callid, call_t **call, hash_tables_t **hts)
+{
+	struct str_hash_entry *call_entry	= NULL;
+
+	*call					= NULL;
+
+	/* by money */
+	*hts					= &_data.money;
+	lock_get(&(*hts)->lock);
+
+	call_entry			= str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
+
+	if (call_entry != NULL)
+	{
+		*call	= call_entry->u.p;
+		lock_release(&(*hts)->lock);
+		return 0;
+	}
+
+	lock_release(&(*hts)->lock);
+
+	/* by time */
+	*hts				= &_data.time;
+	lock_get(&(*hts)->lock);
+
+	call_entry			= str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
+
+	if (call_entry != NULL)
+	{
+		*call	= call_entry->u.p;
+		lock_release(&(*hts)->lock);
+		return 0;
+	}
+
+	lock_release(&(*hts)->lock);
+
+	/* by channel */
+	*hts				= &_data.channel;
+	lock_get(&(*hts)->lock);
+
+	call_entry			= str_hash_get((*hts)->call_data_by_cid, callid->s, callid->len);
+
+	if (call_entry != NULL)
+	{
+		*call	= call_entry->u.p;
+		lock_release(&(*hts)->lock);
+		return 0;
+	}
+
+	lock_release(&(*hts)->lock);
+
+	return -1;
+}
+
+static void stop_billing(str *callid)
+{
+	struct str_hash_entry *cd_entry		= NULL;
+	call_t *call						= NULL;
+	hash_tables_t *hts					= NULL;
+	credit_data_t *credit_data			= NULL;
+
+	/*
+	 * Search call data by call-id
+	 */
+	if (try_get_call_entry(callid, &call, &hts) != 0)
+	{
+		LM_ERR("Call [%.*s] not found", callid->len, callid->s);
+		return;
+	}
+
+	if (call == NULL)
+	{
+		LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
+		return;
+	}
+
+	if (hts == NULL)
+	{
+		LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
+		return;
+	}
+
+	lock_get(&hts->lock);
+
+	/*
+	 * Search credit_data by client_id
+	 */
+	cd_entry			= str_hash_get(hts->credit_data_by_client, call->client_id.s, call->client_id.len);
+
+	if (cd_entry == NULL)
+	{
+		LM_ERR("Credit data not found for CID [%.*s], client-ID [%.*s]\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
+		lock_release(&hts->lock);
+		return;
+	}
+
+	credit_data	= (credit_data_t *) cd_entry->u.p;
+
+	if (credit_data == NULL)
+	{
+		LM_ERR("[%.*s]: credit_data pointer is null", callid->len, callid->s);
+		lock_release(&hts->lock);
+		return;
+	}
+
+	lock_release(&hts->lock);
+
+	/*
+	 * Update calls statistics
+	 */
+	lock_get(&_data.lock);
+
+	_data.stats->active--;
+	_data.stats->total--;
+
+	lock_release(&_data.lock);
+
+	lock(&credit_data->lock);
+
+	LM_DBG("Call [%.*s] of client-ID [%.*s], ended\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
+
+	/*
+	 * This call just ended and we need to remove it from the summ.
+	 */
+	if (call->confirmed)
+	{
+		credit_data->concurrent_calls--;
+		credit_data->ended_calls_consumed_amount += call->consumed_amount;
+	}
+
+	credit_data->number_of_calls--;
+
+	if (credit_data->concurrent_calls < 0)
+	{
+		LM_ERR("[BUG]: number of concurrent calls dropped to negative value: %d", credit_data->concurrent_calls);
+	}
+
+	if (credit_data->number_of_calls < 0)
+	{
+		LM_ERR("[BUG]: number of calls dropped to negative value: %d", credit_data->number_of_calls);
+	}
+
+	/*
+	 * Remove (and free) the call from the list of calls of the current credit_data
+	 */
+	clist_rm(call, next, prev);
+	free_call(call);
+
+	/*
+	 * In case there are no active calls for a certain client, we remove the client-id from the hash table.
+	 * This way, we can save memory for useful clients.
+	 */
+	if (credit_data->number_of_calls == 0)
+	{
+		LM_DBG("Removing client [%.*s] and its calls from the list\n", credit_data->call_list->client_id.len, credit_data->call_list->client_id.s);
+
+		lock(&hts->lock);
+		/*
+		 * Remove the credit_data_t from the hash table
+		 */
+		str_hash_del(cd_entry);
+
+		lock_release(&hts->lock);
+
+		/*
+		 * Free client_id in list's root
+		 */
+		shm_free(credit_data->call_list->client_id.s);
+		shm_free(credit_data->call_list);
+
+		/*
+		 * Release the lock since we are going to free the entry down below
+		 */
+		lock_release(&credit_data->lock);
+
+		/*
+		 * Free the whole entry
+		 */
+		free_credit_data_hash_entry(cd_entry);
+
+		/*
+		 * return without releasing the acquired lock over credit_data. Why? Because we just freed it.
+		 */
+		return;
+	}
+
+	lock_release(&credit_data->lock);
+}
+
+static void setup_billing(str *callid, unsigned int h_entry, unsigned int h_id)
+{
+	call_t *call						= NULL;
+	hash_tables_t *hts					= NULL;
+
+	LM_DBG("Creating dialog for [%.*s], h_id [%u], h_entry [%u]", callid->len, callid->s, h_id, h_entry);
+
+//	lock_get(&_data.lock);
+
+	/*
+	 * Search call data by call-id
+	 */
+	if (try_get_call_entry(callid, &call, &hts) != 0)
+	{
+		LM_ERR("Call [%.*s] not found", callid->len, callid->s);
+		return;
+	}
+
+	if (call == NULL)
+	{
+		LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
+		return;
+	}
+
+	if (hts == NULL)
+	{
+		LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
+		return;
+	}
+
+	/*
+	 * Update calls statistics
+	 */
+	lock_get(&_data.lock);
+
+	_data.stats->active++;
+	_data.stats->total++;
+
+	lock_release(&_data.lock);
+
+	lock_get(&call->lock);
+
+	call->dlg_h_entry		= h_entry;
+	call->dlg_h_id			= h_id;
+
+	LM_DBG("Call [%.*s] from client [%.*s], created\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
+
+	lock_release(&call->lock);
+}
+
+static void start_billing(str *callid, str tags[2])
+{
+	struct str_hash_entry *cd_entry		= NULL;
+	call_t *call						= NULL;
+	hash_tables_t *hts					= NULL;
+	credit_data_t *credit_data			= NULL;
+
+	LM_DBG("Billing started for call [%.*s]", callid->len, callid->s);
+
+//	lock_get(&_data.lock);
+
+	/*
+	 * Search call data by call-id
+	 */
+	if (try_get_call_entry(callid, &call, &hts) != 0)
+	{
+		LM_ERR("Call [%.*s] not found", callid->len, callid->s);
+		return;
+	}
+
+	if (call == NULL)
+	{
+		LM_ERR("[%.*s] call pointer is null", callid->len, callid->s);
+		return;
+	}
+
+	if (hts == NULL)
+	{
+		LM_ERR("[%.*s] result hashtable pointer is null", callid->len, callid->s);
+		return;
+	}
+
+	lock_get(&hts->lock);
+
+	/*
+	 * Search credit_data by client_id
+	 */
+	cd_entry			= str_hash_get(hts->credit_data_by_client, call->client_id.s, call->client_id.len);
+
+	if (cd_entry == NULL)
+	{
+		LM_ERR("Credit data not found for CID [%.*s], client-ID [%.*s]\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
+		lock_release(&hts->lock);
+		return;
+	}
+
+	credit_data	= (credit_data_t *) cd_entry->u.p;
+
+	if (credit_data == NULL)
+	{
+		LM_ERR("[%.*s]: credit_data pointer is null", callid->len, callid->s);
+		lock_release(&hts->lock);
+		return;
+	}
+
+	lock_release(&hts->lock);
+
+	lock(&credit_data->lock);
+
+	/*
+	 * Now that the call is confirmed, we can increase the count of "concurrent_calls".
+	 * This will impact in the discount rate performed by the check_calls() function.
+	 *
+	 */
+	credit_data->concurrent_calls++;
+
+	if (credit_data->max_amount == 0)
+		credit_data->max_amount	= call->max_amount; // first time setup
+
+	if (call->max_amount > credit_data->max_amount)
+	{
+		LM_ALERT("Maximum-speak-time/credit changed, maybe a credit reload? %f > %f. Client [%.*s]", call->max_amount, credit_data->max_amount,
+																							call->client_id.len, call->client_id.s);
+
+		credit_data->max_amount += call->max_amount - credit_data->max_amount;
+	}
+
+	/*
+	 * Update max_amount, discounting what was already consumed by other calls of the same client
+	 */
+
+	call->max_amount = credit_data->max_amount - credit_data->consumed_amount;
+
+	lock_release(&credit_data->lock);
+
+	lock_get(&call->lock);
+
+	/*
+	 * Store from-tag value
+	 */
+	if (shm_str_dup(&call->sip_data.from_tag, &tags[0]) != 0)
+	{
+		LM_ERR("No more pkg memory\n");
+		goto exit;
+	}
+
+	/*
+	 * Store to-tag value
+	 */
+	if (shm_str_dup(&call->sip_data.to_tag, &tags[1]) != 0)
+	{
+		LM_ERR("No more pkg memory\n");
+		goto exit;
+	}
+
+	call->start_timestamp	= get_current_timestamp();
+	call->confirmed			= TRUE;
+
+	LM_DBG("Call [%.*s] from client [%.*s], confirmed\n", callid->len, callid->s, call->client_id.len, call->client_id.s);
+
+exit:
+	lock_release(&call->lock);
+}
+
+
+void terminate_all_calls(credit_data_t *credit_data)
+{
+	call_t 	*call 	= NULL,
+			*tmp 	= NULL;
+
+	clist_foreach_safe(credit_data->call_list, call, tmp, next)
+	{
+		LM_DBG("Killing call with CID [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
+
+		/*
+		 * Update number of calls forced to end
+		 */
+		_data.stats->dropped++;
+
+		terminate_call(call);
+	}
+}
+
+/*
+ * WARNING: When calling this function, the proper lock should have been acquired
+ */
+static void free_call(call_t *call)
+{
+	struct str_hash_entry *e	= NULL;
+
+	LM_DBG("Freeing call [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
+
+	e			= str_hash_get(_data.money.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
+
+	if (e == NULL)
+	{
+		e			= str_hash_get(_data.time.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
+
+		if (e == NULL)
+		{
+			e			= str_hash_get(_data.channel.call_data_by_cid, call->sip_data.callid.s, call->sip_data.callid.len);
+
+			if (e == NULL)
+			{
+				LM_ERR("Call [%.*s] not found. Couldn't be able to free it from hashtable", call->sip_data.callid.len, call->sip_data.callid.s);
+				return;
+			}
+		}
+	}
+
+	str_hash_del(e);
+
+	shm_free(e->key.s);
+	shm_free(e);
+
+	str_shm_free_if_not_null(call->sip_data.callid);
+	str_shm_free_if_not_null(call->sip_data.to_tag);
+	str_shm_free_if_not_null(call->sip_data.from_tag);
+
+	shm_free(call);
+}
+
+/*
+ * WARNING: When calling this function, the proper lock should have been acquired
+ */
+static void free_credit_data_hash_entry(struct str_hash_entry *e)
+{
+	shm_free(e->key.s);
+//	shm_free(((credit_data_t *) e->u.p)->call);
+	shm_free(e->u.p);
+	shm_free(e);
+}
+
+static int shm_str_hash_alloc(struct str_hash_table *ht, int size)
+{
+	ht->table	= shm_malloc(sizeof(struct str_hash_head) * size);
+
+	if (!ht->table)
+		return -1;
+
+	ht->size	= size;
+	return 0;
+}
+
+static credit_data_t *get_or_create_credit_data_entry(str *client_id, credit_type_t type)
+{
+	struct str_hash_table *ht	= NULL;
+	gen_lock_t *lock			= NULL;
+	struct str_hash_entry *e	= NULL;
+
+	switch(type)
+	{
+	case CREDIT_MONEY:
+		ht		= _data.money.credit_data_by_client;
+		lock	=  &_data.money.lock;
+		break;
+	case CREDIT_TIME:
+		ht		= _data.time.credit_data_by_client;
+		lock	=  &_data.time.lock;
+		break;
+	case CREDIT_CHANNEL:
+		ht		= _data.channel.credit_data_by_client;
+		lock	=  &_data.channel.lock;
+		break;
+	default:
+		LM_ERR("Something went terribly wrong");
+		return NULL;
+	}
+
+
+	lock_get(lock);
+	e							= str_hash_get(ht, client_id->s, client_id->len);
+	lock_release(lock);
+
+	/*
+	 * Alloc new call_array_t if it doesn't exist
+	 */
+	if (e != NULL)
+	{
+		LM_DBG("Found key %.*s in hash table\n", e->key.len, e->key.s);
+	}
+	else
+	{
+		credit_data_t *credit_data	= NULL;
+		e							= shm_malloc(sizeof(struct str_hash_entry));
+
+		if (e == NULL)
+		{
+			LM_ERR("No shared memory left\n");
+			return NULL;
+		}
+
+		if (shm_str_dup(&e->key, client_id) != 0)
+		{
+			LM_ERR("No shared memory left\n");
+			return NULL;
+		}
+
+		e->flags					= 0;
+		e->u.p						= (void *) shm_malloc(sizeof(credit_data_t));
+		credit_data					= (credit_data_t *) e->u.p;
+
+		lock_init(&credit_data->lock);
+
+		credit_data->call_list 		= shm_malloc(sizeof(call_t));
+
+		if (credit_data->call_list == NULL)
+		{
+			LM_ERR("No shared memory left\n");
+			return NULL;
+		}
+
+		credit_data->max_amount					= 0;
+		credit_data->concurrent_calls			= 0;
+		credit_data->consumed_amount			= 0;
+		credit_data->ended_calls_consumed_amount= 0;
+		credit_data->number_of_calls			= 0;
+
+		credit_data->type						= type;
+
+		/*
+		 * Copy the client_id value to the root of the calls list.
+		 * This will be used later to get the credit_data_t of the
+		 * call when it is being searched by call ID.
+		 */
+		if (shm_str_dup(&credit_data->call_list->client_id, client_id) != 0)
+		{
+			LM_ERR("No shared memory left\n");
+			return NULL;
+		}
+
+		clist_init(credit_data->call_list, next, prev);
+
+		lock_get(lock);
+		str_hash_add(ht, e);
+		lock_release(lock);
+
+		LM_DBG("Call didn't exist. Allocated new entry\n");
+	}
+
+	return (credit_data_t *) e->u.p;
+}
+
+int terminate_call(call_t *call)
+{
+	LM_DBG("Got kill signal for call [%.*s] client [%.*s] h_id [%u] h_entry [%u]. Dropping it now\n",
+						call->sip_data.callid.len,
+						call->sip_data.callid.s,
+						call->client_id.len,
+						call->client_id.s,
+						call->dlg_h_id,
+						call->dlg_h_entry);
+
+	struct mi_root *root, *result	= NULL;
+	struct mi_node *node, *node1	= NULL;
+	struct mi_cmd *end_dlg_cmd		= NULL;
+
+	root	= init_mi_tree(0, 0, 0);
+	if (root == NULL)
+	{
+		LM_ERR("Error initializing tree to terminate call\n");
+		goto error;
+	}
+
+	node	= &root->node;
+
+	node1	= addf_mi_node_child(node, MI_DUP_VALUE, MI_SSTR("h_entry"), "%u", call->dlg_h_entry);
+	if (node1 == NULL)
+	{
+		LM_ERR("Error initializing h_entry node to terminate call\n");
+		goto error;
+	}
+
+	node1	= addf_mi_node_child(node, MI_DUP_VALUE, MI_SSTR("h_id"), "%u", call->dlg_h_id);
+	if (node1 == NULL)
+	{
+		LM_ERR("Error initializing dlg_h_id node to terminate call\n");
+		goto error;
+	}
+
+	end_dlg_cmd = lookup_mi_cmd(MI_SSTR("dlg_end_dlg"));
+	if (node == NULL)
+	{
+		LM_ERR("Error initializing dlg_end_dlg command\n");
+		goto error;
+	}
+
+	result		= run_mi_cmd(end_dlg_cmd, root);
+	if (result == NULL)
+	{
+		LM_ERR("Error executing dlg_end_dlg command\n");
+		goto error;
+	}
+
+	if (result->code == 200)
+	{
+		LM_DBG("dlg_end_dlg sent to call [%.*s]\n", call->sip_data.callid.len, call->sip_data.callid.s);
+		free_mi_tree(root);
+		free_mi_tree(result);
+
+		notify_call_termination(&call->sip_data.callid, &call->sip_data.from_tag, &call->sip_data.to_tag);
+
+		return 0;
+	}
+
+	LM_ERR("Error executing dlg_end_dlg command. Return code was [%d]\n", result->code);
+error:
+	if (root)
+		free_mi_tree(root);
+
+	return -1;
+}
+
+static call_t *alloc_new_call_by_money(credit_data_t *credit_data,
+										struct sip_msg *msg, double credit, double cost_per_second, int initial_pulse, int final_pulse)
+{
+	call_t *call		= NULL;
+
+	lock_get(&credit_data->lock);
+
+	if (credit_data->call_list == NULL)
+	{
+		LM_ERR("Credit data call list is NULL\n");
+		goto error;
+	}
+
+	call 				= shm_malloc(sizeof(call_t));
+	if (call == NULL)
+	{
+		LM_ERR("No shared memory left\n");
+		goto error;
+	}
+
+	if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
+		   shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
+	{
+		LM_ERR("Error processing CALLID hdr\n");
+		goto error;
+	}
+
+	call->sip_data.to_tag.s		= NULL;
+	call->sip_data.to_tag.len 	= 0;
+	call->sip_data.from_tag.s	= NULL;
+	call->sip_data.from_tag.len = 0;
+
+	call->consumed_amount		= initial_pulse * cost_per_second;
+	call->confirmed				= FALSE;
+	call->max_amount			= credit;
+
+	call->money_based.cost_per_second	= cost_per_second;
+	call->money_based.initial_pulse		= initial_pulse;
+	call->money_based.final_pulse		= final_pulse;
+
+	/*
+	 * Reference the client_id from the root of the list
+	 */
+	call->client_id.s			= credit_data->call_list->client_id.s;
+	call->client_id.len			= credit_data->call_list->client_id.len;
+
+	/*
+	 * Insert the newly created call to the list of calls
+	 */
+	clist_insert(credit_data->call_list, call, next, prev);
+
+	lock_init(&call->lock);
+
+	/*
+	 * Increase the number of calls for this client. This call is not yet confirmed.
+	 */
+	credit_data->number_of_calls++;
+
+	lock_release(&credit_data->lock);
+
+	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
+
+	return call;
+
+error:
+	lock_release(&credit_data->lock);
+	return NULL;
+}
+
+static call_t *alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs)
+{
+	call_t *call		= NULL;
+
+	lock_get(&credit_data->lock);
+
+	if (credit_data->call_list == NULL)
+	{
+		LM_ERR("Credit data call list is NULL\n");
+		goto error;
+	}
+
+	call 				= shm_malloc(sizeof(call_t));
+	if (call == NULL)
+	{
+		LM_ERR("No shared memory left\n");
+		goto error;
+	}
+
+	if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
+		   shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
+	{
+		LM_ERR("Error processing CALLID hdr\n");
+		goto error;
+	}
+
+	call->sip_data.to_tag.s		= NULL;
+	call->sip_data.to_tag.len 	= 0;
+	call->sip_data.from_tag.s	= NULL;
+	call->sip_data.from_tag.len = 0;
+
+	call->consumed_amount		= 0;
+	call->confirmed				= FALSE;
+	call->max_amount			= max_secs;
+
+	/*
+	 * Reference the client_id from the root of the list
+	 */
+	call->client_id.s			= credit_data->call_list->client_id.s;
+	call->client_id.len			= credit_data->call_list->client_id.len;
+
+	/*
+	 * Insert the newly created call to the list of calls
+	 */
+	clist_insert(credit_data->call_list, call, next, prev);
+
+	lock_init(&call->lock);
+
+	/*
+	 * Increase the number of calls for this client. This call is not yet confirmed.
+	 */
+	credit_data->number_of_calls++;
+
+	lock_release(&credit_data->lock);
+
+	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
+
+	return call;
+
+error:
+	lock_release(&credit_data->lock);
+	return NULL;
+}
+
+static call_t *alloc_new_call_by_channel(credit_data_t *credit_data, struct sip_msg *msg, int max_chan)
+{
+	call_t *call		= NULL;
+
+	lock_get(&credit_data->lock);
+
+	if (credit_data->call_list == NULL)
+	{
+		LM_ERR("Credit data call list is NULL\n");
+		goto error;
+	}
+
+	call 				= shm_malloc(sizeof(call_t));
+	if (call == NULL)
+	{
+		LM_ERR("No shared memory left\n");
+		goto error;
+	}
+
+	if ( (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0) ||
+		   shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0 )
+	{
+		LM_ERR("Error processing CALLID hdr\n");
+		goto error;
+	}
+
+	call->sip_data.to_tag.s		= NULL;
+	call->sip_data.to_tag.len 	= 0;
+	call->sip_data.from_tag.s	= NULL;
+	call->sip_data.from_tag.len = 0;
+
+	call->consumed_amount		= 0;
+	call->confirmed				= FALSE;
+	call->max_amount			= max_chan;
+
+	/*
+	 * Reference the client_id from the root of the list
+	 */
+	call->client_id.s			= credit_data->call_list->client_id.s;
+	call->client_id.len			= credit_data->call_list->client_id.len;
+
+	/*
+	 * Insert the newly created call to the list of calls
+	 */
+	clist_insert(credit_data->call_list, call, next, prev);
+
+	lock_init(&call->lock);
+
+	/*
+	 * Increase the number of calls for this client. This call is not yet confirmed.
+	 */
+	credit_data->number_of_calls++;
+
+	lock_release(&credit_data->lock);
+
+	LM_DBG("New call allocated for client [%.*s]\n", call->client_id.len, call->client_id.s);
+
+
+	return call;
+
+error:
+	lock_release(&credit_data->lock);
+	return NULL;
+}
+
+static int add_call_by_cid(str *cid, call_t *call, credit_type_t type)
+{
+	struct str_hash_table *ht	= NULL;
+	gen_lock_t *lock			= NULL;
+	struct str_hash_entry *e	= NULL;
+
+	switch(type)
+	{
+	case CREDIT_MONEY:
+		ht		= _data.money.call_data_by_cid;
+		lock	=  &_data.money.lock;
+		break;
+	case CREDIT_TIME:
+		ht		= _data.time.call_data_by_cid;
+		lock	=  &_data.time.lock;
+		break;
+	case CREDIT_CHANNEL:
+		ht		= _data.channel.call_data_by_cid;
+		lock	=  &_data.channel.lock;
+		break;
+	default:
+		LM_ERR("Something went terribly wrong");
+		return -1;
+	}
+
+	e	= str_hash_get(ht, cid->s, cid->len);
+
+	if (e != NULL)
+	{
+		LM_DBG("e != NULL\n");
+
+		call_t *value	= (call_t *) e->u.p;
+
+		if (value == NULL)
+		{
+			LM_ERR("Value of CID [%.*s] is NULL\n", cid->len, cid->s);
+			return -1;
+		}
+
+		LM_WARN("value cid: len=%d | value [%.*s]", value->sip_data.callid.len, value->sip_data.callid.len, value->sip_data.callid.s);
+		LM_WARN("added cid: len=%d | value [%.*s]", cid->len, cid->len, cid->s);
+
+		if (value->sip_data.callid.len != cid->len ||
+			strncasecmp(value->sip_data.callid.s, cid->s, cid->len) != 0)
+		{
+			LM_ERR("Value of CID is [%.*s] and differs from value being added [%.*s]\n", cid->len, cid->s,
+																			value->sip_data.callid.len, value->sip_data.callid.s);
+			return -1;
+		}
+
+		LM_DBG("CID already present\n");
+
+		return 0;
+	}
+
+	e	= shm_malloc(sizeof(struct str_hash_entry));
+
+	if (e == NULL)
+	{
+		LM_ERR("No shared memory left\n");
+		return -1;
+	}
+
+	if (shm_str_dup(&e->key, cid) != 0)
+	{
+		LM_ERR("No shared memory left\n");
+		return -1;
+	}
+
+	e->u.p		= call;
+
+	lock_get(lock);
+	str_hash_add(ht, e);
+	lock_release(lock);
+
+	return 0;
+}
+
+static inline void set_ctrl_flag(struct sip_msg* msg)
+{
+	if (_data.ctrl_flag != -1)
+	{
+		LM_DBG("Flag set!\n");
+		setflag(msg, _data.ctrl_flag);
+	}
+}
+
+static inline int get_pv_value(struct sip_msg* msg, pv_spec_t* spec, pv_value_t* value)
+{
+	if (pv_get_spec_value(msg, spec, value) != 0)
+	{
+		LM_ERR("Can't get PV's value\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int set_max_credit(struct sip_msg* msg,
+							char *str_pv_client,
+							char *str_pv_credit, char *str_pv_cps,
+							char *str_pv_inip, char *str_pv_finp)
+{
+	credit_data_t *credit_data 	= NULL;
+	call_t *call				= NULL;
+
+	pv_spec_t *client_id_spec		= (pv_spec_t *) str_pv_client,
+			  *credit_spec			= (pv_spec_t *) str_pv_credit,
+			  *cps_spec				= (pv_spec_t *) str_pv_cps,
+			  *initial_pulse_spec	= (pv_spec_t *) str_pv_inip,
+			  *final_pulse_spec		= (pv_spec_t *) str_pv_finp;
+
+	pv_value_t client_id_val,
+				credit_val,
+				cps_val,
+				initial_pulse_val,
+				final_pulse_val;
+
+	double credit					= 0,
+		   cost_per_second			= 0;
+
+	unsigned int initial_pulse		= 0,
+			final_pulse				= 0;
+
+	if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
+	{
+		if (has_to_tag(msg))
+		{
+			LM_ERR("INVITE is a reINVITE\n");
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
+		{
+			LM_ERR("Can't get client_id's value\n");
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, credit_spec, &credit_val) != 0)
+		{
+			LM_ERR("Can't get credit's value\n");
+			return -1;
+		}
+
+		credit	= str2double(&credit_val.rs);
+
+		if (credit <= 0)
+		{
+			LM_ERR("credit value must be > 0: %f", credit);
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, cps_spec, &cps_val) != 0)
+		{
+			LM_ERR("Can't get cost_per_sec's value\n");
+			return -1;
+		}
+
+		cost_per_second	= str2double(&cps_val.rs);
+
+		if (cost_per_second <= 0)
+		{
+			LM_ERR("cost_per_second value must be > 0: %f", cost_per_second);
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, initial_pulse_spec, &initial_pulse_val) != 0)
+		{
+			LM_ERR("Can't get initial_pulse's value\n");
+			return -1;
+		}
+
+		if (str2int(&initial_pulse_val.rs, &initial_pulse) != 0)
+		{
+			LM_ERR("initial_pulse value is invalid: %.*s", initial_pulse_val.rs.len, initial_pulse_val.rs.s);
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, final_pulse_spec, &final_pulse_val) != 0)
+		{
+			LM_ERR("Can't get final_pulse's value\n");
+			return -1;
+		}
+
+		if (str2int(&final_pulse_val.rs, &final_pulse) != 0)
+		{
+			LM_ERR("final_pulse value is invalid: %.*s", final_pulse_val.rs.len, final_pulse_val.rs.s);
+			return -1;
+		}
+
+		if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
+		{
+			LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
+			return -1;
+		}
+
+		LM_DBG("Setting up new call for client [%.*s], max-credit[%f], "
+				"cost-per-sec[%f], initial-pulse [%d], "
+				"final-pulse [%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
+													 credit,
+													 cost_per_second, initial_pulse,
+													 final_pulse, msg->callid->body.len, msg->callid->body.s);
+		set_ctrl_flag(msg);
+
+		if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_MONEY)) == NULL)
+		{
+			LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+
+		if ((call = alloc_new_call_by_money(credit_data, msg, credit, cost_per_second, initial_pulse, final_pulse)) == NULL)
+		{
+			LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+
+		if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_MONEY) != 0)
+		{
+			LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+	}
+	else
+	{
+		LM_ALERT("MSG was not an INVITE\n");
+		return -1;
+	}
+
+	return 1;
+}
+
+static int terminate_all(struct sip_msg* msg, char* str_pv_client)
+{
+	credit_data_t *credit_data 	= NULL;
+	pv_spec_t *client_id_spec	= (pv_spec_t *) str_pv_client;
+
+	pv_value_t client_id_val;
+
+	if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
+	{
+		LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
+		return -1;
+	}
+
+	if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
+	{
+		LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
+		return -1;
+	}
+
+	if (try_get_credit_data_entry(&client_id_val.rs, &credit_data) != 0)
+	{
+		LM_DBG("[%.*s] not found\n", msg->callid->body.len, msg->callid->body.s);
+		return -1;
+	}
+
+	terminate_all_calls(credit_data);
+
+	return 1;
+}
+
+static int get_channel_count(struct sip_msg* msg, char* str_pv_client, char* str_pv_chan_count)
+{
+	credit_data_t *credit_data 	= NULL;
+	pv_spec_t *chan_count_spec	= (pv_spec_t *) str_pv_chan_count,
+			  *client_id_spec	= (pv_spec_t *) str_pv_client;
+
+	pv_value_t chan_count_val, client_id_val;
+	int value					= -1;
+
+	if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
+	{
+		LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
+		return -1;
+	}
+
+	if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
+	{
+		LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
+		return -1;
+	}
+
+	if (try_get_credit_data_entry(&client_id_val.rs, &credit_data) == 0)
+		value	= credit_data->number_of_calls;
+	else
+		LM_ALERT("[%.*s] not found\n", msg->callid->body.len, msg->callid->body.s);
+
+	if (!pv_is_w(chan_count_spec))
+	{
+		LM_ERR("pvar is not writable");
+		return -1;
+	}
+
+	memset(&chan_count_val, 0, sizeof(chan_count_val));
+
+	chan_count_val.flags 	= PV_VAL_STR;
+
+	if (value > 0)
+		chan_count_val.rs.s 	= int2str(value, &chan_count_val.rs.len);
+	else
+	{
+		char buff[2]			= { '-', '1' };
+		chan_count_val.rs.s 	= buff;
+		chan_count_val.rs.len	= 2;
+	}
+
+	if (pv_set_spec_value(msg, chan_count_spec, 0, &chan_count_val) != 0)
+	{
+		LM_ERR("Error writing value to pvar");
+		return -1;
+	}
+
+	return 1;
+}
+
+static int set_max_channels(struct sip_msg* msg, char* str_pv_client, char* str_pv_max_chan)
+{
+	credit_data_t *credit_data 	= NULL;
+	call_t *call				= NULL;
+	pv_spec_t *max_chan_spec	= (pv_spec_t *) str_pv_max_chan,
+			  *client_id_spec	= (pv_spec_t *) str_pv_client;
+	pv_value_t max_chan_val, client_id_val;
+	int max_chan				= 0;
+
+	set_ctrl_flag(msg);
+
+	if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
+	{
+		LM_ERR("Error parsing Call-ID");
+		return -1;
+	}
+
+	if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
+	{
+		if (has_to_tag(msg))
+		{
+			LM_ERR("INVITE is a reINVITE\n");
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, max_chan_spec, &max_chan_val) != 0)
+		{
+			LM_ERR("Can't get max_chan pvar value\n");
+			return -1;
+		}
+		max_chan	= max_chan_val.ri;
+
+		if (max_chan <= 0)
+		{
+			LM_ERR("[%.*s] MAX_CHAN cannot be less than or equal to zero: %d\n", msg->callid->body.len, msg->callid->body.s, max_chan);
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
+		{
+			LM_ERR("[%.*s]: can't get client_id pvar value\n", msg->callid->body.len, msg->callid->body.s);
+			return -1;
+		}
+
+		if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
+		{
+			LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
+			return -1;
+		}
+
+		LM_DBG("Setting up new call for client [%.*s], max-chan[%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
+																		max_chan,
+																		msg->callid->body.len, msg->callid->body.s);
+
+		if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_CHANNEL)) == NULL)
+		{
+			LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+
+		if (credit_data->number_of_calls + 1 > max_chan)
+			return -2; // you have, between calls being setup plus those established, more than you maximum quota
+
+		if (credit_data->concurrent_calls + 1 > max_chan)
+			return -3; // you have the max amount of established calls already
+
+		if ((call = alloc_new_call_by_channel(credit_data, msg, max_chan)) == NULL)
+		{
+			LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+
+		if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_CHANNEL) != 0)
+		{
+			LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+
+		return 1;
+	}
+	else
+	{
+		LM_ALERT("MSG was not an INVITE\n");
+		return -1;
+	}
+}
+
+static int set_max_time(struct sip_msg* msg, char* str_pv_client, char* str_pv_maxsecs)
+{
+	credit_data_t *credit_data 	= NULL;
+	call_t *call				= NULL;
+	pv_spec_t *max_secs_spec	= (pv_spec_t *) str_pv_maxsecs,
+			  *client_id_spec	= (pv_spec_t *) str_pv_client;
+	pv_value_t max_secs_val, client_id_val;
+	int max_secs				= 0;
+
+	set_ctrl_flag(msg);
+
+	if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
+	{
+		LM_ERR("Error parsing Call-ID");
+		return -1;
+	}
+
+	if (msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)
+	{
+		if (has_to_tag(msg))
+		{
+			LM_ERR("INVITE is a reINVITE\n");
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, max_secs_spec, &max_secs_val) != 0)
+		{
+			LM_ERR("Can't get max_secs PV value\n");
+			return -1;
+		}
+		max_secs	= max_secs_val.ri;
+
+		if (max_secs <= 0)
+		{
+			LM_ERR("[%.*s] MAXSECS cannot be less than or equal to zero: %d\n", msg->callid->body.len, msg->callid->body.s, max_secs);
+			return -1;
+		}
+
+		if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
+		{
+			LM_ERR("[%.*s]: can't get client_id PV value\n", msg->callid->body.len, msg->callid->body.s);
+			return -1;
+		}
+
+		if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
+		{
+			LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
+			return -1;
+		}
+
+		LM_DBG("Setting up new call for client [%.*s], max-secs[%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
+																		max_secs,
+																		msg->callid->body.len, msg->callid->body.s);
+
+		if ((credit_data = get_or_create_credit_data_entry(&client_id_val.rs, CREDIT_TIME)) == NULL)
+		{
+			LM_ERR("Error retrieving credit data from shared memory for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+
+		if ((call = alloc_new_call_by_time(credit_data, msg, max_secs)) == NULL)
+		{
+			LM_ERR("Unable to allocate new call for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+
+		if (add_call_by_cid(&call->sip_data.callid, call, CREDIT_TIME) != 0)
+		{
+			LM_ERR("Unable to allocate new cid_by_client for client [%.*s]\n", client_id_val.rs.len, client_id_val.rs.s);
+			return -1;
+		}
+	}
+	else
+	{
+		LM_ALERT("MSG was not an INVITE\n");
+		return -1;
+	}
+
+	return 1;
+}
+
+static int update_max_time(struct sip_msg* msg, char* str_pv_client, char* str_pv_secs)
+{
+	credit_data_t *credit_data 	= NULL;
+	pv_spec_t *secs_spec		= (pv_spec_t *) str_pv_secs,
+		  *client_id_spec	= (pv_spec_t *) str_pv_client;
+	pv_value_t secs_val, client_id_val;
+	int secs				= 0;
+
+	set_ctrl_flag(msg);
+
+	if (parse_headers(msg, HDR_CALLID_F, 0) != 0)
+	{
+		LM_ERR("Error parsing Call-ID");
+		return -1;
+	}
+
+	if (pv_get_spec_value(msg, secs_spec, &secs_val) != 0)
+	{
+		LM_ERR("Can't get secs PV value\n");
+		return -1;
+	}
+	secs	= secs_val.ri;
+
+	if (secs <= 0)
+	{
+		LM_ERR("[%.*s] MAXSECS cannot be less than or equal to zero: %d\n", msg->callid->body.len, msg->callid->body.s, secs);
+		return -1;
+	}
+
+	if (pv_get_spec_value(msg, client_id_spec, &client_id_val) != 0)
+	{
+		LM_ERR("[%.*s]: can't get client_id PV value\n", msg->callid->body.len, msg->callid->body.s);
+		return -1;
+	}
+
+	if (client_id_val.rs.len == 0 || client_id_val.rs.s == NULL)
+	{
+		LM_ERR("[%.*s]: client ID cannot be null\n", msg->callid->body.len, msg->callid->body.s);
+		return -1;
+	}
+
+	LM_DBG("Updating call for client [%.*s], max-secs[%d], call-id[%.*s]\n", client_id_val.rs.len, client_id_val.rs.s,
+													secs,
+													msg->callid->body.len, msg->callid->body.s);
+
+
+
+	struct str_hash_table *ht	= NULL;
+	struct str_hash_entry *e	= NULL;
+	ht				= _data.time.credit_data_by_client;
+	double update_fraction		= secs;
+	call_t *call			= NULL,
+	       *tmp_call		= NULL;
+
+	lock_get(&_data.time.lock);
+	e							= str_hash_get(ht, client_id_val.rs.s, client_id_val.rs.len);
+	lock_release(&_data.time.lock);
+
+	if (e == NULL)
+	{
+		LM_ERR("Client [%.*s] was not found\n", client_id_val.rs.len, client_id_val.rs.s);
+		return -1;
+	}
+		
+	credit_data					= (credit_data_t *) e->u.p;
+
+	lock_get(&credit_data->lock);
+
+	LM_DBG("Updating max-secs for [%.*s] from [%f] to [%f]\n", e->key.len, e->key.s, credit_data->max_amount, credit_data->max_amount + secs);
+	
+	credit_data->max_amount				+= secs;
+
+	if (credit_data->number_of_calls > 0)
+		update_fraction	= secs / credit_data->number_of_calls;
+
+	clist_foreach_safe(credit_data->call_list, call, tmp_call, next)
+	{
+		if (!call->confirmed)
+			continue;
+		
+		call->max_amount	+= update_fraction;
+	}
+
+//redit_data->consumed_amount			= 0;
+
+
+	lock_release(&credit_data->lock);
+
+	return 1;
+}
+
+static int has_to_tag(struct sip_msg *msg)
+{
+	if (msg->to == NULL && parse_headers(msg, HDR_TO_F, 0) != 0)
+	{
+		LM_ERR("Cannot parse to-tag\n");
+		return 0;
+	}
+
+	return !(get_to(msg)->tag_value.s == NULL || get_to(msg)->tag_value.len == 0);
+}
+
+static int pv_parse_calls_param(pv_spec_p sp, str *in)
+{
+	if (sp == NULL || in == NULL || in->len == 0)
+		return -1;
+
+	switch(in->len)
+	{
+	case 5:
+		if (strncmp("total", in->s, in->len) == 0)
+			sp->pvp.pvn.u.isname.name.n	= CNX_PV_TOTAL;
+		else
+			return -1;
+		break;
+	case 6:
+		if (strncmp("active", in->s, in->len) == 0)
+			sp->pvp.pvn.u.isname.name.n	= CNX_PV_ACTIVE;
+		else
+			return -1;
+		break;
+	case 7:
+		if (strncmp("dropped", in->s, in->len) == 0)
+			sp->pvp.pvn.u.isname.name.n	= CNX_PV_DROPPED;
+		else
+			return -1;
+		break;
+
+	}
+
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
+	sp->pvp.pvn.u.isname.type = 0;
+
+	return 0;
+}
+
+static int pv_get_calls(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	switch(param->pvn.u.isname.name.n)
+	{
+	case CNX_PV_ACTIVE:
+		return pv_get_uintval(msg, param, res, _data.stats->active);
+	case CNX_PV_TOTAL:
+		return pv_get_uintval(msg, param, res, _data.stats->total);
+	case CNX_PV_DROPPED:
+		return pv_get_uintval(msg, param, res, _data.stats->dropped);
+	default:
+		LM_ERR("Unknown PV type %d\n", param->pvn.u.isname.name.n);
+		break;
+	}
+
+	return -1;
+}
+
+static struct mi_root *mi_credit_control_stats(struct mi_root *tree, void *param)
+{
+	char *p;
+	int len;
+	struct mi_root *rpl_tree;
+	struct mi_node *node, *node1;
+
+	rpl_tree	= init_mi_tree(200, "OK", 2);
+	node		= &rpl_tree->node;
+
+	node1 = add_mi_node_child(node, 0, MI_SSTR("CNX Credit Control"), 0, 0);
+	if (node1 == NULL)
+	{
+		LM_ERR("Error creating child node\n");
+		goto error;
+	}
+
+	p	= int2str((unsigned long) _data.stats->active, &len);
+	if (p == NULL)
+	{
+		LM_ERR("Error converting INT to STR\n");
+		goto error;
+	}
+	add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("active"), p, len);
+
+	p	= int2str((unsigned long) _data.stats->dropped, &len);
+	if (p == NULL)
+	{
+		LM_ERR("Error converting INT to STR\n");
+		goto error;
+	}
+	add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("dropped"), p, len);
+
+	p	= int2str((unsigned long) _data.stats->total, &len);
+	if (p == NULL)
+	{
+		LM_ERR("Error converting INT to STR\n");
+		goto error;
+	}
+
+	add_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("total"), p, len);
+
+	return rpl_tree;
+
+error:
+	return init_mi_tree(500, MI_INTERNAL_ERR, MI_INTERNAL_ERR_LEN);
+}
diff --git a/modules/cnxcc/cnxcc_mod.h b/modules/cnxcc/cnxcc_mod.h
new file mode 100644
index 0000000..b09d18b
--- /dev/null
+++ b/modules/cnxcc/cnxcc_mod.h
@@ -0,0 +1,156 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _CNXCC_MOD_H
+#define _CNXCC_MOD_H
+
+#include "../../locking.h"
+#include "../../str_hash.h"
+#include "../../parser/parse_rr.h"
+
+#define str_shm_free_if_not_null(_var_) if (_var_.s != NULL)  { shm_free(_var_.s); _var_.s = NULL; _var_.len = 0; }
+
+typedef struct stats
+{
+	unsigned int total;
+	unsigned int active;
+	unsigned int dropped;
+} stats_t;
+
+typedef enum cnxpvtypes
+{
+	CNX_PV_ACTIVE = 1,
+	CNX_PV_TOTAL,
+	CNX_PV_DROPPED
+} cnxpvtypes_t;
+
+typedef enum credit_type
+{
+	CREDIT_TIME,
+	CREDIT_MONEY,
+	CREDIT_CHANNEL
+} credit_type_t;
+
+typedef struct hash_tables
+{
+	struct str_hash_table *credit_data_by_client;
+	struct str_hash_table *call_data_by_cid;
+
+	gen_lock_t lock;
+} hash_tables_t;
+
+typedef struct data
+{
+	gen_lock_t lock;
+
+	hash_tables_t time;
+	hash_tables_t money;
+	hash_tables_t channel;
+
+	/*struct str_hash_table *credit_data_by_client;
+	struct str_hash_table *call_data_by_cid;*/
+
+	stats_t *stats;
+
+	/*
+	 * Call Shutdown Route Number
+	 */
+	int cs_route_number;
+
+	/*
+	 * Dialog flag used to track the call
+	 */
+	flag_t ctrl_flag;
+
+	int check_period;
+
+} data_t;
+
+typedef struct sip_data
+{
+	str callid;
+	str to_tag;
+	str from_tag;
+} sip_data_t;
+
+typedef struct money_spec_data
+{
+	double cost_per_second;
+	int initial_pulse;
+	int final_pulse;
+
+} money_spec_data_t;
+
+struct call;
+typedef struct call
+{
+	struct call *prev;
+	struct call *next;
+
+	gen_lock_t lock;
+
+	char confirmed;
+	double max_amount;
+	money_spec_data_t money_based;
+
+	unsigned int start_timestamp;
+	double consumed_amount;
+
+	unsigned int dlg_h_entry;
+	unsigned int dlg_h_id;
+
+	str client_id;
+
+	sip_data_t sip_data;
+} call_t;
+
+typedef struct call_array
+{
+	call_t *array;
+	int length;
+
+} call_array_t;
+
+typedef struct credit_data
+{
+	gen_lock_t lock;
+
+	double max_amount;
+	double consumed_amount;
+	double ended_calls_consumed_amount;
+	int number_of_calls;
+	int concurrent_calls;
+
+	credit_type_t type;
+
+	call_t *call_list;
+
+} credit_data_t;
+
+
+int try_get_call_entry(str *callid, call_t **call, hash_tables_t **hts);
+int try_get_credit_data_entry(str *client_id, credit_data_t **credit_data);
+int terminate_call(call_t *call);
+void terminate_all_calls(credit_data_t *credit_data);
+
+#endif /* _CNXCC_MOD_H */
diff --git a/modules/cnxcc/cnxcc_rpc.c b/modules/cnxcc/cnxcc_rpc.c
new file mode 100644
index 0000000..6df4423
--- /dev/null
+++ b/modules/cnxcc/cnxcc_rpc.c
@@ -0,0 +1,286 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdio.h>
+
+#include "../../locking.h"
+#include "../../lock_ops.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
+
+#include "cnxcc_mod.h"
+
+extern data_t _data;
+
+void rpc_kill_call(rpc_t* rpc, void* ctx)
+{
+	call_t *call;
+	hash_tables_t *hts;
+	str callid;
+
+	if (!rpc->scan(ctx, "S", &callid))
+	{
+		LM_ERR("%s: error reading RPC param\n", __FUNCTION__);
+		return;
+	}
+
+	if (try_get_call_entry(&callid, &call, &hts) != 0)
+	{
+		LM_ERR("%s: call [%.*s] not found\n", __FUNCTION__, callid.len, callid.s);
+		rpc->fault(ctx, 404, "CallID Not Found");
+		return;
+	}
+
+	if (call == NULL)
+	{
+		LM_ERR("%s: call [%.*s] is in null state\n", __FUNCTION__, callid.len, callid.s);
+		rpc->fault(ctx, 500, "Call is NULL");
+		return;
+	}
+
+	LM_ALERT("Killing call [%.*s] via XMLRPC request\n", callid.len, callid.s);
+
+	lock_get(&call->lock);
+
+	terminate_call(call);
+
+	lock_release(&call->lock);
+}
+
+void rpc_check_client_stats(rpc_t* rpc, void* ctx)
+{
+	call_t *call, *tmp;
+	int index	= 0;
+	str client_id, rows;
+	char row_buffer[512];
+	credit_data_t *credit_data;
+
+	if (!rpc->scan(ctx, "S", &client_id))
+	{
+		LM_ERR("%s: error reading RPC param\n", __FUNCTION__);
+		return;
+	}
+
+	if (try_get_credit_data_entry(&client_id, &credit_data) != 0)
+	{
+		LM_ERR("%s: client [%.*s] not found\n", __FUNCTION__, client_id.len, client_id.s);
+		rpc->fault(ctx, 404, "Not Found");
+		return;
+	}
+
+	if (credit_data == NULL)
+	{
+		LM_ERR("%s: credit data for client [%.*s] is NULL\n", __FUNCTION__, client_id.len, client_id.s);
+		rpc->fault(ctx, 500, "Internal Server Error");
+		return;
+	}
+
+	lock_get(&credit_data->lock);
+
+	if (credit_data->number_of_calls <= 0)
+	{
+		lock_release(&credit_data->lock);
+		LM_INFO("No calls for current client\n");
+		return;
+	}
+
+	rows.len = 0;
+	rows.s	 = pkg_malloc(10);
+
+	if (rows.s == NULL)
+		goto nomem;
+
+	clist_foreach_safe(credit_data->call_list, call, tmp, next)
+	{
+		int row_len = 0;
+
+		memset(row_buffer, 0, sizeof(row_buffer));
+
+		if (credit_data->type == CREDIT_MONEY)
+			snprintf(row_buffer, sizeof(row_buffer), "id:%d,confirmed:%s,local_consumed_amount:%f,global_consumed_amount:%f,local_max_amount:%f,global_max_amount:%f,call_id:%.*s,start_timestamp:%d"
+																",inip:%d,finp:%d,cps:%f;",
+																 index,
+																 call->confirmed ? "yes" : "no",
+																 call->consumed_amount,
+																 credit_data->consumed_amount,
+																 call->max_amount,
+																 credit_data->max_amount,
+																 call->sip_data.callid.len, call->sip_data.callid.s,
+																 call->start_timestamp,
+																 call->money_based.initial_pulse,
+																 call->money_based.final_pulse,
+																 call->money_based.cost_per_second
+																 );
+		else
+			snprintf(row_buffer, sizeof(row_buffer), "id:%d,confirmed:%s,local_consumed_amount:%d,global_consumed_amount:%d,local_max_amount:%d,global_max_amount:%d,call_id:%.*s,start_timestamp:%d;",
+					 	 	 	 	 	 	 	 	 	 	 	 index,
+																 call->confirmed ? "yes" : "no",
+																 (int) call->consumed_amount,
+																 (int) credit_data->consumed_amount,
+																 (int) call->max_amount,
+																 (int) credit_data->max_amount,
+																 call->sip_data.callid.len, call->sip_data.callid.s,
+																 call->start_timestamp);
+
+		row_len 	= strlen(row_buffer);
+		rows.s		= pkg_realloc(rows.s, rows.len + row_len);
+
+		if (rows.s == NULL)
+		{
+			lock_release(&credit_data->lock);
+			goto nomem;
+		}
+
+		memcpy(rows.s + rows.len, row_buffer, row_len);
+		rows.len += row_len;
+
+		index++;
+	}
+
+	lock_release(&credit_data->lock);
+
+	if (rpc->add(ctx, "S", &rows) < 0)
+	{
+		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
+	}
+
+	if (rows.s != NULL)
+		pkg_free(rows.s);
+
+	return;
+
+nomem:
+	LM_ERR("No more pkg memory");
+	rpc->fault(ctx, 500, "No more memory\n");
+}
+
+static int iterate_over_table(hash_tables_t *hts, str *result, credit_type_t type)
+{
+	struct str_hash_entry *h_entry, *tmp;
+	char row_buffer[512];
+	int index = 0;
+
+	lock_get(&hts->lock);
+
+	if (hts->credit_data_by_client->table)
+		for(index = 0; index < hts->credit_data_by_client->size; index++)
+			clist_foreach_safe(&hts->credit_data_by_client->table[index], h_entry, tmp, next)
+			{
+				credit_data_t *credit_data	= (credit_data_t *) h_entry->u.p;
+				lock_get(&credit_data->lock);
+
+				int row_len = 0;
+
+				memset(row_buffer, 0, sizeof(row_buffer));
+
+				if (type == CREDIT_TIME)
+				{
+					snprintf(row_buffer, sizeof(row_buffer), "client_id:%.*s,"
+															 "number_of_calls:%d,"
+															 "concurrent_calls:%d,"
+															 "type:%d,"
+															 "max_amount:%d,"
+															 "consumed_amount:%d;",
+															 credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
+															 credit_data->number_of_calls,
+															 credit_data->concurrent_calls,
+															 type,
+															 (int) credit_data->max_amount,
+															 (int) credit_data->consumed_amount);
+				}
+				else if (type == CREDIT_MONEY)
+				{
+					snprintf(row_buffer, sizeof(row_buffer), "client_id:%.*s,"
+															 "number_of_calls:%d,"
+															 "concurrent_calls:%d,"
+															 "type:%d,"
+															 "max_amount:%f,"
+															 "consumed_amount:%f;",
+															 credit_data->call_list->client_id.len, credit_data->call_list->client_id.s,
+															 credit_data->number_of_calls,
+															 credit_data->concurrent_calls,
+															 type,
+															 credit_data->max_amount,
+															 credit_data->consumed_amount);
+				}
+				else
+				{
+					LM_ERR("Unknown credit type: %d", type);
+					return -1;
+				}
+
+				lock_release(&credit_data->lock);
+
+				row_len 	= strlen(row_buffer);
+				result->s	= pkg_realloc(result->s, result->len + row_len);
+
+				if (result->s == NULL)
+				{
+					lock_release(&hts->lock);
+					goto nomem;
+				}
+
+				memcpy(result->s + result->len, row_buffer, row_len);
+				result->len += row_len;
+
+			}
+
+	lock_release(&hts->lock);
+
+	return 0;
+
+nomem:
+	LM_ERR("No more pkg memory");
+	return -1;
+}
+
+void rpc_active_clients(rpc_t* rpc, void* ctx)
+{
+	str rows;
+
+	rows.s	 = pkg_malloc(10);
+
+	if (rows.s == NULL)
+		goto nomem;
+
+	rows.len = 0;
+
+	iterate_over_table(&_data.time, &rows, CREDIT_TIME);
+	iterate_over_table(&_data.money, &rows, CREDIT_MONEY);
+
+	if (!rpc->add(ctx, "S", &rows) < 0)
+	{
+		LM_ERR("%s: error creating RPC struct\n", __FUNCTION__);
+	}
+
+	if (rows.s != NULL)
+		pkg_free(rows.s);
+
+	return;
+
+nomem:
+	LM_ERR("No more pkg memory");
+	rpc->fault(ctx, 500, "No more memory\n");
+}
+
diff --git a/modules/cnxcc/cnxcc_rpc.h b/modules/cnxcc/cnxcc_rpc.h
new file mode 100644
index 0000000..99dacfd
--- /dev/null
+++ b/modules/cnxcc/cnxcc_rpc.h
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef CNXCC_RPC_H_
+#define CNXCC_RPC_H_
+
+void rpc_active_clients(rpc_t* rpc, void* ctx);
+void rpc_kill_call(rpc_t* rpc, void* ctx);
+void rpc_active_clients(rpc_t* rpc, void* ctx);
+void rpc_check_client_stats(rpc_t* rpc, void* ctx);
+
+#endif /* CNXCC_RPC_H_ */
diff --git a/modules/cnxcc/cnxcc_select.c b/modules/cnxcc/cnxcc_select.c
new file mode 100644
index 0000000..99b6d1f
--- /dev/null
+++ b/modules/cnxcc/cnxcc_select.c
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../../select.h"
+#include "../../select_buf.h"
+
+#include "cnxcc_mod.h"
+
+extern data_t _data;
+
+int sel_root(str* res, select_t* s, struct sip_msg* msg)  /* dummy */
+{
+	return 0;
+}
+
+int sel_channels(str* res, select_t* s, struct sip_msg* msg)
+{
+	LM_DBG("sel_channels");
+
+	return 0;
+}
+
+int sel_channels_count(str* res, select_t* s, struct sip_msg* msg)
+{
+	LM_DBG("sel_channels_count for [%.*s]",  s->params[2].v.s.len, s->params[2].v.s.s);
+
+	credit_data_t *credit_data	= NULL;
+	int value					= 0;
+
+	if (s->params[2].v.s.len <= 0)
+	{
+		LM_ERR("Client must be specified");
+		return -1;
+	}
+
+	if (try_get_credit_data_entry(&s->params[2].v.s, &credit_data) >= 0)
+		value = credit_data->number_of_calls;
+	else
+		LM_DBG("Client [%.*s] not found", s->params[2].v.s.len, s->params[2].v.s.s);
+
+	res->s 	= int2str(value, &res->len);
+
+	return 0;
+}
+
+
diff --git a/modules/cnxcc/cnxcc_select.h b/modules/cnxcc/cnxcc_select.h
new file mode 100644
index 0000000..f1cd3f9
--- /dev/null
+++ b/modules/cnxcc/cnxcc_select.h
@@ -0,0 +1,32 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef CNXCC_SELECT_H_
+#define CNXCC_SELECT_H_
+
+int sel_root(str* res, select_t* s, struct sip_msg* msg);
+int sel_channels(str* res, select_t* s, struct sip_msg* msg);
+int sel_channels_count(str* res, select_t* s, struct sip_msg* msg);
+
+#endif /* CNXCC_SELECT_H_ */
diff --git a/modules/cnxcc/cnxcc_sip_msg_faker.c b/modules/cnxcc/cnxcc_sip_msg_faker.c
new file mode 100644
index 0000000..c47da1c
--- /dev/null
+++ b/modules/cnxcc/cnxcc_sip_msg_faker.c
@@ -0,0 +1,71 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../../parser/msg_parser.h"
+#include "../../globals.h"
+
+#include <sys/socket.h>
+
+#define FAKED_SIP_MSG_FORMAT "OPTIONS sip:you at kamailio.org SIP/2.0\r\nVia: SIP/2.0/UDP 127.0.0.1\r\nFrom: <you at kamailio.org>;tag=%.*s\r\nTo: <you at kamailio.org>;tag=%.*s\r\nCall-ID: %.*s\r\nCSeq: 1 OPTIONS\r\nContent-Length: 0\r\n\r\n"
+
+#define FAKED_SIP_MSG_BUF_LEN	1024
+char _faked_sip_msg_buf[FAKED_SIP_MSG_BUF_LEN];
+
+static struct sip_msg _faked_msg;
+
+int faked_msg_init_with_dlg_info(str *callid, str *from_tag, str *to_tag,  struct sip_msg **msg)
+{
+	memset(_faked_sip_msg_buf, 0, FAKED_SIP_MSG_BUF_LEN);
+
+	sprintf(_faked_sip_msg_buf, FAKED_SIP_MSG_FORMAT, from_tag->len, from_tag->s,
+													  to_tag->len, to_tag->s,
+													  callid->len, callid->s);
+
+	memset(&_faked_msg, 0, sizeof(struct sip_msg));
+
+	_faked_msg.buf = _faked_sip_msg_buf;
+	_faked_msg.len = strlen(_faked_sip_msg_buf);
+
+	_faked_msg.set_global_address	= default_global_address;
+	_faked_msg.set_global_port		= default_global_port;
+
+	if (parse_msg(_faked_msg.buf, _faked_msg.len, &_faked_msg) != 0)
+	{
+			LM_ERR("parse_msg failed\n");
+			return -1;
+	}
+
+	_faked_msg.rcv.proto = PROTO_UDP;
+	_faked_msg.rcv.src_port = 5060;
+	_faked_msg.rcv.src_ip.u.addr32[0] = 0x7f000001;
+	_faked_msg.rcv.src_ip.af = AF_INET;
+	_faked_msg.rcv.src_ip.len = 4;
+	_faked_msg.rcv.dst_port = 5060;
+	_faked_msg.rcv.dst_ip.u.addr32[0] = 0x7f000001;
+	_faked_msg.rcv.dst_ip.af = AF_INET;
+	_faked_msg.rcv.dst_ip.len = 4;
+
+	*msg	= &_faked_msg;
+	return 0;
+}
diff --git a/modules/cnxcc/cnxcc_sip_msg_faker.h b/modules/cnxcc/cnxcc_sip_msg_faker.h
new file mode 100644
index 0000000..18f13e7
--- /dev/null
+++ b/modules/cnxcc/cnxcc_sip_msg_faker.h
@@ -0,0 +1,29 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Carlos Ruiz Díaz (caruizdiaz.com),
+ *                    ConexionGroup (www.conexiongroup.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef CNXCC_SIP_MSG_FAKER_H_
+#define CNXCC_SIP_MSG_FAKER_H_
+
+int faked_msg_init_with_dlg_info(str *callid, str *from_tag, str *to_tag,  struct sip_msg **msg);
+
+#endif /* CNXCC_SIP_MSG_FAKER_H_ */
diff --git a/modules/cnxcc/doc/Makefile b/modules/cnxcc/doc/Makefile
new file mode 100644
index 0000000..258168e
--- /dev/null
+++ b/modules/cnxcc/doc/Makefile
@@ -0,0 +1,4 @@
+docs = cnxcc.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/cnxcc/doc/cnxcc.xml b/modules/cnxcc/doc/cnxcc.xml
new file mode 100644
index 0000000..866be3f
--- /dev/null
+++ b/modules/cnxcc/doc/cnxcc.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+    <title>cnxcc Module</title>
+    <productname class="trade">&kamailioname;</productname>
+    <authorgroup>
+	<author>
+	<firstname>Carlos</firstname>
+	<surname>Ruiz Diaz</surname>
+	<affiliation>
+	    <orgname>ConexionGroup S.A.</orgname>
+	</affiliation>
+	<address>
+	    <email>carlos.ruizdiaz at gmail.com</email>
+	</address>
+	</author>
+    </authorgroup>
+    <copyright>
+	<year>2013</year>
+	<holder>Carlos Ruiz Diaz, carlos.ruizdiaz at gmail.com</holder>
+    </copyright>
+    </bookinfo>
+
+    <toc></toc>
+
+    <xi:include href="cnxcc_admin.xml" />
+</book>
diff --git a/modules/cnxcc/doc/cnxcc_admin.xml b/modules/cnxcc/doc/cnxcc_admin.xml
new file mode 100644
index 0000000..ec52dfc
--- /dev/null
+++ b/modules/cnxcc/doc/cnxcc_admin.xml
@@ -0,0 +1,456 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module Admin Guide -->
+
+<chapter xmlns:xi="http://www.w3.org/2001/XInclude">
+    <title>&adminguide;</title>
+
+    <section>
+	<title>Overview</title>
+	<para>
+		This module was designed to act as a mechanism to limit call duration based on credit information parameters.
+		After getting the credit information of the call being set up, you can instruct the module to start monitoring
+		the consumed credit to shutdown a single call or a group of calls in case of credit exhaustion.	
+	</para>
+	<para>
+		Every call is associated to an unique client/customer identifier. If a credit event occurs, all calls hooked
+	   	to this identifier are automatically shutdown.
+	</para>
+	<para>
+		Cnxcc is dialog-aware so there's no need to explicitly allocate/deallocate the monitoring. Only a single function
+		call inside the script is needed upon reception of the INVITE.
+	</para>
+	<para>
+		The credit discount rate is proportional to the number of calls grouped inside an identifier. Once the setup
+		of the first call is done, the information remains while the call is active. If the customer starts a new call with
+		the same routing criteria, it will land in the same monitoring bag and it will consume the same pool of credit in
+		rates that are equal to the cost per second of both calls.
+	</para>
+	<para>
+		If your accounting program does not maintain the state of the call in real time, this module can provide you
+		that ability.
+	</para>
+	<para>
+		Cnxcc can also provide more common means of monitoring, i.e., by time limit or by maximum simultaneous calls.
+	</para>
+
+
+    </section>
+
+    <section>
+	<title>Dependencies</title>
+	<section>
+	    <title>Modules</title>
+	    <para>
+		The following module must be loaded before this module: 
+		<itemizedlist>
+		    <listitem>
+		    <para>
+			<emphasis>dialog</emphasis>
+		    </para>
+		    </listitem>
+		</itemizedlist>
+	    </para>
+	</section>
+    </section>
+
+    <section>
+	<title>Parameters</title>
+	<section>
+		<title><varname> dlg_flag </varname> (integer)</title>
+	    <para>
+		Flag to indicate if the dialog must be monitored or not. Messages are flagged with this value if we call one of
+		the monitoring functions.
+	    </para>
+	    <example>
+
+		<title>dlg_flag</title>
+		<programlisting format="linespecific">
+...
+modparam("cnxcc", "dlg_flag", 29)
+...		
+		</programlisting>
+	    </example>
+	</section>
+
+	<section>
+	    <title><varname>credit_check_period</varname> (integer)</title>
+	    <para>
+		Indicates how often the credit checking function should be called. It is directly related to the precison of the
+		module. The maximum precision is 1, which means that every call is checked every one second.
+
+	    </para>
+	    <para>
+		Values greater than 1 leads to precision lost but less CPU consumption.
+	    </para>
+	    <example>
+		<title>credit_check_period</title>
+		<programlisting format="linespecific">
+...
+modparam("cnxcc", "credit_check_period", 1)
+...		
+		</programlisting>
+	    </example>
+	</section> 
+   </section>
+
+    <section>
+	<title>Functions</title>
+	<section>
+	    <title>
+		<function moreinfo="none">cnxcc_set_max_credit()</function>
+	    </title>
+	    <para>
+		Specifies the initial pulse, final pulse, max credit and cost per second of a call. The discount
+		is calculated in pulses (30/6, 1/1, etc) and sustracted from the pool of credit.
+	    </para>
+	    <para>
+		<emphasis>Return code:</emphasis>
+		<itemizedlist>
+		    <listitem>
+		    <para>
+			<emphasis>1 - successful</emphasis>
+		    </para>
+		    </listitem>
+
+		    <listitem>
+		    <para>
+			<emphasis>-1 - failed, error logged</emphasis>
+		    </para>
+		    </listitem>
+
+		    <listitem>
+		    <para>
+			<emphasis>-2 - failed, credit value is less than initial pulse value</emphasis>
+		    </para>
+		    </listitem>
+
+		</itemizedlist>
+	    </para>
+	    <example>
+		<title>cnxcc_set_max_credit()</title>
+		<programlisting format="linespecific">
+...
+$var(customer) = "john-doe-123-premium";
+$var(credit) = "100";
+$var(cps)   = "2.00";         # cost per second
+$var(initial_p)   = "030";    # intial pulse
+$var(final_p)   = "006";      # final pulse
+
+cnxcc_set_max_credit("$var(customer)", "$var(credit)", "$var(cps)", "$var(initial_p)", "$var(final_p)");
+...		
+		</programlisting>
+	    </example>
+	</section>
+
+        <section>
+            <title>
+                <function moreinfo="none">cnxcc_set_max_time()</function>
+            </title>
+            <para>
+		Specifies the amount of time the call should last at most.
+            </para>
+            <para>
+                <emphasis>Return code:</emphasis>
+                <itemizedlist>
+                    <listitem>
+                    <para>
+                        <emphasis>1 - successful</emphasis>
+                    </para>
+                    </listitem>
+                     
+                    <listitem>
+                    <para>
+                        <emphasis>-1 - failed, error logged</emphasis>
+                    </para>
+                    </listitem>
+                </itemizedlist>
+            </para>
+            <example>
+		<title>cnxcc_set_max_time()</title>
+                <programlisting format="linespecific">
+...
+$var(customer) = "john-doe-123-basic";
+$var(max_time) = 120;
+
+cnxcc_set_max_time("$var(customer)", "$var(max_time)");
+...
+		</programlisting>
+            </example>
+        </section>
+
+        <section>
+            <title>
+                <function moreinfo="none">cnxcc_update_max_time()</function>
+            </title>
+            <para>
+		Updates max-time of an established and monitored call. This can be used to grant minimum values and to update them every short periods on time as a mean to prevent frauds and/or to mimic requested/granted units of time of Credit Control Application behavior.
+            </para>
+            <para>
+                <emphasis>Return code:</emphasis>
+                <itemizedlist>
+                    <listitem>
+                    <para>
+                        <emphasis>1 - successful</emphasis>
+                    </para>
+                    </listitem>
+                     
+                    <listitem>
+                    <para>
+                        <emphasis>-1 - failed, error logged</emphasis>
+                    </para>
+                    </listitem>
+                </itemizedlist>
+            </para>
+            <example>
+		<title>cnxcc_update_max_time()</title>
+                <programlisting format="linespecific">
+...
+        $var(update_time)  = 5;
+        $var(client)       = "john-doe-123-basic";
+
+        if (!cnxcc_update_max_time("$var(client)",
+                                  "$var(update_time)")) {
+                xlog("Error updating max-time");
+                return;
+        }
+
+...
+		</programlisting>
+            </example>
+        </section>
+
+
+
+    	<section>
+            <title>
+                <function moreinfo="none">cnxcc_set_max_channel()</function>
+            </title>
+            <para>
+		Specifies a limit for the number of simultaneous calls
+            </para>
+            <para>
+                <emphasis>Return code:</emphasis>
+                <itemizedlist>
+                    <listitem>
+                    <para>
+                        <emphasis>1 - successful</emphasis>
+                    </para>
+                    </listitem>
+                     
+                    <listitem>
+                    <para>
+                        <emphasis>-1 - failed, error logged</emphasis>
+                    </para>
+                    </listitem>
+
+                    <listitem>
+                    <para>
+                        <emphasis>-2 - failed, calls established plus calls being established result in more than the limit you specified</emphasis>
+                    </para>
+                    </listitem>
+		    
+		    <listitem>
+                    <para>
+                        <emphasis>-3 - failed, number of calls established is more than the limit you specified</emphasis>
+                    </para>
+                    </listitem>
+
+                </itemizedlist>
+            </para>
+            <example>
+		<title>cnxcc_set_max_channels()</title>
+                <programlisting format="linespecific">
+...
+$var(customer)  = "john-doe-123-basic";
+$var(max_chan)  = 2;
+$var(retcode)   = cnxcc_set_max_channels("$var(customer)", "$var(max_chan)");
+
+if ($var(retcode) == -1) {
+	xlog("Error setting up credit control");
+	return;
+}
+
+if ($var(retcode) < -1) {
+        xlog("Too many channels for customer");
+        sl_send_reply(403, "Forbidden");
+
+        if (!cnxcc_terminate_all("$var(customer)")) {
+		xlog("Error terminating customer's calls");
+	}
+
+	exit;
+}
+
+...
+		</programlisting>
+            </example>
+    	</section>
+	
+    	<section>
+            <title>
+                <function moreinfo="none">cnxcc_terminate_all()</function>
+            </title>
+            <para>
+		Terminates all calls of the specified customer/profile
+            </para>
+            <para>
+                <emphasis>Return code:</emphasis>
+                <itemizedlist>
+                    <listitem>
+                    <para>
+                        <emphasis>1 - successful</emphasis>
+                    </para>
+                    </listitem>
+                     
+                    <listitem>
+                    <para>
+                        <emphasis>-1 - failed, error logged</emphasis>
+                    </para>
+                    </listitem>
+                </itemizedlist>
+            </para>
+            <example>
+		<title>cnxcc_set_max_time()</title>
+                <programlisting format="linespecific">
+...
+$var(customer)  = "john-doe-123-basic";
+
+if (!cnxcc_terminate_all("$var(customer)")) {
+	xlog("Error terminating customer's calls");
+}
+...
+		</programlisting>
+            </example>
+        </section>
+    </section>
+   
+    <section>
+	<title>Exported RPC Commands</title>
+
+	<section>
+	    <title><varname>cnxcc.active_clients</varname></title>
+	    <para>
+		Retrieves all calls grouped by their identifiers.
+	    </para>
+	    <para>
+		Parameters: <emphasis>none</emphasis>
+	    </para>
+	    <para>
+		Example:
+	    </para>
+	    <programlisting format="linespecific">
+	    &sercmd; cnxcc.active_clients
+	    </programlisting>
+	</section>
+
+	<section>
+            <title><varname>cnxcc.check_client</varname></title>
+            <para>
+		Retrives all calls from a particular identifier.
+            </para>
+            <para>
+		    Parameters: <emphasis>client/customer identifier</emphasis>
+            </para>
+            <para>
+                Example:
+            </para>
+            <programlisting format="linespecific">
+	    &sercmd; cnxcc.check_client john-doe-123-premium
+            </programlisting>
+        </section>
+
+        <section>
+            <title><varname>cnxcc.kill_call</varname></title>
+            <para>
+		    Kills an active call using its call ID.
+	    </para>
+            <para>
+                Parameters: <emphasis>Call-ID</emphasis>
+            </para>
+            <para>
+                Example:
+            </para>
+            <programlisting format="linespecific">
+            &sercmd; cnxcc.kill_call qumojlaahitafih at carlosrdcnx-laptop.site
+            </programlisting>
+        </section>
+    </section>
+
+    <section>
+	    <title>Events</title>
+	    
+	    <para>
+		When a call is forced to end an event route is automatically invoked. This route is suited with a fake OPTIONS
+		message containing the call ID, ftag and ttag of the original call so it can be located somehow in the accounting
+		database.
+	    </para>
+	    <para>
+                Example:
+            </para>
+            	<programlisting format="linespecific">
+...
+event_route[cnxcc:call-shutdown]
+{
+	xlog("L_INFO", "[$ci]: call killed");
+
+        # perform some kind of notification, database update, email sending, etc.
+}
+...
+		</programlisting>
+	    
+    </section>
+    <section>
+            <title>Web Interface</title>
+
+            <para>
+		The module contains a web management interface completely optional. With it, you can review your calls in real time
+		and hang them up if necessary.    
+	    </para>
+            <para>
+                Link: https://github.com/caruizdiaz/cnxcc-web
+            </para>
+    </section>
+
+    <section>
+	<title>Sample</title>
+	<example>
+	    <title>kamailio-cnxcc.cfg</title>
+	    <programlisting format="linespecific">
+...
+route[CNXCC]
+{
+	$var(client)              = "test-client-0-123-01";
+      	$var(credit)              = "50";
+      	$var(cost_per_sec)        = "0.5";
+      	$var(i_pulse)             = "30";
+      	$var(f_pulse)             = "6";
+
+      	if (!cnxcc_set_max_credit("$var(client)",
+                          "$var(credit)",
+                          "$var(cost_per_sec)",
+                          "$var(i_pulse)",
+                          "$var(f_pulse)")) {
+		 xlog("Error setting up credit control");
+      	}
+}
+
+event_route[cnxcc:call-shutdown]
+{
+	xlog("L_INFO", "[$ci]: call killed");
+
+
+}	    
+...
+	    </programlisting>
+	</example>
+    </section>
+
+</chapter>
diff --git a/modules/cnxcc/example/kamailio-cnxcc.cfg b/modules/cnxcc/example/kamailio-cnxcc.cfg
new file mode 100644
index 0000000..3656a6f
--- /dev/null
+++ b/modules/cnxcc/example/kamailio-cnxcc.cfg
@@ -0,0 +1,1092 @@
+#!KAMAILIO
+
+#!define CNXCC_TIME
+##!define CNXCC_MONEY
+##!define CNXCC_CHANNEL
+
+#
+# Kamailio (OpenSER) SIP Server v3.2 - default configuration script
+#     - web: http://www.kamailio.org
+#     - git: http://sip-router.org
+#
+# Direct your questions about this file to: <sr-users at lists.sip-router.org>
+#
+# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php
+# for an explanation of possible statements, functions and parameters.
+#
+# Several features can be enabled using '#!define WITH_FEATURE' directives:
+#
+# *** To run in debug mode: 
+#     - define WITH_DEBUG
+#
+# *** To enable mysql: 
+#     - define WITH_MYSQL
+#
+# *** To enable authentication execute:
+#     - enable mysql
+#     - define WITH_AUTH
+#     - add users using 'kamctl'
+#
+# *** To enable IP authentication execute:
+#     - enable mysql
+#     - enable authentication
+#     - define WITH_IPAUTH
+#     - add IP addresses with group id '1' to 'address' table
+#
+# *** To enable persistent user location execute:
+#     - enable mysql
+#     - define WITH_USRLOCDB
+#
+# *** To enable presence server execute:
+#     - enable mysql
+#     - define WITH_PRESENCE
+#
+# *** To enable nat traversal execute:
+#     - define WITH_NAT
+#     - install RTPProxy: http://www.rtpproxy.org
+#     - start RTPProxy:
+#        rtpproxy -l _your_public_ip_ -s udp:localhost:7722
+#
+# *** To enable PSTN gateway routing execute:
+#     - define WITH_PSTN
+#     - set the value of pstn.gw_ip
+#     - check route[PSTN] for regexp routing condition
+#
+# *** To enable database aliases lookup execute:
+#     - enable mysql
+#     - define WITH_ALIASDB
+#
+# *** To enable speed dial lookup execute:
+#     - enable mysql
+#     - define WITH_SPEEDDIAL
+#
+# *** To enable multi-domain support execute:
+#     - enable mysql
+#     - define WITH_MULTIDOMAIN
+#
+# *** To enable TLS support execute:
+#     - adjust CFGDIR/tls.cfg as needed
+#     - define WITH_TLS
+#
+# *** To enable XMLRPC support execute:
+#     - define WITH_XMLRPC
+#     - adjust route[XMLRPC] for access policy
+#
+# *** To enable anti-flood detection execute:
+#     - adjust pike and htable=>ipban settings as needed (default is
+#       block if more than 16 requests in 2 seconds and ban for 300 seconds)
+#     - define WITH_ANTIFLOOD
+#
+# *** To block 3XX redirect replies execute:
+#     - define WITH_BLOCK3XX
+#
+# *** To enable VoiceMail routing execute:
+#     - define WITH_VOICEMAIL
+#     - set the value of voicemail.srv_ip
+#     - adjust the value of voicemail.srv_port
+#
+# *** To enhance accounting execute:
+#     - enable mysql
+#     - define WITH_ACCDB
+#     - add following columns to database
+#!ifdef ACCDB_COMMENT
+  ALTER TABLE acc ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN src_ip varchar(64) NOT NULL default '';
+  ALTER TABLE acc ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE acc ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN src_ip varchar(64) NOT NULL default '';
+  ALTER TABLE missed_calls ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT '';
+  ALTER TABLE missed_calls ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT '';
+#!endif
+
+####### Defined Values #########
+
+# *** Value defines - IDs used later in config
+#!ifdef WITH_MYSQL
+# - database URL - used to connect to database server by modules such
+#       as: auth_db, acc, usrloc, a.s.o.
+#!define DBURL "mysql://openser:openserrw@localhost/openser"
+#!endif
+#!ifdef WITH_MULTIDOMAIN
+# - the value for 'use_domain' parameters
+#!define MULTIDOMAIN 1
+#!else
+#!define MULTIDOMAIN 0
+#!endif
+
+# - flags
+#   FLT_ - per transaction (message) flags
+#	FLB_ - per branch flags
+#!define FLT_ACC 1
+#!define FLT_ACCMISSED 2
+#!define FLT_ACCFAILED 3
+#!define FLT_NATS 5
+
+#!define FLB_NATB 6
+#!define FLB_NATSIPPING 7
+
+#!define WITH_XMLRPC
+
+####### Global Parameters #########
+
+
+#!ifdef WITH_DEBUG
+debug=4
+log_stderror=no
+#!else
+debug=2
+log_stderror=no
+#!endif
+
+memdbg=5
+memlog=5
+
+log_facility=LOG_LOCAL0
+
+fork=yes
+children=4
+
+/* uncomment the next line to disable TCP (default on) */
+#disable_tcp=yes
+
+/* uncomment the next line to disable the auto discovery of local aliases
+   based on reverse DNS on IPs (default on) */
+#auto_aliases=no
+
+/* add local domain aliases */
+#alias="sip.mydomain.com"
+
+/* uncomment and configure the following line if you want Kamailio to 
+   bind on a specific interface/port/proto (default bind on all available) */
+#listen=udp:10.0.0.10:5060
+
+/* port to listen to
+ * - can be specified more than once if needed to listen on many ports */
+port=5060
+
+#!ifdef WITH_TLS
+enable_tls=yes
+#!endif
+
+# life time of TCP connection when there is no traffic
+# - a bit higher than registration expires to cope with UA behind NAT
+tcp_connection_lifetime=3605
+
+####### Custom Parameters #########
+
+# These parameters can be modified runtime via RPC interface
+# - see the documentation of 'cfg_rpc' module.
+#
+# Format: group.id = value 'desc' description
+# Access: $sel(cfg_get.group.id) or @cfg_get.group.id
+#
+
+#!ifdef WITH_PSTN
+# PSTN GW Routing
+#
+# - pstn.gw_ip: valid IP or hostname as string value, example:
+# pstn.gw_ip = "10.0.0.101" desc "My PSTN GW Address"
+#
+# - by default is empty to avoid misrouting
+pstn.gw_ip = "" desc "PSTN GW Address"
+#!endif
+
+#!ifdef WITH_VOICEMAIL
+# VoiceMail Routing on offline, busy or no answer
+#
+# - by default Voicemail server IP is empty to avoid misrouting
+voicemail.srv_ip = "" desc "VoiceMail IP Address"
+voicemail.srv_port = "5060" desc "VoiceMail Port"
+#!endif
+
+####### Modules Section ########
+
+# set paths to location of modules (to sources or installation folders)
+#!ifdef WITH_SRCPATH
+mpath="modules_k:modules"
+#!else
+mpath="/usr/local/lib64/kamailio/modules_k/:/usr/local/lib64/kamailio/modules/"
+#!endif
+
+#!ifdef WITH_MYSQL
+loadmodule "db_mysql.so"
+#!endif
+
+loadmodule "mi_fifo.so"
+loadmodule "kex.so"
+loadmodule "tm.so"
+loadmodule "tmx.so"
+loadmodule "sl.so"
+loadmodule "rr.so"
+loadmodule "pv.so"
+loadmodule "maxfwd.so"
+loadmodule "usrloc.so"
+loadmodule "registrar.so"
+loadmodule "textops.so"
+loadmodule "siputils.so"
+loadmodule "xlog.so"
+loadmodule "sanity.so"
+loadmodule "ctl.so"
+loadmodule "cfg_rpc.so"
+loadmodule "mi_rpc.so"
+loadmodule "acc.so"
+
+#!ifdef WITH_AUTH
+loadmodule "auth.so"
+loadmodule "auth_db.so"
+#!ifdef WITH_IPAUTH
+loadmodule "permissions.so"
+#!endif
+#!endif
+
+#!ifdef WITH_ALIASDB
+loadmodule "alias_db.so"
+#!endif
+
+#!ifdef WITH_SPEEDDIAL
+loadmodule "speeddial.so"
+#!endif
+
+#!ifdef WITH_MULTIDOMAIN
+loadmodule "domain.so"
+#!endif
+
+#!ifdef WITH_PRESENCE
+loadmodule "presence.so"
+loadmodule "presence_xml.so"
+#!endif
+
+#!ifdef WITH_NAT
+loadmodule "nathelper.so"
+loadmodule "rtpproxy.so"
+#!endif
+
+#!ifdef WITH_TLS
+loadmodule "tls.so"
+#!endif
+
+#!ifdef WITH_ANTIFLOOD
+loadmodule "htable.so"
+loadmodule "pike.so"
+#!endif
+
+#!ifdef WITH_XMLRPC
+loadmodule "xmlrpc.so"
+#!endif
+
+#!ifdef WITH_DEBUG
+#loadmodule "debugger.so"
+#!endif
+
+# ----------------- setting module-specific parameters ---------------
+
+
+# ----- mi_fifo params -----
+modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
+
+
+# ----- tm params -----
+# auto-discard branches from previous serial forking leg
+modparam("tm", "failure_reply_mode", 3)
+# default retransmission timeout: 30sec
+modparam("tm", "fr_timer", 30000)
+# default invite retransmission timeout after 1xx: 120sec
+modparam("tm", "fr_inv_timer", 120000)
+
+
+# ----- rr params -----
+# add value to ;lr param to cope with most of the UAs
+modparam("rr", "enable_full_lr", 1)
+# do not append from tag to the RR (no need for this script)
+modparam("rr", "append_fromtag", 0)
+
+
+# ----- registrar params -----
+modparam("registrar", "method_filtering", 1)
+/* uncomment the next line to disable parallel forking via location */
+# modparam("registrar", "append_branches", 0)
+/* uncomment the next line not to allow more than 10 contacts per AOR */
+#modparam("registrar", "max_contacts", 10)
+# max value for expires of registrations
+modparam("registrar", "max_expires", 3600)
+
+
+# ----- acc params -----
+/* what special events should be accounted ? */
+modparam("acc", "early_media", 0)
+modparam("acc", "report_ack", 0)
+modparam("acc", "report_cancels", 0)
+/* by default ww do not adjust the direct of the sequential requests.
+   if you enable this parameter, be sure the enable "append_fromtag"
+   in "rr" module */
+modparam("acc", "detect_direction", 0)
+/* account triggers (flags) */
+modparam("acc", "log_flag", FLT_ACC)
+modparam("acc", "log_missed_flag", FLT_ACCMISSED)
+modparam("acc", "log_extra", 
+	"src_user=$fU;src_domain=$fd;src_ip=$si;"
+	"dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
+modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)
+/* enhanced DB accounting */
+#!ifdef WITH_ACCDB
+modparam("acc", "db_flag", FLT_ACC)
+modparam("acc", "db_missed_flag", FLT_ACCMISSED)
+modparam("acc", "db_url", DBURL)
+modparam("acc", "db_extra",
+	"src_user=$fU;src_domain=$fd;src_ip=$si;"
+	"dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
+#!endif
+
+
+# ----- usrloc params -----
+/* enable DB persistency for location entries */
+#!ifdef WITH_USRLOCDB
+modparam("usrloc", "db_url", DBURL)
+modparam("usrloc", "db_mode", 2)
+modparam("usrloc", "use_domain", MULTIDOMAIN)
+#!endif
+
+
+# ----- auth_db params -----
+#!ifdef WITH_AUTH
+modparam("auth_db", "db_url", DBURL)
+modparam("auth_db", "calculate_ha1", yes)
+modparam("auth_db", "password_column", "password")
+modparam("auth_db", "load_credentials", "")
+modparam("auth_db", "use_domain", MULTIDOMAIN)
+
+# ----- permissions params -----
+#!ifdef WITH_IPAUTH
+modparam("permissions", "db_url", DBURL)
+modparam("permissions", "db_mode", 1)
+#!endif
+
+#!endif
+
+
+# ----- alias_db params -----
+#!ifdef WITH_ALIASDB
+modparam("alias_db", "db_url", DBURL)
+modparam("alias_db", "use_domain", MULTIDOMAIN)
+#!endif
+
+
+# ----- speedial params -----
+#!ifdef WITH_SPEEDDIAL
+modparam("speeddial", "db_url", DBURL)
+modparam("speeddial", "use_domain", MULTIDOMAIN)
+#!endif
+
+
+# ----- domain params -----
+#!ifdef WITH_MULTIDOMAIN
+modparam("domain", "db_url", DBURL)
+# use caching
+modparam("domain", "db_mode", 1)
+# register callback to match myself condition with domains list
+modparam("domain", "register_myself", 1)
+#!endif
+
+
+#!ifdef WITH_PRESENCE
+# ----- presence params -----
+modparam("presence", "db_url", DBURL)
+
+# ----- presence_xml params -----
+modparam("presence_xml", "db_url", DBURL)
+modparam("presence_xml", "force_active", 1)
+#!endif
+
+
+#!ifdef WITH_NAT
+# ----- rtpproxy params -----
+modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:7722")
+
+# ----- nathelper params -----
+modparam("nathelper", "natping_interval", 30)
+modparam("nathelper", "ping_nated_only", 1)
+modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
+modparam("nathelper", "sipping_from", "sip:pinger at kamailio.org")
+
+# params needed for NAT traversal in other modules
+modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")
+modparam("usrloc", "nat_bflag", FLB_NATB)
+#!endif
+
+
+#!ifdef WITH_TLS
+# ----- tls params -----
+modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg")
+#!endif
+
+#!ifdef WITH_ANTIFLOOD
+# ----- pike params -----
+modparam("pike", "sampling_time_unit", 2)
+modparam("pike", "reqs_density_per_unit", 16)
+modparam("pike", "remove_latency", 4)
+
+# ----- htable params -----
+# ip ban htable with autoexpire after 5 minutes
+modparam("htable", "htable", "ipban=>size=8;autoexpire=300;")
+#!endif
+
+#!ifdef WITH_XMLRPC
+# ----- xmlrpc params -----
+modparam("xmlrpc", "route", "XMLRPC");
+#modparam("xmlrpc", "url_match", "^/RPC")
+#!endif
+
+#!ifdef WITH_DEBUG
+# ----- debugger params -----
+#modparam("debugger", "cfgtrace", 1)
+#!endif
+
+#!define DLG_FLAG 28
+#!define CC_FLAG 29
+
+loadmodule "dialog.so"
+modparam("dialog", "hash_size", 2048)
+modparam("dialog", "default_timeout", 3600)
+modparam("dialog", "db_mode", 0)
+modparam("dialog", "dlg_flag", DLG_FLAG)
+
+
+loadmodule "rtimer.so";
+#!ifdef CNXCC_CHANNEL
+modparam("rtimer", "timer", "name=ta;interval=1;mode=1;")
+modparam("rtimer", "exec", "timer=ta;route=SHOW_CHANNEL_COUNT")
+#!endif
+
+#!ifdef CNXCC_TIME
+modparam("rtimer", "timer", "name=ta;interval=5;mode=1;")
+modparam("rtimer", "exec", "timer=ta;route=UPDATE_MAX_TIME")
+#!endif
+
+loadmodule "cnxcc.so"
+modparam("cnxcc", "dlg_flag", CC_FLAG)
+modparam("cnxcc", "credit_check_period", 1) #check every 1 second
+
+####### Routing Logic ########
+
+
+# Main SIP request routing logic
+# - processing of any incoming SIP request starts with this route
+# - note: this is the same as route { ... }
+request_route {
+
+	setflag(DLG_FLAG);
+
+	# per request initial checks
+	route(REQINIT);
+
+	# NAT detection
+	route(NATDETECT);
+
+	# handle requests within SIP dialogs
+	route(WITHINDLG);
+
+	### only initial requests (no To tag)
+
+	# CANCEL processing
+	if (is_method("CANCEL"))
+	{
+		if (t_check_trans())
+			t_relay();
+		exit;
+	}
+
+	t_check_trans();
+
+	# authentication
+	route(AUTH);
+
+	# record routing for dialog forming requests (in case they are routed)
+	# - remove preloaded route headers
+	remove_hf("Route");
+	if (is_method("INVITE|SUBSCRIBE"))
+		record_route();
+
+	# account only INVITEs
+	if (is_method("INVITE"))
+	{
+		setflag(FLT_ACC); # do accounting
+	}
+
+	# dispatch requests to foreign domains
+	route(SIPOUT);
+
+	
+	### requests for my local domains
+
+	# handle presence related requests
+	route(PRESENCE);
+
+	# handle registrations
+	route(REGISTRAR);
+
+	if ($rU==$null)
+	{
+		# request with no Username in RURI
+		sl_send_reply("484","Address Incomplete");
+		exit;
+	}
+
+	# dispatch destinations to PSTN
+	route(PSTN);
+
+	# user location service
+	route(LOCATION);
+	
+	if (is_method("INVITE")) {
+		route(CNXCC);
+	}
+
+        	
+	route(RELAY);
+}
+
+route[CNXCC]
+{
+	#
+	# In real life scenarios, all the authorization values 
+	# are retrieved from a database and calculed on-the-fly.
+	# 
+	# This hardcoded values are just for illustrative purposes
+	#
+	
+	$var(client)		= "customer1";
+
+#!ifdef CNXCC_MONEY
+	xlog("L_INFO", "Setting up money based credit control");
+
+	$var(credit) 		= "10";	# 10$ of credit
+	$var(cost_per_sec) 	= "1";  # 1$ per sec
+	$var(i_pulse)		= "1";  # 1$ to establish the call
+	$var(f_pulse)		= "1";  # 1$ per second
+
+	# if only one call is established, that call should last 9 seconds.
+
+	if (!cnxcc_set_max_credit("$var(client)",
+				  "$var(credit)", 
+				  "$var(cost_per_sec)", 
+				  "$var(i_pulse)", 
+				  "$var(f_pulse)")) {
+		xlog("Error setting up credit control");
+		return;
+	}
+#!endif
+
+#!ifdef CNXCC_CHANNEL	
+	xlog("L_INFO", "Setting up channel based credit control");
+
+	$var(max_chan)	= 2;
+	$var(retcode)	= cnxcc_set_max_channels("$var(client)", "$var(max_chan)");
+
+	if ($var(retcode) == -1) {
+		xlog("Error setting up credit control");
+		return;
+	}
+
+        $var(count)     = -1;
+
+        if (!cnxcc_get_channel_count("$var(client)", "$var(count)")) {
+                xlog("Error getting customer's channel count");
+        }
+
+        xlog("L_INFO", "CNXCC ROUTE: $var(client) has $var(count) call(s)");
+
+	if ($var(retcode) < -1) {
+		xlog("Too many channels for customer");
+		sl_send_reply(403, "Forbidden");
+
+		if (!cnxcc_terminate_all("$var(client)")) {
+			xlog("Error terminating customer's calls");
+		}
+
+		exit;
+	}
+#!endif
+
+#!ifdef CNXCC_TIME
+	xlog("L_INFO", "Setting up time based credit control");
+	
+	$var(max_time)	= 5;
+	
+	if (!cnxcc_set_max_time("$var(client)",
+                                  "$var(max_time)")) {
+                xlog("Error setting up credit control");
+                return;
+        }
+#!endif
+
+}
+
+event_route[cnxcc:call-shutdown]
+{
+        xlog("L_INFO", "[$ci]: call killed");
+	
+	# perform some kind of notification, database update, email sending, etc
+}
+
+#!ifdef CNXCC_CHANNEL
+route[SHOW_CHANNEL_COUNT]
+{
+	$var(count) = @cnxcc.channels["customer1"].count;
+	xlog("L_INFO", "customer1 has $var(count) call(s)");
+}
+#!endif
+
+#!ifdef CNXCC_TIME
+route[UPDATE_MAX_TIME]
+{
+	if ($DLG_count == 0) // no active dialog? no time to be updated 
+		return;	
+	
+	if ($var(granted_units) == 4) // after 25 seconds, we will stop updating the granted time
+		return;
+
+	$var(granted_units) = $var(granted_units) + 1;
+	xlog("L_INFO", "Updating max-time. Granted units $var(granted_units)/4");
+
+        $var(update_time)  = 5;
+	$var(client)	   = "customer1";
+
+        if (!cnxcc_update_max_time("$var(client)",
+                                  "$var(update_time)")) {
+                xlog("Error updating max-time");
+                return;
+        }
+
+}
+#!endif
+
+route[RELAY] {
+
+	# enable additional event routes for forwarded requests
+	# - serial forking, RTP relaying handling, a.s.o.
+	if (is_method("INVITE|SUBSCRIBE")) {
+		t_on_branch("MANAGE_BRANCH");
+		t_on_reply("MANAGE_REPLY");
+	}
+	if (is_method("INVITE")) {
+		t_on_failure("MANAGE_FAILURE");
+	}
+
+	if (!t_relay()) {
+		sl_reply_error();
+	}
+	exit;
+}
+
+# Per SIP request initial checks
+route[REQINIT] {
+#!ifdef WITH_ANTIFLOOD
+	# flood dection from same IP and traffic ban for a while
+	# be sure you exclude checking trusted peers, such as pstn gateways
+	# - local host excluded (e.g., loop to self)
+	if(src_ip!=myself)
+	{
+		if($sht(ipban=>$si)!=$null)
+		{
+			# ip is already blocked
+			xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
+			exit;
+		}
+		if (!pike_check_req())
+		{
+			xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
+			$sht(ipban=>$si) = 1;
+			exit;
+		}
+	}
+#!endif
+
+	if (!mf_process_maxfwd_header("10")) {
+		sl_send_reply("483","Too Many Hops");
+		exit;
+	}
+
+	if(!sanity_check("1511", "7"))
+	{
+		xlog("Malformed SIP message from $si:$sp\n");
+		exit;
+	}
+}
+
+# Handle requests within SIP dialogs
+route[WITHINDLG] {
+	if (has_totag()) {
+		# sequential request withing a dialog should
+		# take the path determined by record-routing
+		if (loose_route()) {
+			if (is_method("BYE")) {
+				setflag(FLT_ACC); # do accounting ...
+				setflag(FLT_ACCFAILED); # ... even if the transaction fails
+			}
+			if ( is_method("ACK") ) {
+				# ACK is forwarded statelessy
+				route(NATMANAGE);
+			}
+			route(RELAY);
+		} else {
+			if (is_method("SUBSCRIBE") && uri == myself) {
+				# in-dialog subscribe requests
+				route(PRESENCE);
+				exit;
+			}
+			if ( is_method("ACK") ) {
+				if ( t_check_trans() ) {
+					# no loose-route, but stateful ACK;
+					# must be an ACK after a 487
+					# or e.g. 404 from upstream server
+					t_relay();
+					exit;
+				} else {
+					# ACK without matching transaction ... ignore and discard
+					exit;
+				}
+			}
+			sl_send_reply("404","Not here");
+		}
+		exit;
+	}
+}
+
+# Handle SIP registrations
+route[REGISTRAR] {
+	if (is_method("REGISTER"))
+	{
+		if(isflagset(FLT_NATS))
+		{
+			setbflag(FLB_NATB);
+			# uncomment next line to do SIP NAT pinging 
+			## setbflag(FLB_NATSIPPING);
+		}
+		if (!save("location"))
+			sl_reply_error();
+
+		exit;
+	}
+}
+
+# USER location service
+route[LOCATION] {
+
+#!ifdef WITH_SPEEDIAL
+	# search for short dialing - 2-digit extension
+	if($rU=~"^[0-9][0-9]$")
+		if(sd_lookup("speed_dial"))
+			route(SIPOUT);
+#!endif
+
+#!ifdef WITH_ALIASDB
+	# search in DB-based aliases
+	if(alias_db_lookup("dbaliases"))
+		route(SIPOUT);
+#!endif
+
+	$avp(oexten) = $rU;
+	if (!lookup("location")) {
+		$var(rc) = $rc;
+		route(TOVOICEMAIL);
+		t_newtran();
+		switch ($var(rc)) {
+			case -1:
+			case -3:
+				send_reply("404", "Not Found");
+				exit;
+			case -2:
+				send_reply("405", "Method Not Allowed");
+				exit;
+		}
+	}
+
+	# when routing via usrloc, log the missed calls also
+	if (is_method("INVITE"))
+	{
+		setflag(FLT_ACCMISSED);
+	}
+}
+
+# Presence server route
+route[PRESENCE] {
+	if(!is_method("PUBLISH|SUBSCRIBE"))
+		return;
+
+#!ifdef WITH_PRESENCE
+	if (!t_newtran())
+	{
+		sl_reply_error();
+		exit;
+	};
+
+	if(is_method("PUBLISH"))
+	{
+		handle_publish();
+		t_release();
+	}
+	else
+	if( is_method("SUBSCRIBE"))
+	{
+		handle_subscribe();
+		t_release();
+	}
+	exit;
+#!endif
+	
+	# if presence enabled, this part will not be executed
+	if (is_method("PUBLISH") || $rU==$null)
+	{
+		sl_send_reply("404", "Not here");
+		exit;
+	}
+	return;
+}
+
+# Authentication route
+route[AUTH] {
+#!ifdef WITH_AUTH
+	if (is_method("REGISTER"))
+	{
+		# authenticate the REGISTER requests (uncomment to enable auth)
+		if (!www_authorize("$td", "subscriber"))
+		{
+			www_challenge("$td", "0");
+			exit;
+		}
+
+		if ($au!=$tU)
+		{
+			sl_send_reply("403","Forbidden auth ID");
+			exit;
+		}
+	} else {
+
+#!ifdef WITH_IPAUTH
+		if(allow_source_address())
+		{
+			# source IP allowed
+			return;
+		}
+#!endif
+
+		# authenticate if from local subscriber
+		if (from_uri==myself)
+		{
+			if (!proxy_authorize("$fd", "subscriber")) {
+				proxy_challenge("$fd", "0");
+				exit;
+			}
+			if (is_method("PUBLISH"))
+			{
+				if ($au!=$fU || $au!=$tU) {
+					sl_send_reply("403","Forbidden auth ID");
+					exit;
+				}
+				if ($au!=$rU) {
+					sl_send_reply("403","Forbidden R-URI");
+					exit;
+				}
+#!ifdef WITH_MULTIDOMAIN
+				if ($fd!=$rd) {
+					sl_send_reply("403","Forbidden R-URI domain");
+					exit;
+				}
+#!endif
+			} else {
+				if ($au!=$fU) {
+					sl_send_reply("403","Forbidden auth ID");
+					exit;
+				}
+			}
+
+			consume_credentials();
+			# caller authenticated
+		} else {
+			# caller is not local subscriber, then check if it calls
+			# a local destination, otherwise deny, not an open relay here
+			if (!uri==myself)
+			{
+				sl_send_reply("403","Not relaying");
+				exit;
+			}
+		}
+	}
+#!endif
+	return;
+}
+
+# Caller NAT detection route
+route[NATDETECT] {
+#!ifdef WITH_NAT
+	force_rport();
+	if (nat_uac_test("19")) {
+		if (is_method("REGISTER")) {
+			fix_nated_register();
+		} else {
+			fix_nated_contact();
+		}
+		setflag(FLT_NATS);
+	}
+#!endif
+	return;
+}
+
+# RTPProxy control
+route[NATMANAGE] {
+#!ifdef WITH_NAT
+	if (is_request()) {
+		if(has_totag()) {
+			if(check_route_param("nat=yes")) {
+				setbflag(FLB_NATB);
+			}
+		}
+	}
+	if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB)))
+		return;
+
+	rtpproxy_manage();
+
+	if (is_request()) {
+		if (!has_totag()) {
+			add_rr_param(";nat=yes");
+		}
+	}
+	if (is_reply()) {
+		if(isbflagset(FLB_NATB)) {
+			fix_nated_contact();
+		}
+	}
+#!endif
+	return;
+}
+
+# Routing to foreign domains
+route[SIPOUT] {
+	if (!uri==myself)
+	{
+		append_hf("P-hint: outbound\r\n");
+		route(RELAY);
+	}
+}
+
+# PSTN GW routing
+route[PSTN] {
+#!ifdef WITH_PSTN
+	# check if PSTN GW IP is defined
+	if (strempty($sel(cfg_get.pstn.gw_ip))) {
+		xlog("SCRIPT: PSTN rotuing enabled but pstn.gw_ip not defined\n");
+		return;
+	}
+
+	# route to PSTN dialed numbers starting with '+' or '00'
+	#     (international format)
+	# - update the condition to match your dialing rules for PSTN routing
+	if(!($rU=~"^(\+|00)[1-9][0-9]{3,20}$"))
+		return;
+
+	# only local users allowed to call
+	if(from_uri!=myself) {
+		sl_send_reply("403", "Not Allowed");
+		exit;
+	}
+
+	$ru = "sip:" + $rU + "@" + $sel(cfg_get.pstn.gw_ip);
+
+	route(RELAY);
+	exit;
+#!endif
+
+	return;
+}
+
+# XMLRPC routing
+#!ifdef WITH_XMLRPC
+route[XMLRPC] {
+	# allow XMLRPC from localhost
+	if ((method=="POST" || method=="GET")
+			&& (src_ip==127.0.0.1)) {
+		# close connection only for xmlrpclib user agents (there is a bug in
+		# xmlrpclib: it waits for EOF before interpreting the response).
+		if ($hdr(User-Agent) =~ "xmlrpclib")
+			set_reply_close();
+		set_reply_no_connect();
+		dispatch_rpc();
+		exit;
+	}
+	send_reply("403", "Forbidden");
+	exit;
+}
+#!endif
+
+# route to voicemail server
+route[TOVOICEMAIL] {
+#!ifdef WITH_VOICEMAIL
+	if(!is_method("INVITE"))
+		return;
+
+	# check if VoiceMail server IP is defined
+	if (strempty($sel(cfg_get.voicemail.srv_ip))) {
+		xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
+		return;
+	}
+	if($avp(oexten)==$null)
+		return;
+
+	$ru = "sip:" + $avp(oexten) + "@" + $sel(cfg_get.voicemail.srv_ip)
+				+ ":" + $sel(cfg_get.voicemail.srv_port);
+	route(RELAY);
+	exit;
+#!endif
+
+	return;
+}
+
+# manage outgoing branches
+branch_route[MANAGE_BRANCH] {
+	xdbg("new branch [$T_branch_idx] to $ru\n");
+	route(NATMANAGE);
+}
+
+# manage incoming replies
+onreply_route[MANAGE_REPLY] {
+	xdbg("incoming reply\n");
+	if(status=~"[12][0-9][0-9]")
+		route(NATMANAGE);
+}
+
+# manage failure routing cases
+failure_route[MANAGE_FAILURE] {
+	route(NATMANAGE);
+
+	if (t_is_canceled()) {
+		exit;
+	}
+
+#!ifdef WITH_BLOCK3XX
+	# block call redirect based on 3xx replies.
+	if (t_check_status("3[0-9][0-9]")) {
+		t_reply("404","Not found");
+		exit;
+	}
+#!endif
+
+#!ifdef WITH_VOICEMAIL
+	# serial forking
+	# - route to voicemail on busy or no answer (timeout)
+	if (t_check_status("486|408")) {
+		route(TOVOICEMAIL);
+		exit;
+	}
+#!endif
+}
+
+event_route[dialog:failed]
+{
+	xlog("dialog failed");
+}
diff --git a/modules/corex/README b/modules/corex/README
index 6ec433e..35520b4 100644
--- a/modules/corex/README
+++ b/modules/corex/README
@@ -123,7 +123,7 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
    4.2. send([ host [ :port ] ])
    4.3. send_tcp([ host [ :port ] ])
 
-4.1. append_branch([ uri, [ q ] ])
+4.1.  append_branch([ uri, [ q ] ])
 
    Append a new branch to the destination set, useful to build the set of
    destination addresses for parallel forking or redirect replies.
@@ -145,7 +145,7 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
     append_branch("$avp(uri)", "0.5");
 ...
 
-4.2. send([ host [ :port ] ])
+4.2.  send([ host [ :port ] ])
 
    Send the original SIP message to a specific destination in stateless
    mode. No changes are applied to received message, no Via header is
@@ -167,7 +167,7 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
         send("$var(res)");
 ...
 
-4.3. send_tcp([ host [ :port ] ])
+4.3.  send_tcp([ host [ :port ] ])
 
    This function is identical to send() described above, except that it
    sends the SIP message using the TCP protocol instead of UDP.
@@ -177,14 +177,14 @@ modparam("corex", "alias_subdomains", "udp:sip-router.org:5060")
    5.1. corex.list_sockets
    5.2. corex.list_aliases
 
-5.1. corex.list_sockets
+5.1.  corex.list_sockets
 
    Print the list of sockets the application is listening on.
 
    Example:
                 kamcmd corex.list_sockets
 
-5.2. corex.list_aliases
+5.2.  corex.list_aliases
 
    Print the list of hostname aliases used to match the myself condition.
 
diff --git a/modules/corex/corex_lib.c b/modules/corex/corex_lib.c
index 7f2ea2a..9d926c2 100644
--- a/modules/corex/corex_lib.c
+++ b/modules/corex/corex_lib.c
@@ -71,7 +71,7 @@ int corex_append_branch(sip_msg_t *msg, gparam_t *pu, gparam_t *pq)
 	getbflagsval(0, &branch_flags);
 	ret = append_branch(msg, (uri.len>0)?&uri:0, &msg->dst_uri,
 			    &msg->path_vec, q, branch_flags,
-			    msg->force_send_socket, 0, 0);
+			    msg->force_send_socket, 0, 0, 0, 0);
 
 
 	if(uri.len<=0)
diff --git a/modules/corex/corex_mod.c b/modules/corex/corex_mod.c
index bddba03..8d62498 100644
--- a/modules/corex/corex_mod.c
+++ b/modules/corex/corex_mod.c
@@ -30,6 +30,7 @@
 
 #include "corex_lib.h"
 #include "corex_rpc.h"
+#include "corex_var.h"
 
 MODULE_VERSION
 
@@ -43,6 +44,13 @@ static int  mod_init(void);
 static int  child_init(int);
 static void mod_destroy(void);
 
+static pv_export_t mod_pvs[] = {
+	{ {"cfg", (sizeof("cfg")-1)}, PVT_OTHER, pv_get_cfg, 0,
+		pv_parse_cfg_name, 0, 0, 0 },
+
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
 static cmd_export_t cmds[]={
 	{"append_branch", (cmd_function)w_append_branch, 0, 0,
 			0, REQUEST_ROUTE | FAILURE_ROUTE },
@@ -76,7 +84,7 @@ struct module_exports exports = {
 	params,
 	0,
 	0,              /* exported MI functions */
-	0,              /* exported pseudo-variables */
+	mod_pvs,        /* exported pseudo-variables */
 	0,              /* extra processes */
 	mod_init,       /* module initialization function */
 	0,              /* response function */
diff --git a/modules/corex/corex_var.c b/modules/corex/corex_var.c
new file mode 100644
index 0000000..2beaf70
--- /dev/null
+++ b/modules/corex/corex_var.c
@@ -0,0 +1,83 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../dprint.h"
+#include "../../action.h"
+
+#include "corex_var.h"
+
+/**
+ *
+ */
+int pv_parse_cfg_name(pv_spec_p sp, str *in)
+{
+	if(sp==NULL || in==NULL || in->len<=0)
+		return -1;
+
+	switch(in->len)
+	{
+		case 4:
+			if(strncmp(in->s, "line", 4)==0)
+				sp->pvp.pvn.u.isname.name.n = 0;
+			else if(strncmp(in->s, "name", 4)==0)
+				sp->pvp.pvn.u.isname.name.n = 1;
+			else goto error;
+		break;
+		default:
+			goto error;
+	}
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
+	sp->pvp.pvn.u.isname.type = 0;
+
+	return 0;
+
+error:
+	LM_ERR("unknown PV af key: %.*s\n", in->len, in->s);
+	return -1;
+}
+
+/**
+ *
+ */
+int pv_get_cfg(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
+{
+	char *n;
+
+	if(param==NULL)
+		return -1;
+
+	switch(param->pvn.u.isname.name.n)
+	{
+		case 1:
+			n = get_cfg_crt_name();
+			if(n==0)
+				return pv_get_null(msg, param, res);
+			return pv_get_strzval(msg, param, res, n);
+		default:
+			return pv_get_sintval(msg, param, res, get_cfg_crt_line());
+	}
+}
+
diff --git a/modules/corex/corex_var.h b/modules/corex/corex_var.h
new file mode 100644
index 0000000..c5c2a23
--- /dev/null
+++ b/modules/corex/corex_var.h
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef _COREX_VAR_H_
+#define _COREX_VAR_H_
+
+#include "../../pvar.h"
+
+int pv_parse_cfg_name(pv_spec_p sp, str *in);
+int pv_get_cfg(sip_msg_t *msg, pv_param_t *param, pv_value_t *res);
+
+#endif
diff --git a/modules/cpl-c/cpl_sig.c b/modules/cpl-c/cpl_sig.c
index 2459086..630dc43 100644
--- a/modules/cpl-c/cpl_sig.c
+++ b/modules/cpl-c/cpl_sig.c
@@ -92,7 +92,7 @@ int cpl_proxy_to_loc_set( struct sip_msg *msg, struct location **locs,
 			(*locs)->addr.uri.len, (*locs)->addr.uri.s, bflags);
 		if(append_branch(msg, &(*locs)->addr.uri,
 				 &(*locs)->addr.received, 0,
-				 Q_UNSPECIFIED, bflags, 0, 0, 0)==-1){
+				 Q_UNSPECIFIED, bflags, 0, 0, 0, 0, 0)==-1){
 			LM_ERR("failed when appending branch <%s>\n",
 			       (*locs)->addr.uri.s);
 			goto error;
diff --git a/modules/db_cluster/README b/modules/db_cluster/README
index 6ece6af..cbdf261 100644
--- a/modules/db_cluster/README
+++ b/modules/db_cluster/README
@@ -62,10 +62,10 @@ Chapter 1. Admin Guide
    used as a middle layer between modules and database connectors.
 
    Via clustering, database operations can be executed across multiple
-   servers, based on policies such as paraller write, serial or round
+   servers, based on policies such as parallel write, serial or round
    robin write and read.
 
-   Following database commands are considered to be write operations:
+   The following database commands are considered to be write operations:
    INSERT, DELETE, UPDATE, REPLACE, INSERT-DELAYED, INSERT-UPDATE. The
    read operations are done for database commands: QUERY and RAW-QUERY.
 
@@ -94,7 +94,8 @@ Chapter 1. Admin Guide
 3.1. connection (str)
 
    Specify the connection to a real database system. The format is
-   'conid=>DBURL' - providing a connection id and the database URL.
+   'conid=>DBURL' - providing a connection id and the database URL used by
+   the database driver used.
 
    Default value is NULL.
 
@@ -112,18 +113,22 @@ modparam("db_cluster", "connection",
    'clsid=>conid1=def1;conid2=def2' - providing a cluster id and the list
    of database connections to be used. For each connection you have to
    provide a usage definition. The usage definition is a 4-char long
-   string, specifying priority and command mode for read an write
-   operations to be done on that connection.
+   string, specifying priority and command mode for read and write
+   operations to be performed on that connection.
 
-   The priority is a digit between 0 and 9, higher value is higher
-   priority. Priority 0 means that connection is not going to be used in
-   that cluster.
+   The priority is a digit between 0 and 9, where a higher value means
+   higher priority. Priority 0 means that the connection is not going to
+   be used in that cluster.
 
    Command mode is a character among s, r and p. s is for doing serial
    operations (try first and if fails, try next); r is for doing round
    robin operations; p - is for doing parallel operations (this is valid
    only for write operations).
 
+   The first two characters is priority and mode for read, followed by two
+   characters for priority and mode for write operations. "p" is only used
+   for write operations.
+
    Default value is NULL.
 
    Example 1.2. Set cluster parameter
diff --git a/modules/db_cluster/doc/db_cluster_admin.xml b/modules/db_cluster/doc/db_cluster_admin.xml
index eef8eb9..d95cdaf 100644
--- a/modules/db_cluster/doc/db_cluster_admin.xml
+++ b/modules/db_cluster/doc/db_cluster_admin.xml
@@ -21,11 +21,11 @@
 	</para>
 	<para>
 		Via clustering, database operations can be executed across multiple
-		servers, based on policies such as paraller write, serial or round
+		servers, based on policies such as parallel write, serial or round
 		robin write and read.
 	</para>
 	<para>
-		Following database commands are considered to be write operations:
+		The following database commands are considered to be write operations:
 		INSERT, DELETE, UPDATE, REPLACE, INSERT-DELAYED, INSERT-UPDATE. The
 		read operations are done for database commands: QUERY and RAW-QUERY.
 	</para>
@@ -63,12 +63,12 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="db_cluster.p.connection">
 		<title><varname>connection</varname> (str)</title>
 		<para>
 			Specify the connection to a real database system. The format is
 			'conid=>DBURL' - providing a connection id and the database
-			URL.
+			URL used by the database driver used.
 		</para>
 		<para>
 		<emphasis>
@@ -87,19 +87,19 @@ modparam("db_cluster", "connection",
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="db_cluster.p.cluster">
 		<title><varname>cluster</varname> (str)</title>
 		<para>
 			Specify the cluster definition. The format is
 			'clsid=>conid1=def1;conid2=def2' - providing a cluster id and the list of
 			database connections to be used. For each connection you have to provide
 			a usage definition. The usage definition is a 4-char long string,
-			specifying priority and command mode for read an write operations to be
-			done on that connection.
+			specifying priority and command mode for read and write operations to be
+			performed on that connection.
 		</para>
 		<para>
-			The priority is a digit between 0 and 9, higher value is higher priority.
-			Priority 0 means that connection is not going to be used in that cluster.
+			The priority is a digit between 0 and 9, where a higher value means higher priority.
+			Priority 0 means that the connection is not going to be used in that cluster.
 		</para>
 		<para>
 			Command mode is a character among s, r and p. s is for doing serial
@@ -108,6 +108,11 @@ modparam("db_cluster", "connection",
 			only for write operations).
 		</para>
 		<para>
+		<para>
+			The first two characters is priority and mode for read, followed by
+			two characters for priority and mode for write operations. "p" is 
+			only used for write operations.
+		</para>
 		<emphasis>
 			Default value is NULL.
 		</emphasis>
@@ -121,7 +126,7 @@ modparam("db_cluster", "cluster", "cls1=>con1=9s8p;con2=9s8p")
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="db_cluster.p.inactive_interval">
 		<title><varname>inactive_interval</varname> (int)</title>
 		<para>
 			How long (seconds) a connection is considered inactive after a DB
diff --git a/modules/db_mysql/README b/modules/db_mysql/README
index 13a578f..def06aa 100644
--- a/modules/db_mysql/README
+++ b/modules/db_mysql/README
@@ -28,6 +28,7 @@ Daniel-Constantin Mierla
               3.1. ping_interval (integer)
               3.2. timeout_interval (integer)
               3.3. auto_reconnect (integer)
+              3.4. insert_delayed (integer)
 
         4. Functions
         5. Installation
@@ -38,9 +39,10 @@ Daniel-Constantin Mierla
    1.1. Set ping_interval parameter
    1.2. Set timeout_interval parameter
    1.3. Set auto_reconnect parameter
-   1.4. Set a my.cnf group in db_url parameter
-   1.5. Adding a kamailio group to my.cnf
-   1.6. Using [client] and specific group
+   1.4. Set insert_delayed parameter
+   1.5. Set a my.cnf group in db_url parameter
+   1.6. Adding a kamailio group to my.cnf
+   1.7. Using [client] and specific group
 
 Chapter 1. Admin Guide
 
@@ -57,6 +59,7 @@ Chapter 1. Admin Guide
         3.1. ping_interval (integer)
         3.2. timeout_interval (integer)
         3.3. auto_reconnect (integer)
+        3.4. insert_delayed (integer)
 
    4. Functions
    5. Installation
@@ -89,6 +92,7 @@ Chapter 1. Admin Guide
    3.1. ping_interval (integer)
    3.2. timeout_interval (integer)
    3.3. auto_reconnect (integer)
+   3.4. insert_delayed (integer)
 
 3.1. ping_interval (integer)
 
@@ -132,6 +136,18 @@ modparam("db_mysql", "timeout_interval", 2)
 modparam("db_mysql", "auto_reconnect", 0)
 ...
 
+3.4. insert_delayed (integer)
+
+   If set to 1, all INSERT SQL queries will be sent to MySQL server as
+   INSERT DELAYED.
+
+   Default value is 0 (1 - on / 0 - off).
+
+   Example 1.4. Set insert_delayed parameter
+...
+modparam("db_mysql", "insert_delayed", 1)
+...
+
 4. Functions
 
    No function exported to be used from configuration file.
@@ -158,12 +174,12 @@ modparam("db_mysql", "auto_reconnect", 0)
      * mysql://user:pass@[group]/db
      * mysql://[group]/db
 
-   Example 1.4. Set a my.cnf group in db_url parameter
+   Example 1.5. Set a my.cnf group in db_url parameter
 ...
 modparam("usrloc", "db_url", "mysql://[kamailio]/kamailio)
 ...
 
-   Example 1.5. Adding a kamailio group to my.cnf
+   Example 1.6. Adding a kamailio group to my.cnf
 ...
 [kamailio]
 socket = /path/to/mysql.sock
@@ -177,7 +193,7 @@ default-character-set = utf8
    both your specific group and the client group, then the value is taken
    from the last one.
 
-   Example 1.6. Using [client] and specific group
+   Example 1.7. Using [client] and specific group
 ...
 [client]
 socket = /var/run/mysql/mysqld.sock
diff --git a/modules/db_mysql/doc/db_mysql_admin.xml b/modules/db_mysql/doc/db_mysql_admin.xml
index 36ce140..738c464 100644
--- a/modules/db_mysql/doc/db_mysql_admin.xml
+++ b/modules/db_mysql/doc/db_mysql_admin.xml
@@ -121,6 +121,26 @@ modparam("db_mysql", "auto_reconnect", 0)
 </programlisting>
 		</example>
 	</section>
+	<section id="db_mysql.p.insert_delayed">
+		<title><varname>insert_delayed</varname> (integer)</title>
+		<para>
+		If set to 1, all INSERT SQL queries will be sent to MySQL server as
+		INSERT DELAYED.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0 (1 - on / 0 - off).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>insert_delayed</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("db_mysql", "insert_delayed", 1)
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 	<section>
 	<title>Functions</title>
diff --git a/modules/db_mysql/km_db_mysql.c b/modules/db_mysql/km_db_mysql.c
index 252b499..5758f6e 100644
--- a/modules/db_mysql/km_db_mysql.c
+++ b/modules/db_mysql/km_db_mysql.c
@@ -50,6 +50,7 @@
 
 unsigned int db_mysql_timeout_interval = 2;   /* Default is 6 seconds */
 unsigned int db_mysql_auto_reconnect = 1;     /* Default is enabled   */
+unsigned int db_mysql_insert_all_delayed = 0; /* Default is off */
 
 /* MODULE_VERSION */
 
@@ -115,6 +116,9 @@ int db_mysql_bind_api(db_func_t *dbb)
 	dbb->insert_update    = db_mysql_insert_update;
 	dbb->insert_delayed   = db_mysql_insert_delayed;
 	dbb->affected_rows    = db_mysql_affected_rows;
+	dbb->start_transaction= db_mysql_start_transaction;
+	dbb->end_transaction  = db_mysql_end_transaction;
+	dbb->abort_transaction= db_mysql_abort_transaction;
 
 	return 0;
 }
diff --git a/modules/db_mysql/km_db_mysql.h b/modules/db_mysql/km_db_mysql.h
index 9fd9747..09997f7 100644
--- a/modules/db_mysql/km_db_mysql.h
+++ b/modules/db_mysql/km_db_mysql.h
@@ -42,6 +42,7 @@
 
 extern unsigned int db_mysql_timeout_interval;
 extern unsigned int db_mysql_auto_reconnect;
+extern unsigned int db_mysql_insert_all_delayed;
 
 int db_mysql_bind_api(db_func_t *dbb);
 
diff --git a/modules/db_mysql/km_dbase.c b/modules/db_mysql/km_dbase.c
index 151a24a..e486e5f 100644
--- a/modules/db_mysql/km_dbase.c
+++ b/modules/db_mysql/km_dbase.c
@@ -406,10 +406,15 @@ int db_mysql_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r)
  * \param _n number of key=value pairs
  * \return zero on success, negative value on failure
  */
-int db_mysql_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n)
+int db_mysql_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v,
+		const int _n)
 {
-	return db_do_insert(_h, _k, _v, _n, db_mysql_val2str,
-	db_mysql_submit_query);
+	if(unlikely(db_mysql_insert_all_delayed==1))
+		return db_do_insert_delayed(_h, _k, _v, _n, db_mysql_val2str,
+				db_mysql_submit_query);
+	else
+		return db_do_insert(_h, _k, _v, _n, db_mysql_val2str,
+				db_mysql_submit_query);
 }
 
 
@@ -497,6 +502,198 @@ int db_mysql_affected_rows(const db1_con_t* _h)
 	return (int)mysql_affected_rows(CON_CONNECTION(_h));
 }
 
+/**
+ * Starts a single transaction that will consist of one or more queries (SQL BEGIN)
+ * \param _h database handle
+ * \return 0 on success, negative on failure
+ */
+int db_mysql_start_transaction(db1_con_t* _h, db_locking_t _l)
+{
+	str begin_str = str_init("SET autocommit=0");
+	str lock_start_str = str_init("LOCK TABLES ");
+	str lock_end_str  = str_init(" WRITE");
+	str lock_str = {0, 0};
+
+	if (!_h) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	if (CON_TRANSACTION(_h) == 1) {
+		LM_ERR("transaction already started\n");
+		return -1;
+	}
+
+	if (db_mysql_raw_query(_h, &begin_str, NULL) < 0)
+	{
+		LM_ERR("executing raw_query\n");
+		return -1;
+	}
+
+	CON_TRANSACTION(_h) = 1;
+
+	switch(_l)
+	{
+	case DB_LOCKING_NONE:
+		break;
+	case DB_LOCKING_FULL:
+		/* Fall-thru */
+	case DB_LOCKING_WRITE:
+		if ((lock_str.s = pkg_malloc((lock_start_str.len + CON_TABLE(_h)->len + lock_end_str.len) * sizeof(char))) == NULL)
+		{
+			LM_ERR("allocating pkg memory\n");
+			goto error;
+		}
+
+		memcpy(lock_str.s, lock_start_str.s, lock_start_str.len);
+		lock_str.len += lock_start_str.len;
+		memcpy(lock_str.s + lock_str.len, CON_TABLE(_h)->s, CON_TABLE(_h)->len);
+		lock_str.len += CON_TABLE(_h)->len;
+		memcpy(lock_str.s + lock_str.len, lock_end_str.s, lock_end_str.len);
+		lock_str.len += lock_end_str.len;
+
+		if (db_mysql_raw_query(_h, &lock_str, NULL) < 0)
+		{
+			LM_ERR("executing raw_query\n");
+			goto error;
+		}
+
+		if (lock_str.s) pkg_free(lock_str.s);
+		CON_LOCKEDTABLES(_h) = 1;
+		break;
+
+	default:
+		LM_WARN("unrecognised lock type\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	if (lock_str.s) pkg_free(lock_str.s);
+	db_mysql_abort_transaction(_h);
+	return -1;
+}
+
+/**
+ * Unlock tables in the session
+ * \param _h database handle
+ * \return 0 on success, negative on failure
+ */
+int db_mysql_unlock_tables(db1_con_t* _h)
+{
+	str query_str = str_init("UNLOCK TABLES");
+
+	if (!_h) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	if (CON_LOCKEDTABLES(_h) == 0) {
+		LM_DBG("no active locked tables\n");
+		return 0;
+	}
+
+	if (db_mysql_raw_query(_h, &query_str, NULL) < 0)
+	{
+		LM_ERR("executing raw_query\n");
+		return -1;
+	}
+
+	CON_LOCKEDTABLES(_h) = 0;
+	return 0;
+}
+
+/**
+ * Ends a transaction and commits the changes (SQL COMMIT)
+ * \param _h database handle
+ * \return 0 on success, negative on failure
+ */
+int db_mysql_end_transaction(db1_con_t* _h)
+{
+	str commit_query_str = str_init("COMMIT");
+	str set_query_str = str_init("SET autocommit=1");
+
+	if (!_h) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	if (CON_TRANSACTION(_h) == 0) {
+		LM_ERR("transaction not in progress\n");
+		return -1;
+	}
+
+	if (db_mysql_raw_query(_h, &commit_query_str, NULL) < 0)
+	{
+		LM_ERR("executing raw_query\n");
+		return -1;
+	}
+
+	if (db_mysql_raw_query(_h, &set_query_str, NULL) < 0)
+	{
+		LM_ERR("executing raw_query\n");
+		return -1;
+	}
+
+	/* Only _end_ the transaction after the raw_query.  That way, if the
+ 	   raw_query fails, and the calling module does an abort_transaction()
+	   to clean-up, a ROLLBACK will be sent to the DB. */
+	CON_TRANSACTION(_h) = 0;
+
+	if(db_mysql_unlock_tables(_h)<0)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * Ends a transaction and rollsback the changes (SQL ROLLBACK)
+ * \param _h database handle
+ * \return 1 if there was something to rollback, 0 if not, negative on failure
+ */
+int db_mysql_abort_transaction(db1_con_t* _h)
+{
+	str rollback_query_str = str_init("ROLLBACK");
+	str set_query_str = str_init("SET autocommit=1");
+	int ret;
+
+	if (!_h) {
+		LM_ERR("invalid parameter value\n");
+		return -1;
+	}
+
+	if (CON_TRANSACTION(_h) == 0) {
+		LM_DBG("nothing to rollback\n");
+		ret = 0;
+		goto done;
+	}
+
+	/* Whether the rollback succeeds or not we need to _end_ the
+ 	   transaction now or all future starts will fail */
+	CON_TRANSACTION(_h) = 0;
+
+	if (db_mysql_raw_query(_h, &rollback_query_str, NULL) < 0)
+	{
+		LM_ERR("executing raw_query\n");
+		ret = -1;
+		goto done;
+	}
+
+	if (db_mysql_raw_query(_h, &set_query_str, NULL) < 0)
+	{
+		LM_ERR("executing raw_query\n");
+		ret = -1;
+		goto done;
+	}
+
+	ret = 1;
+
+done:
+	db_mysql_unlock_tables(_h);
+	return ret;
+}
+
 
 /**
   * Insert a row into a specified table, update on duplicate key.
diff --git a/modules/db_mysql/km_dbase.h b/modules/db_mysql/km_dbase.h
index 2acf517..23fc002 100644
--- a/modules/db_mysql/km_dbase.h
+++ b/modules/db_mysql/km_dbase.h
@@ -40,6 +40,7 @@
 #include "../../lib/srdb1/db_key.h"
 #include "../../lib/srdb1/db_op.h"
 #include "../../lib/srdb1/db_val.h"
+#include "../../lib/srdb1/db_locking.h"
 #include "../../str.h"
 
 /*! \brief
@@ -118,6 +119,21 @@ int db_mysql_last_inserted_id(const db1_con_t* _h);
  */
 int db_mysql_affected_rows(const db1_con_t* _h);
 
+/*! \brief
+ * Starts transaction
+ */
+int db_mysql_start_transaction(db1_con_t* _h, db_locking_t _l);
+
+/*! \brief
+ * Commits transaction
+ */
+int db_mysql_end_transaction(db1_con_t* _h);
+
+/*! \brief
+ * Aborts transaction
+ */
+int db_mysql_abort_transaction(db1_con_t* _h);
+
 
 /*! \brief
  * Insert a row into table, update on duplicate key
diff --git a/modules/db_mysql/km_my_con.h b/modules/db_mysql/km_my_con.h
index 3d71d00..7a58530 100644
--- a/modules/db_mysql/km_my_con.h
+++ b/modules/db_mysql/km_my_con.h
@@ -46,14 +46,18 @@ struct my_con {
 
 	MYSQL* con;              /*!< Connection representation */
 	time_t timestamp;        /*!< Timestamp of last query */
+	int transaction;         /*!< Multi-query transaction is currently open */
+	int lockedtables;        /*!< Table locks were aquired */
 };
 
 
 /*
  * Some convenience wrappers
  */
-#define CON_CONNECTION(db_con) (((struct my_con*)((db_con)->tail))->con)
-#define CON_TIMESTAMP(db_con)  (((struct my_con*)((db_con)->tail))->timestamp)
+#define CON_CONNECTION(db_con)  (((struct my_con*)((db_con)->tail))->con)
+#define CON_TIMESTAMP(db_con)   (((struct my_con*)((db_con)->tail))->timestamp)
+#define CON_TRANSACTION(db_con) (((struct my_con*)((db_con)->tail))->transaction)
+#define CON_LOCKEDTABLES(db_con) (((struct my_con*)((db_con)->tail))->lockedtables)
 
 
 /*! \brief
diff --git a/modules/db_mysql/mysql_mod.c b/modules/db_mysql/mysql_mod.c
index 74c61af..4041370 100644
--- a/modules/db_mysql/mysql_mod.c
+++ b/modules/db_mysql/mysql_mod.c
@@ -5,19 +5,19 @@
  *
  * Copyright (C) 2001-2003 FhG Fokus
  *
- * This file is part of ser, a free SIP server.
+ * This file is part of Kamailio, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
- * For a license to use the ser software under conditions
+ * For a license to use the Kamailio software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info at iptel.org
  *
- * ser is distributed in the hope that it will be useful,
+ * Kamailio is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
@@ -31,6 +31,7 @@
  * --------
  *  2003-03-11  updated to the new module exports interface (andrei)
  *  2003-03-16  flags export parameter added (janakj)
+ *  2013-04-02  added transaction support (haakon.nessjoen at gmail.com)
  */
 /** @addtogroup mysql
  *  @{
@@ -107,6 +108,7 @@ static param_export_t params[] = {
 
 	{"timeout_interval", INT_PARAM, &db_mysql_timeout_interval},
 	{"auto_reconnect",   INT_PARAM, &db_mysql_auto_reconnect},
+	{"insert_delayed",   INT_PARAM, &db_mysql_insert_all_delayed},
 	{0, 0, 0}
 };
 
diff --git a/modules/db_sqlite/Makefile b/modules/db_sqlite/Makefile
index 4a99fe8..150e1d6 100644
--- a/modules/db_sqlite/Makefile
+++ b/modules/db_sqlite/Makefile
@@ -6,7 +6,12 @@ include ../../Makefile.defs
 auto_gen=
 NAME=db_sqlite.so
 
-LIBS +=-lsqlite3
+# sqlite3.h locations (freebsd,openbsd  solaris)
+DEFS += -I$(LOCALBASE)/include
+
+# libodbc locations on RH/Suse, Solaris /OpenBSD, FreeBSD
+# (Debian does the right thing and puts it in /usr/lib)
+LIBS= -L$(LOCALBASE)/lib -lsqlite3
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
diff --git a/modules/db_text/README b/modules/db_text/README
index 37f98a0..530170f 100644
--- a/modules/db_text/README
+++ b/modules/db_text/README
@@ -220,7 +220,7 @@ modparam("db_text", "db_mode", 1)
 
    4.1. db_text.dump
 
-4.1. db_text.dump
+4.1.  db_text.dump
 
    Write back to hard drive all modified tables.
 
diff --git a/modules/db_unixodbc/con.c b/modules/db_unixodbc/con.c
deleted file mode 100644
index d211d9e..0000000
--- a/modules/db_unixodbc/con.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/* 
- * $Id$
- *
- * UNIXODBC module
- *
- * Copyright (C) 2005-2006 Marco Lorrai
- * Copyright (C) 2008 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- *
- * History:
- * --------
- *  2005-12-01  initial commit (chgen)
- *  2006-01-10  UID (username) and PWD (password) attributes added to 
- *              connection string (bogdan)
- *  2006-05-05  extract_error passes back last error state on return (sgupta)
- */
-
-#include "con.h"
-#include "../../mem/mem.h"
-#include "../../dprint.h"
-#include "../../ut.h"
-#include <time.h>
-
-#define DSN_ATTR  "DSN="
-#define DSN_ATTR_LEN  (sizeof(DSN_ATTR)-1)
-#define UID_ATTR  "UID="
-#define UID_ATTR_LEN  (sizeof(UID_ATTR)-1)
-#define PWD_ATTR  "PWD="
-#define PWD_ATTR_LEN  (sizeof(PWD_ATTR)-1)
-
-
-char *db_unixodbc_build_conn_str(const struct db_id* id, char *buf)
-{
-	int len, ld, lu, lp;
-	char *p;
-
-	if (!buf) return 0;
-
-	ld = id->database?strlen(id->database):0;
-	lu = id->username?strlen(id->username):0;
-	lp = id->password?strlen(id->password):0;
-
-	len = (ld?(DSN_ATTR_LEN + ld + 1):0)
-		+ (lu?(UID_ATTR_LEN + lu + 1):0)
-		+ PWD_ATTR_LEN + lp + 1;
-
-	if ( len>=MAX_CONN_STR_LEN ){
-		LM_ERR("connection string too long! Increase MAX_CONN_STR_LEN"
-				" and recompile\n");
-		return 0;
-	}
-
-	p = buf;
-	if (ld) {
-		memcpy( p , DSN_ATTR, DSN_ATTR_LEN);
-		p += DSN_ATTR_LEN;
-		memcpy( p, id->database, ld);
-		p += ld;
-	}
-	if (lu) {
-		*(p++) = ';';
-		memcpy( p , UID_ATTR, UID_ATTR_LEN);
-		p += UID_ATTR_LEN;
-		memcpy( p, id->username, lu);
-		p += lu;
-	}
-	if (lp) {
-		*(p++) = ';';
-		memcpy( p , PWD_ATTR, PWD_ATTR_LEN);
-		p += PWD_ATTR_LEN;
-		memcpy( p, id->password, lp);
-		p += lp;
-	}
-	*(p++) = ';';
-	*p = 0 ; /* make it null terminated */
-
-	return buf;
-}
-
-
-/*
- * Create a new connection structure,
- * open the UNIXODBC connection and set reference count to 1
- */
-struct my_con* db_unixodbc_new_connection(struct db_id* id)
-{
-	SQLCHAR outstr[1024];
-	SQLSMALLINT outstrlen;
-	int ret;
-	struct my_con* ptr;
-	char conn_str[MAX_CONN_STR_LEN];
-
-	if (!id)
-	{
-		LM_ERR("invalid parameter value\n");
-		return 0;
-	}
-
-	ptr = (struct my_con*)pkg_malloc(sizeof(struct my_con));
-	if (!ptr)
-	{
-		LM_ERR("no more memory left\n");
-		return 0;
-	}
-
-	memset(ptr, 0, sizeof(struct my_con));
-	ptr->ref = 1;
-	// allocate environment handle
-	ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(ptr->env));
-	if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
-	{
-		LM_ERR("could not alloc a SQL handle\n");
-		if (ptr) pkg_free(ptr);
-		return 0;
-	}
-	// set the environment
-	ret = SQLSetEnvAttr(ptr->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
-	if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
-	{
-		LM_ERR("could not set the environment\n");
-		goto err1;
-	}
-	// allocate connection handle
-	ret = SQLAllocHandle(SQL_HANDLE_DBC, ptr->env, &(ptr->dbc));
-	if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
-	{
-		LM_ERR("could not alloc a connection handle %d\n", ret);
-		goto err1;
-	}
-
-	if (!db_unixodbc_build_conn_str(id, conn_str)) {
-		LM_ERR("failed to build connection string\n");
-		goto err2;
-	}
-
-	LM_DBG("opening connection: unixodbc://xxxx:xxxx@%s/%s\n", ZSW(id->host),
-		ZSW(id->database));
-
-	ret = SQLDriverConnect(ptr->dbc, NULL, (SQLCHAR*)conn_str, SQL_NTS,
-		outstr, sizeof(outstr), &outstrlen,
-		SQL_DRIVER_COMPLETE);
-	if (SQL_SUCCEEDED(ret))
-	{
-		LM_DBG("connection succeeded with reply <%s>\n", outstr);
-		if (ret == SQL_SUCCESS_WITH_INFO)
-		{
-			LM_DBG("driver reported the following diagnostics\n");
-			db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
-		}
-	}
-	else
-	{
-		LM_ERR("failed to connect\n");
-		db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
-		goto err2;
-	}
-
-	ptr->stmt_handle = NULL;
-
-	ptr->timestamp = time(0);
-	ptr->id = id;
-	return ptr;
-
-err1:
-	SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
-	if (ptr) pkg_free(ptr);
-	return 0;
-
-err2:
-	SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
-	SQLFreeHandle(SQL_HANDLE_DBC, &(ptr->dbc));
-	if (ptr) pkg_free(ptr);
-	return 0;
-}
-
-/*
- * Close the connection and release memory
- */
-void db_unixodbc_free_connection(struct my_con* con)
-{
-	if (!con) return;
-	SQLFreeHandle(SQL_HANDLE_ENV, con->env);
-	SQLDisconnect(con->dbc);
-	SQLFreeHandle(SQL_HANDLE_DBC, con->dbc);
-	pkg_free(con);
-}
-
-
-void db_unixodbc_extract_error(const char *fn, const SQLHANDLE handle, const SQLSMALLINT type, char* stret)
-{
-	SQLINTEGER   i = 0;
-	SQLINTEGER   native;
-	SQLCHAR  state[ 7 ];
-	SQLCHAR  text[256];
-	SQLSMALLINT  len;
-	SQLRETURN	ret;
-
-	do
-	{
-		ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
-			sizeof(text), &len );
-		if (SQL_SUCCEEDED(ret)) {
-			LM_ERR("unixodbc:%s=%s:%ld:%ld:%s\n", fn, state, (long)i, 
-					(long)native, text);
-			if(stret) strcpy( stret, (char*)state );
-		}
-	}
-	while( ret == SQL_SUCCESS );
-}
diff --git a/modules/db_unixodbc/connection.c b/modules/db_unixodbc/connection.c
new file mode 100644
index 0000000..902870e
--- /dev/null
+++ b/modules/db_unixodbc/connection.c
@@ -0,0 +1,225 @@
+/* 
+ * $Id$
+ *
+ * UNIXODBC module
+ *
+ * Copyright (C) 2005-2006 Marco Lorrai
+ * Copyright (C) 2008 1&1 Internet AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * History:
+ * --------
+ *  2005-12-01  initial commit (chgen)
+ *  2006-01-10  UID (username) and PWD (password) attributes added to 
+ *              connection string (bogdan)
+ *  2006-05-05  extract_error passes back last error state on return (sgupta)
+ */
+
+#include "connection.h"
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../ut.h"
+#include <time.h>
+
+#define DSN_ATTR  "DSN="
+#define DSN_ATTR_LEN  (sizeof(DSN_ATTR)-1)
+#define UID_ATTR  "UID="
+#define UID_ATTR_LEN  (sizeof(UID_ATTR)-1)
+#define PWD_ATTR  "PWD="
+#define PWD_ATTR_LEN  (sizeof(PWD_ATTR)-1)
+
+
+char *db_unixodbc_build_conn_str(const struct db_id* id, char *buf)
+{
+	int len, ld, lu, lp;
+	char *p;
+
+	if (!buf) return 0;
+
+	ld = id->database?strlen(id->database):0;
+	lu = id->username?strlen(id->username):0;
+	lp = id->password?strlen(id->password):0;
+
+	len = (ld?(DSN_ATTR_LEN + ld + 1):0)
+		+ (lu?(UID_ATTR_LEN + lu + 1):0)
+		+ PWD_ATTR_LEN + lp + 1;
+
+	if ( len>=MAX_CONN_STR_LEN ){
+		LM_ERR("connection string too long! Increase MAX_CONN_STR_LEN"
+				" and recompile\n");
+		return 0;
+	}
+
+	p = buf;
+	if (ld) {
+		memcpy( p , DSN_ATTR, DSN_ATTR_LEN);
+		p += DSN_ATTR_LEN;
+		memcpy( p, id->database, ld);
+		p += ld;
+	}
+	if (lu) {
+		*(p++) = ';';
+		memcpy( p , UID_ATTR, UID_ATTR_LEN);
+		p += UID_ATTR_LEN;
+		memcpy( p, id->username, lu);
+		p += lu;
+	}
+	if (lp) {
+		*(p++) = ';';
+		memcpy( p , PWD_ATTR, PWD_ATTR_LEN);
+		p += PWD_ATTR_LEN;
+		memcpy( p, id->password, lp);
+		p += lp;
+	}
+	*(p++) = ';';
+	*p = 0 ; /* make it null terminated */
+
+	return buf;
+}
+
+
+/*
+ * Create a new connection structure,
+ * open the UNIXODBC connection and set reference count to 1
+ */
+struct my_con* db_unixodbc_new_connection(struct db_id* id)
+{
+	SQLCHAR outstr[1024];
+	SQLSMALLINT outstrlen;
+	int ret;
+	struct my_con* ptr;
+	char conn_str[MAX_CONN_STR_LEN];
+
+	if (!id)
+	{
+		LM_ERR("invalid parameter value\n");
+		return 0;
+	}
+
+	ptr = (struct my_con*)pkg_malloc(sizeof(struct my_con));
+	if (!ptr)
+	{
+		LM_ERR("no more memory left\n");
+		return 0;
+	}
+
+	memset(ptr, 0, sizeof(struct my_con));
+	ptr->ref = 1;
+	// allocate environment handle
+	ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(ptr->env));
+	if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
+	{
+		LM_ERR("could not alloc a SQL handle\n");
+		if (ptr) pkg_free(ptr);
+		return 0;
+	}
+	// set the environment
+	ret = SQLSetEnvAttr(ptr->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
+	if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
+	{
+		LM_ERR("could not set the environment\n");
+		goto err1;
+	}
+	// allocate connection handle
+	ret = SQLAllocHandle(SQL_HANDLE_DBC, ptr->env, &(ptr->dbc));
+	if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
+	{
+		LM_ERR("could not alloc a connection handle %d\n", ret);
+		goto err1;
+	}
+
+	if (!db_unixodbc_build_conn_str(id, conn_str)) {
+		LM_ERR("failed to build connection string\n");
+		goto err2;
+	}
+
+	LM_DBG("opening connection: unixodbc://xxxx:xxxx@%s/%s\n", ZSW(id->host),
+		ZSW(id->database));
+
+	ret = SQLDriverConnect(ptr->dbc, NULL, (SQLCHAR*)conn_str, SQL_NTS,
+		outstr, sizeof(outstr), &outstrlen,
+		SQL_DRIVER_COMPLETE);
+	if (SQL_SUCCEEDED(ret))
+	{
+		LM_DBG("connection succeeded with reply <%s>\n", outstr);
+		if (ret == SQL_SUCCESS_WITH_INFO)
+		{
+			LM_DBG("driver reported the following diagnostics\n");
+			db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
+		}
+	}
+	else
+	{
+		LM_ERR("failed to connect\n");
+		db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
+		goto err2;
+	}
+
+	ptr->stmt_handle = NULL;
+
+	ptr->timestamp = time(0);
+	ptr->id = id;
+	return ptr;
+
+err1:
+	SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
+	if (ptr) pkg_free(ptr);
+	return 0;
+
+err2:
+	SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
+	SQLFreeHandle(SQL_HANDLE_DBC, &(ptr->dbc));
+	if (ptr) pkg_free(ptr);
+	return 0;
+}
+
+/*
+ * Close the connection and release memory
+ */
+void db_unixodbc_free_connection(struct my_con* con)
+{
+	if (!con) return;
+	SQLFreeHandle(SQL_HANDLE_ENV, con->env);
+	SQLDisconnect(con->dbc);
+	SQLFreeHandle(SQL_HANDLE_DBC, con->dbc);
+	pkg_free(con);
+}
+
+
+void db_unixodbc_extract_error(const char *fn, const SQLHANDLE handle, const SQLSMALLINT type, char* stret)
+{
+	SQLINTEGER   i = 0;
+	SQLINTEGER   native;
+	SQLCHAR  state[ 7 ];
+	SQLCHAR  text[256];
+	SQLSMALLINT  len;
+	SQLRETURN	ret;
+
+	do
+	{
+		ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
+			sizeof(text), &len );
+		if (SQL_SUCCEEDED(ret)) {
+			LM_ERR("unixodbc:%s=%s:%ld:%ld:%s\n", fn, state, (long)i, 
+					(long)native, text);
+			if(stret) strcpy( stret, (char*)state );
+		}
+	}
+	while( ret == SQL_SUCCESS );
+}
diff --git a/modules/db_unixodbc/con.h b/modules/db_unixodbc/connection.h
similarity index 100%
rename from modules/db_unixodbc/con.h
rename to modules/db_unixodbc/connection.h
diff --git a/modules/db_unixodbc/dbase.c b/modules/db_unixodbc/dbase.c
index 72edf1e..61300a3 100644
--- a/modules/db_unixodbc/dbase.c
+++ b/modules/db_unixodbc/dbase.c
@@ -38,7 +38,7 @@
 #include "../../dprint.h"
 #include "../../lib/srdb1/db_query.h"
 #include "val.h"
-#include "con.h"
+#include "connection.h"
 #include "row.h"
 #include "res.h"
 #include "list.h"
diff --git a/modules/db_unixodbc/list.h b/modules/db_unixodbc/list.h
index 100bae0..1ab737b 100644
--- a/modules/db_unixodbc/list.h
+++ b/modules/db_unixodbc/list.h
@@ -35,7 +35,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include "con.h"
+#include "connection.h"
 
 
 typedef struct list
diff --git a/modules/db_unixodbc/res.c b/modules/db_unixodbc/res.c
index 592755a..c575d5a 100644
--- a/modules/db_unixodbc/res.c
+++ b/modules/db_unixodbc/res.c
@@ -34,7 +34,7 @@
 #include "../../dprint.h"
 #include "row.h"
 #include "../../lib/srdb1/db_res.h"
-#include "con.h"
+#include "connection.h"
 #include "res.h"
 #include "list.h"
 #include <stdlib.h>
diff --git a/modules/db_unixodbc/row.c b/modules/db_unixodbc/row.c
index 4b1e564..1134bbe 100644
--- a/modules/db_unixodbc/row.c
+++ b/modules/db_unixodbc/row.c
@@ -35,7 +35,7 @@
 #include "../../lib/srdb1/db_val.h"
 #include "val.h"
 #include "row.h"
-#include "con.h"
+#include "connection.h"
 
 /*
  * Convert a row from result into db API representation
diff --git a/modules/db_unixodbc/val.c b/modules/db_unixodbc/val.c
index c2b26cd..a6e21b9 100644
--- a/modules/db_unixodbc/val.c
+++ b/modules/db_unixodbc/val.c
@@ -34,7 +34,7 @@
 #include "../../lib/srdb1/db_ut.h"
 #include "db_unixodbc.h"
 #include "val.h"
-#include "con.h"
+#include "connection.h"
 
 /*
  * Used when converting the query to a result
diff --git a/modules/debugger/Makefile b/modules/debugger/Makefile
index 579bcde..a87111c 100644
--- a/modules/debugger/Makefile
+++ b/modules/debugger/Makefile
@@ -9,4 +9,6 @@ LIBS=
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules
diff --git a/modules/debugger/README b/modules/debugger/README
index 6a7d677..b63f333 100644
--- a/modules/debugger/README
+++ b/modules/debugger/README
@@ -32,16 +32,25 @@ Daniel-Constantin Mierla
               3.5. log_prefix (str)
               3.6. step_usleep (int)
               3.7. step_loops (int)
+              3.8. mod_hash_size (int)
+              3.9. mod_level_mode (int)
+              3.10. mod_level (str)
+              3.11. log_assign (int)
+              3.12. cfgpkgcheck (int)
+              3.13. reset_msgid (int)
 
         4. Functions
 
               4.1. dbg_breakpoint(mode)
+              4.2. dbg_pv_dump([mask] [, level])
 
         5. Exported RPC Functions
 
               5.1. dbg.ls
               5.2. dbg.trace
               5.3. dbg.bp
+              5.4. dbg.mod_level
+              5.5. dbg.reset_msgid
 
         6. Usage
 
@@ -54,7 +63,14 @@ Daniel-Constantin Mierla
    1.5. Set log_prefix parameter
    1.6. Set step_usleep parameter
    1.7. Set step_loops parameter
-   1.8. dbg_breakpoint usage
+   1.8. Set mod_hash_size parameter
+   1.9. Set mod_level_mode parameter
+   1.10. Set mod_level parameter
+   1.11. Set log_assign parameter
+   1.12. Set cfgpkgcheck parameter
+   1.13. Set reset_msgid parameter
+   1.14. dbg_breakpoint usage
+   1.15. dbg_pv_dump usage
 
 Chapter 1. Admin Guide
 
@@ -75,16 +91,25 @@ Chapter 1. Admin Guide
         3.5. log_prefix (str)
         3.6. step_usleep (int)
         3.7. step_loops (int)
+        3.8. mod_hash_size (int)
+        3.9. mod_level_mode (int)
+        3.10. mod_level (str)
+        3.11. log_assign (int)
+        3.12. cfgpkgcheck (int)
+        3.13. reset_msgid (int)
 
    4. Functions
 
         4.1. dbg_breakpoint(mode)
+        4.2. dbg_pv_dump([mask] [, level])
 
    5. Exported RPC Functions
 
         5.1. dbg.ls
         5.2. dbg.trace
         5.3. dbg.bp
+        5.4. dbg.mod_level
+        5.5. dbg.reset_msgid
 
    6. Usage
 
@@ -136,6 +161,12 @@ Chapter 1. Admin Guide
    3.5. log_prefix (str)
    3.6. step_usleep (int)
    3.7. step_loops (int)
+   3.8. mod_hash_size (int)
+   3.9. mod_level_mode (int)
+   3.10. mod_level (str)
+   3.11. log_assign (int)
+   3.12. cfgpkgcheck (int)
+   3.13. reset_msgid (int)
 
 3.1. cfgtrace (int)
 
@@ -223,9 +254,84 @@ modparam("debugger", "step_usleep", 500000)
 modparam("debugger", "step_loops", 100)
 ...
 
+3.8. mod_hash_size (int)
+
+   Used to compute power of two as size of internal hash table to store
+   levels per module (e.g., if its set to 4, internal hash table has 16
+   slots). This parameter is accesible readonly via the Kamailio config
+   framework.
+
+   Default value is "0" - feature disabled.
+
+   Example 1.8. Set mod_hash_size parameter
+...
+modparam("debugger", "mod_hash_size", 5)
+...
+
+3.9. mod_level_mode (int)
+
+   Enable or disable per module log level (0 - disabled, 1 - enabled).
+   This parameter is tunable via the Kamailio config framework.
+
+   Default value is "0".
+
+   Example 1.9. Set mod_level_mode parameter
+...
+modparam("debugger", "mod_level_mode", 1)
+...
+
+3.10. mod_level (str)
+
+   Specify module log level - the value must be in the format:
+   modulename=level. The parameter can be set many times. For core log
+   level, use module name 'core'.
+
+   Example 1.10. Set mod_level parameter
+...
+modparam("debugger", "mod_level", "core=3")
+modparam("debugger", "mod_level", "tm=3")
+...
+
+3.11. log_assign (int)
+
+   Enable or disable log assign actions on config (0 - disabled, 1 -
+   enabled).
+
+   Default value is "0".
+
+   Example 1.11. Set log_assign parameter
+...
+modparam("debugger", "log_assign", 1)
+...
+
+3.12. cfgpkgcheck (int)
+
+   If set, before each config action is done pkg memory check, useful to
+   detect buffer overflows.
+
+   Default value is "0" (disabled).
+
+   Example 1.12. Set cfgpkgcheck parameter
+...
+modparam("debugger", "cfgpkgcheck", 1)
+...
+
+3.13. reset_msgid (int)
+
+   Used to enable or disable the ability to reset the msgid ($mi) through
+   the dbg.reset_msgid RPC command. (0 - disabled, 1 - enabled).
+
+   Default value is "0" - feature disabled.
+
+   Example 1.13. Set reset_msgid parameter
+...
+modparam("debugger", "reset_msgid", 1)
+...
+
 4. Functions
 
    4.1. dbg_breakpoint(mode)
+   4.2. dbg_pv_dump([mask] [, level])
 
 4.1. dbg_breakpoint(mode)
 
@@ -236,17 +342,64 @@ modparam("debugger", "step_loops", 100)
    Note that this version of the module does not export this anchors to
    RPC for interactive debugging (temporarily disabled).
 
-   Example 1.8. dbg_breakpoint usage
+   Example 1.14. dbg_breakpoint usage
 ...
 if($si=="10.0.0.10")
         dbg_breakpoint("1");
 ...
 
+4.2. dbg_pv_dump([mask] [, level])
+
+   Prints the content of pv_cache on json format. Defaults are mask=31 and
+   level = "L_DBG"
+
+   mask - Controls the content to dump:
+     * 1 - dump null values
+     * 2 - dump avp vars
+     * 4 - dump script vars
+     * 8 - dump xavp vars
+     * 16 - dump DP_OTHER vars
+
+   level - The level that will be used in LOG function. It can be:
+     * L_ALERT - log level -5
+     * L_BUG - log level -4
+     * L_CRIT - log level -3
+     * L_ERR - log level -1
+     * L_WARN - log level 0
+     * L_NOTICE - log level 1
+     * L_INFO - log level 2
+     * L_DBG - log level 3
+
+   Example 1.15. dbg_pv_dump usage
+...
+$var(temp) = 1;
+$avp(s:more_avp) = 2;
+$avp(s:more_avp) = 3;
+$xavp(x=>more) = "bye";
+$xavp(x[0]=>more) = "hi";
+$xavp(x[0]=>other) = 1;
+$xavp(x[0]=>other) = 2;
+$xavp(x=>different) = "foo";
+$var(empty) = $null;
+
+dbg_pv_dump(30, "L_DBG");
+...
+
+   Output
+...
+ 4(30943) DEBUG: debugger [debugger_api.c:1613]: dbg_dump_json(): {"$sp":37597,"
+$var(rc)":0,"$var(temp)":1,"$avp(more_avp)":[3,2],"$si":"127.0.0.1","$rc":0,"$xa
+vp(x)":[{"different":["foo"]},{"other":[2,1],"more":["hi","bye"]}],"$T_branch_id
+x":0,"$var(empty)":0}
+ ...
+
 5. Exported RPC Functions
 
    5.1. dbg.ls
    5.2. dbg.trace
    5.3. dbg.bp
+   5.4. dbg.mod_level
+   5.5. dbg.reset_msgid
 
 5.1. dbg.ls
 
@@ -317,6 +470,32 @@ if($si=="10.0.0.10")
                 dbg.bp eval 1234 $fu
                 dbg.bp move 1234
 
+5.4. dbg.mod_level
+
+   Specify module log level.
+
+   Name: dbg.mod_level
+
+   Parameters:
+     * _module_ : For core log level, use module name 'core'
+     * _level_ : integer
+
+   Examples of use with kamcmd:
+                dbg.mod_level core 3
+                dbg.mod_level tm 3
+
+5.5. dbg.reset_msgid
+
+   Resets the message sequence ($mi). Internally there is no real change.
+   This can be useful for unit test cases in order to be able to replicate
+   exactly the same kamailio output. You need to set the debugger
+   parameter reset_msgid to 1 to activate this functionallity.
+
+   Name: dbg.reset_msgid
+
+   Examples of use with kamcmd:
+                dbg.reset_msgid
+
 6. Usage
 
    A common usage is to investigate the execution path for a specific SIP
diff --git a/modules/debugger/debugger_api.c b/modules/debugger/debugger_api.c
index bbf31a0..56d2975 100644
--- a/modules/debugger/debugger_api.c
+++ b/modules/debugger/debugger_api.c
@@ -35,9 +35,16 @@
 #include "../../rpc_lookup.h"
 #include "../../route_struct.h"
 #include "../../mem/shm_mem.h"
-		       
+#include "../../locking.h"
+#include "../../lvalue.h"
+#include "../../hashes.h"
+#include "../../lib/srutils/srjson.h"
+#include "../../xavp.h"
+#include "../pv/pv_xavp.h"
+
 #include "debugger_act.h"
 #include "debugger_api.h"
+#include "debugger_config.h"
 
 #define DBG_CMD_SIZE 256
 
@@ -145,6 +152,11 @@ int _dbg_cfgtrace = 0;
 /**
  *
  */
+int _dbg_cfgpkgcheck = 0;
+
+/**
+ *
+ */
 int _dbg_breakpoint = 0;
 
 /**
@@ -173,6 +185,11 @@ int _dbg_step_usleep = 100000;
 int _dbg_step_loops = 200;
 
 /**
+ * disabled by default
+ */
+int _dbg_reset_msgid = 0;
+
+/**
  *
  */
 typedef struct _dbg_cmd
@@ -192,6 +209,9 @@ typedef struct _dbg_pid
 	unsigned int state;
 	dbg_cmd_t in;
 	dbg_cmd_t out;
+	gen_lock_t *lock;
+	unsigned int reset_msgid; /* flag to reset the id */
+	unsigned int msgid_base; /* real id since the reset */
 } dbg_pid_t;
 
 /**
@@ -220,6 +240,48 @@ typedef struct _dbg_bp
  */
 static dbg_bp_t *_dbg_bp_list = NULL;
 
+/* defined later */
+int dbg_get_pid_index(unsigned int pid);
+
+/*!
+ * \brief Callback function that checks if reset_msgid is set
+ *  and modifies msg->id if necessary.
+ * \param msg SIP message
+ * \param flags unused
+ * \param bar unused
+ * \return 1 on success, -1 on failure
+ */
+int dbg_msgid_filter(struct sip_msg *msg, unsigned int flags, void *bar)
+{
+	unsigned int process_no = my_pid();
+	int indx = dbg_get_pid_index(process_no);
+	unsigned int msgid_base = 0;
+	unsigned int msgid_new = 0;
+	if(indx<0) return -1;
+	LM_DBG("process_no:%d indx:%d\n", process_no, indx);
+	lock_get(_dbg_pid_list[indx].lock);
+	if(_dbg_pid_list[indx].reset_msgid==1)
+	{
+		LM_DBG("reset_msgid! msgid_base:%d\n", msg->id);
+		_dbg_pid_list[indx].reset_msgid = 0;
+		_dbg_pid_list[indx].msgid_base = msg->id - 1;
+	}
+	msgid_base = _dbg_pid_list[indx].msgid_base;
+	lock_release(_dbg_pid_list[indx].lock);
+	msgid_new = msg->id - msgid_base;
+	LM_DBG("msg->id:%d msgid_base:%d -> %d\n", msg->id, msgid_base, msgid_new);
+	if(msgid_new>0)
+	{
+		msg->id = msgid_new;
+		return 1;
+	}
+	else
+	{
+		LM_WARN("msgid_new<=0??\n");
+		return -1;
+	}
+}
+
 /**
  * callback executed for each cfg action
  */
@@ -245,6 +307,17 @@ int dbg_cfg_trace(void *data)
 
 	an = dbg_get_action_name(a);
 
+	if(_dbg_cfgpkgcheck!=0)
+	{
+#ifdef q_malloc_h
+		LM_DBG("checking pkg memory before action %.*s (line %d)\n",
+				an->len, an->s, a->cline);
+		qm_check(mem_block);
+#else
+		LM_DBG("cfg pkg check is disbled due to missing qm handler\n");
+#endif
+	}
+
 	if(_dbg_pid_list[process_no].set&DBG_CFGTRACE_ON)
 	{
 		if(is_printable(_dbg_cfgtrace_level))
@@ -490,6 +563,22 @@ int dbg_init_mypid(void)
 		_dbg_pid_list[process_no].set |= DBG_ABKPOINT_ON;
 	if(_dbg_cfgtrace==1)
 		_dbg_pid_list[process_no].set |= DBG_CFGTRACE_ON;
+	if(_dbg_reset_msgid==1)
+	{
+		LM_DBG("[%d] create locks\n", process_no);
+		_dbg_pid_list[process_no].lock = lock_alloc();
+		if(_dbg_pid_list[process_no].lock==NULL)
+		{
+			LM_ERR("cannot allocate the lock\n");
+			return -1;
+		}
+		if(lock_init(_dbg_pid_list[process_no].lock)==NULL)
+		{
+			LM_ERR("cannot init the lock\n");
+			lock_dealloc(_dbg_pid_list[process_no].lock);
+			return -1;
+		}
+	}
 	return 0;
 }
 
@@ -843,14 +932,74 @@ static void  dbg_rpc_trace(rpc_t* rpc, void* ctx)
 	rpc->add(ctx, "s", "200 ok");
 }
 
+/**
+ *
+ */
+static const char* dbg_rpc_mod_level_doc[2] = {
+	"Specify module log level",
+	0
+};
+
+static void dbg_rpc_mod_level(rpc_t* rpc, void* ctx){
+	int l;
+	str value = {0,0};
+
+	if (rpc->scan(ctx, "Sd", &value, &l) < 1)
+	{
+		rpc->fault(ctx, 500, "invalid parameters");
+		return;
+	}
+
+	if(dbg_set_mod_debug_level(value.s, value.len, &l)<0)
+	{
+		rpc->fault(ctx, 500, "cannot store parameter\n");
+		return;
+	}
+	rpc->add(ctx, "s", "200 ok");
+}
+
+/**
+ *
+ */
+static const char* dbg_rpc_reset_msgid_doc[2] = {
+	"Reset msgid on all process",
+	0
+};
+
+static void dbg_rpc_reset_msgid(rpc_t* rpc, void* ctx){
+	int i;
+	if (_dbg_reset_msgid==0)
+	{
+		rpc->fault(ctx, 500, "reset_msgid is 0. Set it to 1 to enable.");
+		return;
+	}
+	if(_dbg_pid_list==NULL)
+	{
+		rpc->fault(ctx, 500, "_dbg_pid_list is NULL");
+		return;
+	}
+	LM_DBG("set reset_msgid\n");
+	for(i=0; i<_dbg_pid_no; i++)
+	{
+		if (_dbg_pid_list[i].lock!=NULL)
+		{
+			lock_get(_dbg_pid_list[i].lock);
+			_dbg_pid_list[i].reset_msgid = 1;
+			lock_release(_dbg_pid_list[i].lock);
+		}
+	}
+	rpc->add(ctx, "s", "200 ok");
+}
 
 /**
  *
  */
 rpc_export_t dbg_rpc[] = {
-	{"dbg.bp",    dbg_rpc_bp,        dbg_rpc_bp_doc,       0},
-	{"dbg.ls",    dbg_rpc_list,      dbg_rpc_list_doc,     0},
-	{"dbg.trace", dbg_rpc_trace,     dbg_rpc_trace_doc,    0},
+	{"dbg.bp",        dbg_rpc_bp,        dbg_rpc_bp_doc,        0},
+	{"dbg.ls",        dbg_rpc_list,      dbg_rpc_list_doc,      0},
+	{"dbg.trace",     dbg_rpc_trace,     dbg_rpc_trace_doc,     0},
+	{"dbg.mod_level", dbg_rpc_mod_level, dbg_rpc_mod_level_doc, 0},
+	{"dbg.reset_msgid", dbg_rpc_reset_msgid, dbg_rpc_reset_msgid_doc, 0},
 	{0, 0, 0, 0}
 };
 
@@ -867,3 +1016,759 @@ int dbg_init_rpc(void)
 	return 0;
 }
 
+typedef struct _dbg_mod_level {
+	str name;
+	unsigned int hashid;
+	int level;
+	struct _dbg_mod_level *next;
+} dbg_mod_level_t;
+
+typedef struct _dbg_mod_slot
+{
+	dbg_mod_level_t *first;
+	gen_lock_t lock;
+} dbg_mod_slot_t;
+
+static dbg_mod_slot_t *_dbg_mod_table = NULL;
+static unsigned int _dbg_mod_table_size = 0;
+
+/**
+ *
+ */
+int dbg_init_mod_levels(int dbg_mod_hash_size)
+{
+	int i;
+	if(dbg_mod_hash_size<=0)
+		return 0;
+	if(_dbg_mod_table!=NULL)
+		return 0;
+	_dbg_mod_table_size = 1 << dbg_mod_hash_size;
+	_dbg_mod_table = (dbg_mod_slot_t*)shm_malloc(_dbg_mod_table_size*sizeof(dbg_mod_slot_t));
+	if(_dbg_mod_table==NULL)
+	{
+		LM_ERR("no more shm.\n");
+		return -1;
+	}
+	memset(_dbg_mod_table, 0, _dbg_mod_table_size*sizeof(dbg_mod_slot_t));
+
+	for(i=0; i<_dbg_mod_table_size; i++)
+	{
+		if(lock_init(&_dbg_mod_table[i].lock)==0)
+		{
+			LM_ERR("cannot initalize lock[%d]\n", i);
+			i--;
+			while(i>=0)
+			{
+				lock_destroy(&_dbg_mod_table[i].lock);
+				i--;
+			}
+			shm_free(_dbg_mod_table);
+			_dbg_mod_table = NULL;
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * case insensitive hashing - clone here to avoid usage of LOG*()
+ * - s1 - str to hash
+ * - s1len - len of s1
+ * return computed hash id
+ */
+#define dbg_ch_h_inc h+=v^(v>>3)
+#define dbg_ch_icase(_c) (((_c)>='A'&&(_c)<='Z')?((_c)|0x20):(_c))
+static inline unsigned int dbg_compute_hash(char *s1, int s1len)
+{
+	char *p, *end;
+	register unsigned v;
+	register unsigned h;
+
+	h=0;
+
+	end=s1+s1len;
+	for ( p=s1 ; p<=(end-4) ; p+=4 ){
+		v=(dbg_ch_icase(*p)<<24)+(dbg_ch_icase(p[1])<<16)+(dbg_ch_icase(p[2])<<8)
+			+ dbg_ch_icase(p[3]);
+		dbg_ch_h_inc;
+	}
+	v=0;
+	for (; p<end ; p++){ v<<=8; v+=dbg_ch_icase(*p);}
+	dbg_ch_h_inc;
+
+	h=((h)+(h>>11))+((h>>13)+(h>>23));
+	return h;
+}
+
+int dbg_set_mod_debug_level(char *mname, int mnlen, int *mlevel)
+{
+	unsigned int idx;
+	unsigned int hid;
+	dbg_mod_level_t *it;
+	dbg_mod_level_t *itp;
+	dbg_mod_level_t *itn;
+
+	if(_dbg_mod_table==NULL)
+		return -1;
+
+	hid = dbg_compute_hash(mname, mnlen);
+	idx = hid&(_dbg_mod_table_size-1);
+
+	lock_get(&_dbg_mod_table[idx].lock);
+	it = _dbg_mod_table[idx].first;
+	itp = NULL;
+	while(it!=NULL && it->hashid < hid) {
+		itp = it;
+		it = it->next;
+	}
+	while(it!=NULL && it->hashid==hid)
+	{
+		if(mnlen==it->name.len
+				&& strncmp(mname, it->name.s, mnlen)==0)
+		{
+			/* found */
+			if(mlevel==NULL) {
+				/* remove */
+				if(itp!=NULL) {
+					itp->next = it->next;
+				} else {
+					_dbg_mod_table[idx].first = it->next;
+				}
+				shm_free(it);
+			} else {
+				/* set */
+				it->level = *mlevel;
+			}
+			lock_release(&_dbg_mod_table[idx].lock);
+			return 0;
+		}
+		itp = it;
+		it = it->next;
+	}
+	/* not found - add */
+	if(mlevel==NULL) {
+		lock_release(&_dbg_mod_table[idx].lock);
+		return 0;
+	}
+	itn = (dbg_mod_level_t*)shm_malloc(sizeof(dbg_mod_level_t) + (mnlen+1)*sizeof(char));
+	if(itn==NULL) {
+		LM_ERR("no more shm\n");
+		lock_release(&_dbg_mod_table[idx].lock);
+		return -1;
+	}
+	memset(itn, 0, sizeof(dbg_mod_level_t) + (mnlen+1)*sizeof(char));
+	itn->level    = *mlevel;
+	itn->hashid   = hid;
+	itn->name.s   = (char*)(itn) + sizeof(dbg_mod_level_t);
+	itn->name.len = mnlen;
+	strncpy(itn->name.s, mname, mnlen);
+	itn->name.s[itn->name.len] = '\0';
+
+	if(itp==NULL) {
+		itn->next = _dbg_mod_table[idx].first;
+		_dbg_mod_table[idx].first = itn;
+	} else {
+		itn->next = itp->next;
+		itp->next = itn;
+	}
+	lock_release(&_dbg_mod_table[idx].lock);
+	return 0;
+
+}
+
+static int _dbg_get_mod_debug_level = 0;
+int dbg_get_mod_debug_level(char *mname, int mnlen, int *mlevel)
+{
+	unsigned int idx;
+	unsigned int hid;
+	dbg_mod_level_t *it;
+	/* no LOG*() usage in this function and those executed insite it
+	 * - use fprintf(stderr, ...) if need for troubleshooting
+	 * - it will loop otherwise */
+	if(_dbg_mod_table==NULL)
+		return -1;
+
+	if(cfg_get(dbg, dbg_cfg, mod_level_mode)==0)
+		return -1;
+
+	if(_dbg_get_mod_debug_level!=0)
+		return -1;
+	_dbg_get_mod_debug_level = 1;
+
+	hid = dbg_compute_hash(mname, mnlen);
+	idx = hid&(_dbg_mod_table_size-1);
+	lock_get(&_dbg_mod_table[idx].lock);
+	it = _dbg_mod_table[idx].first;
+	while(it!=NULL && it->hashid < hid)
+		it = it->next;
+	while(it!=NULL && it->hashid == hid)
+	{
+		if(mnlen==it->name.len
+				&& strncmp(mname, it->name.s, mnlen)==0)
+		{
+			/* found */
+			*mlevel = it->level;
+			lock_release(&_dbg_mod_table[idx].lock);
+			_dbg_get_mod_debug_level = 0;
+			return 0;
+		}
+		it = it->next;
+	}
+	lock_release(&_dbg_mod_table[idx].lock);
+	_dbg_get_mod_debug_level = 0;
+	return -1;
+}
+
+/**
+ *
+ */
+void dbg_enable_mod_levels(void)
+{
+	if(_dbg_mod_table==NULL)
+		return;
+	set_module_debug_level_cb(dbg_get_mod_debug_level);
+}
+
+#define DBG_PVCACHE_SIZE 32
+
+typedef struct _dbg_pvcache {
+	pv_spec_t *spec;
+	str *pvname;
+	struct _dbg_pvcache *next;
+} dbg_pvcache_t;
+
+static dbg_pvcache_t **_dbg_pvcache = NULL;
+
+int dbg_init_pvcache()
+{
+	_dbg_pvcache = (dbg_pvcache_t**)pkg_malloc(sizeof(dbg_pvcache_t*)*DBG_PVCACHE_SIZE);
+	if(_dbg_pvcache==NULL)
+	{
+		LM_ERR("no more memory.\n");
+		return -1;
+	}
+	memset(_dbg_pvcache, 0, sizeof(dbg_pvcache_t*)*DBG_PVCACHE_SIZE);
+	return 0;
+}
+
+int dbg_assign_add(str *name, pv_spec_t *spec)
+{
+	dbg_pvcache_t *pvn, *last, *next;
+	unsigned int pvid;
+
+	if(name==NULL||spec==NULL)
+		return -1;
+
+	if(_dbg_pvcache==NULL)
+		return -1;
+
+	pvid = get_hash1_raw((char *)&spec, sizeof(pv_spec_t*));
+	pvn = (dbg_pvcache_t*)pkg_malloc(sizeof(dbg_pvcache_t));
+	if(pvn==NULL)
+	{
+		LM_ERR("no more memory\n");
+		return -1;
+	}
+	memset(pvn, 0, sizeof(dbg_pvcache_t));
+	pvn->pvname = name;
+	pvn->spec = spec;
+	next = _dbg_pvcache[pvid%DBG_PVCACHE_SIZE];
+	if(next==NULL)
+	{
+		_dbg_pvcache[pvid%DBG_PVCACHE_SIZE] = pvn;
+	}
+	else
+	{
+		while(next)
+		{
+			last = next;
+			next = next->next;
+		}
+		last->next = pvn;
+	}
+	return 0;
+}
+
+str *_dbg_pvcache_lookup(pv_spec_t *spec)
+{
+	dbg_pvcache_t *pvi;
+	unsigned int pvid;
+	str *name = NULL;
+
+	if(spec==NULL)
+		return NULL;
+
+	if(_dbg_pvcache==NULL)
+		return NULL;
+
+	pvid = get_hash1_raw((char *)&spec, sizeof(pv_spec_t*));
+	pvi = _dbg_pvcache[pvid%DBG_PVCACHE_SIZE];
+	while(pvi)
+	{
+		if(pvi->spec==spec) {
+			return pvi->pvname;
+		}
+		pvi = pvi->next;
+	}
+	name = pv_cache_get_name(spec);
+	if(name!=NULL)
+	{
+		/*LM_DBG("Add name[%.*s] to pvcache\n", name->len, name->s);*/
+		dbg_assign_add(name, spec);
+	}
+	return name;
+}
+
+int _dbg_log_assign_action_avp(struct sip_msg* msg, struct lvalue* lv)
+{
+	int_str avp_val;
+	avp_t* avp;
+	avp_spec_t* avp_s = &lv->lv.avps;
+	avp = search_avp_by_index(avp_s->type, avp_s->name,
+				&avp_val, avp_s->index);
+	if (likely(avp)){
+		if (avp->flags&(AVP_VAL_STR)){
+			LM_DBG("%.*s:\"%.*s\"\n", avp_s->name.s.len, avp_s->name.s.s,
+				avp_val.s.len, avp_val.s.s);
+		}else{
+			LM_DBG("%.*s:%d\n", avp_s->name.s.len, avp_s->name.s.s,
+				avp_val.n);
+		}
+	}
+	return 0;
+}
+
+int _dbg_log_assign_action_pvar(struct sip_msg* msg, struct lvalue* lv)
+{
+	pv_value_t value;
+	pv_spec_t* pvar = lv->lv.pvs;
+	str def_name = {"unknown", 7};
+	str *name = _dbg_pvcache_lookup(pvar);
+
+	if(name==NULL)
+		name = &def_name;
+	if(pv_get_spec_value(msg, pvar, &value)!=0)
+	{
+		LM_ERR("can't get value\n");
+		return -1;
+	}
+
+	if(value.flags&(PV_VAL_NULL|PV_VAL_EMPTY|PV_VAL_NONE)){
+		LM_DBG("%.*s: $null\n", name->len, name->s);
+	}else if(value.flags&(PV_VAL_INT)){
+		LM_DBG("%.*s:%d\n", name->len, name->s, value.ri);
+	}else if(value.flags&(PV_VAL_STR)){
+		LM_DBG("%.*s:\"%.*s\"\n", name->len, name->s, value.rs.len, value.rs.s);
+	}
+	return 0;
+}
+
+int dbg_log_assign(struct sip_msg* msg, struct lvalue *lv)
+{
+	if(lv==NULL)
+	{
+		LM_ERR("left value is NULL\n");
+		return -1;
+	}
+	switch(lv->type){
+		case LV_AVP:
+			return _dbg_log_assign_action_avp(msg, lv);
+			break;
+		case LV_PVAR:
+			return _dbg_log_assign_action_pvar(msg, lv);
+			break;
+		case LV_NONE:
+			break;
+	}
+	return 0;
+}
+
+void dbg_enable_log_assign(void)
+{
+	if(_dbg_pvcache==NULL)
+		return;
+	set_log_assign_action_cb(dbg_log_assign);
+}
+
+int dbg_level_mode_fixup(void *temp_handle,
+	str *group_name, str *var_name, void **value){
+	if(_dbg_mod_table==NULL)
+	{
+		LM_ERR("mod_hash_size must be set on start\n");
+		return -1;
+	}
+	return 0;
+}
+
+int _dbg_get_array_avp_vals(struct sip_msg *msg,
+		pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobj,
+		str *item_name)
+{
+	struct usr_avp *avp;
+	unsigned short name_type;
+	int_str avp_name;
+	int_str avp_value;
+	struct search_state state;
+	srjson_t *jobjt;
+	memset(&state, 0, sizeof(struct search_state));
+
+	if(pv_get_avp_name(msg, param, &avp_name, &name_type)!=0)
+	{
+		LM_ERR("invalid name\n");
+		return -1;
+	}
+	*jobj = srjson_CreateArray(jdoc);
+	if(*jobj==NULL)
+	{
+		LM_ERR("cannot create json object\n");
+		return -1;
+	}
+	if ((avp=search_first_avp(name_type, avp_name, &avp_value, &state))==0)
+	{
+		goto ok;
+	}
+	do
+	{
+		if(avp->flags & AVP_VAL_STR)
+		{
+			jobjt = srjson_CreateStr(jdoc, avp_value.s.s, avp_value.s.len);
+			if(jobjt==NULL)
+			{
+				LM_ERR("cannot create json object\n");
+				return -1;
+			}
+		} else {
+			jobjt = srjson_CreateNumber(jdoc, avp_value.n);
+			if(jobjt==NULL)
+			{
+				LM_ERR("cannot create json object\n");
+				return -1;
+			}
+		}
+		srjson_AddItemToArray(jdoc, *jobj, jobjt);
+	} while ((avp=search_next_avp(&state, &avp_value))!=0);
+ok:
+	item_name->s = avp_name.s.s;
+	item_name->len = avp_name.s.len;
+	return 0;
+}
+#define DBG_XAVP_DUMP_SIZE 32
+static str* _dbg_xavp_dump[DBG_XAVP_DUMP_SIZE];
+int _dbg_xavp_dump_lookup(pv_param_t *param)
+{
+	unsigned int i = 0;
+	pv_xavp_name_t *xname;
+
+	if(param==NULL)
+		return -1;
+
+	xname = (pv_xavp_name_t*)param->pvn.u.dname;
+
+	while(_dbg_xavp_dump[i]!=NULL&&i<DBG_XAVP_DUMP_SIZE)
+	{
+		if(_dbg_xavp_dump[i]->len==xname->name.len)
+		{
+			if(strncmp(_dbg_xavp_dump[i]->s, xname->name.s, xname->name.len)==0)
+				return 1; /* already dump before */
+		}
+		i++;
+	}
+	if(i==DBG_XAVP_DUMP_SIZE)
+	{
+		LM_WARN("full _dbg_xavp_dump cache array\n");
+		return 0; /* end cache names */
+	}
+	_dbg_xavp_dump[i] = &xname->name;
+	return 0;
+}
+
+void _dbg_get_obj_xavp_val(sr_xavp_t *avp, srjson_doc_t *jdoc, srjson_t **jobj)
+{
+	static char _pv_xavp_buf[128];
+	int result = 0;
+
+	switch(avp->val.type) {
+		case SR_XTYPE_NULL:
+			*jobj = srjson_CreateNull(jdoc);
+		break;
+		case SR_XTYPE_INT:
+			*jobj = srjson_CreateNumber(jdoc, avp->val.v.i);
+		break;
+		case SR_XTYPE_STR:
+			*jobj = srjson_CreateStr(jdoc, avp->val.v.s.s, avp->val.v.s.len);
+		break;
+		case SR_XTYPE_TIME:
+			result = snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t);
+		break;
+		case SR_XTYPE_LONG:
+			result = snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l);
+		break;
+		case SR_XTYPE_LLONG:
+			result = snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll);
+		break;
+		case SR_XTYPE_XAVP:
+			result = snprintf(_pv_xavp_buf, 128, "<<xavp:%p>>", avp->val.v.xavp);
+		break;
+		case SR_XTYPE_DATA:
+			result = snprintf(_pv_xavp_buf, 128, "<<data:%p>>", avp->val.v.data);
+		break;
+		default:
+			LM_WARN("unknown data type\n");
+			*jobj = srjson_CreateNull(jdoc);
+	}
+	if(result<0)
+	{
+		LM_ERR("cannot convert to str\n");
+		*jobj = srjson_CreateNull(jdoc);
+	}
+	else if(*jobj==NULL)
+	{
+		*jobj = srjson_CreateStr(jdoc, _pv_xavp_buf, 128);
+	}
+}
+
+int _dbg_get_obj_avp_vals(str name, sr_xavp_t *xavp, srjson_doc_t *jdoc, srjson_t **jobj)
+{
+	sr_xavp_t *avp = NULL;
+	srjson_t *jobjt = NULL;
+
+	*jobj = srjson_CreateArray(jdoc);
+	if(*jobj==NULL)
+	{
+		LM_ERR("cannot create json object\n");
+		return -1;
+	}
+	avp = xavp;
+	while(avp!=NULL&&!STR_EQ(avp->name,name))
+	{
+		avp = avp->next;
+	}
+	while(avp!=NULL)
+	{
+		_dbg_get_obj_xavp_val(avp, jdoc, &jobjt);
+		srjson_AddItemToArray(jdoc, *jobj, jobjt);
+		jobjt = NULL;
+		avp = xavp_get_next(avp);
+	}
+
+	return 0;
+}
+
+int _dbg_get_obj_xavp_vals(struct sip_msg *msg,
+		pv_param_t *param, srjson_doc_t *jdoc, srjson_t **jobjr,
+		str *item_name)
+{
+	pv_xavp_name_t *xname = (pv_xavp_name_t*)param->pvn.u.dname;
+	sr_xavp_t *xavp = NULL;
+	sr_xavp_t *avp = NULL;
+	srjson_t *jobj = NULL;
+	srjson_t *jobjt = NULL;
+	struct str_list *keys;
+	struct str_list *k;
+
+	*jobjr = srjson_CreateArray(jdoc);
+	if(*jobjr==NULL)
+	{
+		LM_ERR("cannot create json object\n");
+		return -1;
+	}
+
+	item_name->s = xname->name.s;
+	item_name->len = xname->name.len;
+	xavp = xavp_get_by_index(&xname->name, 0, NULL);
+	if(xavp==NULL)
+	{
+		return 0; /* empty */
+	}
+
+	do
+	{
+		if(xavp->val.type==SR_XTYPE_XAVP)
+		{
+			avp = xavp->val.v.xavp;
+			jobj = srjson_CreateObject(jdoc);
+			if(jobj==NULL)
+			{
+				LM_ERR("cannot create json object\n");
+				return -1;
+			}
+			keys = xavp_get_list_key_names(xavp);
+			if(keys!=NULL)
+			{
+				do
+				{
+					_dbg_get_obj_avp_vals(keys->s, avp, jdoc, &jobjt);
+					srjson_AddStrItemToObject(jdoc, jobj, keys->s.s,
+						keys->s.len, jobjt);
+					k = keys;
+					keys = keys->next;
+					pkg_free(k);
+					jobjt = NULL;
+				}while(keys!=NULL);
+			}
+		}
+		if(jobj!=NULL)
+		{
+			srjson_AddItemToArray(jdoc, *jobjr, jobj);
+			jobj = NULL;
+		}
+	}while((xavp = xavp_get_next(xavp))!=0);
+
+	return 0;
+}
+
+int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level)
+{
+	int i;
+	pv_value_t value;
+	pv_cache_t **_pv_cache = pv_cache_get_table();
+	pv_cache_t *el = NULL;
+	srjson_doc_t jdoc;
+	srjson_t *jobj = NULL;
+	char *output = NULL;
+	str item_name = STR_NULL;
+	static char iname[128];
+	int result = -1;
+
+	if(_pv_cache==NULL)
+	{
+		LM_ERR("cannot access pv_cache\n");
+		return -1;
+	}
+
+	memset(_dbg_xavp_dump, 0, sizeof(str*)*DBG_XAVP_DUMP_SIZE);
+	srjson_InitDoc(&jdoc, NULL);
+	if(jdoc.root==NULL)
+	{
+		jdoc.root = srjson_CreateObject(&jdoc);
+		if(jdoc.root==NULL)
+		{
+			LM_ERR("cannot create json root\n");
+			goto error;
+		}
+	}
+	for(i=0;i<PV_CACHE_SIZE;i++)
+	{
+		el = _pv_cache[i];
+		while(el)
+		{
+			if(!(el->spec.type==PVT_AVP||
+				el->spec.type==PVT_SCRIPTVAR||
+				el->spec.type==PVT_XAVP||
+				el->spec.type==PVT_OTHER)||
+				!((el->spec.type==PVT_AVP&&mask&DBG_DP_AVP)||
+				(el->spec.type==PVT_XAVP&&mask&DBG_DP_XAVP)||
+				(el->spec.type==PVT_SCRIPTVAR&&mask&DBG_DP_SCRIPTVAR)||
+				(el->spec.type==PVT_OTHER&&mask&DBG_DP_OTHER))||
+				(el->spec.trans!=NULL))
+			{
+				el = el->next;
+				continue;
+			}
+			jobj = NULL;
+			item_name.len = 0;
+			item_name.s = 0;
+			iname[0] = '\0';
+			if(el->spec.type==PVT_AVP)
+			{
+				if(el->spec.pvp.pvi.type==PV_IDX_ALL||
+					(el->spec.pvp.pvi.type==PV_IDX_INT&&el->spec.pvp.pvi.u.ival!=0))
+				{
+					el = el->next;
+					continue;
+				}
+				else
+				{
+					if(_dbg_get_array_avp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0)
+					{
+						LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s);
+						el = el->next;
+						continue;
+					}
+					if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL))
+					{
+						el = el->next;
+						continue;
+					}
+					snprintf(iname, 128, "$avp(%.*s)", item_name.len, item_name.s);
+				}
+			}
+			else if(el->spec.type==PVT_XAVP)
+			{
+				if(_dbg_xavp_dump_lookup(&el->spec.pvp)!=0)
+				{
+					el = el->next;
+					continue;
+				}
+				if(_dbg_get_obj_xavp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0)
+				{
+					LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s);
+					el = el->next;
+					continue;
+				}
+				if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL))
+				{
+					el = el->next;
+					continue;
+				}
+				snprintf(iname, 128, "$xavp(%.*s)", item_name.len, item_name.s);
+			}
+			else
+			{
+				if(pv_get_spec_value(msg, &el->spec, &value)!=0)
+				{
+					LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s);
+					el = el->next;
+					continue;
+				}
+				if(value.flags&(PV_VAL_NULL|PV_VAL_EMPTY|PV_VAL_NONE))
+				{
+					if(mask&DBG_DP_NULL)
+					{
+						jobj = srjson_CreateNull(&jdoc);
+					}
+					else
+					{
+						el = el->next;
+						continue;
+					}
+				}else if(value.flags&(PV_VAL_INT)){
+					jobj = srjson_CreateNumber(&jdoc, value.ri);
+				}else if(value.flags&(PV_VAL_STR)){
+					jobj = srjson_CreateStr(&jdoc, value.rs.s, value.rs.len);
+				}else {
+					LM_WARN("el->pvname[%.*s] value[%d] unhandled\n", el->pvname.len, el->pvname.s,
+						value.flags);
+					el = el->next;
+					continue;
+				}
+				if(jobj==NULL)
+				{
+					LM_ERR("el->pvname[%.*s] empty json object\n", el->pvname.len,
+						el->pvname.s);
+					goto error;
+				}
+				snprintf(iname, 128, "%.*s", el->pvname.len, el->pvname.s);
+			}
+			if(jobj!=NULL)
+			{
+				srjson_AddItemToObject(&jdoc, jdoc.root, iname, jobj);
+			}
+			el = el->next;
+		}
+	}
+	output = srjson_PrintUnformatted(&jdoc, jdoc.root);
+	if(output==NULL)
+	{
+		LM_ERR("cannot print json doc\n");
+		goto error;
+	}
+	LOG(level, "%s\n", output);
+	result = 0;
+
+error:
+	if(output!=NULL) jdoc.free_fn(output);
+	srjson_DestroyDoc(&jdoc);
+
+	return result;
+}
diff --git a/modules/debugger/debugger_api.h b/modules/debugger/debugger_api.h
index e5a5ca2..011013a 100644
--- a/modules/debugger/debugger_api.h
+++ b/modules/debugger/debugger_api.h
@@ -33,5 +33,29 @@ int dbg_init_pid_list(void);
 int dbg_init_mypid(void);
 int dbg_init_rpc(void);
 
+int dbg_init_mod_levels(int _dbg_mod_hash_size);
+int dbg_set_mod_debug_level(char *mname, int mnlen, int *mlevel);
+void dbg_enable_mod_levels(void);
+
+int dbg_init_pvcache(void);
+void dbg_enable_log_assign(void);
+
+/*!
+ * \brief Callback function that checks if reset_msgid is set
+ *  and modifies msg->id if necessary.
+ * \param msg SIP message
+ * \param flags unused
+ * \param bar unused
+ * \return 1 on success, -1 on failure
+ */
+int dbg_msgid_filter(struct sip_msg *msg, unsigned int flags, void *bar);
+
+#define DBG_DP_NULL			1
+#define DBG_DP_AVP			2
+#define DBG_DP_SCRIPTVAR	4
+#define DBG_DP_XAVP			8
+#define DBG_DP_OTHER		16
+#define DBG_DP_ALL			31
+int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level);
 #endif
 
diff --git a/modules/debugger/debugger_config.c b/modules/debugger/debugger_config.c
new file mode 100644
index 0000000..3eaf82d
--- /dev/null
+++ b/modules/debugger/debugger_config.c
@@ -0,0 +1,48 @@
+/*
+ * $Id$
+ *
+ * This file is part of SIP-router, a free SIP server.
+ *
+ * SIP-router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Debugger :: Configuration
+ * \ingroup debugger
+ */
+
+
+#include "../../cfg/cfg.h"
+
+#include "debugger_config.h"
+
+struct cfg_group_dbg	default_dbg_cfg = {
+	0, /* level_mode */
+	0  /* hash_size */
+};
+
+void *dbg_cfg = &default_dbg_cfg;
+
+cfg_def_t dbg_cfg_def[] = {
+	{"mod_level_mode", CFG_VAR_INT|CFG_ATOMIC, 0, 1,
+		dbg_level_mode_fixup, 0,
+		"Enable or disable per module log level (0 - disabled, 1 - enabled)"},
+	{"mod_hash_size", CFG_VAR_INT|CFG_READONLY, 0, 0,
+		0, 0,
+		"power of two as size of internal hash table to store levels per module"},
+	{0, 0, 0, 0, 0, 0}
+};
diff --git a/modules/debugger/debugger_config.h b/modules/debugger/debugger_config.h
new file mode 100644
index 0000000..9b5ab8d
--- /dev/null
+++ b/modules/debugger/debugger_config.h
@@ -0,0 +1,46 @@
+/*
+ * $Id$
+ *
+ * This file is part of SIP-router, a free SIP server.
+ *
+ * SIP-router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Debugger :: Configuration
+ * \ingroup debugger
+ */
+
+
+#ifndef _DEBUGGER_CONFIG_H
+#define _DEBUGGER_CONFIG_H
+
+#include "../../cfg/cfg.h"
+#include "../../str.h"
+
+struct cfg_group_dbg {
+	unsigned int mod_level_mode;
+	unsigned int mod_hash_size;
+};
+
+extern struct cfg_group_dbg	default_dbg_cfg;
+extern void	*dbg_cfg;
+extern cfg_def_t dbg_cfg_def[];
+
+extern int dbg_level_mode_fixup(void *temp_handle,
+	str *group_name, str *var_name, void **value);
+#endif
diff --git a/modules/debugger/debugger_mod.c b/modules/debugger/debugger_mod.c
index 8b85afb..2f0caa7 100644
--- a/modules/debugger/debugger_mod.c
+++ b/modules/debugger/debugger_mod.c
@@ -33,8 +33,10 @@
 #include "../../mod_fix.h"
 #include "../../parser/parse_param.h"
 #include "../../shm_init.h"
+#include "../../script_cb.h"
 
 #include "debugger_api.h"
+#include "debugger_config.h"
 
 MODULE_VERSION
 
@@ -44,21 +46,34 @@ static void mod_destroy(void);
 
 static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2);
 static int fixup_dbg_breakpoint(void** param, int param_no);
+static int dbg_mod_level_param(modparam_t type, void *val);
+
+static int fixup_dbg_pv_dump(void** param, int param_no);
+static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level);
 
 /* parameters */
 extern int _dbg_cfgtrace;
+extern int _dbg_cfgpkgcheck;
 extern int _dbg_breakpoint;
 extern int _dbg_cfgtrace_level;
 extern int _dbg_cfgtrace_facility;
 extern char *_dbg_cfgtrace_prefix;
 extern int _dbg_step_usleep;
 extern int _dbg_step_loops;
+extern int _dbg_reset_msgid;
 
 static char * _dbg_cfgtrace_facility_str = 0;
+static int _dbg_log_assign = 0;
 
 static cmd_export_t cmds[]={
 	{"dbg_breakpoint", (cmd_function)w_dbg_breakpoint, 1,
 		fixup_dbg_breakpoint, 0, ANY_ROUTE},
+	{"dbg_pv_dump", (cmd_function)w_dbg_dump, 0,
+		fixup_dbg_pv_dump, 0, ANY_ROUTE},
+	{"dbg_pv_dump", (cmd_function)w_dbg_dump, 1,
+		fixup_dbg_pv_dump, 0, ANY_ROUTE},
+	{"dbg_pv_dump", (cmd_function)w_dbg_dump, 2,
+		fixup_dbg_pv_dump, 0, ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -68,8 +83,14 @@ static param_export_t params[]={
 	{"log_level",         INT_PARAM, &_dbg_cfgtrace_level},
 	{"log_facility",      STR_PARAM, &_dbg_cfgtrace_facility_str},
 	{"log_prefix",        STR_PARAM, &_dbg_cfgtrace_prefix},
+	{"log_assign",        INT_PARAM, &_dbg_log_assign},
 	{"step_usleep",       INT_PARAM, &_dbg_step_usleep},
 	{"step_loops",        INT_PARAM, &_dbg_step_loops},
+	{"mod_hash_size",     INT_PARAM, &default_dbg_cfg.mod_hash_size},
+	{"mod_level_mode",    INT_PARAM, &default_dbg_cfg.mod_level_mode},
+	{"mod_level",         STR_PARAM|USE_FUNC_PARAM, (void*)dbg_mod_level_param},
+	{"reset_msgid",       INT_PARAM, &_dbg_reset_msgid},
+	{"cfgpkgcheck",       INT_PARAM, &_dbg_cfgpkgcheck},
 	{0, 0, 0}
 };
 
@@ -113,6 +134,38 @@ static int mod_init(void)
 		return -1;
 	}
 
+	if(cfg_declare("dbg", dbg_cfg_def, &default_dbg_cfg, cfg_sizeof(dbg), &dbg_cfg))
+	{
+		LM_ERR("Fail to declare the configuration\n");
+		return -1;
+	}
+	LM_DBG("cfg level_mode:%d hash_size:%d\n",
+		cfg_get(dbg, dbg_cfg, mod_level_mode),
+		cfg_get(dbg, dbg_cfg, mod_hash_size));
+
+	if(dbg_init_mod_levels(cfg_get(dbg, dbg_cfg, mod_hash_size))<0)
+	{
+		LM_ERR("failed to init per module log level\n");
+		return -1;
+	}
+
+	if(_dbg_log_assign>0)
+	{
+		if(dbg_init_pvcache()!=0)
+		{
+			LM_ERR("failed to create pvcache\n");
+			return -1;
+		}
+	}
+	if(_dbg_reset_msgid==1)
+	{
+		unsigned int ALL = REQUEST_CB+FAILURE_CB+ONREPLY_CB
+		  +BRANCH_CB+ONSEND_CB+ERROR_CB+LOCAL_CB+EVENT_CB+BRANCH_FAILURE_CB;
+		if (register_script_cb(dbg_msgid_filter, PRE_SCRIPT_CB|ALL, 0) != 0) {
+			LM_ERR("could not insert callback");
+			return -1;
+		}
+	}
 	return dbg_init_bp_list();
 }
 
@@ -122,8 +175,11 @@ static int mod_init(void)
 static int child_init(int rank)
 {
 	LM_DBG("rank is (%d)\n", rank);
-	if (rank==PROC_INIT)
+	if (rank==PROC_INIT) {
+		dbg_enable_mod_levels();
+		dbg_enable_log_assign();
 		return dbg_init_pid_list();
+	}
 	return dbg_init_mypid();
 }
 
@@ -143,6 +199,64 @@ static int w_dbg_breakpoint(struct sip_msg* msg, char* point, char* str2)
 }
 
 /**
+ * fixup for cfg dbg_pv_dump
+ */
+static int fixup_dbg_pv_dump(void** param, int param_no)
+{
+	unsigned int mask;
+	int level;
+	str s = STR_NULL;
+
+	switch(param_no)
+	{
+		case 2:
+			switch(((char*)(*param))[2])
+			{
+				case 'A': level = L_ALERT; break;
+				case 'B': level = L_BUG; break;
+				case 'C': level = L_CRIT2; break;
+				case 'E': level = L_ERR; break;
+				case 'W': level = L_WARN; break;
+				case 'N': level = L_NOTICE; break;
+				case 'I': level = L_INFO; break;
+				case 'D': level = L_DBG; break;
+				default:
+					LM_ERR("unknown log level\n");
+					return E_UNSPEC;
+			}
+			*param = (void*)(long)level;
+		break;
+		case 1:
+			s.s = *param;
+			s.len = strlen(s.s);
+			if(str2int(&s, &mask) == 0) {
+				*param = (void*)(long)mask;
+			}
+			else return E_UNSPEC;
+		break;
+	}
+
+    return 0;
+}
+
+/**
+ * dump pv_cache contents as json
+ */
+static int w_dbg_dump(struct sip_msg* msg, char* mask, char* level)
+{
+	unsigned int umask = DBG_DP_ALL;
+	int ilevel = L_DBG;
+	if(level!=NULL){
+		ilevel = (int)(long)level;
+	}
+	if(mask!=NULL){
+		umask = (unsigned int)(unsigned long)mask;
+	}
+	dbg_dump_json(msg, umask, ilevel);
+	return 1;
+}
+
+/**
  * get the pointer to action structure
  */
 static struct action *dbg_fixup_get_action(void **param, int param_no)
@@ -173,4 +287,42 @@ static int fixup_dbg_breakpoint(void** param, int param_no)
     return dbg_add_breakpoint(a, (*p=='0')?0:1);
 }
 
+static int dbg_mod_level_param(modparam_t type, void *val)
+{
+	char *p;
+	str s;
+	int l;
+	if(val==NULL)
+		return -1;
+
+	p = strchr((char*)val, '=');
+	if(p==NULL) {
+		LM_ERR("invalid parameter value: %s\n", (char*)val);
+		return -1;
+	}
+	s.s = p + 1;
+	s.len = strlen(s.s);
+
+	if(str2sint(&s, &l)<0) {
+		LM_ERR("invalid parameter - level value: %s\n", (char*)val);
+		return -1;
+	}
+	s.s = (char*)val;
+	s.len = p - s.s;
+	LM_DBG("cfg level_mode:%d hash_size:%d\n",
+		cfg_get(dbg, dbg_cfg, mod_level_mode),
+		cfg_get(dbg, dbg_cfg, mod_hash_size));
+	if(dbg_init_mod_levels(cfg_get(dbg, dbg_cfg, mod_hash_size))<0)
+	{
+		LM_ERR("failed to init per module log level\n");
+		return -1;
+	}
+	if(dbg_set_mod_debug_level(s.s, s.len, &l)<0)
+	{
+		LM_ERR("cannot store parameter: %s\n", (char*)val);
+		return -1;
+	}
+	return 0;
+
+}
 
diff --git a/modules/debugger/doc/debugger_admin.xml b/modules/debugger/doc/debugger_admin.xml
index b265724..ec77755 100644
--- a/modules/debugger/doc/debugger_admin.xml
+++ b/modules/debugger/doc/debugger_admin.xml
@@ -74,7 +74,7 @@
     </section>
     <section>
 	<title>Parameters</title>
-	<section>
+	<section id="dbg.p.cfgtrace">
 	    <title><varname>cfgtrace</varname> (int)</title>
 	    <para>
 			Control whether the config script trace is enabled or disabled
@@ -96,7 +96,7 @@ modparam("debugger", "cfgtrace", 1)
 	    </example>
 	</section>
 
-	<section>
+	<section id="dbg.p.breakpoint">
 	    <title><varname>breakpoint</varname> (int)</title>
 	    <para>
 			Control whether every line (global) breakpoint is enabled
@@ -117,7 +117,7 @@ modparam("debugger", "breakpoint", 1)
 	    </example>
 	</section>
 
-	<section>
+	<section id="dbg.p.log_level">
 	    <title><varname>log_level</varname> (int)</title>
 	    <para>
 			What log level is to be used to print module-specific messages.
@@ -137,7 +137,7 @@ modparam("debugger", "log_level", 1)
 	    </example>
 	</section>
 
-	<section>
+	<section id="dbg.p.log_facility">
 	    <title><varname>log_facility</varname> (str)</title>
 	    <para>
 			Which log facility is to be used to print module-specific messages.
@@ -159,7 +159,7 @@ modparam("debugger", "log_facility", "LOG_DAEMON")
 	    </example>
 	</section>
 
-	<section>
+	<section id="dbg.p.log_prefix">
 	    <title><varname>log_prefix</varname> (str)</title>
 	    <para>
 			String to print before any module-specific messages.
@@ -179,7 +179,7 @@ modparam("debugger", "log_prefix", "from-debugger-with-love:")
 	    </example>
 	</section>
 
-	<section>
+	<section id="dbg.p.step_usleep">
 	    <title><varname>step_usleep</varname> (int)</title>
 	    <para>
 			Microseconds to sleep before checking for new commands when
@@ -200,7 +200,7 @@ modparam("debugger", "step_usleep", 500000)
 	    </example>
 	</section>
 
-	<section>
+	<section id="dbg.p.step_loops">
 	    <title><varname>step_loops</varname> (int)</title>
 	    <para>
 			How many sleeps of 'step_usleep' the RPC process performs when
@@ -223,11 +223,134 @@ modparam("debugger", "step_loops", 100)
 	    </example>
 	</section>
 
+	<section id="dbg.p.mod_hash_size">
+	    <title><varname>mod_hash_size</varname> (int)</title>
+	    <para>
+		Used to compute power of two as size of internal hash table to store levels
+		per module (e.g., if its set to 4, internal hash table has 16 slots). This
+		parameter is accesible readonly via the Kamailio config framework.
+	    </para>
+	    <para>
+		<emphasis>
+		    Default value is <quote>0</quote> - feature disabled.
+		</emphasis>
+	    </para>
+	    <example>
+		<title>Set <varname>mod_hash_size</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("debugger", "mod_hash_size", 5)
+...
+</programlisting>
+	    </example>
 	</section>
-	
+
+	<section id="dbg.p.mod_level_mode">
+	    <title><varname>mod_level_mode</varname> (int)</title>
+	    <para>
+			Enable or disable per module log level (0 - disabled, 1 - enabled).
+			This parameter is tunable via the Kamailio config framework.
+	    </para>
+	    <para>
+		<emphasis>
+		    Default value is <quote>0</quote>.
+		</emphasis>
+	    </para>
+	    <example>
+		<title>Set <varname>mod_level_mode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("debugger", "mod_level_mode", 1)
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section id="dbg.p.mod_level">
+	    <title><varname>mod_level</varname> (str)</title>
+	    <para>
+		Specify module log level - the value must be in the format:
+		modulename=level. The parameter can be set many times. For core
+		log level, use module name 'core'.
+	    </para>
+	    <example>
+		<title>Set <varname>mod_level</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("debugger", "mod_level", "core=3")
+modparam("debugger", "mod_level", "tm=3")
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section id="dbg.p.log_assign">
+	    <title><varname>log_assign</varname> (int)</title>
+	    <para>
+		Enable or disable log assign actions on config (0 - disabled, 1 - enabled).
+	    </para>
+		<para>
+		<emphasis>
+		    Default value is <quote>0</quote>.
+		</emphasis>
+	    </para>
+	    <example>
+		<title>Set <varname>log_assign</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("debugger", "log_assign", 1)
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section id="dbg.p.cfgpkgcheck">
+	    <title><varname>cfgpkgcheck</varname> (int)</title>
+	    <para>
+			If set, before each config action is done pkg memory check,
+			useful to detect buffer overflows.
+	    </para>
+	    <para>
+		<emphasis>
+		    Default value is <quote>0</quote> (disabled).
+		</emphasis>
+	    </para>
+	    <example>
+		<title>Set <varname>cfgpkgcheck</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("debugger", "cfgpkgcheck", 1)
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section id="dbg.p.reset_msgid">
+	    <title><varname>reset_msgid</varname> (int)</title>
+	    <para>
+		Used to enable or disable the ability to reset the msgid ($mi)
+		through the dbg.reset_msgid RPC command. (0 - disabled, 1 - enabled).
+	    </para>
+	    <para>
+		<emphasis>
+		    Default value is <quote>0</quote> - feature disabled.
+		</emphasis>
+	    </para>
+	    <example>
+		<title>Set <varname>reset_msgid</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("debugger", "reset_msgid", 1)
+...
+</programlisting>
+	    </example>
+	</section>
+
+	</section>
+
     <section>
 	<title>Functions</title>
- 	<section>
+ 	<section id="dbg.f.db_breakpoint">
 	    <title>
 		<function moreinfo="none">dbg_breakpoint(mode)</function>
 	    </title>
@@ -250,13 +373,98 @@ if($si=="10.0.0.10")
 </programlisting>
 	    </example>
 	</section>
-	
+
+	<section id="dbg.f.dbg_pv_dump">
+	    <title>
+		<function moreinfo="none">dbg_pv_dump([mask] [, level])</function>
+	    </title>
+	    <para>
+			Prints the content of pv_cache on json format.
+			Defaults are mask=31 and level = "L_DBG"
+	    </para>
+		<para>
+		</para>
+		<itemizedlist>
+			<para><emphasis>mask</emphasis> - Controls the content to dump:
+			</para>
+			<itemizedlist>
+			<listitem><para>
+			  1 - dump null values
+			</para></listitem>
+			<listitem><para>
+			  2 - dump avp vars
+			</para></listitem>
+			<listitem><para>
+			  4 - dump script vars
+			</para></listitem>
+			<listitem><para>
+			  8 - dump xavp vars
+			</para></listitem>
+			<listitem><para>
+			  16 - dump DP_OTHER vars
+			</para></listitem>
+			</itemizedlist>
+			<para><emphasis>level</emphasis> - The level that will be used in LOG function. It can be:
+			</para>
+			<itemizedlist>
+			<listitem><para>
+				L_ALERT - log level -5
+			</para></listitem>
+			<listitem><para>
+				L_BUG - log level -4
+			</para></listitem>
+			<listitem><para>
+				L_CRIT - log level -3
+			</para></listitem>
+			<listitem><para>
+				L_ERR - log level -1
+			</para></listitem>
+			<listitem><para>
+				L_WARN - log level 0
+			</para></listitem>
+			<listitem><para>
+				L_NOTICE - log level 1
+			</para></listitem>
+			<listitem><para>
+				L_INFO - log level 2
+			</para></listitem>
+			<listitem><para>
+				L_DBG - log level 3
+				</para></listitem>
+			</itemizedlist>
+		</itemizedlist>
+		<example>
+		<title><function>dbg_pv_dump</function> usage</title>
+		<programlisting format="linespecific">
+...
+$var(temp) = 1;
+$avp(s:more_avp) = 2;
+$avp(s:more_avp) = 3;
+$xavp(x=>more) = "bye";
+$xavp(x[0]=>more) = "hi";
+$xavp(x[0]=>other) = 1;
+$xavp(x[0]=>other) = 2;
+$xavp(x=>different) = "foo";
+$var(empty) = $null;
+
+dbg_pv_dump(30, "L_DBG");
+...
+</programlisting>
+		<para>Output</para>
+		<programlisting format="linespecific">
+...
+ 4(30943) DEBUG: debugger [debugger_api.c:1613]: dbg_dump_json(): {"$sp":37597,"$var(rc)":0,"$var(temp)":1,"$avp(more_avp)":[3,2],"$si":"127.0.0.1","$rc":0,"$xavp(x)":[{"different":["foo"]},{"other":[2,1],"more":["hi","bye"]}],"$T_branch_idx":0,"$var(empty)":0}
+ ...
+</programlisting>
+	    </example>
+	</section>
+
     </section>
 	
 	<section>
 		<title>Exported RPC Functions</title>
 
-	<section>
+	<section id="dbg.r.ls">
 		<title>
 		<function moreinfo="none">dbg.ls</function>
 		</title>
@@ -281,7 +489,7 @@ if($si=="10.0.0.10")
 		</programlisting>
     </section>
 
-	<section>
+	<section id="dbg.r.trace">
 		<title>
 		<function moreinfo="none">dbg.trace</function>
 		</title>
@@ -310,7 +518,7 @@ if($si=="10.0.0.10")
 		</programlisting>
     </section>
 
-	<section>
+	<section id="dbg.r.bp">
 		<title>
 		<function moreinfo="none">dbg.bp</function>
 		</title>
@@ -386,6 +594,54 @@ if($si=="10.0.0.10")
 		</programlisting>
     </section>
 
+    <section id="dbg.r.mod_level">
+		<title>
+		<function moreinfo="none">dbg.mod_level</function>
+		</title>
+		<para>
+			Specify module log level.
+		</para>
+		<para>
+		Name: <emphasis>dbg.mod_level</emphasis>
+		</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>_module_ : For core log
+				level, use module name 'core'</para></listitem>
+			<listitem><para>_level_ : integer</para></listitem>
+		</itemizedlist>
+		<para>
+		Examples of use with &sercmd;:
+		</para>
+        <programlisting  format="linespecific">
+		dbg.mod_level core 3
+		dbg.mod_level tm 3
+		</programlisting>
+    </section>
+
+	<section id="dbg.r.reset_msgid">
+		<title>
+		<function moreinfo="none">dbg.reset_msgid</function>
+		</title>
+		<para>
+			Resets the message sequence ($mi). Internally there is no real change.
+			This can be useful for unit test cases in order to be able to replicate
+			exactly the same kamailio output.
+
+			You need to set the debugger parameter reset_msgid to 1 to activate this
+			functionallity.
+		</para>
+		<para>
+		Name: <emphasis>dbg.reset_msgid</emphasis>
+		</para>
+		<para>
+		Examples of use with &sercmd;:
+		</para>
+        <programlisting  format="linespecific">
+		dbg.reset_msgid
+		</programlisting>
+    </section>
+
     </section>
 	<section>
 		<title>Usage</title>
diff --git a/modules/dialog/dialog.c b/modules/dialog/dialog.c
index 804bc46..8d7be33 100644
--- a/modules/dialog/dialog.c
+++ b/modules/dialog/dialog.c
@@ -138,6 +138,7 @@ int dlg_db_mode_param = DB_MODE_NONE;
 str dlg_xavp_cfg = {0};
 int dlg_ka_timer = 0;
 int dlg_ka_interval = 0;
+int dlg_clean_timer = 90;
 
 /* db stuff */
 static str db_url = str_init(DEFAULT_DB_URL);
@@ -147,6 +148,7 @@ static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 
 void dlg_ka_timer_exec(unsigned int ticks, void* param);
+void dlg_clean_timer_exec(unsigned int ticks, void* param);
 
 /* commands wrappers and fixups */
 static int fixup_profile(void** param, int param_no);
@@ -453,7 +455,7 @@ static int mod_init(void)
 #ifdef STATISTICS
 	/* register statistics */
 	if (register_module_stats( exports.name, mod_stats)!=0 ) {
-		LM_ERR("failed to register core statistics\n");
+		LM_ERR("failed to register %s statistics\n", exports.name);
 		return -1;
 	}
 #endif
@@ -697,9 +699,14 @@ static int mod_init(void)
 	}
 
 	destroy_dlg_callbacks( DLGCB_LOADED );
+
+	/* timer process to send keep alive requests */
 	if(dlg_ka_timer>0 && dlg_ka_interval>0)
 		register_sync_timers(1);
 
+	/* timer process to clean old unconfirmed dialogs */
+	register_sync_timers(1);
+
 	return 0;
 }
 
@@ -708,11 +715,18 @@ static int child_init(int rank)
 {
 	dlg_db_mode = dlg_db_mode_param;
 
-	if(rank==PROC_MAIN && dlg_ka_timer>0 && dlg_ka_interval>0)
-	{
-		if(fork_sync_timer(PROC_TIMER, "Dialog KA Timer", 1 /*socks flag*/,
-				dlg_ka_timer_exec, NULL, dlg_ka_timer /*sec*/)<0) {
-			LM_ERR("failed to start ka timer routine as process\n");
+	if(rank==PROC_MAIN) {
+		if(dlg_ka_timer>0 && dlg_ka_interval>0) {
+			if(fork_sync_timer(PROC_TIMER, "Dialog KA Timer", 1 /*socks flag*/,
+					dlg_ka_timer_exec, NULL, dlg_ka_timer /*sec*/)<0) {
+				LM_ERR("failed to start ka timer routine as process\n");
+				return -1; /* error */
+			}
+		}
+
+		if(fork_sync_timer(PROC_TIMER, "Dialog Clean Timer", 1 /*socks flag*/,
+					dlg_clean_timer_exec, NULL, dlg_clean_timer /*sec*/)<0) {
+			LM_ERR("failed to start clean timer routine as process\n");
 			return -1; /* error */
 		}
 	}
@@ -1097,7 +1111,7 @@ static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
 		return -1;
 	}
 
-	if(dlg_bridge(&sf, &st, &so)!=0)
+	if(dlg_bridge(&sf, &st, &so, NULL)!=0)
 		return -1;
 	return 1;
 }
@@ -1221,6 +1235,11 @@ void dlg_ka_timer_exec(unsigned int ticks, void* param)
 	dlg_ka_run(ticks);
 }
 
+void dlg_clean_timer_exec(unsigned int ticks, void* param)
+{
+	dlg_clean_run(ticks);
+}
+
 static int fixup_dlg_bye(void** param, int param_no)
 {
 	char *val;
@@ -1345,6 +1364,7 @@ struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
 	str from = {0,0};
 	str to = {0,0};
 	str op = {0,0};
+	str bd = {0,0};
 	struct mi_node* node;
 
 	node = cmd_tree->node.kids;
@@ -1374,9 +1394,23 @@ struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
 		{
 			return init_mi_tree(500, "Bad OP value", 12);
 		}
+		if(op.len==1 && *op.s=='.')
+		{
+			op.s = NULL;
+			op.len = 0;
+		}
+		node= node->next;
+		if(node != NULL)
+		{
+			bd = node->value;
+			if(bd.len<=0 || bd.s==NULL)
+			{
+				return init_mi_tree(500, "Bad SDP value", 13);
+			}
+		}
 	}
 
-	if(dlg_bridge(&from, &to, &op)!=0)
+	if(dlg_bridge(&from, &to, &op, &bd)!=0)
 		return init_mi_tree(500, MI_INTERNAL_ERR_S,  MI_INTERNAL_ERR_LEN);
 
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
@@ -1676,6 +1710,7 @@ static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
 	str from = {NULL,0};
 	str to = {NULL,0};
 	str op = {NULL,0};
+	str bd = {NULL,0};
 	int n;
 
 	n = rpc->scan(c, "SS", &from, &to);
@@ -1687,9 +1722,18 @@ static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
 	if(rpc->scan(c, "*S", &op)<1) {
 		op.s = NULL;
 		op.len = 0;
+	} else {
+		if(op.len==1 && *op.s=='.') {
+			op.s = NULL;
+			op.len = 0;
+		}
+		if(rpc->scan(c, "*S", &bd)<1) {
+			bd.s = NULL;
+			bd.len = 0;
+		}
 	}
 
-	dlg_bridge(&from, &to, &op);
+	dlg_bridge(&from, &to, &op, &bd);
 }
 
 static rpc_export_t rpc_methods[] = {
diff --git a/modules/dialog/dlg_hash.c b/modules/dialog/dlg_hash.c
index bba619a..d346800 100644
--- a/modules/dialog/dlg_hash.c
+++ b/modules/dialog/dlg_hash.c
@@ -223,6 +223,38 @@ int dlg_ka_run(ticks_t ti)
 	return 0;
 }
 
+/**
+ * clean old unconfirmed dialogs
+ *
+ */
+int dlg_clean_run(ticks_t ti)
+{
+	unsigned int i;
+	unsigned int tm;
+	dlg_cell_t *dlg;
+	dlg_cell_t *tdlg;
+
+	tm = (unsigned int)time(NULL);
+	for(i=0; i<d_table->size; i++)
+	{
+		lock_set_get(d_table->locks, d_table->entries[i].lock_idx);
+		dlg = d_table->entries[i].first;
+		while (dlg) {
+			tdlg = dlg;
+			dlg = dlg->next;
+			if(tdlg->state==DLG_STATE_UNCONFIRMED && tdlg->init_ts<tm-300) {
+				/* dialog in early state older than 5min */
+				LM_NOTICE("dialog in early state is too old (%p ref %d)\n",
+						tdlg, tdlg->ref);
+				unlink_unsafe_dlg(&d_table->entries[i], tdlg);
+				destroy_dlg(tdlg);
+			}
+		}
+		lock_set_release(d_table->locks, d_table->entries[i].lock_idx);
+	}
+	return 0;
+}
+
 /*!
  * \brief Initialize the global dialog table
  * \param size size of the table
@@ -434,6 +466,7 @@ struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri,
 
 	memset( dlg, 0, len);
 	dlg->state = DLG_STATE_UNCONFIRMED;
+	dlg->init_ts = (unsigned int)time(NULL);
 
 	dlg->h_entry = core_hash( callid, 0, d_table->size);
 	LM_DBG("new dialog on hash %u\n",dlg->h_entry);
@@ -484,18 +517,24 @@ int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
 					str *cseq, unsigned int leg)
 {
 	char *p;
+	str cs = {"0", 1};
+
+	/* if we don't have cseq, set it to 0 */
+	if(cseq->len>0) {
+		cs = *cseq;
+	}
 
 	if(dlg->tag[leg].s)
 		shm_free(dlg->tag[leg].s);
 	dlg->tag[leg].s = (char*)shm_malloc( tag->len + rr->len + contact->len );
 
 	if(dlg->cseq[leg].s) {
-		if (dlg->cseq[leg].len < cseq->len) {
+		if (dlg->cseq[leg].len < cs.len) {
 			shm_free(dlg->cseq[leg].s);
-			dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
+			dlg->cseq[leg].s = (char*)shm_malloc(cs.len);
 		}
 	} else {
-		dlg->cseq[leg].s = (char*)shm_malloc( cseq->len );
+		dlg->cseq[leg].s = (char*)shm_malloc( cs.len );
 	}
 
 	if ( dlg->tag[leg].s==NULL || dlg->cseq[leg].s==NULL) {
@@ -531,8 +570,8 @@ int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
 	}
 
 	/* cseq */
-	dlg->cseq[leg].len = cseq->len;
-	memcpy( dlg->cseq[leg].s, cseq->s, cseq->len);
+	dlg->cseq[leg].len = cs.len;
+	memcpy( dlg->cseq[leg].s, cs.s, cs.len);
 
 	return 0;
 }
diff --git a/modules/dialog/dlg_hash.h b/modules/dialog/dlg_hash.h
index ed295cc..4bfc911 100644
--- a/modules/dialog/dlg_hash.h
+++ b/modules/dialog/dlg_hash.h
@@ -114,6 +114,7 @@ typedef struct dlg_cell
 	unsigned int         h_entry;	/*!< index of hash table entry (the slot number) */
 	unsigned int         state;		/*!< dialog state */
 	unsigned int         lifetime;		/*!< dialog lifetime */
+	unsigned int         init_ts;		/*!< init (creation) time (absolute UNIX ts)*/
 	unsigned int         start_ts;		/*!< start time  (absolute UNIX ts)*/
 	unsigned int         dflags;		/*!< internal dialog memory flags */
 	unsigned int         iflags;		/*!< internal dialog persistent flags */
@@ -527,6 +528,8 @@ int dlg_ka_add(dlg_cell_t *dlg);
 
 int dlg_ka_run(ticks_t ti);
 
+int dlg_clean_run(ticks_t ti);
+
 /*!
  * \brief Update dialog lifetime - for internal callers.
  */
diff --git a/modules/dialog/dlg_req_within.c b/modules/dialog/dlg_req_within.c
index bdd09eb..29ee23f 100644
--- a/modules/dialog/dlg_req_within.c
+++ b/modules/dialog/dlg_req_within.c
@@ -34,6 +34,7 @@
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../socket_info.h"
+#include "../../dset.h"
 #include "../../modules/tm/dlg.h"
 #include "../../modules/tm/tm_load.h"
 #include "../../lib/kmi/tree.h"
@@ -70,14 +71,39 @@ dlg_t * build_dlg_t(struct dlg_cell * cell, int dir){
 	dlg_t* td = NULL;
 	str cseq;
 	unsigned int loc_seq;
+	char nbuf[MAX_URI_SIZE];
+	char dbuf[80];
+	str nuri;
+	str duri;
+	size_t sz;
+	char *p;
 
-	td = (dlg_t*)pkg_malloc(sizeof(dlg_t));
+	/*remote target--- Request URI*/
+	if(cell->contact[dir].s==0 || cell->contact[dir].len==0){
+		LM_ERR("no contact available\n");
+		goto error;
+	}
+	/*restore alias parameter*/
+	nuri.s = nbuf;
+	nuri.len = MAX_URI_SIZE;
+	duri.s = dbuf;
+	duri.len = 80;
+	if(uri_restore_rcv_alias(&cell->contact[dir], &nuri, &duri)<0) {
+		nuri.len = 0;
+		duri.len = 0;
+	}
+	if(nuri.len>0 && duri.len>0) {
+		sz = sizeof(dlg_t) + (nuri.len+duri.len+2)*sizeof(char);
+	} else {
+		sz = sizeof(dlg_t);
+	}
+	td = (dlg_t*)pkg_malloc(sz);
 	if(!td){
 	
 		LM_ERR("out of pkg memory\n");
 		return NULL;
 	}
-	memset(td, 0, sizeof(dlg_t));
+	memset(td, 0, sz);
 
 	/*local sequence number*/
 	cseq = (dir == DLG_CALLER_LEG) ?	cell->cseq[DLG_CALLEE_LEG]:
@@ -100,13 +126,22 @@ dlg_t * build_dlg_t(struct dlg_cell * cell, int dir){
 		}
 	} 
 
-	/*remote target--- Request URI*/
-	if(cell->contact[dir].s==0 || cell->contact[dir].len==0){
-
-		LM_ERR("no contact available\n");
-		goto error;
+	if(nuri.len>0 && duri.len>0) {
+		/* req uri */
+		p = (char*)td + sizeof(dlg_t);
+		strncpy(p, nuri.s, nuri.len);
+		p[nuri.len] = '\0';
+		td->rem_target.s = p;
+		td->rem_target.len = nuri.len;
+		/* dst uri */
+		p += nuri.len + 1;
+		strncpy(p, duri.s, duri.len);
+		p[duri.len] = '\0';
+		td->dst_uri.s = p;
+		td->dst_uri.len = duri.len;
+	} else {
+		td->rem_target = cell->contact[dir];
 	}
-	td->rem_target = cell->contact[dir];
 
 	td->rem_uri	=   (dir == DLG_CALLER_LEG)?	cell->from_uri: cell->to_uri;
 	td->loc_uri	=	(dir == DLG_CALLER_LEG)?	cell->to_uri: cell->from_uri;
@@ -308,7 +343,6 @@ static inline int send_bye(struct dlg_cell * cell, int dir, str *hdrs)
 		goto err;
 	}
 
-	memset(&uac_r,'\0', sizeof(uac_req_t));
 	set_uac_req(&uac_r, &met, hdrs, NULL, dialog_info, TMCB_LOCAL_COMPLETED,
 				bye_reply_cb, (void*)iuid);
 	result = d_tmb.t_request_within(&uac_r);
@@ -363,7 +397,7 @@ int dlg_send_ka(dlg_cell_t *dlg, int dir, str *hdrs)
 	else
 		di->loc_seq.value -= 1;
 
-	LM_DBG("sending BYE to %s\n", (dir==DLG_CALLER_LEG)?"caller":"callee");
+	LM_DBG("sending OPTIONS to %s\n", (dir==DLG_CALLER_LEG)?"caller":"callee");
 
 	iuid = dlg_get_iuid_shm_clone(dlg);
 	if(iuid==NULL)
@@ -372,13 +406,12 @@ int dlg_send_ka(dlg_cell_t *dlg, int dir, str *hdrs)
 		goto err;
 	}
 
-	memset(&uac_r,'\0', sizeof(uac_req_t));
 	set_uac_req(&uac_r, &met, hdrs, NULL, di, TMCB_LOCAL_COMPLETED,
 				dlg_ka_cb, (void*)iuid);
 	result = d_tmb.t_request_within(&uac_r);
 
 	if(result < 0){
-		LM_ERR("failed to send the BYE request\n");
+		LM_ERR("failed to send the OPTIONS request\n");
 		goto err;
 	}
 
diff --git a/modules/dialog/dlg_transfer.c b/modules/dialog/dlg_transfer.c
index 25d9e8d..80c5c39 100644
--- a/modules/dialog/dlg_transfer.c
+++ b/modules/dialog/dlg_transfer.c
@@ -140,7 +140,6 @@ void dlg_refer_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
 		goto error;
 	}
 
-	memset(&uac_r, '\0', sizeof(uac_req_t));
 	set_uac_req(&uac_r, &met, NULL, NULL, dialog_info, 0, NULL, NULL);
 	result = d_tmb.t_request_within(&uac_r);
 
@@ -198,7 +197,6 @@ static int dlg_refer_callee(dlg_transfer_ctx_t *dtc)
 	memcpy(hdrs.s+23+dlg_bridge_controller.len+CRLF_LEN+dtc->to.len+CRLF_LEN,
 			dlg_bridge_controller.s, dlg_bridge_controller.len);
 
-	memset(&uac_r, '\0', sizeof(uac_req_t));
 	set_uac_req(&uac_r, &met, &hdrs, NULL, dialog_info, TMCB_LOCAL_COMPLETED,
 				dlg_refer_tm_callback, (void*)dtc);
 	result = d_tmb.t_request_within(&uac_r);
@@ -311,7 +309,7 @@ error:
 }
 
 
-int dlg_bridge(str *from, str *to, str *op)
+int dlg_bridge(str *from, str *to, str *op, str *bd)
 {
 	dlg_transfer_ctx_t *dtc;
 	int ret;
@@ -350,8 +348,13 @@ int dlg_bridge(str *from, str *to, str *op)
 
 	LM_DBG("bridge <%.*s> to <%.*s>\n", dtc->from.len, dtc->from.s,
 			dtc->to.len, dtc->to.s);
-	s_body.s   = DLG_HOLD_SDP;
-	s_body.len = DLG_HOLD_SDP_LEN;
+	if(bd!=NULL && bd->s!=NULL && bd->len>0) {
+		s_body.s = bd->s;
+		s_body.len = bd->len;
+	} else {
+		s_body.s   = DLG_HOLD_SDP;
+		s_body.len = DLG_HOLD_SDP_LEN;
+	}
 
 	memset(&uac_r, '\0', sizeof(uac_req_t));
 	uac_r.method = &s_method;
diff --git a/modules/dialog/dlg_transfer.h b/modules/dialog/dlg_transfer.h
index ef05eeb..5337f38 100644
--- a/modules/dialog/dlg_transfer.h
+++ b/modules/dialog/dlg_transfer.h
@@ -32,7 +32,7 @@ typedef struct _dlg_transfer_ctx {
 	struct dlg_cell *dlg;
 } dlg_transfer_ctx_t;
 
-int dlg_bridge(str *from, str *to, str *op);
+int dlg_bridge(str *from, str *to, str *op, str *bd);
 int dlg_transfer(struct dlg_cell *dlg, str *to, int side);
 int dlg_bridge_init_hdrs(void);
 void dlg_bridge_destroy_hdrs(void);
diff --git a/modules/dialog_ng/dialog.c b/modules/dialog_ng/dialog.c
index 748515d..078d198 100644
--- a/modules/dialog_ng/dialog.c
+++ b/modules/dialog_ng/dialog.c
@@ -69,6 +69,7 @@ pv_spec_t timeout_avp;
 static int fixup_profile(void** param, int param_no);
 static int fixup_get_profile2(void** param, int param_no);
 static int fixup_get_profile3(void** param, int param_no);
+static int fixup_dlg_bridge(void** param, int param_no);
 static int fixup_dlg_terminate(void** param, int param_no);
 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
@@ -79,6 +80,7 @@ static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
 static int w_dlg_terminate(struct sip_msg*, char*, char*);
+static int w_dlg_get(struct sip_msg*, char*, char*, char*);
 static int w_is_known_dlg(struct sip_msg *);
 
 static cmd_export_t cmds[] = {
@@ -108,6 +110,7 @@ static cmd_export_t cmds[] = {
         0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
     {"dlg_terminate", (cmd_function) w_dlg_terminate, 2, fixup_dlg_terminate,
         0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
+   {"dlg_get", (cmd_function)w_dlg_get, 3, fixup_dlg_bridge, 0, ANY_ROUTE },
     {"is_known_dlg", (cmd_function) w_is_known_dlg, 0, NULL,
         0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
     {"load_dlg", (cmd_function) load_dlg, 0, 0, 0, 0},
@@ -244,6 +247,79 @@ static int fixup_dlg_terminate(void** param, int param_no) {
     return 0;
 }
 
+static int fixup_dlg_bridge(void** param, int param_no)
+{
+	if (param_no>=1 && param_no<=3) {
+		return fixup_spve_null(param, 1);
+	} else {
+		LM_ERR("called with parameter idx %d\n", param_no);
+		return E_BUG;
+	}
+	return 0;
+}
+
+static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
+{
+	struct dlg_cell *dlg = NULL;
+	str sc = {0,0};
+	str sf = {0,0};
+	str st = {0,0};
+	unsigned int dir = 0;
+
+	if(ci==0 || ft==0 || tt==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
+	{
+		LM_ERR("unable to get Call-ID\n");
+		return -1;
+	}
+	if(sc.s==NULL || sc.len == 0)
+	{
+		LM_ERR("invalid Call-ID parameter\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
+	{
+		LM_ERR("unable to get From tag\n");
+		return -1;
+	}
+	if(sf.s==NULL || sf.len == 0)
+	{
+		LM_ERR("invalid From tag parameter\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
+	{
+		LM_ERR("unable to get To Tag\n");
+		return -1;
+	}
+	if(st.s==NULL || st.len == 0)
+	{
+		LM_ERR("invalid To tag parameter\n");
+		return -1;
+	}
+
+	dlg = get_dlg(&sc, &sf, &st, &dir);
+	if(dlg==NULL)
+		return -1;
+	
+	/* 
+		note: we should unref the dlg here (from get_dlg). BUT, because we are setting the current dialog
+		we can ignore the unref... instead of unreffing and reffing again for the set_current_dialog. NB.
+		this function is generally called from the cfg file. If used via API, remember to unref the dlg
+		afterwards
+	*/	
+
+	set_current_dialog(msg, dlg);
+    _dlg_ctx.dlg = dlg;
+    _dlg_ctx.dir = dir;
+	return 1;
+}
+
 int load_dlg(struct dlg_binds *dlgb) {
 
     dlgb->register_dlgcb = register_dlgcb;
@@ -251,7 +327,9 @@ int load_dlg(struct dlg_binds *dlgb) {
     dlgb->set_dlg_var = api_set_dlg_variable;
     dlgb->get_dlg_var = api_get_dlg_variable;
     dlgb->terminate_dlg = w_api_terminate_dlg;
+    dlgb->lookup_terminate_dlg = w_api_lookup_terminate_dlg;
     dlgb->get_dlg_expires = api_get_dlg_expires;
+    dlgb->get_dlg = dlg_get_msg_dialog;
 
     return 1;
 }
diff --git a/modules/dialog_ng/dlg_handlers.c b/modules/dialog_ng/dlg_handlers.c
index 7536725..262e923 100644
--- a/modules/dialog_ng/dlg_handlers.c
+++ b/modules/dialog_ng/dlg_handlers.c
@@ -380,14 +380,14 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) {
         return;
     }
 
-    if (type == TMCB_RESPONSE_READY) {
-        LM_DBG("TMCB_RESPONSE_READY\n");
+    if (type == TMCB_RESPONSE_OUT) {
+        LM_DBG("TMCB_RESPONSE_OUT\n");
         return;
     }
 
-    if (type == TMCB_RESPONSE_OUT) {
+    if (type == TMCB_RESPONSE_READY) {
         if (rpl == FAKED_REPLY) {
-            LM_ERR("Faked reply\n");
+            LM_DBG("Faked reply\n");
             return;
         }
 
@@ -426,7 +426,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) {
     LM_DBG("Calling next_state_dlg and event is %i\n", event);
     next_state_dlg(dlg, event, &old_state, &new_state, &unref, &to_tag);
 
-    if (type == TMCB_RESPONSE_OUT) {
+    if (type == TMCB_RESPONSE_READY) {
         LM_DBG("Checking if there is an existing dialog_out entry with same to-tag");
 
         dlg_entry_out = &dlg->dlg_entry_out;
@@ -1423,3 +1423,29 @@ void print_all_dlgs() {
 
 }
 
+struct dlg_cell *dlg_get_msg_dialog(sip_msg_t *msg)
+{
+	struct dlg_cell *dlg = NULL;
+	str callid;
+	str ftag;
+	str ttag;
+	unsigned int dir;
+
+	/* Retrieve the current dialog */
+	dlg = dlg_get_ctx_dialog();
+	if (dlg != NULL )
+		return dlg;
+
+	if (pre_match_parse(msg, &callid, &ftag, &ttag, 0) < 0)
+		return NULL ;
+	dir = DLG_DIR_NONE;
+	dlg = get_dlg(&callid, &ftag, &ttag, &dir);
+	if (dlg == NULL ) {
+		LM_DBG("dlg with callid '%.*s' not found\n",
+				msg->callid->body.len, msg->callid->body.s);
+		return NULL ;
+	}
+	return dlg;
+}
+
+
diff --git a/modules/dialog_ng/dlg_handlers.h b/modules/dialog_ng/dlg_handlers.h
index 210ed8f..e4d3999 100644
--- a/modules/dialog_ng/dlg_handlers.h
+++ b/modules/dialog_ng/dlg_handlers.h
@@ -179,7 +179,13 @@ void print_all_dlgs();
  * \param dlg dialog cell
  * \return void
  */
-
 void internal_print_all_dlg(struct dlg_cell *dlg);
 
+/*!
+ * \get the current dialog based on the current SIP message
+ * \param msg SIP message
+ * \return current dialog, null if none.
+ */
+struct dlg_cell *dlg_get_msg_dialog(sip_msg_t *msg);
+
 #endif
diff --git a/modules/dialog_ng/dlg_hash.c b/modules/dialog_ng/dlg_hash.c
index 97e1371..6bfdde3 100644
--- a/modules/dialog_ng/dlg_hash.c
+++ b/modules/dialog_ng/dlg_hash.c
@@ -1267,14 +1267,16 @@ int dlg_set_toroute(struct dlg_cell *dlg, str * route) {
  * \return void
  */
 void create_concurrent_did(struct dlg_cell *dlg, str * new_did) {
-    int len  = dlg->did.len + 1;
-    new_did = shm_malloc(len);
-    if (new_did == 0) {
+    int len  = dlg->did.len + 1 + 1;
+    new_did->s = shm_malloc(len);
+    if (new_did->s == 0) {
         LM_ERR("no more shm mem (%d)\n", len);
+        return;
     }
+    memset(new_did->s, 0, len);
     memcpy(new_did->s, dlg->did.s, dlg->did.len);
-    new_did->s[dlg->did.len+1]= 'x';
-    new_did->len = len;
+    new_did->s[dlg->did.len] = 'x';
+    new_did->len = dlg->did.len + 1;
 }
 
 /*!
diff --git a/modules/dialog_ng/dlg_load.h b/modules/dialog_ng/dlg_load.h
index 9c6ec4d..5f9c8a1 100644
--- a/modules/dialog_ng/dlg_load.h
+++ b/modules/dialog_ng/dlg_load.h
@@ -35,16 +35,23 @@
 /* terminate_dlg function prototype */
 typedef int (*terminate_dlg_f)(str *callid, str *ftag, str *ttag, str *hdrs, str *reason);
 
+typedef int (*lookup_terminate_dlg_f)(unsigned int h_entry, unsigned int h_id, str *hdrs);
+
+/* get the current dialog based on message function prototype */
+typedef struct dlg_cell *(*get_dlg_f)(struct sip_msg *msg);
+
 /* get_dlg_lifetime function prototype */
 typedef time_t (*get_dlg_expires_f)(str *callid, str *ftag, str *ttag);
 
 struct dlg_binds {
-	register_dlgcb_f  register_dlgcb;
-        register_dlgcb_nodlg_f register_dlgcb_nodlg;
-	terminate_dlg_f terminate_dlg;
-        set_dlg_variable_f set_dlg_var;
-	get_dlg_variable_f get_dlg_var;
-        get_dlg_expires_f get_dlg_expires;      
+	register_dlgcb_f  		register_dlgcb;
+	register_dlgcb_nodlg_f 	register_dlgcb_nodlg;
+	terminate_dlg_f 		terminate_dlg;
+	lookup_terminate_dlg_f 		lookup_terminate_dlg;
+	set_dlg_variable_f 		set_dlg_var;
+	get_dlg_variable_f 		get_dlg_var;
+	get_dlg_expires_f 		get_dlg_expires;
+	get_dlg_f				get_dlg;
 };
 
 
diff --git a/modules/dialog_ng/dlg_req_within.c b/modules/dialog_ng/dlg_req_within.c
index 9a2d598..2d366eb 100644
--- a/modules/dialog_ng/dlg_req_within.c
+++ b/modules/dialog_ng/dlg_req_within.c
@@ -519,3 +519,21 @@ int dlg_bye_all(struct dlg_cell *dlg, str *hdrs) {
 
 }
 
+
+/* Wrapper for terminating dialog from API - from other modules */
+int w_api_lookup_terminate_dlg(unsigned int h_entry, unsigned int h_id, str *hdrs) {
+    struct dlg_cell *dlg;
+
+    dlg = lookup_dlg(h_entry, h_id); //increments ref count!
+
+    if (!dlg) {
+        LM_ERR("Asked to tear down non existent dialog\n");
+        return -1;
+    }
+
+    unref_dlg(dlg, 1);
+
+    return dlg_terminate(dlg, NULL, NULL/*reason*/, 2, hdrs);
+
+}
+
diff --git a/modules/dialog_ng/dlg_req_within.h b/modules/dialog_ng/dlg_req_within.h
index 34316a5..43d11a7 100644
--- a/modules/dialog_ng/dlg_req_within.h
+++ b/modules/dialog_ng/dlg_req_within.h
@@ -53,6 +53,7 @@ int free_tm_dlg(dlg_t *td);
 int dlg_bye(struct dlg_cell *dlg, str *hdrs, int side);
 int dlg_bye_all(struct dlg_cell *dlg, str *hdrs);
 int w_api_terminate_dlg(str *call_id, str *from_tag, str *to_tag, str *hdrs, str* reason);
+int w_api_lookup_terminate_dlg(unsigned int h_entry, unsigned int h_id, str *hdrs);
 int dlg_terminate(struct dlg_cell *dlg, struct sip_msg* msg, str *reason, int side, str *extra_headers);
 
 #endif
diff --git a/modules/dialog_ng/doc/dialog_ng.xml b/modules/dialog_ng/doc/dialog_ng.xml
index 7835c66..820538f 100644
--- a/modules/dialog_ng/doc/dialog_ng.xml
+++ b/modules/dialog_ng/doc/dialog_ng.xml
@@ -27,7 +27,7 @@
                 <firstname>Carsten</firstname>
                 <surname>Bock</surname>
                 <affiliation>
-                    <orgname>ng-voice.com</orgname>
+                    <orgname>ng-voice GmbH</orgname>
                 </affiliation>
                 <address>
                     <email>carsten at ng-voice.com</email>
@@ -88,7 +88,7 @@
             <holder>Voice Sistem SRL</holder>
         </copyright>
         <copyright>
-            <year>2011</year>
+            <year>2011-2013</year>
             <holder>Carsten Bock, http://www.ng-voice.com</holder>
         </copyright>
     </bookinfo>
diff --git a/modules/dialog_ng/doc/dialog_ng_admin.xml b/modules/dialog_ng/doc/dialog_ng_admin.xml
index 2b9047e..c6353e2 100644
--- a/modules/dialog_ng/doc/dialog_ng_admin.xml
+++ b/modules/dialog_ng/doc/dialog_ng_admin.xml
@@ -839,14 +839,44 @@ dlg_terminate("all", "Insufficient QoS");
         </section>
 
         <section>
-            <title>
-                <function moreinfo="none">dlg_get(callid, ftag, ttag)</function>
-            </title>
-            <para>
-                    This function is currently not supported by the dialog_ng module.
-                    To be incorporated in the future.
-            </para>
-        </section>
+		<title>
+		<function moreinfo="none">dlg_get(callid, ftag, ttag)</function>
+		</title>
+		<para>
+			Search and set current dialog based on Call-ID, From-Tag and To-Tag
+			parameters.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>callid</emphasis> - SIP call-id.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>ftag</emphasis> - SIP From tag.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>ttag</emphasis> - SIP To tag.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from BRANCH_ROUTE,
+			REQUEST_ROUTE, ONREPLY_ROUTE and FAILURE_ROUTE.
+		</para>
+		<example>
+		<title><function>dlg_get</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(dlg_get("abcdef", "123", "456"))
+{
+	dlg_bye("all");
+}
+...
+</programlisting>
+		</example>
+	</section>
 	
         <section>
             <title>
diff --git a/modules/dialog_ng/doc/dialog_ng_devel.xml b/modules/dialog_ng/doc/dialog_ng_devel.xml
index 148edd1..d6102b3 100644
--- a/modules/dialog_ng/doc/dialog_ng_devel.xml
+++ b/modules/dialog_ng/doc/dialog_ng_devel.xml
@@ -200,6 +200,35 @@
                 </listitem>
             </itemizedlist>
         </section>
+
+        <section>
+            <title>
+                <function moreinfo="none">lookup_terminate_dlg (unsigned int h_entry, unsigned int h_id, hdrs)</function>
+            </title>
+            <para>
+		Terminate a Dialog identified by h_entry and h_id (similar to dlg_end_dlg command via XMLRPC).
+            </para>
+            <para>Meaning of parameters is as follows:</para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <emphasis>unsigned int h_entry</emphasis> - Number of the table, where to find the dialog
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>unsigned int h_id</emphasis> - Number of the entry in the table, where to find the dialog
+			terminate.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <emphasis>str* hdrs</emphasis> - string containg extra headers (full format) 
+			to be added to the BYE requests of the dialog.
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </section>
         
         <section>
             <title>
diff --git a/modules/dialplan/dialplan.c b/modules/dialplan/dialplan.c
index ffa8bb4..07c3271 100644
--- a/modules/dialplan/dialplan.c
+++ b/modules/dialplan/dialplan.c
@@ -160,15 +160,13 @@ static int mod_init(void)
 	attrs_column.len    = strlen(attrs_column.s);
 
 	if(attr_pvar_s.s) {
-		attr_pvar = (pv_spec_t *)shm_malloc(sizeof(pv_spec_t));
-		if(!attr_pvar){
-			LM_ERR("out of shm memory\n");
-			return -1;
-		}
 
 		attr_pvar_s.len = strlen(attr_pvar_s.s);
-		if( (pv_parse_spec(&attr_pvar_s, attr_pvar)==NULL) ||
-				((attr_pvar->type != PVT_AVP) && (attr_pvar->type!=PVT_SCRIPTVAR))) {
+		attr_pvar = pv_cache_get(&attr_pvar_s);
+		if( (attr_pvar==NULL) ||
+				((attr_pvar->type != PVT_AVP) &&
+				 (attr_pvar->type != PVT_XAVP) &&
+				 (attr_pvar->type!=PVT_SCRIPTVAR))) {
 			LM_ERR("invalid pvar name\n");
 			return -1;
 		}
@@ -182,13 +180,15 @@ static int mod_init(void)
 	memset(default_par2, 0, sizeof(dp_param_t));
 
 	default_param_s.len = strlen(default_param_s.s);
-	if (pv_parse_spec( &default_param_s, &default_par2->v.sp[0])==NULL) {
+	default_par2->v.sp[0] = pv_cache_get(&default_param_s);
+	if (default_par2->v.sp[0]==NULL) {
 		LM_ERR("input pv is invalid\n");
 		return -1;
 	}
 
 	default_param_s.len = strlen(default_param_s.s);
-	if (pv_parse_spec( &default_param_s, &default_par2->v.sp[1])==NULL) {
+	default_par2->v.sp[1] = pv_cache_get(&default_param_s);
+	if (default_par2->v.sp[1]==NULL) {
 		LM_ERR("output pv is invalid\n");
 		return -1;
 	}
@@ -218,10 +218,6 @@ static void mod_destroy(void)
 		shm_free(default_par2);
 		default_par2 = NULL;
 	}
-	if(attr_pvar){
-		shm_free(attr_pvar);
-		attr_pvar = NULL;
-	}
 	destroy_data();
 }
 
@@ -237,32 +233,33 @@ static int dp_get_ivalue(struct sip_msg* msg, dp_param_p dp, int *val)
 	pv_value_t value;
 
 	if(dp->type==DP_VAL_INT) {
-		LM_DBG("integer value\n");
 		*val = dp->v.id;
+		LM_DBG("dpid is %d from constant argument\n", *val);
 		return 0;
 	}
 
-	LM_DBG("searching %d\n",dp->v.sp[0].type);
+	LM_DBG("searching %d\n",dp->v.sp[0]->type);
 
-	if( pv_get_spec_value( msg, &dp->v.sp[0], &value)!=0
+	if( pv_get_spec_value( msg, dp->v.sp[0], &value)!=0
 			|| value.flags&(PV_VAL_NULL|PV_VAL_EMPTY) || !(value.flags&PV_VAL_INT)) {
-		LM_ERR("no AVP or SCRIPTVAR found (error in scripts)\n");
+		LM_ERR("no AVP, XAVP or SCRIPTVAR found (error in scripts)\n");
 		return -1;
 	}
 	*val = value.ri;
+	LM_DBG("dpid is %d from pv argument\n", *val);
 	return 0;
 }
 
 
-static int dp_get_svalue(struct sip_msg * msg, pv_spec_t spec, str* val)
+static int dp_get_svalue(struct sip_msg * msg, pv_spec_t *spec, str* val)
 {
 	pv_value_t value;
 
-	LM_DBG("searching %d \n", spec.type);
+	LM_DBG("searching %d \n", spec->type);
 
-	if ( pv_get_spec_value(msg,&spec,&value)!=0 || value.flags&PV_VAL_NULL
+	if ( pv_get_spec_value(msg,spec,&value)!=0 || value.flags&PV_VAL_NULL
 			|| value.flags&PV_VAL_EMPTY || !(value.flags&PV_VAL_STR)){
-		LM_ERR("no AVP or SCRIPTVAR found (error in scripts)\n");
+		LM_ERR("no AVP, XAVP or SCRIPTVAR found (error in scripts)\n");
 		return -1;
 	}
 
@@ -280,7 +277,7 @@ static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest,
 	memset(&val, 0, sizeof(pv_value_t));
 	val.flags = PV_VAL_STR;
 
-	no_change = (dest->type == PVT_NONE) || (!repl->s) || (!repl->len);
+	no_change = (dest==NULL) || (dest->type == PVT_NONE) || (!repl->s) || (!repl->len);
 
 	if (no_change)
 		goto set_attr_pvar;
@@ -295,7 +292,7 @@ static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest,
 
 	if(is_route_type(FAILURE_ROUTE)
 			&& (dest->type==PVT_RURI || dest->type==PVT_RURI_USERNAME)) {
-	    if (append_branch(msg, 0, 0, 0, Q_UNSPECIFIED, 0, 0, 0, 0) != 1) {
+	    if (append_branch(msg, 0, 0, 0, Q_UNSPECIFIED, 0, 0, 0, 0, 0, 0) != 1) {
 			LM_ERR("append_branch action failed\n");
 			return -1;
 		}
@@ -358,7 +355,7 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
 			input.len, input.s, idp->dp_id, output.len, output.s);
 
 	/*set the output*/
-	if (dp_update(msg, &repl_par->v.sp[0], &repl_par->v.sp[1], 
+	if (dp_update(msg, repl_par->v.sp[0], repl_par->v.sp[1],
 				&output, attrs_par) !=0){
 		LM_ERR("cannot set the output\n");
 		return -1;
@@ -371,20 +368,22 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
 #define verify_par_type(_par_no, _spec)\
 	do{\
 		if( ((_par_no == 1) \
-					&& ((_spec).type != PVT_AVP) && ((_spec).type!=PVT_SCRIPTVAR) )\
+					&& (_spec->type != PVT_AVP) && (_spec->type != PVT_XAVP) && \
+					(_spec->type!=PVT_SCRIPTVAR) )\
 				||((_par_no == 2) \
-					&& ((_spec).type != PVT_AVP) && ((_spec).type!=PVT_SCRIPTVAR) \
-					&& ((_spec).type!=PVT_RURI) && (_spec.type!=PVT_RURI_USERNAME))){\
+					&& (_spec->type != PVT_AVP) && (_spec->type != PVT_XAVP) && \
+					(_spec->type!=PVT_SCRIPTVAR) \
+					&& (_spec->type!=PVT_RURI) && (_spec->type!=PVT_RURI_USERNAME))){\
 			\
-			LM_ERR("Unsupported Parameter TYPE\n");\
+			LM_ERR("Unsupported Parameter TYPE[%d]\n", _spec->type);\
 			return E_UNSPEC;\
 		}\
 	}while(0);
 
 
-/* first param: DPID: type: INT, AVP, SVAR
+/* first param: DPID: type: INT, AVP, XAVP, SVAR
  * second param: SRC type: any psedo variable type
- * second param: DST type: RURI, RURI_USERNAME, AVP, SVAR, N/A
+ * second param: DST type: RURI, RURI_USERNAME, AVP, XAVP, SVAR, N/A
  * default value for the second param: $ru.user/$ru.user
  */
 static int dp_trans_fixup(void ** param, int param_no){
@@ -394,7 +393,7 @@ static int dp_trans_fixup(void ** param, int param_no){
 	char *p, *s=NULL;
 	str lstr;
 
-	if(param_no!=1 && param_no!=2) 
+	if(param_no!=1 && param_no!=2)
 		return 0;
 
 	p = (char*)*param;
@@ -426,7 +425,8 @@ static int dp_trans_fixup(void ** param, int param_no){
 			dp_par->v.id = dpid;
 		}else{
 			lstr.s = p; lstr.len = strlen(p);
-			if (pv_parse_spec( &lstr, &dp_par->v.sp[0])==NULL)
+			dp_par->v.sp[0] = pv_cache_get(&lstr);
+			if (dp_par->v.sp[0]==NULL)
 				goto error;
 
 			verify_par_type(param_no, dp_par->v.sp[0]);
@@ -442,16 +442,16 @@ static int dp_trans_fixup(void ** param, int param_no){
 		}
 
 		lstr.s = p; lstr.len = strlen(p);
-		if(pv_parse_spec( &lstr, &dp_par->v.sp[0])==NULL)
+		dp_par->v.sp[0] = pv_cache_get(&lstr);
+		if(dp_par->v.sp[0]==NULL)
 			goto error;
 
 		if (s != 0) {
 			lstr.s = s; lstr.len = strlen(s);
-			if (pv_parse_spec( &lstr, &dp_par->v.sp[1] )==NULL)
+			dp_par->v.sp[1] = pv_cache_get(&lstr);
+			if (dp_par->v.sp[1]==NULL)
 				goto error;
 			verify_par_type(param_no, dp_par->v.sp[1]);
-		} else {
-			dp_par->v.sp[1].type = PVT_NONE;
 		}
 
 		dp_par->type = DP_VAL_SPEC;
diff --git a/modules/dialplan/dialplan.h b/modules/dialplan/dialplan.h
index b3396a0..fd3319e 100644
--- a/modules/dialplan/dialplan.h
+++ b/modules/dialplan/dialplan.h
@@ -83,7 +83,7 @@ typedef struct dp_param{
 	int type;
 	union {
 		int id;
-		pv_spec_t sp[2];
+		pv_spec_t* sp[2];
 	} v;
 }dp_param_t, *dp_param_p;
 
diff --git a/modules/dispatcher/README b/modules/dispatcher/README
index db71948..edd9801 100644
--- a/modules/dispatcher/README
+++ b/modules/dispatcher/README
@@ -14,7 +14,7 @@ Edited by
 
 Carsten Bock
 
-   ng-voice.com
+   ng-voice GmbH
 
    Copyright � 2004 FhG FOKUS
 
@@ -52,17 +52,18 @@ Carsten Bock
               3.15. attrs_avp (str)
               3.16. hash_pvar (str)
               3.17. setid_pvname (str)
-              3.18. ds_ping_method (string)
-              3.19. ds_ping_from (string)
-              3.20. ds_ping_interval (int)
-              3.21. ds_probing_threshhold (int)
-              3.22. ds_ping_reply_codes (string)
-              3.23. ds_probing_mode (int)
-              3.24. ds_hash_size (int)
-              3.25. ds_hash_expire (int)
-              3.26. ds_hash_initexpire (int)
-              3.27. ds_hash_check_interval (int)
-              3.28. outbound_proxy (str)
+              3.18. attrs_pvname (str)
+              3.19. ds_ping_method (string)
+              3.20. ds_ping_from (string)
+              3.21. ds_ping_interval (int)
+              3.22. ds_probing_threshold (int)
+              3.23. ds_ping_reply_codes (string)
+              3.24. ds_probing_mode (int)
+              3.25. ds_hash_size (int)
+              3.26. ds_hash_expire (int)
+              3.27. ds_hash_initexpire (int)
+              3.28. ds_hash_check_interval (int)
+              3.29. outbound_proxy (str)
 
         4. Functions
 
@@ -119,23 +120,24 @@ Carsten Bock
    1.16. Use $avp(i:273) for hashing:
    1.17. Use combination of PVs for hashing:
    1.18. Set the "setid_pvname" parameter
-   1.19. Set the "ds_ping_method" parameter
-   1.20. Set the "ds_ping_from" parameter
-   1.21. Set the "ds_ping_interval" parameter
-   1.22. Set the "ds_probing_threshhold" parameter
-   1.23. Set the "ds_ping_reply_codes" parameter
-   1.24. Set the "ds_probing_mode" parameter
-   1.25. Set the "ds_hash_size" parameter
-   1.26. Set the "ds_hash_expire" parameter
-   1.27. Set the "ds_hash_initexpire" parameter
-   1.28. Set the "ds_hash_check_interval" parameter
-   1.29. Set the "outbound_proxy" parameter
-   1.30. ds_select_dst usage
-   1.31. ds_mark_dst usage
+   1.19. Set the "attrs_pvname" parameter
+   1.20. Set the "ds_ping_method" parameter
+   1.21. Set the "ds_ping_from" parameter
+   1.22. Set the "ds_ping_interval" parameter
+   1.23. Set the "ds_probing_threshhold" parameter
+   1.24. Set the "ds_ping_reply_codes" parameter
+   1.25. Set the "ds_probing_mode" parameter
+   1.26. Set the "ds_hash_size" parameter
+   1.27. Set the "ds_hash_expire" parameter
+   1.28. Set the "ds_hash_initexpire" parameter
+   1.29. Set the "ds_hash_check_interval" parameter
+   1.30. Set the "outbound_proxy" parameter
+   1.31. ds_select_dst usage
    1.32. ds_mark_dst usage
-   1.33. ds_load_unset usage
-   1.34. dispatcher list file
-   1.35. Kamailio config script - sample dispatcher usage
+   1.33. ds_mark_dst usage
+   1.34. ds_load_unset usage
+   1.35. dispatcher list file
+   1.36. Kamailio config script - sample dispatcher usage
 
 Chapter 1. Admin Guide
 
@@ -166,17 +168,18 @@ Chapter 1. Admin Guide
         3.15. attrs_avp (str)
         3.16. hash_pvar (str)
         3.17. setid_pvname (str)
-        3.18. ds_ping_method (string)
-        3.19. ds_ping_from (string)
-        3.20. ds_ping_interval (int)
-        3.21. ds_probing_threshhold (int)
-        3.22. ds_ping_reply_codes (string)
-        3.23. ds_probing_mode (int)
-        3.24. ds_hash_size (int)
-        3.25. ds_hash_expire (int)
-        3.26. ds_hash_initexpire (int)
-        3.27. ds_hash_check_interval (int)
-        3.28. outbound_proxy (str)
+        3.18. attrs_pvname (str)
+        3.19. ds_ping_method (string)
+        3.20. ds_ping_from (string)
+        3.21. ds_ping_interval (int)
+        3.22. ds_probing_threshold (int)
+        3.23. ds_ping_reply_codes (string)
+        3.24. ds_probing_mode (int)
+        3.25. ds_hash_size (int)
+        3.26. ds_hash_expire (int)
+        3.27. ds_hash_initexpire (int)
+        3.28. ds_hash_check_interval (int)
+        3.29. outbound_proxy (str)
 
    4. Functions
 
@@ -264,17 +267,18 @@ Chapter 1. Admin Guide
    3.15. attrs_avp (str)
    3.16. hash_pvar (str)
    3.17. setid_pvname (str)
-   3.18. ds_ping_method (string)
-   3.19. ds_ping_from (string)
-   3.20. ds_ping_interval (int)
-   3.21. ds_probing_threshhold (int)
-   3.22. ds_ping_reply_codes (string)
-   3.23. ds_probing_mode (int)
-   3.24. ds_hash_size (int)
-   3.25. ds_hash_expire (int)
-   3.26. ds_hash_initexpire (int)
-   3.27. ds_hash_check_interval (int)
-   3.28. outbound_proxy (str)
+   3.18. attrs_pvname (str)
+   3.19. ds_ping_method (string)
+   3.20. ds_ping_from (string)
+   3.21. ds_ping_interval (int)
+   3.22. ds_probing_threshold (int)
+   3.23. ds_ping_reply_codes (string)
+   3.24. ds_probing_mode (int)
+   3.25. ds_hash_size (int)
+   3.26. ds_hash_expire (int)
+   3.27. ds_hash_initexpire (int)
+   3.28. ds_hash_check_interval (int)
+   3.29. outbound_proxy (str)
 
 3.1. list_file (string)
 
@@ -521,7 +525,19 @@ Note
  modparam("dispatcher", "setid_pvname", "$var(setid)")
  ...
 
-3.18. ds_ping_method (string)
+3.18. attrs_pvname (str)
+
+   The name of the PV where to store the attributes of matching address
+   when calling ds_is_from_list().
+
+   Default value is "null" - don't set PV.
+
+   Example 1.19. Set the "attrs_pvname" parameter
+ ...
+ modparam("dispatcher", "attrs_pvname", "$var(attrs)")
+ ...
+
+3.19. ds_ping_method (string)
 
    With this method you can define, with which method you want to probe
    the gateways. Pinging gateways feature depends on ds_ping_interval
@@ -529,12 +545,12 @@ Note
 
    Default value is "OPTIONS".
 
-   Example 1.19. Set the "ds_ping_method" parameter
+   Example 1.20. Set the "ds_ping_method" parameter
  ...
  modparam("dispatcher", "ds_ping_method", "INFO")
  ...
 
-3.19. ds_ping_from (string)
+3.20. ds_ping_from (string)
 
    With this Method you can define the "From:"-Line for the request, sent
    to the failed gateways. This method is only available, if compiled with
@@ -542,12 +558,12 @@ Note
 
    Default value is "sip:dispatcher at localhost".
 
-   Example 1.20. Set the "ds_ping_from" parameter
+   Example 1.21. Set the "ds_ping_from" parameter
  ...
  modparam("dispatcher", "ds_ping_from", "sip:proxy at sip.somehost.com")
  ...
 
-3.20. ds_ping_interval (int)
+3.21. ds_ping_interval (int)
 
    With this parameter you can define the interval for sending a request
    to a gateway marked as inactive upon a failed request routing to it.
@@ -556,12 +572,12 @@ Note
 
    Default value is "0".
 
-   Example 1.21. Set the "ds_ping_interval" parameter
+   Example 1.22. Set the "ds_ping_interval" parameter
  ...
  modparam("dispatcher", "ds_ping_interval", 30)
  ...
 
-3.21. ds_probing_threshhold (int)
+3.22. ds_probing_threshold (int)
 
    If you want to set a gateway into inactive mode, there can be a
    specific number of failed requests until it will change from "active"
@@ -572,12 +588,12 @@ Note
 
    Default value is "1" (set inactive with first failure).
 
-   Example 1.22. Set the "ds_probing_threshhold" parameter
+   Example 1.23. Set the "ds_probing_threshhold" parameter
  ...
  modparam("dispatcher", "ds_probing_threshhold", 10)
  ...
 
-3.22. ds_ping_reply_codes (string)
+3.23. ds_ping_reply_codes (string)
 
    This parameter defines the valid response codes, which are accepted as
    a valid reply to the PING-Method. It is a list separated by colons,
@@ -589,13 +605,13 @@ Note
 
    Default value is "" (only 200 OK is accepted).
 
-   Example 1.23. Set the "ds_ping_reply_codes" parameter
+   Example 1.24. Set the "ds_ping_reply_codes" parameter
  ...
  modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=403;code=488;class=
 3")
  ...
 
-3.23. ds_probing_mode (int)
+3.24. ds_probing_mode (int)
 
    Controls what gateways are tested to see if they are reachable. If set
    to 0, only the gateways with state PROBING are tested; if set to 1, all
@@ -605,12 +621,12 @@ Note
 
    Default value is "0".
 
-   Example 1.24. Set the "ds_probing_mode" parameter
+   Example 1.25. Set the "ds_probing_mode" parameter
  ...
  modparam("dispatcher", "ds_probing_mode", 1)
  ...
 
-3.24. ds_hash_size (int)
+3.25. ds_hash_size (int)
 
    The value to be used as power of two to set the number of slots to hash
    table storing data for call load dispatching (e.g., value 8 will create
@@ -619,24 +635,24 @@ Note
 
    Default value is "0".
 
-   Example 1.25. Set the "ds_hash_size" parameter
+   Example 1.26. Set the "ds_hash_size" parameter
  ...
  modparam("dispatcher", "ds_hash_size", 9)
  ...
 
-3.25. ds_hash_expire (int)
+3.26. ds_hash_expire (int)
 
    Expiration time in seconds to remove the load on a destination if no
    BYE was received meanwhile.
 
    Default value is "7200".
 
-   Example 1.26. Set the "ds_hash_expire" parameter
+   Example 1.27. Set the "ds_hash_expire" parameter
  ...
  modparam("dispatcher", "ds_hash_expire", 3600)
  ...
 
-3.26. ds_hash_initexpire (int)
+3.27. ds_hash_initexpire (int)
 
    Expiration time in seconds to remove the load on a destination if no
    200 for INVITE was received meanwhile and state updated with
@@ -644,30 +660,30 @@ Note
 
    Default value is "7200".
 
-   Example 1.27. Set the "ds_hash_initexpire" parameter
+   Example 1.28. Set the "ds_hash_initexpire" parameter
  ...
  modparam("dispatcher", "ds_hash_initexpire", 60)
  ...
 
-3.27. ds_hash_check_interval (int)
+3.28. ds_hash_check_interval (int)
 
    Time interval in seconds to scan internal hash table with call load
    dispatching data for expired items.
 
    Default value is "30".
 
-   Example 1.28. Set the "ds_hash_check_interval" parameter
+   Example 1.29. Set the "ds_hash_check_interval" parameter
  ...
  modparam("dispatcher", "ds_hash_check_interval", 60)
  ...
 
-3.28. outbound_proxy (str)
+3.29. outbound_proxy (str)
 
    SIP URI of outbound proxy to be used when sending pings.
 
    By default no outbound proxy is defined.
 
-   Example 1.29. Set the "outbound_proxy" parameter
+   Example 1.30. Set the "outbound_proxy" parameter
  ...
  modparam("dispatcher", "outbound_proxy", "sip:outbound.example.com")
  ...
@@ -733,7 +749,7 @@ Note
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.30. ds_select_dst usage
+   Example 1.31. ds_select_dst usage
 ...
 ds_select_dst("1", "0");
 ...
@@ -795,7 +811,7 @@ ds_select_dst("1", "$var(a)");
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.31. ds_mark_dst usage
+   Example 1.32. ds_mark_dst usage
 ...
 failure_route[tryagain] {
 ...
@@ -813,11 +829,13 @@ failure_route[tryagain] {
    Parameter groupid is optional, when it is missing, then the matching
    will be done against all addresses in all groups. Upon a match, the
    variable specified by 'setid_pvname' parameter will be set to groupid
-   of matching address.
+   of matching address and the attributes will be set in variable
+   specified by 'attrs_pvname'. The parameter can be an integer or a
+   variable holding an integer value.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.32. ds_mark_dst usage
+   Example 1.33. ds_mark_dst usage
 ...
 if(ds_is_from_list("10")) {
     ...
@@ -842,7 +860,7 @@ if(ds_is_from_list("10")) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE and ONREPLY_ROUTE.
 
-   Example 1.33. ds_load_unset usage
+   Example 1.34. ds_load_unset usage
 ...
 route {
     ...
@@ -1014,7 +1032,7 @@ setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attrs(str,opt)
    For database, each element of a line resides in a different column.
    Next is a dispatcher.list file example:
 
-   Example 1.34. dispatcher list file
+   Example 1.35. dispatcher list file
 ...
 # $Id$
 # dispatcher destination sets
@@ -1039,7 +1057,7 @@ r,opt)
 
    Next picture shows a sample usage of the dispatcher module.
 
-   Example 1.35. Kamailio config script - sample dispatcher usage
+   Example 1.36. Kamailio config script - sample dispatcher usage
 ...
 #!KAMAILIO
 #
diff --git a/modules/dispatcher/dispatch.c b/modules/dispatcher/dispatch.c
index cc8b7bf..56d2f06 100644
--- a/modules/dispatcher/dispatch.c
+++ b/modules/dispatcher/dispatch.c
@@ -92,7 +92,7 @@ static ds_ht_t *_dsht_load = NULL;
 extern int ds_force_dst;
 
 static db_func_t ds_dbf;
-static db1_con_t* ds_db_handle=0;
+static db1_con_t* ds_db_handle=NULL;
 
 ds_set_t **ds_lists=NULL;
 
@@ -655,8 +655,8 @@ int init_ds_db(void)
 		return -1;
 	}
 
-	if(ds_connect_db()!=0){
-
+	if(ds_connect_db()!=0)
+	{
 		LM_ERR("unable to connect to the database\n");
 		return -1;
 	}
@@ -689,6 +689,26 @@ int init_ds_db(void)
 	return ret;
 }
 
+/*! \brief reload groups of destinations from DB*/
+int ds_reload_db(void)
+{
+	int ret;
+
+	if(ds_connect_db()!=0)
+	{
+		LM_ERR("unable to connect to the database\n");
+		return -1;
+	}
+	ret = ds_load_db();
+	if (ret == -2)
+	{
+		LM_WARN("failure while loading one or more dispatcher entries\n");
+	}
+	ds_disconnect_db();
+
+	return ret;
+}
+
 /*! \brief load groups of destinations from DB*/
 int ds_load_db(void)
 {
@@ -2244,6 +2264,18 @@ int ds_is_from_list(struct sip_msg *_m, int group)
 							return -2;
 						}
 					}
+					if(ds_attrs_pvname.s!=0 && list->dlist[j].attrs.body.len>0)
+					{
+						memset(&val, 0, sizeof(pv_value_t));
+						val.flags = PV_VAL_STR;
+						val.rs = list->dlist[j].attrs.body;
+						if(ds_attrs_pv.setf(_m, &ds_attrs_pv.pvp,
+									(int)EQ_T, &val)<0)
+						{
+							LM_ERR("setting attrs pv failed\n");
+							return -3;
+						}
+					}
 					return 1;
 				}
 			}
@@ -2352,10 +2384,10 @@ static void ds_options_callback( struct cell *t, int type,
 	 *  cast it to an int. */
 	group = (int)(long)(*ps->param);
 	/* The SIP-URI is taken from the Transaction.
-	 * Remove the "To: " (s+4) and the trailing new-line (s - 4 (To: )
-	 * - 2 (\r\n)). */
-	uri.s = t->to.s + 4;
-	uri.len = t->to.len - 6;
+	 * Remove the "To: <" (s+5) and the trailing >+new-line (s - 5 (To: <)
+	 * - 3 (>\r\n)). */
+	uri.s = t->to.s + 5;
+	uri.len = t->to.len - 8;
 	LM_DBG("OPTIONS-Request was finished with code %d (to %.*s, group %d)\n",
 			ps->code, uri.len, uri.s, group);
 	/* ps->code contains the result-code of the request.
diff --git a/modules/dispatcher/dispatch.h b/modules/dispatcher/dispatch.h
index db055ee..cfa9ac0 100644
--- a/modules/dispatcher/dispatch.h
+++ b/modules/dispatcher/dispatch.h
@@ -87,6 +87,8 @@ extern pv_elem_t * hash_param_model;
 
 extern str ds_setid_pvname;
 extern pv_spec_t ds_setid_pv;
+extern str ds_attrs_pvname;
+extern pv_spec_t ds_attrs_pv;
 
 /* Structure containing pointers to TM-functions */
 extern struct tm_binds tmb;
@@ -103,6 +105,7 @@ int ds_load_list(char *lfile);
 int ds_connect_db(void);
 void ds_disconnect_db(void);
 int ds_load_db(void);
+int ds_reload_db(void);
 int ds_destroy_list(void);
 int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode);
 int ds_next_dst(struct sip_msg *msg, int mode);
diff --git a/modules/dispatcher/dispatcher.c b/modules/dispatcher/dispatcher.c
index cf79d90..a084ce8 100644
--- a/modules/dispatcher/dispatcher.c
+++ b/modules/dispatcher/dispatcher.c
@@ -136,6 +136,8 @@ str ds_table_name        = str_init(DS_TABLE_NAME);
 
 str ds_setid_pvname   = {NULL, 0};
 pv_spec_t ds_setid_pv;
+str ds_attrs_pvname   = {NULL, 0};
+pv_spec_t ds_attrs_pv;
 
 /** module functions */
 static int mod_init(void);
@@ -181,7 +183,7 @@ static cmd_export_t cmds[]={
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list0, 0,
 		0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list1, 1,
-		fixup_uint_null, 0, ANY_ROUTE},
+		fixup_igp_null, 0, ANY_ROUTE},
 	{"ds_load_unset",    (cmd_function)w_ds_load_unset,   0,
 		0, 0, ANY_ROUTE},
 	{"ds_load_update",   (cmd_function)w_ds_load_update,  0,
@@ -211,6 +213,7 @@ static param_export_t params[]={
 	{"attrs_avp",       STR_PARAM, &attrs_avp_param.s},
 	{"hash_pvar",       STR_PARAM, &hash_pvar_param.s},
 	{"setid_pvname",    STR_PARAM, &ds_setid_pvname.s},
+	{"attrs_pvname",    STR_PARAM, &ds_attrs_pvname.s},
 	{"ds_probing_threshhold", INT_PARAM, &probing_threshhold},
 	{"ds_ping_method",     STR_PARAM, &ds_ping_method.s},
 	{"ds_ping_from",       STR_PARAM, &ds_ping_from.s},
@@ -282,6 +285,8 @@ static int mod_init(void)
 		hash_pvar_param.len = strlen(hash_pvar_param.s);
 	if (ds_setid_pvname.s)
 		ds_setid_pvname.len = strlen(ds_setid_pvname.s);
+	if (ds_attrs_pvname.s)
+		ds_attrs_pvname.len = strlen(ds_attrs_pvname.s);
 	if (ds_ping_from.s) ds_ping_from.len = strlen(ds_ping_from.s);
 	if (ds_ping_method.s) ds_ping_method.len = strlen(ds_ping_method.s);
 	if (ds_outbound_proxy.s) ds_outbound_proxy.len = strlen(ds_outbound_proxy.s);
@@ -462,6 +467,17 @@ static int mod_init(void)
 			return -1;
 		}
 	}
+
+	if(ds_attrs_pvname.s!=0)
+	{
+		if(pv_parse_spec(&ds_attrs_pvname, &ds_attrs_pv)==NULL
+				|| !pv_is_w(&ds_attrs_pv))
+		{
+			LM_ERR("[%s]- invalid attrs_pvname\n", ds_attrs_pvname.s);
+			return -1;
+		}
+	}
+
 	if (dstid_avp_param.s && dstid_avp_param.len > 0)
 	{
 		if(ds_hash_size>0)
@@ -776,7 +792,7 @@ static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param)
 		if (ds_load_list(dslistfile)!=0)
 			return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
 	} else {
-		if(ds_load_db()<0)
+		if(ds_reload_db()<0)
 			return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
 	}
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
@@ -791,7 +807,13 @@ static int w_ds_is_from_list0(struct sip_msg *msg, char *str1, char *str2)
 
 static int w_ds_is_from_list1(struct sip_msg *msg, char *set, char *str2)
 {
-	return ds_is_from_list(msg, (int)(long)set);
+	int s;
+	if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0)
+	{
+		LM_ERR("cannot get set id value\n");
+		return -1;
+	}
+	return ds_is_from_list(msg, s);
 }
 
 static int ds_parse_reply_codes() {
@@ -934,7 +956,7 @@ static void dispatcher_rpc_reload(rpc_t* rpc, void* ctx)
 			return;
 		}
 	} else {
-		if(ds_load_db()<0) {
+		if(ds_reload_db()<0) {
 			rpc->fault(ctx, 500, "Reload Failed");
 			return;
 		}
diff --git a/modules/dispatcher/doc/dispatcher.xml b/modules/dispatcher/doc/dispatcher.xml
index 29c0105..dada67e 100644
--- a/modules/dispatcher/doc/dispatcher.xml
+++ b/modules/dispatcher/doc/dispatcher.xml
@@ -26,7 +26,7 @@
             <editor>
                 <firstname>Carsten</firstname>
                 <surname>Bock</surname>
-                <affiliation><orgname>ng-voice.com</orgname></affiliation>
+                <affiliation><orgname>ng-voice GmbH</orgname></affiliation>
                 <address>
                 <email>carsten at ng-voice.com</email>
                 </address>
diff --git a/modules/dispatcher/doc/dispatcher_admin.xml b/modules/dispatcher/doc/dispatcher_admin.xml
index 7a02921..d375fd0 100644
--- a/modules/dispatcher/doc/dispatcher_admin.xml
+++ b/modules/dispatcher/doc/dispatcher_admin.xml
@@ -74,7 +74,7 @@
 
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="dispatcher.p.list_file">
 		<title><varname>list_file</varname> (string)</title>
 		<para>
 		Path to the file with destination sets.
@@ -95,7 +95,7 @@ modparam("dispatcher", "list_file", "/var/run/kamailio/dispatcher.list")
 		</example>
 	</section>
 
-	<section>
+	<section id="dispatcher.p.db_url">
  		<title><varname>db_url</varname> (string)</title>
  		<para>
 		If you want to load the sets of gateways from the database you must set
@@ -116,7 +116,7 @@ modparam("dispatcher", "db_url", "mysql://user:passwb@localhost/database")
 		</example>
 	</section>
 
-	<section>
+	<section id="dispatcher.p.table_name">
 		<title><varname>table_name</varname> (string)</title>
 		<para>
 		If you want to load the sets of gateways from the database you must set
@@ -137,7 +137,7 @@ modparam("dispatcher", "table_name", "my_dispatcher")
 		</example>
 	</section>
 
-	<section>
+	<section id="dispatcher.p.setid_col">
 		<title><varname>setid_col</varname> (string)</title>
 		<para>
 			The column's name in the database storing the gateway's group id.
@@ -157,7 +157,7 @@ modparam("dispatcher", "setid_col", "groupid")
 		</example>
 	</section>
 
-	<section>
+	<section id="dispatcher.p.destination_col">
 		<title><varname>destination_col</varname> (string)</title>
 		<para>
 			The column's name in the database storing the destination
@@ -178,7 +178,7 @@ modparam("dispatcher", "destination_col", "uri")
 		</example>
 	</section>
 
-	<section>
+	<section id="dispatcher.p.flags_col">
 		<title><varname>flags_col</varname> (string)</title>
 		<para>
 			The column's name in the database storing the flags for
@@ -199,7 +199,7 @@ modparam("dispatcher", "flags_col", "dstflags")
 		</example>
 	</section>
 
-	<section>
+	<section id="dispatcher.p.priority_col">
 		<title><varname>priority_col</varname> (string)</title>
 		<para>
 			The column's name in the database storing the priority for
@@ -220,7 +220,7 @@ modparam("dispatcher", "priority_col", "dstpriority")
 		</example>
 	</section>
 
-	<section>
+	<section id="dispatcher.p.force_dst">
 		<title><varname>force_dst</varname> (int)</title>
 		<para>
 		If set to 1, force overwriting of destination address (outbound proxy)
@@ -241,7 +241,7 @@ modparam("dispatcher", "force_dst", 1)
 </programlisting>
 		</example>
 	</section>
- 	<section>
+ 	<section id="dispatcher.p.flags">
  		<title><varname>flags</varname> (int)</title>
  		<para>
  		Various flags that affect dispatcher's behaviour. The flags are defined
@@ -272,7 +272,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
  	</section>
- 	<section>
+ 	<section id="dispatcher.p.use_default">
  		<title><varname>use_default</varname> (int)</title>
  		<para>
  		If the parameter is set to 1, the last address in destination set
@@ -294,7 +294,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
- 	<section>
+ 	<section id="dispatcher.p.dst_avp">
  		<title><varname>dst_avp</varname> (str)</title>
  		<para>
  		The name of the avp which will hold the list with addresses, in the
@@ -324,7 +324,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
  	</section>
- 	<section>
+ 	<section id="dispatcher.p.grp_avp">
  		<title><varname>grp_avp</varname> (str)</title>
  		<para>
  		The name of the avp storing the group id of the destination set. Good
@@ -349,7 +349,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
  	</section>
- 	<section>
+ 	<section id="dispatcher.p.cnt_avp">
  		<title><varname>cnt_avp</varname> (str)</title>
  		<para>
  		The name of the avp storing the number of destination addresses kept in
@@ -374,7 +374,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
  	</section>
- 	<section>
+ 	<section id="dispatcher.p.dstid_avp">
  		<title><varname>dstid_avp</varname> (str)</title>
  		<para>
 		The name of the avp storing the destination unique ID used for
@@ -400,7 +400,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
  	</section>
- 	<section>
+ 	<section id="dispatcher.p.attrs_avp">
  		<title><varname>attrs_avp</varname> (str)</title>
  		<para>
 		The name of the avp storing destination's attributes value.
@@ -421,7 +421,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
  	</section>
- 	<section>
+ 	<section id="dispatcher.p.hash_pvar">
  		<title><varname>hash_pvar</varname> (str)</title>
  		<para>
  		String with PVs used for the hashing algorithm 7.
@@ -454,7 +454,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
  	</section>
- 	<section>
+ 	<section id="dispatcher.p.setid_pvname">
  		<title><varname>setid_pvname</varname> (str)</title>
  		<para>
 		The name of the PV where to store the set ID (group ID) when calling
@@ -473,9 +473,28 @@ modparam("dispatcher", "force_dst", 1)
  ...
  </programlisting>
  		</example>
- 	</section>
-
- 	<section>
+	</section>
+	<section id="dispatcher.p.attrs_pvname">
+		<title><varname>attrs_pvname</varname> (str)</title>
+		<para>
+		The name of the PV where to store the attributes of matching address
+		when calling ds_is_from_list().
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>null</quote> - don't set PV.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set the <quote>attrs_pvname</quote> parameter</title>
+ <programlisting format="linespecific">
+ ...
+ modparam("dispatcher", "attrs_pvname", "$var(attrs)")
+ ...
+ </programlisting>
+		</example>
+	</section>
+ 	<section id="dispatcher.p.ds_ping_method">
  		<title><varname>ds_ping_method</varname> (string)</title>
  		<para>
 		With this method you can define, with which method you want to probe the gateways.
@@ -495,7 +514,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section> 	
- 	<section>
+ 	<section id="dispatcher.p.ds_ping_from">
  		<title><varname>ds_ping_from</varname> (string)</title>
  		<para>
  		With this Method you can define the "From:"-Line for the request, sent to the failed gateways. 		
@@ -516,7 +535,7 @@ modparam("dispatcher", "force_dst", 1)
  		</example>
 	</section> 	
 
- 	<section>
+ 	<section id="dispatcher.p.ds_ping_interval">
  		<title><varname>ds_ping_interval</varname> (int)</title>
  		<para>
 		With this parameter you can define the interval for sending a request
@@ -539,8 +558,8 @@ modparam("dispatcher", "force_dst", 1)
  		</example>
 	</section> 	
 	
- 	<section>
- 		<title><varname>ds_probing_threshhold</varname> (int)</title>
+ 	<section id="dispatcher.p.ds_probing_threshold">
+ 		<title><varname>ds_probing_threshold</varname> (int)</title>
  		<para>
 		If you want to set a gateway into inactive mode, there can be
 		a specific number of failed requests until it will change from "active"
@@ -563,7 +582,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
- 	<section>
+ 	<section id="dispatcher.p.ds_ping_reply_codes">
  		<title><varname>ds_ping_reply_codes</varname> (string)</title>
  		<para>
 		This parameter defines the valid response codes, which are accepted as a valid reply to the PING-Method.
@@ -584,7 +603,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section> 	
- 	<section>
+ 	<section id="dispatcher.p.ds_probing_mode">
  		<title><varname>ds_probing_mode</varname> (int)</title>
  		<para>
 		Controls what gateways are tested to see if they are reachable. If set
@@ -608,7 +627,7 @@ modparam("dispatcher", "force_dst", 1)
  		</example>
 	</section>
 
- 	<section>
+ 	<section id="dispatcher.p.ds_hash_size">
  		<title><varname>ds_hash_size</varname> (int)</title>
  		<para>
 		The value to be used as power of two to set the number of slots
@@ -631,7 +650,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
- 	<section>
+ 	<section id="dispatcher.p.ds_hash_expire">
  		<title><varname>ds_hash_expire</varname> (int)</title>
  		<para>
 		Expiration time in seconds to remove the load on a destination if no
@@ -651,7 +670,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
- 	<section>
+ 	<section id="dispatcher.p.ds_hash_initexpires">
  		<title><varname>ds_hash_initexpire</varname> (int)</title>
  		<para>
 		Expiration time in seconds to remove the load on a destination if no
@@ -672,7 +691,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
- 	<section>
+ 	<section id="dispatcher.p.ds_hash_check_interval">
  		<title><varname>ds_hash_check_interval</varname> (int)</title>
  		<para>
 		Time interval in seconds to scan internal hash table with call load
@@ -692,7 +711,7 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
- 	<section>
+ 	<section id="dispatcher.p.outbound_proxy">
  		<title><varname>outbound_proxy</varname> (str)</title>
  		<para>
 		SIP URI of outbound proxy to be used when sending pings.
@@ -716,7 +735,7 @@ modparam("dispatcher", "force_dst", 1)
 
 	<section>
 	<title>Functions</title>
-	<section>
+	<section id="dispatcher.f.ds_select_dst">
 		<title>
 		<function moreinfo="none">ds_select_dst(set, alg)</function>
 		</title>
@@ -851,7 +870,7 @@ ds_select_dst("1", "$var(a)");
 </programlisting>
 		</example>
 	</section>
-  	<section>
+  	<section id="dispatcher.f.ds_select_domain">
  		<title>
  		<function moreinfo="none">ds_select_domain(set, alg)</function>
  		</title>
@@ -894,7 +913,7 @@ ds_select_dst("1", "$var(a)");
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 		</para>
  	</section>
-  	<section>
+  	<section id="dispatcher.f.ds_mark_dst">
  		<title>
  		<function moreinfo="none">ds_mark_dst([state])</function>
  		</title>
@@ -955,7 +974,7 @@ failure_route[tryagain] {
 </programlisting>
 		</example>
  	</section>
-  	<section>
+  	<section  id="dispatcher.f.ds_is_from_list">
  		<title>
  		<function moreinfo="none">ds_is_from_list([groupid])</function>
  		</title>
@@ -967,7 +986,9 @@ failure_route[tryagain] {
 		Parameter groupid is optional, when it is missing, then the matching
 		will be done against all addresses in all groups. Upon a match, the
 		variable specified by 'setid_pvname' parameter will be set to groupid
-		of matching address.
+		of matching address and the attributes will be set in variable
+		specified by 'attrs_pvname'. The parameter can be an integer or a
+		variable holding an integer value.
  		</para>
 		<para>
 			This function can be used from ANY_ROUTE.
@@ -983,7 +1004,7 @@ if(ds_is_from_list("10")) {
 </programlisting>
 		</example>
  	</section>
-  	<section>
+  	<section id="dispatcher.f.ds_load_update">
  		<title>
  		<function moreinfo="none">ds_load_update()</function>
  		</title>
@@ -1049,7 +1070,7 @@ onreply_route {
 
 	<section>
 	<title>MI Commands</title>
-	<section>
+	<section id="dispatcher.mi.ds_set_state">
 		<title>
 		<function moreinfo="none">ds_set_state</function>
 		</title>
@@ -1089,7 +1110,7 @@ onreply_route {
 		_empty_line_
 		</programlisting>
     </section>
-	<section>
+	<section id="dispatcher.mi.ds_list">
 		<title>
 		<function moreinfo="none">ds_list</function>
 		</title>
@@ -1108,7 +1129,7 @@ onreply_route {
 		_empty_line_
 		</programlisting>
     </section>
-	<section>
+	<section id="dispatcher.mi.ds_reload">
 		<title>
 		<function moreinfo="none">ds_reload</function>
 		</title>
@@ -1135,7 +1156,7 @@ onreply_route {
 
 	<section>
 	<title>Exported RPC Commands</title>
-	<section>
+	<section id="dispatcher.rpc.set_state">
 		<title>
 		<function moreinfo="none">dispatcher.set_state</function>
 		</title>
@@ -1174,7 +1195,7 @@ onreply_route {
 ...
 </programlisting>
     </section>
-	<section>
+	<section id="dispatcher.rpc.list">
 		<title>
 		<function moreinfo="none">dispatcher.list</function>
 		</title>
@@ -1192,7 +1213,7 @@ onreply_route {
 		&sercmd; dispatcher.list
 		</programlisting>
     </section>
-	<section>
+	<section id="dispatcher.f.reload">
 		<title>
 		<function moreinfo="none">dispatcher.reload</function>
 		</title>
diff --git a/modules/dmq/README b/modules/dmq/README
index a54bd25..650616d 100644
--- a/modules/dmq/README
+++ b/modules/dmq/README
@@ -2,11 +2,21 @@ Distributed Message Queue Module
 
 Marius Ovidiu Bucur
 
+Charles Chance
+
+   Sipcentric Ltd.
+
 Edited by
 
 Marius Ovidiu Bucur
 
-   Copyright � 2011 Marius Bucur
+Edited by
+
+Charles Chance
+
+   Copyright © 2011 Marius Bucur
+
+   Copyright © 2013 Charles Chance, Sipcentric Ltd.
      __________________________________________________________________
 
    Table of Contents
@@ -21,18 +31,40 @@ Marius Ovidiu Bucur
 
         3. Parameters
 
-              3.1. dmq_server_address(str)
-              3.2. dmq_notification_address(str)
+              3.1. server_address(str)
+              3.2. notification_address(str)
+              3.3. num_workers(int)
+              3.4. ping_interval(int)
+
+        4. Functions
+
+              4.1. dmq_handle_message()
+              4.2. dmq_send_message(peer, node, body, content_type)
 
    2. Developer Guide
 
         1. dmq_load_api(dmq_api_t* api)
+        2. register_dmq_peer(dmq_peer_t* peer)
+        3. bcast_message(dmq_peer_t* peer, str* body, dmq_node_t* except,
+                dmq_resp_cback_t* resp_cback, int max_forwards, str*
+                content_type)
+
+        4. send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
+                dmq_resp_cback_t* resp_cback, int max_forwards, str*
+                content_type)
 
    List of Examples
 
-   1.1. Set dmq_server_address parameter
-   1.2. Set dmq_notification_address parameter
+   1.1. Set server_address parameter
+   1.2. Set notification_address parameter
+   1.3. Set num_workers parameter
+   1.4. Set ping_interval parameter
+   1.5. dmq_handle_message usage
+   1.6. dmq_send_message usage
    2.1. dmq_api_t structure
+   2.2. register_dmq_peer usage
+   2.3. bcast_message usage
+   2.4. send_message usage
 
 Chapter 1. Admin Guide
 
@@ -46,17 +78,31 @@ Chapter 1. Admin Guide
 
    3. Parameters
 
-        3.1. dmq_server_address(str)
-        3.2. dmq_notification_address(str)
+        3.1. server_address(str)
+        3.2. notification_address(str)
+        3.3. num_workers(int)
+        3.4. ping_interval(int)
+
+   4. Functions
+
+        4.1. dmq_handle_message()
+        4.2. dmq_send_message(peer, node, body, content_type)
 
 1. Overview
 
-   The DMQ module implements a distributed message passing system on top
-   of Kamailio. The DMQ nodes within the system are grouped in a logical
-   entity called DMQ bus and are able to communicate with each others by
-   sending/receiving messages (either by broadcast or sending a DMQ
-   message to a specific node). The system transparently deals with node
-   discovery, node consistency within the DMQ bus, retransmissions, etc.
+   The DMQ module implements a distributed message queue on top of
+   Kamailio in order to enable the passing/replication of data between
+   multiple instances. The DMQ "nodes" within the system are grouped in a
+   logical entity called the DMQ "bus" and are able to communicate with
+   each other by sending/receiving messages (either by broadcast or
+   directly to a specific node). The system transparently deals with node
+   discovery, consistency, retransmissions, etc.
+
+   Other entities ("peers") are then able to utlize the DMQ bus to pass
+   messages between themselves. Peers are grouped by name in order to
+   ensure the correct messages are passed to the relevant peers. This
+   grouping of peers can be compared to a topic in a typical pub/sub
+   system.
 
 2. Dependencies
 
@@ -71,40 +117,100 @@ Chapter 1. Admin Guide
 
 2.2. External Libraries or Applications
 
-     * Each peer needs to use its own serialization mechanism. Some
+     * The DMQ module itself has no external dependencies. However, each
+       peer will need to use its own (de)serialization mechanism. Some
        examples are libtpl, protobuf. .
 
 3. Parameters
 
-   3.1. dmq_server_address(str)
-   3.2. dmq_notification_address(str)
+   3.1. server_address(str)
+   3.2. notification_address(str)
+   3.3. num_workers(int)
+   3.4. ping_interval(int)
+
+3.1. server_address(str)
+
+   The local server address. This is the interface over which the DMQ
+   engine will send/receive messages.
+
+   Default value is “NULL”.
+
+   Example 1.1. Set server_address parameter
+...
+modparam("dmq", "server_address", "sip:10.0.0.20:5060")
+...
+
+3.2. notification_address(str)
+
+   The address of another DMQ node from which the local node should
+   retrieve initial information about all other nodes.
+
+   Default value is “NULL”.
+
+   Example 1.2. Set notification_address parameter
+...
+modparam("dmq", "notification_address", "sip:10.0.0.21:5060")
+...
+
+3.3. num_workers(int)
+
+   The number of worker threads for sending/receiving messages.
+
+   Default value is “2”.
 
-3.1. dmq_server_address(str)
+   Example 1.3. Set num_workers parameter
+...
+modparam("dmq", "num_threads", 4)
+...
+
+3.4. ping_interval(int)
+
+   The number of seconds between node pings (for checking status of other
+   nodes).
+
+   Minimum value is “60” (default).
+
+   Example 1.4. Set ping_interval parameter
+...
+modparam("dmq", "ping_interval", 90)
+...
+
+4. Functions
 
-   The local server address.
+   4.1. dmq_handle_message()
+   4.2. dmq_send_message(peer, node, body, content_type)
 
-   The modules needs it to know on which interface the DMQ engine should
-   send and receive messages.
+4.1.  dmq_handle_message()
 
-   Default value is "NULL".
+   Handles a DMQ message by passing it to the appropriate local peer
+   (module). The peer is identified by the user part of the To header.
 
-   Example 1.1. Set dmq_server_address parameter
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.5. dmq_handle_message usage
 ...
-modparam("dmq", "dmq_server_address", "mysql://kamailio:kamailiorw@localhost/kam
-ailio")
+        if(is_method("KDMQ"))
+        {
+                dmq_handle_message();
+        }
 ...
 
-3.2. dmq_notification_address(str)
+4.2.  dmq_send_message(peer, node, body, content_type)
+
+   Sends a DMQ message directly from config file.
 
-   The address of the DMQ node from which the local node should retrieve
-   initial information.
+   Meaning of parameters:
+     * peer - name of peer that should handle the message.
+     * node - the node to which the message should be sent.
+     * body - the message body.
+     * content_type - the MIME type of the message body.
 
-   Default value is "NULL".
+   This function can be used from any route.
 
-   Example 1.2. Set dmq_notification_address parameter
+   Example 1.6. dmq_send_message usage
 ...
-modparam("dmq", "dmq_notification_address", "mysql://kamailio:kamailiorw@localho
-st/kamailio")
+        dmq_send_message("peer_name", "sip:10.0.0.21:5060", "Message body...", "
+text/plain");
 ...
 
 Chapter 2. Developer Guide
@@ -112,18 +218,22 @@ Chapter 2. Developer Guide
    Table of Contents
 
    1. dmq_load_api(dmq_api_t* api)
+   2. register_dmq_peer(dmq_peer_t* peer)
+   3. bcast_message(dmq_peer_t* peer, str* body, dmq_node_t* except,
+          dmq_resp_cback_t* resp_cback, int max_forwards, str*
+          content_type)
+
+   4. send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
+          dmq_resp_cback_t* resp_cback, int max_forwards, str*
+          content_type)
 
    The module provides the following functions that can be used in other
    Kamailio modules.
 
-1. dmq_load_api(dmq_api_t* api)
+1.  dmq_load_api(dmq_api_t* api)
 
-   This function binds the dmq modules and fills the structure with the
-   exported functions -> register_dmq_peer - registers an entity as a DMQ
-   peer which permits receiving/sending messages between nodes which
-   support the same peer, -> bcast_message - broadcast a DMQ message to
-   all peers available in the DMQ bus, -> send_message - sends a DMQ
-   message to a specific peer in the local DMQ bus.
+   This function binds the DMQ module and fills the structure with the
+   exported functions below.
 
    Example 2.1. dmq_api_t structure
 ...
@@ -133,3 +243,34 @@ typedef struct dmq_api {
         send_message_t send_message;
 } dmq_api_t;
 ...
+
+2.  register_dmq_peer(dmq_peer_t* peer)
+
+   Registers an entity as a DMQ peer which permits receiving/sending
+   messages between nodes which support the same peer.
+
+   Example 2.2. register_dmq_peer usage
+...
+        Example to follow.
+...
+
+3.  bcast_message(dmq_peer_t* peer, str* body, dmq_node_t* except,
+dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type)
+
+   Broadcast a DMQ message to all nodes in the DMQ bus excluding self,
+   inactive nodes and "except" if specified.
+
+   Example 2.3. bcast_message usage
+...
+        Example to follow.
+...
+
+4.  send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
+dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type)
+
+   Send a DMQ message to a single node.
+
+   Example 2.4. send_message usage
+...
+        Example to follow.
+...
diff --git a/modules/dmq/bind_dmq.h b/modules/dmq/bind_dmq.h
index d0330d4..fc5242f 100644
--- a/modules/dmq/bind_dmq.h
+++ b/modules/dmq/bind_dmq.h
@@ -31,9 +31,9 @@
 #include "dmq_funcs.h"
 
 typedef int (*bcast_message_t)(dmq_peer_t* peer, str* body, dmq_node_t* except,
-		dmq_resp_cback_t* resp_cback, int max_forwards);
+		dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type);
 typedef int (*send_message_t)(dmq_peer_t* peer, str* body, dmq_node_t* node,
-		dmq_resp_cback_t* resp_cback, int max_forwards);
+		dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type);
 
 typedef struct dmq_api {
 	register_dmq_peer_t register_dmq_peer;
@@ -45,5 +45,20 @@ typedef int (*bind_dmq_f)(dmq_api_t* api);
 
 int bind_dmq(dmq_api_t* api);
 
+static inline int dmq_load_api(dmq_api_t* api) {
+	bind_dmq_f binddmq;
+	binddmq = (bind_dmq_f)find_export("bind_dmq", 0, 0);
+	if ( binddmq == 0) {
+		LM_ERR("cannot find bind_dmq\n");
+		return -1;
+	}
+	if (binddmq(api) < 0)
+	{
+		LM_ERR("cannot bind dmq api\n");
+		return -1;
+	}
+	return 0;
+}
+
 #endif
 
diff --git a/modules/dmq/dmq.c b/modules/dmq/dmq.c
index 4ed75bf..4b430a6 100644
--- a/modules/dmq/dmq.c
+++ b/modules/dmq/dmq.c
@@ -32,27 +32,21 @@
 #include <fcntl.h>
 #include <time.h>
 
-#include "../../sr_module.h"
-#include "../../dprint.h"
-#include "../../error.h"
 #include "../../ut.h"
 #include "../../mem/mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../usr_avp.h"
-#include "../../modules/tm/tm_load.h"
-#include "../../parser/parse_uri.h"
-#include "../../modules/sl/sl.h"
 #include "../../pt.h"
 #include "../../lib/kmi/mi.h"
 #include "../../hashes.h"
+#include "../../mod_fix.h"
+
 #include "dmq.h"
 #include "dmq_funcs.h"
-#include "peer.h"
 #include "bind_dmq.h"
-#include "worker.h"
+#include "message.h"
 #include "notification_peer.h"
 #include "dmqnode.h"
-#include "../../mod_fix.h"
 
 static int mod_init(void);
 static int child_init(int);
@@ -70,7 +64,7 @@ struct sip_uri dmq_server_uri;
 
 str dmq_notification_address = {0, 0};
 struct sip_uri dmq_notification_uri;
-int ping_interval = 4;
+int ping_interval = MIN_PING_INTERVAL;
 
 /* TM bind */
 struct tm_binds tmb;
@@ -97,8 +91,9 @@ static int parse_server_address(str* uri, struct sip_uri* parsed_uri);
 static cmd_export_t cmds[] = {
 	{"dmq_handle_message",  (cmd_function)dmq_handle_message, 0, handle_dmq_fixup, 0, 
 		REQUEST_ROUTE},
-	{"dmq_send_message", (cmd_function)cfg_dmq_send_message, 3, send_dmq_fixup, 0,
+	{"dmq_send_message", (cmd_function)cfg_dmq_send_message, 4, send_dmq_fixup, 0,
 		ANY_ROUTE},
+        {"bind_dmq",        (cmd_function)bind_dmq,       0, 0,              0},
 	{0, 0, 0, 0, 0, 0}
 };
 
diff --git a/modules/dmq/dmq.h b/modules/dmq/dmq.h
index 02c1fcc..c5dfcbf 100644
--- a/modules/dmq/dmq.h
+++ b/modules/dmq/dmq.h
@@ -32,7 +32,6 @@
 #include "../../modules/tm/tm_load.h"
 #include "../../parser/parse_uri.h"
 #include "../../modules/sl/sl.h"
-#include "bind_dmq.h"
 #include "peer.h"
 #include "worker.h"
 
@@ -57,22 +56,5 @@ extern str dmq_400_rpl;
 extern str dmq_500_rpl;
 extern str dmq_404_rpl;
 
-static inline int dmq_load_api(dmq_api_t* api) {
-	bind_dmq_f binddmq;
-	binddmq = (bind_dmq_f)find_export("bind_dmq", 0, 0);
-	if ( binddmq == 0) {
-		LM_ERR("cannot find bind_dmq\n");
-		return -1;
-	}
-	if (binddmq(api) < 0)
-	{
-		LM_ERR("cannot bind dmq api\n");
-		return -1;
-	}
-	return 0;
-}
-
-int dmq_handle_message(struct sip_msg* msg, char* str1 ,char* str2);
-
 #endif
 
diff --git a/modules/dmq/dmq_funcs.c b/modules/dmq/dmq_funcs.c
index 33c4ab1..df17fb9 100644
--- a/modules/dmq/dmq_funcs.c
+++ b/modules/dmq/dmq_funcs.c
@@ -31,6 +31,10 @@
 dmq_peer_t* register_dmq_peer(dmq_peer_t* peer)
 {
 	dmq_peer_t* new_peer;
+	if (!peer_list) {
+		LM_ERR("peer list not initialized\n");
+		return NULL;
+	}
 	lock_get(&peer_list->lock);
 	if(search_peer_list(peer_list, peer)) {
 		LM_ERR("peer already exists: %.*s %.*s\n", peer->peer_id.len, peer->peer_id.s,
@@ -118,7 +122,7 @@ int build_uri_str(str* username, struct sip_uri* uri, str* from)
  * resp_cback - a response callback that gets called when the transaction is complete
  */
 int bcast_dmq_message(dmq_peer_t* peer, str* body, dmq_node_t* except,
-		dmq_resp_cback_t* resp_cback, int max_forwards)
+		dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type)
 {
 	dmq_node_t* node;
 	
@@ -136,7 +140,7 @@ int bcast_dmq_message(dmq_peer_t* peer, str* body, dmq_node_t* except,
 			node = node->next;
 			continue;
 		}
-		if(dmq_send_message(peer, body, node, resp_cback, max_forwards) < 0) {
+		if(dmq_send_message(peer, body, node, resp_cback, max_forwards, content_type) < 0) {
 			LM_ERR("error sending dmq message\n");
 			goto error;
 		}
@@ -158,23 +162,27 @@ error:
  * resp_cback - a response callback that gets called when the transaction is complete
  */
 int dmq_send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
-		dmq_resp_cback_t* resp_cback, int max_forwards)
+		dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type)
 {
 	uac_req_t uac_r;
 	str str_hdr = {0, 0};
-	str from, to, req_uri;
+	str from, to;
 	dmq_cback_param_t* cb_param = NULL;
 	int result = 0;
 	int len = 0;
 	
-	/* Max-Forwards */
-	str_hdr.len = 20 + CRLF_LEN;
+	if (!content_type) {
+		LM_ERR("content-type is null\n");
+		return -1;
+	}
+	/* add Max-Forwards and Content-Type headers */
+	str_hdr.len = 34 + content_type->len + (CRLF_LEN*2);
 	str_hdr.s = pkg_malloc(str_hdr.len);
 	if(str_hdr.s==NULL) {
 		LM_ERR("no more pkg\n");
 		return -1;
 	}
-	len += sprintf(str_hdr.s, "Max-Forwards: %d%s", max_forwards, CRLF);
+	len += sprintf(str_hdr.s, "Max-Forwards: %d" CRLF "Content-Type: %.*s" CRLF, max_forwards, content_type->len, content_type->s);
 	str_hdr.len = len;
 	
 	cb_param = shm_malloc(sizeof(*cb_param));
@@ -191,11 +199,10 @@ int dmq_send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
 		LM_ERR("error building to string\n");
 		goto error;
 	}
-	req_uri = to;
 	
 	set_uac_req(&uac_r, &dmq_request_method, &str_hdr, body, NULL,
 			TMCB_LOCAL_COMPLETED, dmq_tm_callback, (void*)cb_param);
-	result = tmb.t_request(&uac_r, &req_uri,
+	result = tmb.t_request(&uac_r, &to,
 			       &to, &from,
 			       NULL);
 	if(result < 0) {
@@ -203,20 +210,27 @@ int dmq_send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
 		goto error;
 	}
 	pkg_free(str_hdr.s);
+	pkg_free(from.s);
+	pkg_free(to.s);
 	return 0;
 error:
 	pkg_free(str_hdr.s);
+	if (from.s!=NULL) 
+		pkg_free(from.s);
+	if (to.s!=NULL) 
+		pkg_free(to.s);
 	return -1;
 }
 
 /**
  * @brief config file function for sending dmq message
  */
-int cfg_dmq_send_message(struct sip_msg* msg, char* peer, char* to, char* body)
+int cfg_dmq_send_message(struct sip_msg* msg, char* peer, char* to, char* body, char* content_type)
 {
 	str peer_str;
 	str to_str;
 	str body_str;
+	str ct_str;
 	
 	if(get_str_fparam(&peer_str, msg, (fparam_t*)peer)<0) {
 		LM_ERR("cannot get peer value\n");
@@ -230,11 +244,17 @@ int cfg_dmq_send_message(struct sip_msg* msg, char* peer, char* to, char* body)
 		LM_ERR("cannot get body value\n");
 		return -1;
 	}
+	if(get_str_fparam(&ct_str, msg, (fparam_t*)content_type)<0) {
+		LM_ERR("cannot get content-type value\n");
+		return -1;
+	}
+
 	
-	LM_INFO("cfg_dmq_send_message: %.*s - %.*s - %.*s\n",
+	LM_INFO("cfg_dmq_send_message: %.*s - %.*s - %.*s - %.*s\n",
 		peer_str.len, peer_str.s,
 		to_str.len, to_str.s,
-		body_str.len, body_str.s);
+		body_str.len, body_str.s,
+		ct_str.len, ct_str.s);
 	
 	dmq_peer_t* destination_peer = find_peer(peer_str);
 	if(!destination_peer) {
@@ -256,7 +276,7 @@ int cfg_dmq_send_message(struct sip_msg* msg, char* peer, char* to, char* body)
 		goto error;
 	}
 	if(dmq_send_message(destination_peer, &body_str, to_dmq_node,
-				&notification_callback, 1) < 0) {
+				&notification_callback, 1, &ct_str) < 0) {
 		LM_ERR("cannot send dmq message\n");
 		goto error;
 	}
@@ -280,7 +300,7 @@ void ping_servers(unsigned int ticks, void *param) {
 	LM_DBG("ping_servers\n");
 	body = build_notification_body();
 	ret = bcast_dmq_message(dmq_notification_peer, body, notification_node,
-			&notification_callback, 1);
+			&notification_callback, 1, &notification_content_type);
 	pkg_free(body->s);
 	pkg_free(body);
 	if(ret < 0) {
diff --git a/modules/dmq/dmq_funcs.h b/modules/dmq/dmq_funcs.h
index e0f615a..c24d059 100644
--- a/modules/dmq/dmq_funcs.h
+++ b/modules/dmq/dmq_funcs.h
@@ -47,12 +47,12 @@ typedef struct dmq_cback_param {
 } dmq_cback_param_t;
 
 int cfg_dmq_send_message(struct sip_msg* msg, char* peer, char* to,
-		char* body);
+		char* body, char* content_type);
 dmq_peer_t* register_dmq_peer(dmq_peer_t* peer);
 int dmq_send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
-		dmq_resp_cback_t* resp_cback, int max_forwards);
+		dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type);
 int bcast_dmq_message(dmq_peer_t* peer, str* body, dmq_node_t* except,
-		dmq_resp_cback_t* resp_cback, int max_forwards);
+		dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type);
 
 #endif
 
diff --git a/modules/dmq/dmqnode.c b/modules/dmq/dmqnode.c
index 5bf0fc3..bc7c108 100644
--- a/modules/dmq/dmqnode.c
+++ b/modules/dmq/dmqnode.c
@@ -203,12 +203,7 @@ dmq_node_t* build_dmq_node(str* uri, int shm) {
 
 error:
 	if(ret!=NULL) {
-		/* tbd: free uri and params */
-		if(shm) {
-			shm_free(ret);
-		} else {
-			pkg_free(ret);
-		}
+		destroy_dmq_node(ret, shm);
 	}
 	return NULL;
 }
@@ -232,7 +227,6 @@ dmq_node_t* find_dmq_node_uri(dmq_node_list_t* list, str* uri)
  */
 void destroy_dmq_node(dmq_node_t* node, int shm)
 {
-	/* tbd: check inner fields */
 	if(shm) {
 		shm_free_node(node);
 	} else {
@@ -278,9 +272,7 @@ dmq_node_t* shm_dup_node(dmq_node_t* node)
 	}
 	return newnode;
 error:
-	if(newnode->orig_uri.s!=NULL)
-		shm_free(newnode->orig_uri.s);
-	shm_free(newnode);
+	destroy_dmq_node(newnode, 1);
 	return NULL;
 }
 
@@ -289,7 +281,10 @@ error:
  */
 void shm_free_node(dmq_node_t* node)
 {
-	shm_free(node->orig_uri.s);
+	if (node->orig_uri.s!=NULL) 
+		shm_free(node->orig_uri.s);
+	if (node->params!=NULL) 
+		shm_free_params(node->params);
 	shm_free(node);
 }
 
@@ -298,7 +293,10 @@ void shm_free_node(dmq_node_t* node)
  */
 void pkg_free_node(dmq_node_t* node)
 {
-	pkg_free(node->orig_uri.s);
+	if (node->orig_uri.s!=NULL) 
+		pkg_free(node->orig_uri.s);
+        if (node->params!=NULL)
+                free_params(node->params);
 	pkg_free(node);
 }
 
diff --git a/modules/dmq/doc/dmq.xml b/modules/dmq/doc/dmq.xml
index 7d9620a..f64c11b 100644
--- a/modules/dmq/doc/dmq.xml
+++ b/modules/dmq/doc/dmq.xml
@@ -21,18 +21,31 @@
 		<email>bucur_marius_ovidiu at yahoo.com</email>
 		</address>
 	    </author>
-	    <editor>
-		<firstname>Marius Ovidiu</firstname>
-		<surname>Bucur</surname>
-		<address>
-		    <email>bucur_marius_ovidiu at yahoo.com</email>
-		</address>
-	    </editor>
+            <author>
+                <firstname>Charles</firstname>
+                <surname>Chance</surname>
+		<affiliation>Sipcentric Ltd.</affiliation>
+            </author>
+            <editor>
+                <firstname>Marius Ovidiu</firstname>
+                <surname>Bucur</surname>
+                <address>
+                <email>bucur_marius_ovidiu at yahoo.com</email>
+                </address>
+            </editor>
+            <editor>
+                <firstname>Charles</firstname>
+                <surname>Chance</surname>
+            </editor>
 	</authorgroup>
 	<copyright>
 	    <year>2011</year>
 	    <holder>Marius Bucur</holder>
 	</copyright>
+        <copyright>
+            <year>2013</year>
+            <holder>Charles Chance, Sipcentric Ltd.</holder>
+        </copyright>
   </bookinfo>
     <toc></toc>
     
diff --git a/modules/dmq/doc/dmq_admin.xml b/modules/dmq/doc/dmq_admin.xml
index 9d6b440..957a463 100644
--- a/modules/dmq/doc/dmq_admin.xml
+++ b/modules/dmq/doc/dmq_admin.xml
@@ -14,12 +14,17 @@
 	
 	<section>
 	<title>Overview</title>
-	<para> The DMQ module implements a distributed message passing system on top of Kamailio.
-	The DMQ nodes within the system are grouped in a logical entity called DMQ bus and are able to
-	communicate with each others by sending/receiving messages (either by broadcast or sending a DMQ
-	message to a specific node).
-	The system transparently deals with node discovery, node consistency within the DMQ bus, retransmissions,
-	etc.
+	<para>
+	The DMQ module implements a distributed message queue on top of Kamailio in order to enable the 
+	passing/replication of data between multiple instances. The DMQ "nodes" within the system are grouped 
+	in a logical entity called the DMQ "bus" and are able to communicate with each other by 
+	sending/receiving messages (either by broadcast or directly to a specific node). The system 
+	transparently deals with node discovery, consistency, retransmissions, etc.
+	</para>
+	<para>
+	Other entities ("peers") are then able to utlize the DMQ bus to pass messages between themselves. 
+	Peers are grouped by name in order to ensure the correct messages are passed to the relevant peers. 
+	This grouping of peers can be compared to a topic in a typical pub/sub system.
 	</para>
 	
 	</section>
@@ -51,8 +56,8 @@
 			<listitem>
 			<para>
 				<emphasis>
-				Each peer needs to use its own serialization mechanism.
-				Some examples are libtpl, protobuf.
+				The DMQ module itself has no external dependencies. However, each peer will need 
+				to use its own (de)serialization mechanism. Some examples are libtpl, protobuf.
 				</emphasis>.
 			</para>
 			</listitem>
@@ -62,45 +67,146 @@
 	
 	<section>
 	<title>Parameters</title>
-	<section>
-		<title><varname>dmq_server_address</varname>(str)</title>
-		<para>
-		The local server address.
-		</para>
+	<section id="dmq.p.server_address">
+		<title><varname>server_address</varname>(str)</title>
 		<para>
-		The modules needs it to know on which interface the DMQ engine should send and receive messages.
+		The local server address. This is the interface over which the DMQ engine will send/receive messages.
 		</para>
 		<para>
-		<emphasis>Default value is <quote>NULL</quote>.	
-		</emphasis>
+		<emphasis>Default value is <quote>NULL</quote>.</emphasis>
 		</para>
 		<example>
-		<title>Set <varname>dmq_server_address</varname> parameter</title>
+		<title>Set <varname>server_address</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("dmq", "dmq_server_address", "&defaultdb;")
+modparam("dmq", "server_address", "sip:10.0.0.20:5060")
 ...
 </programlisting>
 		</example>
 	</section>
-	<section>
-		<title><varname>dmq_notification_address</varname>(str)</title>
+	<section id="dmq.p.notification_address">
+		<title><varname>notification_address</varname>(str)</title>
 		<para>
-		The address of the DMQ node from which the local node should retrieve initial information.
+		The address of another DMQ node from which the local node should retrieve initial information about all other nodes.
 		</para>
 		<para>
-		<emphasis>	Default value is <quote>NULL</quote>.
-		</emphasis>
+		<emphasis>Default value is <quote>NULL</quote>.</emphasis>
 		</para>
 		<example>
-		<title>Set <varname>dmq_notification_address</varname> parameter</title>
+		<title>Set <varname>notification_address</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("dmq", "dmq_notification_address", "&defaultdb;")
+modparam("dmq", "notification_address", "sip:10.0.0.21:5060")
 ...
 </programlisting>
 		</example>
 	</section>
+        <section id="dmq.p.num_workers">
+                <title><varname>num_workers</varname>(int)</title>
+                <para>
+                The number of worker threads for sending/receiving messages.
+                </para>
+                <para>
+                <emphasis>Default value is <quote>2</quote>.</emphasis>
+                </para>
+                <example>
+                <title>Set <varname>num_workers</varname> parameter</title>
+                <programlisting format="linespecific">
+...
+modparam("dmq", "num_threads", 4)
+...
+</programlisting>
+                </example>
+        </section>
+        <section id="dmq.p.ping_interval">
+                <title><varname>ping_interval</varname>(int)</title>
+                <para>
+                The number of seconds between node pings (for checking status of other nodes).
+                </para>
+                <para>
+                <emphasis>Minimum value is <quote>60</quote> (default).</emphasis>
+                </para>
+                <example>
+                <title>Set <varname>ping_interval</varname> parameter</title>
+                <programlisting format="linespecific">
+...
+modparam("dmq", "ping_interval", 90)
+...
+</programlisting>
+                </example>
+        </section>
+	</section>
+
+	<section>
+        <title>Functions</title>
+        <section id="dmq.f.dmq_handle_message">
+                <title>
+                <function moreinfo="none">dmq_handle_message()</function>
+                </title>
+                <para>
+                Handles a DMQ message by passing it to the appropriate local peer (module). 
+		The peer is identified by the user part of the To header.
+                </para>
+                <para>
+                This function can be used from REQUEST_ROUTE.
+                </para>
+
+                <example>
+                <title><function>dmq_handle_message</function> usage</title>
+                <programlisting format="linespecific">
+...
+        if(is_method("KDMQ"))
+        {
+                dmq_handle_message();
+        }
+...
+</programlisting>
+                </example>
+        </section>
+        <section id="dmq.f.dmq_send_message">
+                <title>
+               	<function moreinfo="none">dmq_send_message(peer, node, body, content_type)</function>
+                </title>
+                <para>
+                Sends a DMQ message directly from config file.
+                </para>
+		<para>Meaning of parameters:</para>
+                <itemizedlist>
+	                <listitem>
+        	                <para>
+               	        	<emphasis>peer</emphasis> - name of peer that should handle the message.
+                        	</para>
+	                </listitem>
+        	        <listitem>
+                	        <para>
+                       		<emphasis>node</emphasis> - the node to which the message should be sent.
+	                        </para>
+        	        </listitem>
+                	<listitem>
+                        	<para>
+	                        <emphasis>body</emphasis> - the message body.
+	                        </para>
+	                </listitem>
+                	<listitem>
+                        	<para>
+	                        <emphasis>content_type</emphasis> - the MIME type of the message body.
+	                        </para>
+	                </listitem>
+		</itemizedlist>
+                <para>
+                This function can be used from any route.
+                </para>
+
+                <example>
+                <title><function>dmq_send_message</function> usage</title>
+                <programlisting format="linespecific">
+...
+	dmq_send_message("peer_name", "sip:10.0.0.21:5060", "Message body...", "text/plain");
+...
+</programlisting>
+                </example>
+        </section>
 	</section>
+
 </chapter>
 
diff --git a/modules/dmq/doc/dmq_devel.xml b/modules/dmq/doc/dmq_devel.xml
index afa561b..b2216a3 100644
--- a/modules/dmq/doc/dmq_devel.xml
+++ b/modules/dmq/doc/dmq_devel.xml
@@ -10,23 +10,20 @@
 <!-- Module Developer's Guide -->
 
 <chapter>
-    <title>&develguide;</title>
-    <para>
-		The module provides the following functions that can be used
-		in other &kamailio; modules.
-   </para>
- 		<section>
-				<title>
-				<function moreinfo="none">dmq_load_api(dmq_api_t* api)</function>
-				</title>
-			<para>
-				This function binds the dmq modules and fills the structure 
-				with the exported functions
-				-> register_dmq_peer - registers an entity as a DMQ peer which permits receiving/sending
-				messages between nodes which support the same peer,
-				-> bcast_message - broadcast a DMQ message to all peers available in the DMQ bus,
-				-> send_message - sends a DMQ message to a specific peer in the local DMQ bus.
-			</para>
+	<title>&develguide;</title>
+	<para>
+	The module provides the following functions that can be used
+	in other &kamailio; modules.
+	</para>
+ 	<section>
+		<title>
+		<function moreinfo="none">dmq_load_api(dmq_api_t* api)</function>
+		</title>
+		<para>
+		This function binds the DMQ module and fills the structure 
+		with the exported functions below.
+		</para>
+
 		<example>
 		<title><function>dmq_api_t</function> structure</title>
 	<programlisting format="linespecific">
@@ -39,7 +36,65 @@ typedef struct dmq_api {
 ...
 </programlisting>
 		</example>
+	</section>
+
+        <section>
+                <title>
+                <function moreinfo="none">register_dmq_peer(dmq_peer_t* peer)</function>
+                </title>
+                <para>
+                Registers an entity as a DMQ peer which permits receiving/sending 
+                messages between nodes which support the same peer.
+                </para>
+
+                <example>
+                <title><function>register_dmq_peer</function> usage</title>
+                <programlisting format="linespecific">
+...
+	Example to follow.
+...
+</programlisting>
+                </example>
+        </section>
+
+        <section>
+                <title>
+                <function moreinfo="none">bcast_message(dmq_peer_t* peer, str* body, dmq_node_t* except,
+                dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type)</function>
+                </title>
+                <para>
+                Broadcast a DMQ message to all nodes in the DMQ bus excluding self, 
+		inactive nodes and "except" if specified.
+                </para>
+		
+                <example>
+                <title><function>bcast_message</function> usage</title>
+                <programlisting format="linespecific">
+...
+        Example to follow.
+...
+</programlisting>
+                </example>
+        </section>
+
+        <section>
+                <title>
+                <function moreinfo="none">send_message(dmq_peer_t* peer, str* body, dmq_node_t* node,
+                dmq_resp_cback_t* resp_cback, int max_forwards, str* content_type)</function>
+                </title>
+                <para>
+                Send a DMQ message to a single node.
+                </para>
+
+                <example>
+                <title><function>send_message</function> usage</title>
+                <programlisting format="linespecific">
+...
+        Example to follow.
+...
+</programlisting>
+                </example>
+        </section>
 
-		</section>
 </chapter>
 
diff --git a/modules/dmq/message.c b/modules/dmq/message.c
index a6ce2d4..a695fee 100644
--- a/modules/dmq/message.c
+++ b/modules/dmq/message.c
@@ -1,6 +1,3 @@
-#include "../../parser/parse_to.h"
-#include "../../parser/parse_uri.h"
-#include "../../sip_msg_clone.h"
 /*
  * $Id$
  *
@@ -27,6 +24,8 @@
  */
 
 
+#include "../../parser/parse_to.h"
+#include "../../parser/parse_uri.h"
 #include "../../parser/parse_content.h"
 #include "../../parser/parse_from.h"
 #include "../../ut.h"
@@ -46,8 +45,6 @@ str dmq_404_rpl  = str_init("User Not Found");
 int dmq_handle_message(struct sip_msg* msg, char* str1, char* str2)
 {
 	dmq_peer_t* peer;
-	struct sip_msg* cloned_msg = NULL;
-	int cloned_msg_len;
 	if ((parse_sip_msg_uri(msg) < 0) || (!msg->parsed_uri.user.s)) {
 			LM_ERR("error parsing msg uri\n");
 			goto error;
@@ -68,12 +65,7 @@ int dmq_handle_message(struct sip_msg* msg, char* str1, char* str2)
 		return 0;
 	}
 	LM_DBG("dmq_handle_message peer found: %.*s\n", msg->parsed_uri.user.len, msg->parsed_uri.user.s);
-	cloned_msg = sip_msg_shm_clone(msg, &cloned_msg_len, 1);
-	if(!cloned_msg) {
-		LM_ERR("error cloning sip message\n");
-		goto error;
-	}
-	if(add_dmq_job(cloned_msg, peer)<0) {
+	if(add_dmq_job(msg, peer)<0) {
 		LM_ERR("failed to add dmq job\n");
 		goto error;
 	}
diff --git a/modules/dmq/message.h b/modules/dmq/message.h
index 6763960..4e9dc3a 100644
--- a/modules/dmq/message.h
+++ b/modules/dmq/message.h
@@ -26,6 +26,6 @@
 #ifndef _MESSAGE_H_
 #define _MESSAGE_H_
 
-int dmq_handle_message(struct sip_msg*, char*, char*);
+int dmq_handle_message(struct sip_msg*, char* str1, char* str2);
 
 #endif
diff --git a/modules/dmq/notification_peer.c b/modules/dmq/notification_peer.c
index 3ea0239..fc35618 100644
--- a/modules/dmq/notification_peer.c
+++ b/modules/dmq/notification_peer.c
@@ -26,7 +26,7 @@
 
 #include "notification_peer.h"
 
-static str notification_content_type = str_init("text/plain");
+str notification_content_type = str_init("text/plain");
 dmq_resp_cback_t notification_callback = {&notification_resp_callback_f, 0};
 
 /**
@@ -162,11 +162,6 @@ int dmq_notification_callback(struct sip_msg* msg, peer_reponse_t* resp)
 	unsigned int maxforwards = 1;
 	/* received dmqnode list */
 	LM_DBG("dmq triggered from dmq_notification_callback\n");
-	/* parse the message headers */
-	if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
-		LM_ERR("error parsing message headers\n");
-		goto error;
-	}
 	
 	/* extract the maxforwards value, if any */
 	if(msg->maxforwards) {
@@ -191,7 +186,7 @@ int dmq_notification_callback(struct sip_msg* msg, peer_reponse_t* resp)
 	if(nodes_recv > 0 && maxforwards > 0) {
 		/* maxforwards is set to 0 so that the message is will not be in a spiral */
 		bcast_dmq_message(dmq_notification_peer, response_body, 0,
-				&notification_callback, maxforwards);
+				&notification_callback, maxforwards, &notification_content_type);
 	}
 	LM_DBG("broadcasted message\n");
 	pkg_free(response_body);
@@ -267,7 +262,7 @@ int request_nodelist(dmq_node_t* node, int forward)
 		return -1;
 	}
 	ret = dmq_send_message(dmq_notification_peer, body, node,
-			&notification_callback, forward);
+			&notification_callback, forward, &notification_content_type);
 	pkg_free(body->s);
 	pkg_free(body);
 	return ret;
diff --git a/modules/dmq/notification_peer.h b/modules/dmq/notification_peer.h
index a25371a..31f8422 100644
--- a/modules/dmq/notification_peer.h
+++ b/modules/dmq/notification_peer.h
@@ -33,6 +33,8 @@
 #include "peer.h"
 #include "dmq_funcs.h"
 
+extern str notification_content_type;
+
 int add_notification_peer();
 int dmq_notification_callback(struct sip_msg* msg, peer_reponse_t* resp);
 int extract_node_list(dmq_node_list_t* update_list, struct sip_msg* msg);
diff --git a/modules/dmq/worker.c b/modules/dmq/worker.c
index a265712..3965f5a 100644
--- a/modules/dmq/worker.c
+++ b/modules/dmq/worker.c
@@ -28,6 +28,7 @@
 #include "worker.h"
 #include "../../data_lump_rpl.h"
 #include "../../mod_fix.h"
+#include "../../sip_msg_clone.h"
 
 /**
  * @brief set the body of a response
@@ -131,17 +132,31 @@ void worker_loop(int id)
 int add_dmq_job(struct sip_msg* msg, dmq_peer_t* peer)
 {
 	int i, found_available = 0;
-	int ret;
 	dmq_job_t new_job = { 0 };
 	dmq_worker_t* worker;
+	struct sip_msg* cloned_msg = NULL;
+	int cloned_msg_len;
+
+	/* Pre-parse headers so they are included in our clone. Parsing later
+	 * will result in linking pkg structures to shm msg, eventually leading 
+	 * to memory errors. */
+	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
+		LM_ERR("failed to parse headers\n");
+		return -1;
+	}
+
+	cloned_msg = sip_msg_shm_clone(msg, &cloned_msg_len, 1);
+	if(!cloned_msg) {
+		LM_ERR("error cloning sip message\n");
+		return -1;
+	}
 
-	ret = 0;
 	new_job.f = peer->callback;
-	new_job.msg = msg;
+	new_job.msg = cloned_msg;
 	new_job.orig_peer = peer;
 	if(!num_workers) {
 		LM_ERR("error in add_dmq_job: no workers spawned\n");
-		return -1;
+		goto error;
 	}
 	/* initialize the worker with the first one */
 	worker = workers;
@@ -162,9 +177,16 @@ int add_dmq_job(struct sip_msg* msg, dmq_peer_t* peer)
 				" to the least busy one [%d %d]\n",
 				worker->pid, job_queue_size(worker->queue));
 	}
-	ret = job_queue_push(worker->queue, &new_job);
+	if (job_queue_push(worker->queue, &new_job)<0) {
+		goto error;
+	}
 	lock_release(&worker->lock);
-	return ret;
+	return 0;
+error:
+	if (cloned_msg!=NULL) {
+		shm_free(cloned_msg);
+	}
+	return -1;
 }
 
 /**
diff --git a/modules/dmq/worker.h b/modules/dmq/worker.h
index bda80b4..8d0e0b7 100644
--- a/modules/dmq/worker.h
+++ b/modules/dmq/worker.h
@@ -30,6 +30,7 @@
 #include "../../atomic_ops.h"
 #include "../../parser/msg_parser.h"
 
+
 typedef struct dmq_job {
 	peer_callback_t f;
 	struct sip_msg* msg;
diff --git a/modules/dnssec/Makefile b/modules/dnssec/Makefile
new file mode 100644
index 0000000..a5ae601
--- /dev/null
+++ b/modules/dnssec/Makefile
@@ -0,0 +1,17 @@
+# $Id$
+#
+# example module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=dnssec.so
+LIBS= -lval-threads -lcrypto -lsres -lpthread
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+include ../../Makefile.modules
diff --git a/modules/dnssec/README b/modules/dnssec/README
new file mode 100644
index 0000000..4ef2e0a
--- /dev/null
+++ b/modules/dnssec/README
@@ -0,0 +1,124 @@
+Dnssec Module
+
+Marius Zbihlei
+
+   Copyright � 2013
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. general_query_flags (integer)
+
+   List of Examples
+
+   1.1. Set enable_full_lr parameter
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. general_query_flags (integer)
+
+1. Overview
+
+   The module replaces the common system dns resolver functions from core
+   with the DNSSEC wrappers provided by libval. Practically, by loading
+   the module, Kamailio will make use of extensions to DNS which provide
+   origin authentication of DNS data, authenticated denial of existence,
+   and data integrity.
+
+   There is no module parameter that should be set nor fuction that has to
+   be executed by the configuration file. Existing SIP server deployments
+   can be updated to use DNSSEC by loading this module and setting
+   appropriate DNS server to the operating system.
+
+   Installing libval can be done from https://www.dnssec-tools.org.
+
+   More details about DNSSEC are available at:
+   http://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * No dependencies on other Kamailio modules.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * libval - check https://www.dnssec-tools.org for installation
+       guidelines.
+
+3. Parameters
+
+   3.1. general_query_flags (integer)
+
+3.1. general_query_flags (integer)
+
+   Set this parameter to an integer value containing of an ORed result of
+   one or more of the following values (constant present only for
+   documentation process, as they are mostly mapped to libval
+   flags).Setting this parameter will cause the libval defaults to be
+   completely overwritten
+
+   QUERY_DONT_VALIDATE == 1<<0 causes the validator to disable validation
+   for this query.
+
+   QUERY_IGNORE_SKEW == 1<<1 causes the validator to disable checking
+   signature inception and expiration times on RRSIGs.
+
+   QUERY_AC_DETAIL == 1<<2 causes the validator to copy the authentication
+   chain details into the val_rc_answer member within the returned
+   val_result_chain structure.
+
+   QUERY_NO_DLV == 1<<3 causes the validator to disable DLV processing for
+   this query. This is only available if the libval(3) library has been
+   compiled with DLV support.
+
+   QUERY_NO_EDNS0_FALLBACK = 1<<4 In querying various name servers,
+   libsres will also attempt multiple EDNS0 sizes, ending with a query
+   that has EDNS0 disabled (i.e. no CD bit set). This option causes libval
+   to disable EDNS0 fallback for the query.
+
+   QUERY_RECURSE == 1<<5 forces libval to recursively answer the query by
+   iteratively querying various name servers in the delegation hierarchy,
+   instead of requesting this information from any caching name server
+   that may be configured in dnsval.conf
+
+   SKIP_RESOLVER == 1<<6 forces libval to only look at its cache while
+   trying to resolve a name.
+
+   SKIP_CACHE == 1<<7 forces libval to ignore cached data while trying to
+   resolve a name.
+
+   Default value is 0(no changes)
+
+   Example 1.1. Set enable_full_lr parameter
+ ...
+ modparam("dnssec", "general_query_flags", 1) # QUERY_DONT_VALIDATE disable vali
+dation
+ modparam("dnssec", "general_query_flags", 10) # QUERY_IGNORE_SKEW | QUERY_NO_DLV
+ ...
diff --git a/modules/dnssec/dnssec_func.c b/modules/dnssec/dnssec_func.c
new file mode 100644
index 0000000..6da71ad
--- /dev/null
+++ b/modules/dnssec/dnssec_func.c
@@ -0,0 +1,150 @@
+/*
+ * $Id$
+ *
+ * DNSSEC module
+ *
+ * Copyright (C) 2013 mariuszbi at gmail.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ *  2013-03	initial implementation
+ */
+
+#include <validator/validator-config.h>
+#include <validator/validator.h>
+#include <validator/resolver.h>
+
+#include "../../dprint.h"
+#include "dnssec_func.h"
+
+static struct libval_context  *libval_ctx = NULL;
+static unsigned int context_flags = 0;
+
+
+unsigned int
+set_context_flags(unsigned int flags) {
+#define CHECK_AND_SET(flag) \
+	if ((flag & flags) != 0) {\
+			context_flags |= VAL_##flag;\
+			LOG(L_INFO, "setting param %s\n", #flag);\
+	}
+	unsigned int old_flags = context_flags;
+	context_flags = 0;
+
+	CHECK_AND_SET(QUERY_DONT_VALIDATE);
+	CHECK_AND_SET(QUERY_IGNORE_SKEW);
+	CHECK_AND_SET(QUERY_AC_DETAIL);
+	CHECK_AND_SET(QUERY_NO_DLV);  
+	CHECK_AND_SET(QUERY_NO_EDNS0_FALLBACK);
+	CHECK_AND_SET(QUERY_RECURSE);
+ 	CHECK_AND_SET(QUERY_SKIP_RESOLVER);
+ 	CHECK_AND_SET(QUERY_SKIP_CACHE);
+
+	return old_flags;
+}
+
+static inline int
+dnssec_init_context(void) {
+  	if (libval_ctx == NULL) {
+    	if (val_create_context(NULL, &libval_ctx) != VAL_NO_ERROR)
+	  		return -1;
+		if (context_flags != 0) {
+	  		val_context_setqflags(libval_ctx, VAL_CTX_FLAG_SET, context_flags);
+		}	
+  	}
+  	return 0;
+}
+
+struct hostent *
+dnssec_gethostbyname(const char *name) {
+  	val_status_t          val_status;
+  	struct hostent *      res;
+
+  	if (dnssec_init_context())
+    	return NULL;
+
+  	LOG(L_INFO, " gethostbyname(%s) called: wrapper\n", name);
+  
+  	res = val_gethostbyname(libval_ctx, name, &val_status);
+
+  	if (val_istrusted(val_status) && !val_does_not_exist(val_status)) {
+   		return res;
+  	} 
+  	return NULL; 
+}
+
+
+struct hostent *
+dnssec_gethostbyname2(const char *name, int family) {
+  	val_status_t          val_status;
+  	struct hostent *      res;
+
+  	if (dnssec_init_context())
+    	return NULL;
+
+  	LOG(L_INFO, " gethostbyname2(%s) called: wrapper\n", name);
+  
+  	res = val_gethostbyname2(libval_ctx, name, family,  &val_status);
+
+  	if (val_istrusted(val_status) && !val_does_not_exist(val_status)) {
+      	return res;
+  	}
+  	return NULL; 
+}
+
+int
+dnssec_res_init(void) {
+  	LOG(L_INFO, "res_init called: wrapper\n");
+
+  	return dnssec_init_context();
+}
+
+int
+dnssec_res_destroy(void) {
+	LOG(L_INFO, "destroying dnssec context\n");
+	val_free_context(libval_ctx);
+	libval_ctx = NULL;
+	return 0;
+}
+
+
+int
+dnssec_res_search(const char *dname, int class_h, int type_h, 
+	  unsigned char *answer, int anslen) {
+  	val_status_t          val_status;
+  	int ret;
+
+  	if (dnssec_init_context())
+    	return -1;
+
+  	LOG(L_INFO, "res_query(%s,%d,%d) called: wrapper\n",
+	  	dname, class_h, type_h);
+
+  	ret = val_res_search(libval_ctx, dname, class_h, type_h, answer, anslen,
+			&val_status);
+
+  	if (val_istrusted(val_status) && !val_does_not_exist(val_status)) {
+		return ret;
+  	} else {
+		LOG(L_INFO, "invalid domain %s reason %s\n", dname, p_val_status(val_status));
+	}
+
+ 	return -1;
+}
+
diff --git a/modules/dnssec/dnssec_func.h b/modules/dnssec/dnssec_func.h
new file mode 100644
index 0000000..b57347e
--- /dev/null
+++ b/modules/dnssec/dnssec_func.h
@@ -0,0 +1,54 @@
+/*
+ * $Id$
+ *
+ * DNSSEC module
+ *
+ * Copyright (C) 2013 mariuszbi at gmail.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ *  2013-03	initial implementation
+ */
+
+#ifndef DNSSEC_FUNC_H
+#define DNSSEC_FUNC_H
+
+struct hostent;
+
+typedef enum {
+	QUERY_DONT_VALIDATE = 1<<0,
+	QUERY_IGNORE_SKEW = 1<<1,
+	QUERY_AC_DETAIL = 1<<2,
+	QUERY_NO_DLV = 1<<3,
+	QUERY_NO_EDNS0_FALLBACK = 1<<4,
+	QUERY_RECURSE = 1<<5,
+	QUERY_SKIP_RESOLVER = 1<<6,
+	QUERY_SKIP_CACHE = 1<<7
+} query_flags_t;
+
+int dnssec_res_init(void);
+int dnssec_res_destroy(void);
+unsigned int set_context_flags(unsigned int flags);
+struct hostent* dnssec_gethostbyname(const char *);
+struct hostent* dnssec_gethostbyname2(const char *, int);
+int dnssec_res_search(const char*, int, int, unsigned char*, int);
+
+
+#endif // DNSSEC_FUNC_H
+
diff --git a/modules/dnssec/dnssec_mod.c b/modules/dnssec/dnssec_mod.c
new file mode 100644
index 0000000..6467246
--- /dev/null
+++ b/modules/dnssec/dnssec_mod.c
@@ -0,0 +1,135 @@
+/*
+ * $Id$
+ *
+ * DNSSEC module
+ *
+ * Copyright (C) 2013 mariuszbi at gmail.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ *  2013-03	initial implementation
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "../../sr_module.h"
+#include "../../error.h"
+#include "../../dprint.h"
+#include "../../ut.h"
+#include "../../dns_func.h"
+
+#include "dnssec_func.h"
+
+MODULE_VERSION
+
+
+static int dnssec_init(void);
+static int dnssec_exit(void);
+
+
+/* parameters */
+static unsigned int flags=0;
+
+/* global variables */
+gen_lock_t*             timer_lock=0;
+struct list_link*       timer = 0;
+
+
+static cmd_export_t cmds[]={
+	{0,0,0,0,0,0}
+};
+
+static param_export_t params[]={
+	{"general_query_flags", INT_PARAM, &flags},
+	{0,0,0}
+};
+
+
+static mi_export_t mi_cmds [] = {
+	{0,0,0,0,0}
+};
+
+
+struct module_exports exports= {
+	"dnssec",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,           /* exported statistics */
+	mi_cmds,     /* exported MI functions */
+	0,           /* exported pseudo-variables */
+	0,           /* extra processes */
+	dnssec_init,   /* module initialization function */
+	0,
+	(destroy_function) dnssec_exit,   /* module exit function */
+	0  /* per-child init function */
+};
+
+
+static int load_dns(void)
+{
+	struct dns_func_t *f = pkg_malloc(sizeof(struct dns_func_t));
+	if( NULL == f ) {
+		return -1;
+	}
+	memset(f, 0, sizeof(struct dns_func_t));
+	f->sr_res_init = dnssec_res_init;
+	f->sr_gethostbyname = dnssec_gethostbyname;
+	f->sr_gethostbyname2 = dnssec_gethostbyname2;
+	f->sr_res_search = dnssec_res_search;
+
+	load_dnsfunc(f);
+	return 0;
+}
+
+static int dnssec_init(void)
+{
+	LOG(L_INFO, "DNSSEC  - initializing\n");
+
+/*	if(register_mi_mod(exports.name, mi_cmds)!=0)
+	{
+		LM_ERR("failed to register MI commands\n");
+		return -1;
+	}
+*/
+	
+	//set parameters
+	if(flags) set_context_flags(flags);
+
+	if(load_dns() != 0) {
+		LM_ERR("loaded dnssec wrappers failed\n");
+	}
+	/* load dnssec resolver wrappers */
+	return 0;
+}
+
+
+
+static int dnssec_exit(void)
+{
+	(void)dnssec_res_destroy();
+	return 0;
+}
+
+
diff --git a/modules/dnssec/doc/Makefile b/modules/dnssec/doc/Makefile
new file mode 100644
index 0000000..093424d
--- /dev/null
+++ b/modules/dnssec/doc/Makefile
@@ -0,0 +1,3 @@
+docs = dnssec.xml
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/dnssec/doc/dnssec.xml b/modules/dnssec/doc/dnssec.xml
new file mode 100644
index 0000000..69c003e
--- /dev/null
+++ b/modules/dnssec/doc/dnssec.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>Dnssec Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+		<author>
+		<firstname>Marius</firstname>
+		<surname>Zbihlei</surname>
+		<affiliation><orgname></orgname></affiliation>
+		<address>
+			<email>mariuszbi at gmail.com</email>
+		</address>
+		</author>
+	</authorgroup>
+	<copyright>
+		<year>2013</year>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+	
+	<xi:include href="dnssec_admin.xml"/>
+	
+</book>
diff --git a/modules/dnssec/doc/dnssec_admin.xml b/modules/dnssec/doc/dnssec_admin.xml
new file mode 100644
index 0000000..47ae535
--- /dev/null
+++ b/modules/dnssec/doc/dnssec_admin.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		The module replaces the common system dns resolver functions from core
+		with the DNSSEC wrappers provided by libval. Practically, by loading
+		the module, &kamailio; will make use of extensions to DNS which provide
+		origin authentication of DNS data, authenticated denial of existence,
+		and data integrity.
+	</para>
+	<para>
+		There is no module parameter that should be set nor fuction that has to
+		be executed by the configuration file. Existing SIP server deployments
+		can be updated to use DNSSEC by loading this module and setting
+		appropriate DNS server to the operating system.
+	</para>
+	<para>
+		Installing libval can be done from
+		<ulink url="https://www.dnssec-tools.org/">https://www.dnssec-tools.org</ulink>.
+	</para>
+	<para>
+		More details about DNSSEC are available at:
+		<ulink url="http://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions">
+			http://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions</ulink>.
+	</para>
+	</section>
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>No dependencies on other &kamailio; modules</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before 
+		running &kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>libval</emphasis> - check
+				<ulink url="https://www.dnssec-tools.org/">https://www.dnssec-tools.org</ulink>
+				for installation guidelines.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+<section>
+     <title>Parameters</title>
+ 
+     <section>
+       <title><varname>general_query_flags</varname> (integer)</title>
+ 
+ 
+ 		<para> Set this parameter to an integer value containing of an ORed result of one or more of the following
+		values
+		(constant present only for documentation process, as they are mostly mapped to libval flags).Setting this
+		parameter will cause the libval defaults to be completely overwritten</para> 
+ 		<para>QUERY_DONT_VALIDATE == 1<<0
+		causes the validator to disable validation for this query.</para>
+
+		<para>QUERY_IGNORE_SKEW == 1<<1
+		causes the validator to disable checking signature inception and expiration times on RRSIGs.</para>
+
+		<para>QUERY_AC_DETAIL == 1<<2 
+		causes the validator to copy the authentication chain details into the val_rc_answer member within the returned val_result_chain structure.
+		</para>
+
+		<para>
+		QUERY_NO_DLV == 1<<3
+		causes the validator to disable DLV processing for this query. This is only available if the libval(3) library has been compiled with DLV support.
+		</para>
+		<para>
+		QUERY_NO_EDNS0_FALLBACK = 1<<4
+		In querying various name servers, libsres will also attempt multiple EDNS0 sizes, ending with a query that has EDNS0 disabled (i.e. no CD bit set). This option causes libval to disable EDNS0 fallback for the query.
+		</para>
+		<para>
+		QUERY_RECURSE == 1<<5
+		forces libval to recursively answer the query by iteratively querying various name servers in the delegation hierarchy, instead of requesting this information from any caching name server that may be configured in dnsval.conf
+		</para>
+		<para>
+		SKIP_RESOLVER == 1<<6
+		forces libval to only look at its cache while trying to resolve a name.
+		</para>
+		<para>
+		SKIP_CACHE == 1<<7
+		forces libval to ignore cached data while trying to resolve a name.
+		</para>
+       <para><emphasis> Default value is 0(no changes)</emphasis></para>
+ 
+       <example>
+         <title>Set <varname>enable_full_lr</varname> parameter</title>
+ 
+         <programlisting format="linespecific">
+ ...
+ modparam("dnssec", "general_query_flags", 1) # QUERY_DONT_VALIDATE disable validation  
+ modparam("dnssec", "general_query_flags", 10) # QUERY_IGNORE_SKEW | QUERY_NO_DLV
+ ...
+ </programlisting>
+       </example>
+     </section>
+	 </section>
+</chapter>
+
diff --git a/modules/domain/README b/modules/domain/README
index f921c27..18b45d7 100644
--- a/modules/domain/README
+++ b/modules/domain/README
@@ -402,7 +402,7 @@ Chapter 2. Developer Guide
 
    1.1. is_domain_local(domain)
 
-1.1. is_domain_local(domain)
+1.1.  is_domain_local(domain)
 
    Checks if domain given in str* parameter is local.
 
diff --git a/modules/domain/domain.c b/modules/domain/domain.c
index b13ff7f..1134941 100644
--- a/modules/domain/domain.c
+++ b/modules/domain/domain.c
@@ -142,7 +142,7 @@ int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2)
 	}
 	return hash_table_lookup(&(_msg->parsed_uri.host), &did, &attrs);
     } else if (is_route_type(FAILURE_ROUTE)) {
-	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0);
+	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0, 0, 0);
 	if (branch.s) {
 	    if (parse_uri(branch.s, branch.len, &puri) < 0) {
 		LM_ERR("error while parsing branch URI\n");
diff --git a/modules/domainpolicy/README b/modules/domainpolicy/README
index 89655cd..0c337f1 100644
--- a/modules/domainpolicy/README
+++ b/modules/domainpolicy/README
@@ -151,7 +151,7 @@ Chapter 1. Admin Guide
 
    This is URL of the database to be used.
 
-   Default value is "mysql://kamailio:kamailiorw@localhost/kamailio"
+   Default value is "mysql://openser:openserrw@localhost/openser"
 
    Example 1.1. Setting db_url parameter
 modparam("domainpolicy", "db_url", "postgres://proxy:frog23@db.sip-router.org/si
diff --git a/modules/drouting/README b/modules/drouting/README
index 040965d..2977033 100644
--- a/modules/drouting/README
+++ b/modules/drouting/README
@@ -10,7 +10,7 @@ Edited by
 
 Anca-Maria Vamanu
 
-   Copyright � 2005-2008 Voice Sistem SRL
+   Copyright © 2005-2008 Voice Sistem SRL
      __________________________________________________________________
 
    Table of Contents
@@ -234,7 +234,7 @@ Chapter 1. Admin Guide
 
 1.4.1. Gateway Addresses
 
-   Default name for the table storing gateway addresses is "dr_gateways".
+   Default name for the table storing gateway addresses is “dr_gateways”.
    Gateway addresses are stored in a separate table because of need to
    access them independent of Dynamic Routing processing (e.g., adding/
    removing gateway PRI prefix before/after performing other operation --
@@ -270,12 +270,12 @@ Chapter 1. Admin Guide
    group of destinations is delimited by semi-colon char. inside the whole
    destination list ( like: 2,4;5,78,23;4;7;2 ). The destinations from
    within a group may be act differently (like load-balancing, random
-   selection, etc), depending of the "sort_order" module parameter - more
+   selection, etc), depending of the “sort_order” module parameter - more
    about this is available under the module paramters section.
 
 1.4.3. Routing Rules
 
-   Default name for the table storing rule definitions is "dr_rules".
+   Default name for the table storing rule definitions is “dr_rules”.
 
    Table 1.3. Definition of dr_rules table
    Column name     Type     Default            Description
@@ -304,18 +304,18 @@ Chapter 1. Admin Guide
        draft 09):
        Table 1.4. Time recurrence attributes
 
-   Attribute Description
-   dastard Start of interval (RFC 2445 DATE-TIME)
-   duration Length of interval (RFC 2445 DURATION)
-   freq Frequency of recurrence (secondly,minutely,hourly, daily,weekly,
-   monthly, or yearly).
-   until bound of recurrence (RFC 2445 DATE-TIME)
-   interval How often the recurrence repeats
-   byday List of days of the week
-   bymonthday List of days of the month
-   byyearday List of days of the year
-   byweekno List of weeks of the year
-   bymonth List of months of the year
+     Attribute                            Description
+     dastard    Start of interval (RFC 2445 DATE-TIME)
+     duration   Length of interval (RFC 2445 DURATION)
+     freq       Frequency of recurrence (secondly,minutely,hourly, daily,weekly,
+                monthly, or yearly).
+     until      bound of recurrence (RFC 2445 DATE-TIME)
+     interval   How often the recurrence repeats
+     byday      List of days of the week
+     bymonthday List of days of the month
+     byyearday  List of days of the year
+     byweekno   List of weeks of the year
+     bymonth    List of months of the year
        The value stored in database has the format of:
        <dtstart>|<duration>|<freq>|<until>|<interval>|<byday>|<bymonthday>
        |<byyearday>|<byweekno>|<bymonth>
@@ -325,48 +325,48 @@ Chapter 1. Admin Guide
        Detailed description of time recurrence attributes:
           + dtstart - specifies the beginning of the first period.
           + duration - specifies the duration of the period. For a
-            recurring interval, the "duration" parameter MUST be small
+            recurring interval, the “duration” parameter MUST be small
             enough such that subsequent intervals do not overlap. For
             non-recurring intervals, durations of any positive length are
-            permitted, zero-length duration means "forever".
+            permitted, zero-length duration means “forever”.
             Negative-length durations are not allowed.
-          + freq - takes one of the following values: "daily", to specify
+          + freq - takes one of the following values: “daily”, to specify
             repeating periods based on an interval of a day or more;
-            "weekly", to specify repeating periods based on an interval of
-            a week or more; "monthly", to specify repeating periods based
-            on an interval of a month or more; and "yearly", to specify
+            “weekly”, to specify repeating periods based on an interval of
+            a week or more; “monthly”, to specify repeating periods based
+            on an interval of a month or more; and “yearly”, to specify
             repeating periods based on an interval of a year or more.
             These values are not case-sensitive.
           + until - defines an iCalendar COS DATE or DATE-TIME value which
             bounds the recurrence rule in an inclusive manner. If the
-            value specified by "until" is synchronized with the specified
+            value specified by “until” is synchronized with the specified
             recurrence, this date or date-time becomes the last instance
             of the recurrence. If not present, the recurrence is
             considered to repeat forever.
           + interval - contains a positive integer representing how often
-            the recurrence rule repeats. The default value is "1", meaning
-            every day for a "daily" rule, every week for a "weekly" rule,
-            every month for a "monthly" rule and every year for a "yearly"
+            the recurrence rule repeats. The default value is “1”, meaning
+            every day for a “daily” rule, every week for a “weekly” rule,
+            every month for a “monthly” rule and every year for a “yearly”
             rule.
           + interval - contains a positive integer representing how often
-            the recurrence rule repeats. The default value is "1", meaning
-            every day for a "daily" rule, every week for a "weekly" rule,
-            every month for a "monthly" rule and every year for a "yearly"
+            the recurrence rule repeats. The default value is “1”, meaning
+            every day for a “daily” rule, every week for a “weekly” rule,
+            every month for a “monthly” rule and every year for a “yearly”
             rule.
           + byday - specifies a comma-separated list of days of the week.
-            "MO" indicates Monday; "TU" indicates Tuesday; "WE" indicates
-            Wednesday; "TH" indicates Thursday; "FR" indicates Friday;
-            "SA" indicates Saturday; "SU" indicates Sunday. These values
+            “MO” indicates Monday; “TU” indicates Tuesday; “WE” indicates
+            Wednesday; “TH” indicates Thursday; “FR” indicates Friday;
+            “SA” indicates Saturday; “SU” indicates Sunday. These values
             are not case-sensitive.
-            Each "byday" value can also be preceded by a positive (+n) or
+            Each “byday” value can also be preceded by a positive (+n) or
             negative (-n) integer. If present, this indicates the nth
-            occurrence of the specific day within the "monthly" or
-            "yearly" recurrence. For example, within a "monthly" rule,
+            occurrence of the specific day within the “monthly” or
+            “yearly” recurrence. For example, within a “monthly” rule,
             +1MO (or simply 1MO) represents the first Monday within the
             month, whereas -1MO represents the last Monday of the month.
             If an integer modifier is not present, it means all days of
             this type within the specified frequency. For example, within
-            a "monthly" rule, MO represents all Mondays within the month.
+            a “monthly” rule, MO represents all Mondays within the month.
           + bymonthday - parameter specifies a comma-separated list of
             days of the month. Valid values are 1 to 31 or -31 to -1. For
             example, -10 represents the tenth to the last day of the
@@ -380,37 +380,37 @@ Chapter 1. Admin Guide
             to -1.
           + bymonth - parameter specifies a comma-separated list of months
             of the year. Valid values are 1 to 12.
-       A recurrence is specified by including the "freq" parameter, which
+       A recurrence is specified by including the “freq” parameter, which
        indicates the type of recurrence rule. Parameters other than
-       "dtstart" and "duration" SHOULD NOT be specified unless "freq" is
+       “dtstart” and “duration” SHOULD NOT be specified unless “freq” is
        present.
        If byxxx parameter values are found which are beyond the available
-       scope (ie, bymonthday="30" in February), they are simply ignored.
+       scope (ie, bymonthday=“30” in February), they are simply ignored.
        Byxxx parameters modify the recurrence in some manner. Byxxx rule
        parts for a period of time which is the same or greater than the
        frequency generally reduce or limit the number of occurrences of
-       the recurrence generated. For example, freq="daily" bymonth="1"
+       the recurrence generated. For example, freq=“daily” bymonth=“1”
        reduces the number of recurrence instances from all days (if the
-       "bymonth" parameter is not present) to all days in January. Byxxx
+       “bymonth” parameter is not present) to all days in January. Byxxx
        parameters for a period of time less than the frequency generally
        increase or expand the number of occurrences of the recurrence. For
-       example, freq="yearly" bymonth="1,2" increases the number of days
-       within the yearly recurrence set from 1 (if "bymonth" parameter is
+       example, freq=“yearly” bymonth=“1,2” increases the number of days
+       within the yearly recurrence set from 1 (if “bymonth” parameter is
        not present) to 2.
        If multiple Byxxx parameters are specified, then after evaluating
-       the specified "freq" and "interval" parameters, the Byxxx
+       the specified “freq” and “interval” parameters, the Byxxx
        parameters are applied to the current set of evaluated occurrences
-       in the following order: "bymonth", "byweekno", "byyearday",
-       "bymonthday", "byday"; then "until" is evaluated.
+       in the following order: “bymonth”, “byweekno”, “byyearday”,
+       “bymonthday”, “byday”; then “until” is evaluated.
        Here is an example of evaluating multiple Byxxx parameters.
-       dtstart="19970105T083000" duration="10M" freq="yearly" interval="2"
-       bymonth="1" byday="SU"
-       First, the interval="2" would be applied to freq="yearly" to arrive
-       at "every other year" . Then, bymonth="1" would be applied to
-       arrive at "every January, every other year". Then, byday="SU" would
-       be applied to arrive at "every Sunday in January, every other year,
-       from 8:30 to 8:40 ". The appropriate minutes and hours have been
-       retrieved from the "dtstart" and "duration" parameters.
+       dtstart=“19970105T083000” duration=“10M” freq=“yearly” interval=“2”
+       bymonth=“1” byday=“SU”
+       First, the interval=“2” would be applied to freq=“yearly” to arrive
+       at “every other year” . Then, bymonth=“1” would be applied to
+       arrive at “every January, every other year”. Then, byday=“SU” would
+       be applied to arrive at “every Sunday in January, every other year,
+       from 8:30 to 8:40 ”. The appropriate minutes and hours have been
+       retrieved from the “dtstart” and “duration” parameters.
     d. priority column
        If many rules are eligible, choose the one with highest priority.
     e. routeid column
@@ -420,8 +420,8 @@ Chapter 1. Admin Guide
        level.
     f. gwlist column
        A comma separated list of gateway identifiers corresponding to a
-       row in table "dr_gateways". You can use a predefined list from the
-       table "dr_gw_lists" preceded by the character "#". The first
+       row in table “dr_gateways”. You can use a predefined list from the
+       table “dr_gw_lists” preceded by the character “#”. The first
        gateway is tried first and if routing to it fails, then the second
        one, and so one. If no gateway is left a negative response is sent
        back to caller.
@@ -433,7 +433,7 @@ Chapter 1. Admin Guide
    2 8 0049 20040101T083000 0 0 1,2 Rule 2
    3 7,8,9 0049 20040101T083000 0 0 3 Rule 3
        (The time recurrence for first rule is:
-       "20040101T083000|10H|weekly|||MO,TU,WE,TH,FR")
+       “20040101T083000|10H|weekly|||MO,TU,WE,TH,FR”)
 
 1.5. Routing Rule Processing
 
@@ -501,7 +501,7 @@ Chapter 1. Admin Guide
 
    The database url.
 
-   Default value is "NULL".
+   Default value is “NULL”.
 
    Example 1.1. Set db_url parameter
 ...
@@ -513,7 +513,7 @@ modparam("drouting", "db_url",
 
    The name of the db table storing gateway addresses.
 
-   Default value is "dr_gateways".
+   Default value is “dr_gateways”.
 
    Example 1.2. Set drd_table parameter
 ...
@@ -524,7 +524,7 @@ modparam("drouting", "drd_table", "dr_gateways")
 
    The name of the db table storing routing rules.
 
-   Default value is "dr_rules".
+   Default value is “dr_rules”.
 
    Example 1.3. Set drr_table parameter
 ...
@@ -535,7 +535,7 @@ modparam("drouting", "drr_table", "rules")
 
    The name of the db table storing groups.
 
-   Default value is "dr_groups".
+   Default value is “dr_groups”.
 
    Example 1.4. Set drg_table parameter
 ...
@@ -550,7 +550,7 @@ modparam("drouting", "drg_table", "groups")
    individual elements. Very useful to reuse a list of gateways in
    different places.
 
-   Default value is "dr_gw_lists".
+   Default value is “dr_gw_lists”.
 
    Example 1.5. Set drl_table parameter
 ...
@@ -570,11 +570,18 @@ modparam("drouting", "drl_table", "my_gw_lists")
        destinations). Ex: 1,2;3,4,5;6 -> randomizer -> (A) 2,1;4,3,5;6 ->
        usage 2,1,4,3,5,6 (B) 1,2;3,5,4;6 -> usage 1,2,3,5,4,6
      * 2 - from each destination group, only a single destination is
-       randomly selected; groups do maintain their order (as given); Ex:
-       1,2;3,4,5;6 -> randomizer -> (A) 2;4;6 -> usage 2,4,6 (B) 1;5;6 ->
-       usage 1,5,6
-
-   Default value is "0".
+       randomly selected; groups do maintain their order (as given);
+       Ex: 1,2;3,4,5;6 -> randomizer ->
+       (A) 2;4;6 -> usage 2,4,6
+       (B) 1;5;6 -> usage 1,5,6
+       It is ok to have repeating gateways in different groups. The module
+       will take care internally in case of failure not to choose a
+       gateway that was tried already.
+       Ex: 1,2,3; 1,2,3; 1,2,3 -> no gateway will be choosen twice. So in
+       case there are 2 failures, all the three gateways (1,2,3) will be
+       tried in a random order.
+
+   Default value is “0”.
 
    Example 1.6. Set sort_order parameter
 ...
@@ -586,7 +593,7 @@ modparam("drouting", "sort_order", 2)
    The name of the avp for storing Request URIs to be later used
    (alternative destiantions for the current one).
 
-   Default value is "NULL".
+   Default value is “NULL”.
 
    Example 1.7. Set ruri_avp parameter
 ...
@@ -601,7 +608,7 @@ modparam("drouting", "ruri_avp", '$avp(i:33)')
    function), the AVP will be updated with the attrs of the new used
    destination.
 
-   Default value is "NULL".
+   Default value is “NULL”.
 
    Example 1.8. Set attrs_avp parameter
 ...
@@ -614,7 +621,7 @@ modparam("drouting", "atrrs_avp", '$avp(i:67)')
    Flag to configure whether to use domain match when querying database
    for user's routing group.
 
-   Default value is "1".
+   Default value is “1”.
 
    Example 1.9. Set use_domain parameter
 ...
@@ -625,7 +632,7 @@ modparam("drouting", "use_domain", 0)
 
    The name of the column in group db table where the username is stored.
 
-   Default value is "username".
+   Default value is “username”.
 
    Example 1.10. Set drg_user_col parameter
 ...
@@ -636,7 +643,7 @@ modparam("drouting", "drg_user_col", "user")
 
    The name of the column in group db table where the domain is stored.
 
-   Default value is "domain".
+   Default value is “domain”.
 
    Example 1.11. Set drg_domain_col parameter
 ...
@@ -647,7 +654,7 @@ modparam("drouting", "drg_domain_col", "host")
 
    The name of the column in group db table where the group id is stored.
 
-   Default value is "groupid".
+   Default value is “groupid”.
 
    Example 1.12. Set drg_grpid_col parameter
 ...
@@ -659,7 +666,7 @@ modparam("drouting", "drg_grpid_col", "grpid")
    The number of rows that should be fetched from the result of a query in
    rules db table.
 
-   Default value is "2000".
+   Default value is “2000”.
 
    Example 1.13. Set fetch_rows parameter
 ...
@@ -672,7 +679,7 @@ modparam("drouting", "fetch_rows", 1500)
    startup. If not enabled, the GW name will be blindly used during
    routing.
 
-   Default value is "1 (enabled)".
+   Default value is “1 (enabled)”.
 
    Example 1.14. Set force_dns parameter
 ...
@@ -687,7 +694,7 @@ modparam("drouting", "force_dns", 0)
    4.4. is_from_gw([type])
    4.5. is_from_gw( type, [flag])
 
-4.1. do_routing("[groupID]")
+4.1.  do_routing("[groupID]")
 
    Function to trigger routing of the message according to the rules in
    the database table and the configured parameters.
@@ -707,7 +714,7 @@ do_routing("0");
 ...
 do_routing("$avp(i:10)");
 
-4.2. use_next_gw()/next_routing()
+4.2.  use_next_gw()/next_routing()
 
    The function takes the next available destination (set by do_routing,
    as alternative destinations) and push it into RURI. Note that the
@@ -730,7 +737,7 @@ if (use_next_gw()) {
 }
 ...
 
-4.3. goes_to_gw([type])
+4.3.  goes_to_gw([type])
 
    Function returns true if the destination of the current request
    (destination URI or Request URI) points (as IP) to one of the gateways.
@@ -751,7 +758,7 @@ if (goes_to_gw("1")) {
 }
 ...
 
-4.4. is_from_gw([type])
+4.4.  is_from_gw([type])
 
    The function checks if the sender of the message is a gateway from a
    certain group.
@@ -770,7 +777,7 @@ if (is_from_gw("1") {
 }
 ...
 
-4.5. is_from_gw( type, [flag])
+4.5.  is_from_gw( type, [flag])
 
    The function checks if the sender of the message is a gateway from a
    certain group.
@@ -792,7 +799,7 @@ if (is_from_gw("3","1") {
 
    5.1. drouting.reload
 
-5.1. drouting.reload
+5.1.  drouting.reload
 
    Command to reload routing rules from database.
 
diff --git a/modules/drouting/doc/drouting_admin.xml b/modules/drouting/doc/drouting_admin.xml
index 3dbcdd9..7bde362 100644
--- a/modules/drouting/doc/drouting_admin.xml
+++ b/modules/drouting/doc/drouting_admin.xml
@@ -942,9 +942,24 @@ modparam("drouting", "drl_table", "my_gw_lists")
 			<emphasis>2</emphasis> - from each destination group, only a 
 			single destination is randomly selected; groups do maintain their
 			order (as given);
+			<para>
 			Ex: 1,2;3,4,5;6 -> randomizer ->
+			</para>
+			<para>
 			(A) 2;4;6  -> usage 2,4,6
+			</para>
+			<para>
 			(B) 1;5;6  -> usage 1,5,6
+			</para>
+			<para>
+			It is ok to have repeating gateways in different groups. The module will
+			take care internally in case of failure not to choose a gateway that
+			was tried already.
+			</para>
+			<para>
+			Ex: 1,2,3; 1,2,3; 1,2,3 -> no gateway will be choosen twice. So in case there
+			are 2 failures, all the three gateways (1,2,3) will be tried in a random order.
+			</para>
 		</listitem>
 		</itemizedlist>
 		</para>
diff --git a/modules/drouting/drouting.c b/modules/drouting/drouting.c
index 43fd73e..60006b1 100644
--- a/modules/drouting/drouting.c
+++ b/modules/drouting/drouting.c
@@ -646,6 +646,20 @@ static int use_next_gw(struct sip_msg* msg)
 	return 1;
 }
 
+int dr_already_choosen(rt_info_t* rt_info, int* local_gwlist, int lgw_size, int check)
+{
+	int l;
+
+	for ( l = 0; l<lgw_size; l++ ) {
+		if ( rt_info->pgwl[local_gwlist[l]].pgw == rt_info->pgwl[check].pgw ) {
+			LM_INFO("Gateway already choosen %.*s, local_gwlist[%d]=%d, %d\n",
+					rt_info->pgwl[check].pgw->ip.len, rt_info->pgwl[check].pgw->ip.s, l, local_gwlist[l], check);
+			return 1;
+		}
+	}
+
+	return 0;
+}
 
 static int do_routing(struct sip_msg* msg, dr_group_t *drg)
 {
@@ -806,6 +820,30 @@ again:
 					}
 				}
 			}
+
+			if ( sort_order == 2 ) {
+				/* check not to use the same gateway as before */
+				if ( t>1 ) {
+					/* check if all in the current set were already chosen */
+					if (i-j <= t-1) {
+						for( l = j; l< i; l++) {
+							if ( ! dr_already_choosen(rt_info, local_gwlist, t-1, l) )
+								break;
+						}
+						if ( l == i ) {
+							LM_INFO("All gateways in group from %d - %d were already used\n", j, i);
+							t--; /* jump over this group, nothing to choose here */
+							j=i; continue;
+						}
+					}
+					while ( dr_already_choosen(rt_info, local_gwlist, t-1, local_gwlist[t-1]) ) {
+						local_gwlist[t-1]   = j + rand()%(i-j);
+					}
+				}
+				LM_DBG("The %d gateway is %.*s [%d]\n", t, rt_info->pgwl[local_gwlist[t-1]].pgw->ip.len,
+						rt_info->pgwl[local_gwlist[t-1]].pgw->ip.s, local_gwlist[t-1]);
+			}
+
 			/* next group starts from i */
 			j=i;
 		}
@@ -1070,9 +1108,7 @@ static int goes_to_gw_1(struct sip_msg* msg, char* _type, char* _f2)
 	}
 
 	if ( ((ip=str2ip(&puri.host))!=0)
-#ifdef USE_IPV6
 	|| ((ip=str2ip6(&puri.host))!=0)
-#endif
 	){
 		pgwa = (*rdata)->pgw_addr_l;
 		while(pgwa) {
diff --git a/modules/enum/enum.c b/modules/enum/enum.c
index 771eafb..177669a 100644
--- a/modules/enum/enum.c
+++ b/modules/enum/enum.c
@@ -256,7 +256,7 @@ static inline int is_e164(str* _user)
 	int i;
 	char c;
 	
-	if ((_user->len > 2) && (_user->len < 17) && ((_user->s)[0] == '+')) {
+	if ((_user->len > 2) && (_user->len < MAX_NUM_LEN) && ((_user->s)[0] == '+')) {
 		for (i = 1; i < _user->len; i++) {
 			c = (_user->s)[i];
 			if ((c < '0') || (c > '9')) return -1;
@@ -309,7 +309,7 @@ int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service)
 	struct naptr_rdata* naptr;
 
 	str pattern, replacement, result;
-	char string[17];
+	char string[MAX_NUM_LEN];
 
 	if (parse_from_header(_msg) < 0) {
 	    LM_ERR("Failed to parse From header\n");
@@ -687,7 +687,7 @@ int do_query(struct sip_msg* _msg, char *user, char *name, str *service) {
 		q = q - 10;
 		curr_prio = priority;
 	    }
-	    if (append_branch(_msg, &result, 0, 0, q, 0, 0, 0, 0) == -1) {
+	    if (append_branch(_msg, &result, 0, 0, q, 0, 0, 0, 0, 0, 0) == -1) {
 		goto done;
 	    }
 	}
@@ -754,7 +754,7 @@ int enum_query(struct sip_msg* _msg, str* suffix, str* service)
 	char *user_s;
 	int user_len, i, j;
 	char name[MAX_DOMAIN_SIZE];
-	char string[17];
+	char string[MAX_NUM_LEN];
 
 	LM_DBG("enum_query on suffix <%.*s> service <%.*s>\n",
 	       suffix->len, suffix->s, service->len, service->s);
@@ -818,7 +818,7 @@ int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
 	int cc_len;
 	struct rdata* head;
 
-	char string[17];
+	char string[MAX_NUM_LEN];
 
 	str *suffix, *service;
 
@@ -1137,7 +1137,7 @@ int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix,
 				q = q - 10;
 				curr_prio = priority;
 			}
-			if (append_branch(_msg, &result, 0, 0, q, 0, 0, 0, 0)
+			if (append_branch(_msg, &result, 0, 0, q, 0, 0, 0, 0, 0, 0)
 			    == -1) {
 				goto done;
 			}
diff --git a/modules/enum/enum.h b/modules/enum/enum.h
index 2dffce0..d3d5e2a 100644
--- a/modules/enum/enum.h
+++ b/modules/enum/enum.h
@@ -37,8 +37,9 @@
 
 
 #define MAX_DOMAIN_SIZE 256
-#define MAX_COMPONENT_SIZE 32  /* separator, apex, ... This simplifies checks */
-		
+#define MAX_NUM_LEN 22
+#define MAX_COMPONENT_SIZE (MAX_NUM_LEN * 2)  /* separator, apex, ... This simplifies checks */
+
 
 /*
  * Check if from user is an e164 number and has a naptr record
diff --git a/modules/exec/exec.c b/modules/exec/exec.c
index a97f471..9e2e464 100644
--- a/modules/exec/exec.c
+++ b/modules/exec/exec.c
@@ -168,7 +168,7 @@ int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len) {
 			}
 		} else {
 		    if (append_branch(msg, &uri, 0, 0, Q_UNSPECIFIED, 0, 0,
-				      0, 0) == -1) {
+				      0, 0, 0, 0) == -1) {
 				LM_ERR("append_branch failed; too many or too long URIs?\n");
 				goto error02;
 			}
diff --git a/modules/group/README b/modules/group/README
index 84060f4..c0a27b1 100644
--- a/modules/group/README
+++ b/modules/group/README
@@ -56,7 +56,7 @@ Jan Janak
    1.5. Set group_column parameter
    1.6. Set use_domain parameter
    1.7. Set re_table parameter
-   1.8. Set reg_exp_column parameter
+   1.8. Set re_exp_column parameter
    1.9. Set re_gid_column parameter
    1.10. Set multiple_gid parameter
    1.11. is_user_in usage
@@ -108,7 +108,8 @@ Chapter 1. Admin Guide
    groups they belong to. The module provides the possibility to check if
    a specific user belongs to a specific group.
 
-   There is no DB caching support, each check involving a DB query.
+   There is no DB caching support, which means that each check involves a
+   DB query.
 
 1.2. Regular Expression based checking
 
@@ -129,7 +130,7 @@ Chapter 1. Admin Guide
 2.1. Kamailio Modules
 
    The following modules must be loaded before this module:
-     * A database module, like mysql, postgres or dbtext
+     * A database module, like db_mysql, db_postgres or db_text
 
 2.2. External Libraries or Applications
 
@@ -239,9 +240,9 @@ modparam("group", "re_table", "re_grp")
 
    Default value is "reg_exp".
 
-   Example 1.8. Set reg_exp_column parameter
+   Example 1.8. Set re_exp_column parameter
 ...
-modparam("group", "reg_exp_column", "re")
+modparam("group", "re_exp_column", "re")
 ...
 
 3.9. re_gid_column (string)
diff --git a/modules/group/doc/group_admin.xml b/modules/group/doc/group_admin.xml
index 7fd83fd..cc4177f 100644
--- a/modules/group/doc/group_admin.xml
+++ b/modules/group/doc/group_admin.xml
@@ -27,7 +27,7 @@
 			specific user belongs to a specific group.
 			</para>
 			<para>
-			There is no DB caching support, each check involving a DB query.
+			There is no DB caching support, which means that each check involves a DB query.
 			</para>
 		</section>
 		<section>
@@ -55,7 +55,7 @@
 			<itemizedlist>
 			<listitem>
 			<para>
-				A database module, like mysql, postgres or dbtext
+				A database module, like db_mysql, db_postgres or db_text
 			</para>
 			</listitem>
 			</itemizedlist>
@@ -79,7 +79,7 @@
 
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="group.p.db_url">
 		<title><varname>db_url</varname> (string)</title>
 		<para>
 		&url; of the database table to be used.
@@ -100,7 +100,7 @@ modparam("group", "db_url", "&exampledb;")
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.table">
 		<title><varname>table</varname> (string)</title>
 		<para>
 		Name of the table holding strict definitions of groups and 
@@ -121,7 +121,7 @@ modparam("group", "table", "grp_table")
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.user_column">
 		<title><varname>user_column</varname> (string)</title>
 		<para>
 		Name of the <quote>table</quote> column holding usernames.
@@ -141,7 +141,7 @@ modparam("group", "user_column", "user")
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.domain_column">
 		<title><varname>domain_column</varname> (string)</title>
 		<para>
 		Name of the <quote>table</quote> column holding domains.
@@ -161,7 +161,7 @@ modparam("group", "domain_column", "realm")
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.group_column">
 		<title><varname>group_column</varname> (string)</title>
 		<para>
 		Name of the <quote>table</quote> column holding group names.
@@ -181,7 +181,7 @@ modparam("group", "group_column", "grp")
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.use_domain">
 		<title><varname>use_domain</varname> (integer)</title>
 		<para>
 		If enabled (set to a non zero value) then the domain will be used also used
@@ -203,7 +203,7 @@ modparam("group", "use_domain", 1)
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.re_table">
 		<title><varname>re_table</varname> (string)</title>
 		<para>
 		Name of the table holding definitions for regular-expression 
@@ -225,7 +225,7 @@ modparam("group", "re_table", "re_grp")
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.re_exp_column">
 		<title><varname>re_exp_column</varname> (string)</title>
 		<para>
 		Name of the <quote>re_table</quote> column holding the regular
@@ -237,10 +237,10 @@ modparam("group", "re_table", "re_grp")
 		</emphasis>
 		</para>
 		<example>
-		<title>Set <varname>reg_exp_column</varname> parameter</title>
+		<title>Set <varname>re_exp_column</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("group", "reg_exp_column", "re")
+modparam("group", "re_exp_column", "re")
 ...
 </programlisting>
 		</example>
@@ -266,7 +266,7 @@ modparam("group", "re_gid_column", "grp_id")
 		</example>
 	</section>
 
-	<section>
+	<section id="group.p.multiple_gid">
 		<title><varname>multiple_gid</varname> (integer)</title>
 		<para>
 		If enabled (non zero value) the regular-expression matching will
@@ -291,7 +291,7 @@ modparam("group", "multiple_gid", 0)
 
 	<section>
 	<title>Functions</title>
-	<section>
+	<section id="group.f.is_user_in">
 		<title>
 		<function moreinfo="none">is_user_in(URI, group)</function>
 		</title>
@@ -346,7 +346,7 @@ if (is_user_in("Request-URI", "ld")) {
 		</example>
 	</section>
 
-	<section>
+	<section id="group.f.get_user_group">
 		<title>
 		<function moreinfo="none">get_user_group(URI, AVP)</function>
 		</title>
diff --git a/modules/gzcompress/Makefile b/modules/gzcompress/Makefile
new file mode 100644
index 0000000..aa24a3f
--- /dev/null
+++ b/modules/gzcompress/Makefile
@@ -0,0 +1,25 @@
+#
+# gzcompress module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=gzcompress.so
+
+ifeq ($(CROSS_COMPILE),)
+	BUILDER = $(shell which pkg-config)
+endif
+
+ifneq ($(BUILDER),)
+	DEFS += $(shell $(BUILDER) --cflags zlib)
+	LIBS += $(shell $(BUILDER) --libs zlib)
+else
+	DEFS += -I$(LOCALBASE)/include
+	LIBS += -L$(LOCALBASE)/lib -lz
+endif
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+include ../../Makefile.modules
diff --git a/modules/gzcompress/README b/modules/gzcompress/README
new file mode 100644
index 0000000..bfd9412
--- /dev/null
+++ b/modules/gzcompress/README
@@ -0,0 +1,220 @@
+GZCompress Module
+
+Daniel-Constantin Mierla
+
+   <miconda at gmail.com>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <miconda at gmail.com>
+
+   Copyright � 2013 asipto.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. header_name (str)
+              3.2. header_value (str)
+              3.3. sanity_checks (integer)
+
+        4. Functions
+        5. Config File
+
+   List of Examples
+
+   1.1. Set header_name parameter
+   1.2. Set header_value parameter
+   1.3. Set sanity_checks parameter
+   1.4. Enable body compression
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. header_name (str)
+        3.2. header_value (str)
+        3.3. sanity_checks (integer)
+
+   4. Functions
+   5. Config File
+
+1. Overview
+
+   This module is able to detect compressed body in received SIP message
+   and decompress it as well as compress the body for outgoing SIP
+   message. It works also for received HTTP request and replied HTTP
+   response (Kamailio cannot work in HTTP proxy mode).
+
+   The decision of whether to do compression or decompression is made by
+   detecting a special SIP header (default 'Content-Encoding') that
+   matches a given value - both header name and value can be set via
+   module parameters. If a SIP message is received with clear body and you
+   want to compress the body for outgoing, add the header in config file.
+   The header can be added to the local generated replies as well.
+
+   In other words, if the header is present in incoming SIP message, its
+   body is decompressed. If the header is present in outgoing SIP message,
+   its body is compressed. Therefore inside configuration file, the body
+   is in original format(e.g., plain text). In this way, the existing
+   functions to handle content of the body work as usual (e.g., to strip
+   codecs in sdp via sdpops or do substitutions via textops).
+
+   The functions used to compress and decompress are from zlib library
+   (http://zlib.net).
+
+   NOTE: for the moment the module cannot be used with topoh module,
+   overlapping in core event callbacks (will be fixed soon).
+
+   The immediate benefit of compressing the body is to reduce the size of
+   the SIP message, increasing the chances to stay under MTU for UDP
+   packts. From observation, the compressed body is in between 50% to 67%
+   smaller than the original size (e.g., a body of 431 bytes was
+   compressed to 230).
+
+   An use case can be when having peering traffic between two Kamailio
+   servers. Before relaying to the other Kamailio, use in config file:
+   append_hf("Content-Encoding: deflate\r\n").
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * zlib compression library (http://zlib.net).
+
+3. Parameters
+
+   3.1. header_name (str)
+   3.2. header_value (str)
+   3.3. sanity_checks (integer)
+
+3.1. header_name (str)
+
+   Name of the header that indicates compression or decompression has to
+   be done.
+
+   Default value is "Content-Encoding".
+
+   Example 1.1. Set header_name parameter
+...
+modparam("gzcompress", "header_name", "Encoded")
+...
+
+3.2. header_value (str)
+
+   Name of the header that indicates compression or decompression has to
+   be done.
+
+   Default value is "deflate".
+
+   Example 1.2. Set header_value parameter
+...
+modparam("gzcompress", "header_value", "gzip")
+...
+
+3.3. sanity_checks (integer)
+
+   If set to 1, gzcompress module will bind to sanity module in order to
+   perform sanity checks over received SIP request. Default sanity checks
+   are done. It is useful to check if received request is well formated
+   before proceeding to encoding/decoding.
+
+   Default value is 0 (do not bind to sanity module).
+
+   Example 1.3. Set sanity_checks parameter
+...
+modparam("gzcompress", "sanity_checks", 1)
+...
+
+4. Functions
+
+   None.
+
+5. Config File
+
+   Next example shows how to enable compression for forwarded requests, as
+   well as replying with compressed body for HTTP requests. For SIP, the
+   request is recevied and forwarded to itself once, just for the sake of
+   showing a simple example.
+
+   Example 1.4. Enable body compression
+...
+
+#!KAMAILIO
+
+debug=3
+memdbg=5
+memlog=5
+
+children=2
+
+log_stderror=yes
+listen=udp:127.0.0.1:5060
+listen=tcp:127.0.0.1:5060
+
+tcp_accept_no_cl=yes
+http_reply_parse=yes
+
+mpath="modules/"
+
+loadmodule "sl.so"
+loadmodule "pv.so"
+loadmodule "xlog.so"
+loadmodule "corex.so"
+loadmodule "textops.so"
+loadmodule "xhttp.so"
+loadmodule "gzcompress.so"
+
+modparam("gzcompress", "header_value", "deflate")
+
+request_route {
+        xlog("received sip request from $si:$sp\r\n");
+
+        if(src_port==5060) {
+                remove_hf("Content-Encoding");
+                $du = "sip:127.0.0.1:9";
+        } else {
+                append_hf("Content-Encoding: deflate\r\n");
+                $du = "sip:127.0.0.1:5060";
+        }
+        forward();
+        exit;
+}
+
+event_route[xhttp:request] {
+        xlog("received http request from $si:$sp\r\n");
+        append_to_reply("Content-Encoding: deflate\r\n");
+    xhttp_reply("200", "OK", "text/html",
+        "<html><body>OK - [$si:$sp]</body></html>");
+}
+
+...
diff --git a/modules/gzcompress/doc/Makefile b/modules/gzcompress/doc/Makefile
new file mode 100644
index 0000000..beb5851
--- /dev/null
+++ b/modules/gzcompress/doc/Makefile
@@ -0,0 +1,4 @@
+docs = gzcompress.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/gzcompress/doc/gzcompress.xml b/modules/gzcompress/doc/gzcompress.xml
new file mode 100644
index 0000000..156252a
--- /dev/null
+++ b/modules/gzcompress/doc/gzcompress.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>GZCompress Module</title>
+	<productname class="trade">kamailio.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>miconda at gmail.com</email>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>miconda at gmail.com</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2013</year>
+	    <holder>asipto.com</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="gzcompress_admin.xml"/>
+    
+    
+</book>
diff --git a/modules/gzcompress/doc/gzcompress_admin.xml b/modules/gzcompress/doc/gzcompress_admin.xml
new file mode 100644
index 0000000..ab46622
--- /dev/null
+++ b/modules/gzcompress/doc/gzcompress_admin.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		This module is able to detect compressed body in received SIP message
+		and decompress it as well as compress the body for outgoing SIP
+		message. It works also for received HTTP request and replied HTTP
+		response (&kamailio; cannot work in HTTP proxy mode).
+	</para>
+	<para>
+		The decision of whether to do compression or decompression is made
+		by detecting a special SIP header (default 'Content-Encoding') that
+		matches a given value - both header name and value can be set via
+		module parameters. If a SIP message is received with clear body and
+		you want to compress the body for outgoing, add the header in config
+		file. The header can be added to the local generated replies as well.
+	</para>
+	<para>
+		In other words, if the header is present in incoming SIP message, its
+		body is decompressed. If the header is present in outgoing SIP message,
+		its body is compressed. Therefore inside configuration file, the body
+		is in original format(e.g., plain text). In this way, the existing
+		functions to handle content of the body work as usual (e.g., to strip
+		codecs in sdp via sdpops or do substitutions via textops).
+	</para>
+	<para>
+		The functions used to compress and decompress are from zlib
+		library (http://zlib.net).
+	</para>
+	<para>
+		NOTE: for the moment the module cannot be used with topoh module,
+		overlapping in core event callbacks (will be fixed soon).
+	</para>
+	<para>
+		The immediate benefit of compressing the body is to reduce the size
+		of the SIP message, increasing the chances to stay under MTU for UDP
+		packts. From observation, the compressed body is in between 50% to 67%
+		smaller than the original size (e.g., a body of 431 bytes was
+		compressed to 230).
+	</para>
+	<para>
+		An use case can be when having peering traffic between two Kamailio
+		servers. Before relaying to the other Kamailio,  use
+		in config file: append_hf("Content-Encoding: deflate\r\n").
+	</para>
+	</section>
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>zlib</emphasis> compression library (http://zlib.net).
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Parameters</title>
+	<section id="gzcompress.p.header_name">
+		<title><varname>header_name</varname> (str)</title>
+		<para>
+			Name of the header that indicates compression or decompression has
+			to be done.
+		</para>
+		<para>
+		<emphasis>
+			Default value is "Content-Encoding".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>header_name</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("gzcompress", "header_name", "Encoded")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="gzcompress.p.header_value">
+		<title><varname>header_value</varname> (str)</title>
+		<para>
+			Name of the header that indicates compression or decompression has
+			to be done.
+		</para>
+		<para>
+		<emphasis>
+			Default value is "deflate".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>header_value</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("gzcompress", "header_value", "gzip")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="gzcompress.p.sanity_checks">
+		<title><varname>sanity_checks</varname> (integer)</title>
+		<para>
+			If set to 1, gzcompress module will bind to sanity module in order
+			to perform sanity checks over received SIP request. Default
+			sanity checks are done. It is useful to check if received request
+			is well formated before proceeding to encoding/decoding.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0 (do not bind to sanity module).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sanity_checks</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("gzcompress", "sanity_checks", 1)
+...
+</programlisting>
+		</example>
+	</section>
+
+	</section>
+	<section>
+	<title>Functions</title>
+		<para>
+			None.
+		</para>
+	</section>
+	<section>
+	<title>Config File</title>
+	<para>
+		Next example shows how to enable compression for forwarded requests,
+		as well as replying with compressed body for HTTP requests. For SIP,
+		the request is recevied and forwarded to itself once, just for the
+		sake of showing a simple example.
+	</para>
+		<example>
+		<title>Enable body compression</title>
+		<programlisting format="linespecific">
+...
+<![CDATA[
+#!KAMAILIO
+
+debug=3
+memdbg=5
+memlog=5
+
+children=2
+
+log_stderror=yes
+listen=udp:127.0.0.1:5060
+listen=tcp:127.0.0.1:5060
+
+tcp_accept_no_cl=yes
+http_reply_parse=yes
+
+mpath="modules/"
+
+loadmodule "sl.so"
+loadmodule "pv.so"
+loadmodule "xlog.so"
+loadmodule "corex.so"
+loadmodule "textops.so"
+loadmodule "xhttp.so"
+loadmodule "gzcompress.so"
+
+modparam("gzcompress", "header_value", "deflate")
+
+request_route {
+	xlog("received sip request from $si:$sp\r\n");
+
+	if(src_port==5060) {
+		remove_hf("Content-Encoding");
+		$du = "sip:127.0.0.1:9";
+	} else {
+		append_hf("Content-Encoding: deflate\r\n");
+		$du = "sip:127.0.0.1:5060";
+	}
+	forward();
+	exit;
+}
+
+event_route[xhttp:request] {
+	xlog("received http request from $si:$sp\r\n");
+	append_to_reply("Content-Encoding: deflate\r\n");
+    xhttp_reply("200", "OK", "text/html",
+        "<html><body>OK - [$si:$sp]</body></html>");
+}
+]]>
+...
+</programlisting>
+		</example>
+	</section>
+</chapter>
+
diff --git a/modules/gzcompress/gzcompress_mod.c b/modules/gzcompress/gzcompress_mod.c
new file mode 100644
index 0000000..7927e03
--- /dev/null
+++ b/modules/gzcompress/gzcompress_mod.c
@@ -0,0 +1,396 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*!
+ * \file
+ * \brief Kamailio gzcompress :: Module interface
+ * \ingroup gzcompress
+ * Module: \ref gzcompress
+ */
+
+/*! \defgroup gzcompress Kamailio :: compress-decompress message body with zlib
+ *
+ * This module compresses/decompresses SIP message body using zlib.
+ * The script interpreter gets the SIP messages decoded, so all
+ * existing functionality is preserved.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <zlib.h>
+
+#include "../../sr_module.h"
+#include "../../events.h"
+#include "../../dprint.h"
+#include "../../tcp_options.h"
+#include "../../ut.h"
+#include "../../forward.h"
+#include "../../msg_translator.h"
+#include "../../data_lump.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/parse_to.h"
+#include "../../parser/parse_from.h"
+
+#include "../../modules/sanity/api.h"
+
+MODULE_VERSION
+
+/** local functions */
+int gzc_msg_received(void *data);
+int gzc_msg_sent(void *data);
+
+/** module parameters */
+static str _gzc_hdr_name = str_init("Content-Encoding");
+static str _gzc_hdr_value = str_init("deflate");
+
+static int _gzc_sanity_checks = 0;
+static sanity_api_t scb = {0};
+
+/** module functions */
+static int mod_init(void);
+
+static param_export_t params[]={
+	{"header_name",		PARAM_STR, &_gzc_hdr_name},
+	{"header_value",	PARAM_STR, &_gzc_hdr_value},
+	{"sanity_checks",	PARAM_INT, &_gzc_sanity_checks},
+	{0,0,0}
+};
+
+
+/** module exports */
+struct module_exports exports= {
+	"gzcompress",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	0,
+	params,
+	0,          /* exported statistics */
+	0,          /* exported MI functions */
+	0,          /* exported pseudo-variables */
+	0,          /* extra processes */
+	mod_init,   /* module initialization function */
+	0,
+	0,
+	0           /* per-child init function */
+};
+
+/**
+ * init module function
+ */
+static int mod_init(void)
+{
+	if(_gzc_sanity_checks!=0)
+	{
+		if(sanity_load_api(&scb)<0)
+		{
+			LM_ERR("cannot bind to sanity module\n");
+			goto error;
+		}
+	}
+	
+	sr_event_register_cb(SREV_NET_DATA_IN, gzc_msg_received);
+	sr_event_register_cb(SREV_NET_DATA_OUT, gzc_msg_sent);
+#ifdef USE_TCP
+	tcp_set_clone_rcvbuf(1);
+#endif
+	return 0;
+error:
+	return -1;
+}
+
+/**
+ *
+ */
+int gzc_prepare_msg(sip_msg_t *msg)
+{
+	if (parse_msg(msg->buf, msg->len, msg)!=0)
+	{
+		LM_DBG("outbuf buffer parsing failed!");
+		return 1;
+	}
+
+	if(msg->first_line.type==SIP_REQUEST)
+	{
+		if(!IS_SIP(msg) && !IS_HTTP(msg))
+		{
+			LM_DBG("non sip or http request\n");
+			return 1;
+		}
+	} else if(msg->first_line.type==SIP_REPLY) {
+		if(!IS_SIP_REPLY(msg) && !IS_HTTP_REPLY(msg))
+		{
+			LM_DBG("non sip or http response\n");
+			return 1;
+		}
+	} else {
+		LM_DBG("non sip or http message\n");
+		return 1;
+	}
+
+	if (parse_headers(msg, HDR_EOH_F, 0)==-1)
+	{
+		LM_DBG("parsing headers failed");
+		return 2;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int gzc_skip_msg(sip_msg_t *msg)
+{
+	hdr_field_t *h;
+	char *sp;
+
+	if(_gzc_hdr_name.len<=0 || _gzc_hdr_value.len<=0)
+		return -1;
+	h = get_hdr_by_name(msg, _gzc_hdr_name.s, _gzc_hdr_name.len);
+	if(h==NULL)
+		return 1;
+	
+	for (sp = h->body.s; sp <= h->body.s + h->body.len - _gzc_hdr_value.len;
+			sp++)
+	{
+        if (*sp == *_gzc_hdr_value.s
+        		&& memcmp(sp, _gzc_hdr_value.s, _gzc_hdr_value.len)==0) {
+        	/* found */
+            return 0;
+        }
+    }
+
+	return 2;
+}
+
+/**
+ *
+ */
+char* gzc_msg_update(sip_msg_t *msg, unsigned int *olen)
+{
+	struct dest_info dst;
+
+	init_dest_info(&dst);
+	dst.proto = PROTO_UDP;
+	return build_req_buf_from_sip_req(msg,
+			olen, &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
+}
+
+/**
+ *
+ */
+int gzc_set_msg_body(sip_msg_t *msg, str *obody, str *nbody)
+{
+	struct lump *anchor;
+	char* buf;
+
+	/* none should be here - just for safety */
+	del_nonshm_lump( &(msg->body_lumps) );
+	msg->body_lumps = NULL;
+
+	if(del_lump(msg, obody->s - msg->buf, obody->len, 0) == 0)
+	{
+		LM_ERR("cannot delete existing body");
+		return -1;
+	}
+
+	anchor = anchor_lump(msg, obody->s - msg->buf, 0, 0);
+
+	if (anchor == 0)
+	{
+		LM_ERR("failed to get body anchor\n");
+		return -1;
+	} 
+
+	buf=pkg_malloc(nbody->len * sizeof(char));
+	if (buf==0)
+	{
+		LM_ERR("out of pkg memory\n");
+		return -1;
+	}
+	memcpy(buf, nbody->s, nbody->len);
+	if (insert_new_lump_after(anchor, buf, nbody->len, 0) == 0)
+	{
+		LM_ERR("failed to insert body lump\n");
+		pkg_free(buf);
+		return -1;
+	}
+	return 0;
+}
+
+/* local buffer to use for compressing/decompressing */
+static char _gzc_local_buffer[BUF_SIZE];
+
+/**
+ *
+ */
+int gzc_msg_received(void *data)
+{
+	sip_msg_t msg;
+	str *obuf;
+	char *nbuf = NULL;
+	str obody;
+	str nbody;
+	unsigned long olen;
+	unsigned long nlen;
+	int ret;
+
+	obuf = (str*)data;
+	memset(&msg, 0, sizeof(sip_msg_t));
+	msg.buf = obuf->s;
+	msg.len = obuf->len;
+
+	if(gzc_prepare_msg(&msg)!=0)
+	{
+		goto done;
+	}
+
+	if(gzc_skip_msg(&msg))
+	{
+		goto done;
+	}
+
+	if(msg.first_line.type==SIP_REQUEST)
+	{
+		if(_gzc_sanity_checks!=0)
+		{
+			if(scb.check_defaults(&msg)<1)
+			{
+				LM_ERR("sanity checks failed\n");
+				goto done;
+			}
+		}
+	}
+
+	obody.s = get_body(&msg);
+	if (obody.s==NULL)
+	{
+		LM_DBG("no body for this SIP message\n");
+		goto done;
+	}
+	obody.len = msg.buf + msg.len - obody.s;
+
+	/* decompress the body */
+	nbody.s = _gzc_local_buffer;
+	nlen = BUF_SIZE;
+	olen = obody.len;
+	ret = uncompress((unsigned char*)nbody.s, &nlen,
+			(unsigned char*)obody.s, olen);
+	if(ret!=Z_OK)
+	{
+		LM_ERR("error decompressing body (%d)\n", ret);
+		goto done;
+	}
+	nbody.len = (int)nlen;
+	LM_DBG("body decompressed - old size: %d - new size: %d\n",
+			obody.len, nbody.len);
+
+	if(gzc_set_msg_body(&msg, &obody, &nbody)<0)
+	{
+		LM_ERR("error replacing body\n");
+		goto done;
+	}
+
+	nbuf = gzc_msg_update(&msg, (unsigned int*)&obuf->len);
+
+	if(obuf->len>=BUF_SIZE)
+	{
+		LM_ERR("new buffer overflow (%d)\n", obuf->len);
+		pkg_free(nbuf);
+		return -1;
+	}
+	memcpy(obuf->s, nbuf, obuf->len);
+	obuf->s[obuf->len] = '\0';
+
+done:
+	if(nbuf!=NULL)
+		pkg_free(nbuf);
+	free_sip_msg(&msg);
+	return 0;
+}
+
+/**
+ *
+ */
+int gzc_msg_sent(void *data)
+{
+	sip_msg_t msg;
+	str *obuf;
+	str obody;
+	str nbody;
+	unsigned long olen;
+	unsigned long nlen;
+	int ret;
+
+	obuf = (str*)data;
+	memset(&msg, 0, sizeof(sip_msg_t));
+	msg.buf = obuf->s;
+	msg.len = obuf->len;
+
+	if(gzc_prepare_msg(&msg)!=0)
+	{
+		goto done;
+	}
+
+	if(gzc_skip_msg(&msg))
+	{
+		goto done;
+	}
+
+	obody.s = get_body(&msg);
+	if (obody.s==NULL)
+	{
+		LM_DBG("no body for this SIP message\n");
+		goto done;
+	}
+	obody.len = msg.buf + msg.len - obody.s;
+
+	/* decompress the body */
+	nbody.s = _gzc_local_buffer;
+	nlen = BUF_SIZE;
+	olen = obody.len;
+	ret = compress((unsigned char*)nbody.s, &nlen,
+			(unsigned char*)obody.s, olen);
+	if(ret!=Z_OK)
+	{
+		LM_ERR("error compressing body (%d)\n", ret);
+		goto done;
+	}
+	nbody.len = (int)nlen;
+	LM_DBG("body compressed - old size: %d - new size: %d\n",
+			obody.len, nbody.len);
+
+	if(gzc_set_msg_body(&msg, &obody, &nbody)<0)
+	{
+		LM_ERR("error replacing body\n");
+		goto done;
+	}
+
+	obuf->s = gzc_msg_update(&msg, (unsigned int*)&obuf->len);
+
+done:
+	free_sip_msg(&msg);
+	return 0;
+}
+
diff --git a/modules/htable/Makefile b/modules/htable/Makefile
index c1e683a..de7ea25 100644
--- a/modules/htable/Makefile
+++ b/modules/htable/Makefile
@@ -16,4 +16,5 @@ SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi
 SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules
diff --git a/modules/htable/README b/modules/htable/README
index 69cc2be..31db1bc 100644
--- a/modules/htable/README
+++ b/modules/htable/README
@@ -17,7 +17,7 @@ Alex Balashov
 
    <abalashov at evaristesys.com>
 
-   Copyright � 2008-2011 http://www.asipto.com
+   Copyright © 2008-2011 http://www.asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -45,12 +45,15 @@ Alex Balashov
               3.10. timer_interval (integer)
               3.11. timer_mode (integer)
               3.12. db_expires (integer)
+              3.13. enable_dmq (integer)
 
         4. Functions
 
               4.1. sht_print()
               4.2. sht_rm_name_re(htable=>regexp)
               4.3. sht_rm_value_re(htable=>regexp)
+              4.4. sht_lock(htable=>key)
+              4.5. sht_unlock(htable=>key)
 
         5. Exported pseudo-variables
         6. MI Commands
@@ -63,8 +66,12 @@ Alex Balashov
 
               7.1. htable.get htable key
               7.2. htable.delete htable key
-              7.3. htable.dump htable
-              7.4. htable.listTables
+              7.3. htable.sets htable key value
+              7.4. htable.seti htable key value
+              7.5. htable.dump htable
+              7.6. htable.reload htable
+              7.7. htable.listTables
+              7.8. htable.stats
 
         8. Event routes
 
@@ -86,9 +93,12 @@ Alex Balashov
    1.12. Set timer_interval parameter
    1.13. Set timer_mode parameter
    1.14. Set db_expires parameter
-   1.15. sht_print usage
-   1.16. sht_rm_name_re usage
-   1.17. sht_rm_value_re usage
+   1.15. Set enable_dmq parameter
+   1.16. sht_print usage
+   1.17. sht_rm_name_re usage
+   1.18. sht_rm_value_re usage
+   1.19. sht_lock usage
+   1.20. sht_unlock usage
 
 Chapter 1. Admin Guide
 
@@ -115,12 +125,15 @@ Chapter 1. Admin Guide
         3.10. timer_interval (integer)
         3.11. timer_mode (integer)
         3.12. db_expires (integer)
+        3.13. enable_dmq (integer)
 
    4. Functions
 
         4.1. sht_print()
         4.2. sht_rm_name_re(htable=>regexp)
         4.3. sht_rm_value_re(htable=>regexp)
+        4.4. sht_lock(htable=>key)
+        4.5. sht_unlock(htable=>key)
 
    5. Exported pseudo-variables
    6. MI Commands
@@ -133,8 +146,12 @@ Chapter 1. Admin Guide
 
         7.1. htable.get htable key
         7.2. htable.delete htable key
-        7.3. htable.dump htable
-        7.4. htable.listTables
+        7.3. htable.sets htable key value
+        7.4. htable.seti htable key value
+        7.5. htable.dump htable
+        7.6. htable.reload htable
+        7.7. htable.listTables
+        7.8. htable.stats
 
    8. Event routes
 
@@ -155,10 +172,13 @@ Chapter 1. Admin Guide
    expiration time of cached items. The expiration time can be adjusted
    per itme via assignment operation at runtime.
 
+   Replication between multiple servers is performed automatically (if
+   enabled) via the DMQ module.
+
    You can read more about hash tables at:
    http://en.wikipedia.org/wiki/Hash_table.
 
-   The "name" can be a static string or can include pseudo- variables that
+   The “name” can be a static string or can include pseudo- variables that
    will be replaced at runtime.
 
    Example 1.1. Accessing $sht(htname=>key)
@@ -181,7 +201,7 @@ $sht(a=>$ci::srcip) = $si;
    the failed authentications per user and one for storing the time of
    last authentication attempt. To ensure unique name per user, the hash
    table uses a combination of authentication username and text
-   "::auth_count" and "::last_auth".
+   “::auth_count” and “::last_auth”.
 
    Example 1.2. Dictionary attack limitation
 ...
@@ -234,7 +254,8 @@ if(is_present_hf("Authorization"))
 2.1. Kamailio Modules
 
    The following modules must be loaded before this module:
-     * No dependencies on other Kamailio modules.
+     * If DMQ replication is enabled, the DMQ module must be loaded
+       first..
 
 2.2. External Libraries or Applications
 
@@ -273,6 +294,7 @@ if(is_present_hf("Authorization"))
    3.10. timer_interval (integer)
    3.11. timer_mode (integer)
    3.12. db_expires (integer)
+   3.13. enable_dmq (integer)
 
 3.1. htable (str)
 
@@ -287,8 +309,8 @@ if(is_present_hf("Authorization"))
      * size - number specifying the size of hash table. Larger value means
        less collisions. The number of entries (aka slots or buckets) in
        the table is 2^size. The possible range for this value is from 2 to
-       14, smaller or larger values will be increased or decreased
-       respectivly.
+       31, smaller or larger values will be increased to 3 (8 slots) or
+       decreased to 14 (16384 slots).
      * autoexpire -time in seconds to delete an item from hash table if no
        update was done to it. If is missing or set to 0, the items won't
        expire.
@@ -304,6 +326,11 @@ if(is_present_hf("Authorization"))
        an item is reset when that item is updated. Certain uses of htable
        may dictate that updates should not reset the expiration timeout,
        however, in which case this attribute can be set to 0.
+     * dmqreplicate - if set to 1, any actions (set, update, delete etc.)
+       performed upon entries in this table will be replicated to other
+       nodes (htable peers). Please note, module parameter "enable_dmq"
+       must also be set in order for this to apply (see below). Default is
+       0 (no replication).
 
    Default value is NULL.
 
@@ -311,7 +338,8 @@ if(is_present_hf("Authorization"))
 ...
 modparam("htable", "htable", "a=>size=4;autoexpire=7200;dbtable=htable_a;")
 modparam("htable", "htable", "b=>size=5;")
-modparam("htable", "htable", "c=>size=4;autoexpire=7200;initval=1;")
+modparam("htable", "htable", "c=>size=4;autoexpire=7200;initval=1;dmqreplicate=1
+;")
 ...
 
 3.2. db_url (str)
@@ -439,13 +467,35 @@ modparam("htable", "timer_mode", 1)
 modparam("htable", "db_expires", 1)
 ...
 
+3.13. enable_dmq (integer)
+
+   If set to 1, will enable DMQ replication of actions performed upon
+   entries in all tables having "dmqreplicate" parameter set. Any update
+   action performed via psuedo-variables, MI and RPC commands will be
+   repeated on all other nodes. Therefore, it is important to ensure the
+   table definition (size, autoexpire etc.) is identical across all
+   instances.
+
+   Currently, values are not replicated on load from DB as it is expected
+   that in these cases, all servers will load their values from the same
+   DB.
+
+   Default value is 0.
+
+   Example 1.15. Set enable_dmq parameter
+...
+modparam("htable", "enable_dmq", 1)
+...
+
 4. Functions
 
    4.1. sht_print()
    4.2. sht_rm_name_re(htable=>regexp)
    4.3. sht_rm_value_re(htable=>regexp)
+   4.4. sht_lock(htable=>key)
+   4.5. sht_unlock(htable=>key)
 
-4.1. sht_print()
+4.1.  sht_print()
 
    Dump content of hash table to L_ERR log level. Intended for debug
    purposes.
@@ -453,12 +503,12 @@ modparam("htable", "db_expires", 1)
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE.
 
-   Example 1.15. sht_print usage
+   Example 1.16. sht_print usage
 ...
 sht_print();
 ...
 
-4.2. sht_rm_name_re(htable=>regexp)
+4.2.  sht_rm_name_re(htable=>regexp)
 
    Delete all entries in the htable that match the name against regular
    expression.
@@ -466,12 +516,12 @@ sht_print();
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE.
 
-   Example 1.16. sht_rm_name_re usage
+   Example 1.17. sht_rm_name_re usage
 ...
 sht_rm_name_re("ha=>.*");
 ...
 
-4.3. sht_rm_value_re(htable=>regexp)
+4.3.  sht_rm_value_re(htable=>regexp)
 
    Delete all entries in the htable that match the value against regular
    expression.
@@ -479,11 +529,35 @@ sht_rm_name_re("ha=>.*");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE.
 
-   Example 1.17. sht_rm_value_re usage
+   Example 1.18. sht_rm_value_re usage
 ...
 sht_rm_value_re("ha=>.*");
 ...
 
+4.4.  sht_lock(htable=>key)
+
+   Lock the slot in htable corespoding to the key item.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.19. sht_lock usage
+...
+sht_lock("ha=>test");
+...
+
+4.5.  sht_unlock(htable=>key)
+
+   Unlock the slot in htable corespoding to the key item.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.20. sht_unlock usage
+...
+sht_lock("ha=>test");
+$sht(ha=>test) = $sht(ha=>test) + 10;
+sht_unlock("ha=>test");
+...
+
 5. Exported pseudo-variables
 
      * $sht(htable=>key)
@@ -502,7 +576,7 @@ sht_rm_value_re("ha=>.*");
    6.2. sht_dump
    6.3. sht_delete
 
-6.1. sht_reload
+6.1.  sht_reload
 
    Reload a hash table from database.
 
@@ -515,7 +589,7 @@ sht_rm_value_re("ha=>.*");
                 _hash_table_name_
                 _empty_line_
 
-6.2. sht_dump
+6.2.  sht_dump
 
    Dump content of a hash table via MI.
 
@@ -528,7 +602,7 @@ sht_rm_value_re("ha=>.*");
                 _hash_table_name_
                 _empty_line_
 
-6.3. sht_delete
+6.3.  sht_delete
 
    Delete a key from a hash table via MI.
 
@@ -551,10 +625,14 @@ sht_rm_value_re("ha=>.*");
 
    7.1. htable.get htable key
    7.2. htable.delete htable key
-   7.3. htable.dump htable
-   7.4. htable.listTables
+   7.3. htable.sets htable key value
+   7.4. htable.seti htable key value
+   7.5. htable.dump htable
+   7.6. htable.reload htable
+   7.7. htable.listTables
+   7.8. htable.stats
 
-7.1. htable.get htable key
+7.1.  htable.get htable key
 
    Lists one value in a hash table
 
@@ -570,7 +648,7 @@ sht_rm_value_re("ha=>.*");
 kamcmd htable.get students daniel
 ...
 
-7.2. htable.delete htable key
+7.2.  htable.delete htable key
 
    Delete one value in a hash table
 
@@ -586,7 +664,41 @@ kamcmd htable.get students daniel
 kamcmd htable.get students anna
 ...
 
-7.3. htable.dump htable
+7.3.  htable.sets htable key value
+
+   Set an item in hash table to string value.
+
+   Name: htable.sets
+
+   Parameters:
+     * htable : Name of the hash table
+     * key : Key name in the hash table
+     * Value : String value for the item
+
+   Example:
+...
+# Set $sht(test=>x)
+kamcmd htable.sets test x abc
+...
+
+7.4.  htable.seti htable key value
+
+   Set an item in hash table to integer value.
+
+   Name: htable.seti
+
+   Parameters:
+     * htable : Name of the hash table
+     * key : Key name in the hash table
+     * Value : Integer value for the item
+
+   Example:
+...
+# Set $sht(test=>x)
+kamcmd htable.sets test x 123
+...
+
+7.5.  htable.dump htable
 
    Lists all the values in a hash table
 
@@ -600,11 +712,25 @@ kamcmd htable.get students anna
 kamcmd htable.dump ipban
 ...
 
-7.4. htable.listTables
+7.6.  htable.reload htable
+
+   Reload hash table from database.
+
+   Name: dhtable.reload
+
+   Parameters:
+     * htable : Name of the hash table to reload
+
+   Example:
+...
+kamcmd htable.reload ipban
+...
+
+7.7.  htable.listTables
 
    Lists all defined tables
 
-   Name: dhtable.listTables
+   Name: htable.listTables
 
    Parameters:
      * None
@@ -614,11 +740,26 @@ kamcmd htable.dump ipban
 kamcmd htable.listTables
 ...
 
+7.8.  htable.stats
+
+   Get statistics for hash tables - name, number of slots, number of
+   items, max number of items per slot, min number of items per slot.
+
+   Name: htable.stats
+
+   Parameters:
+     * None
+
+   Example:
+...
+kamcmd htable.stats
+...
+
 8. Event routes
 
    8.1. htable:mod-init
 
-8.1. htable:mod-init
+8.1.  htable:mod-init
 
    When defined, the module calls event_route[htable:mod-init] after all
    modules have been initialized. A typical use case is to initialise
diff --git a/modules/htable/api.c b/modules/htable/api.c
index 27d13a0..a3deccc 100644
--- a/modules/htable/api.c
+++ b/modules/htable/api.c
@@ -28,6 +28,7 @@
 
 #include "ht_api.h"
 #include "api.h"
+#include "ht_dmq.h"
 
 /**
  *
@@ -39,6 +40,11 @@ int ht_api_set_cell(str *hname, str *name, int type,
 	ht = ht_get_table(hname);
 	if(ht==NULL)
 		return -1;
+
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, hname, name, type, val, mode)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}
+
 	return ht_set_cell(ht, name, type, val, mode);
 }
 
@@ -51,6 +57,9 @@ int ht_api_del_cell(str *hname, str *name)
 	ht = ht_get_table(hname);
 	if(ht==NULL)
 		return -1;
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, hname, name, 0, NULL, 0)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}
 	return ht_del_cell(ht, name);
 }
 
@@ -64,6 +73,9 @@ int ht_api_set_cell_expire(str *hname, str *name,
 	ht = ht_get_table(hname);
 	if(ht==NULL)
 		return -1;
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL_EXPIRE, hname, name, type, val, 0)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}
 	return ht_set_cell_expire(ht, name, type, val);
 }
 
@@ -86,9 +98,17 @@ int ht_api_get_cell_expire(str *hname, str *name,
 int ht_api_rm_cell_re(str *hname, str *sre, int mode)
 {
 	ht_t* ht;
+	int_str isval;
 	ht = ht_get_table(hname);
 	if(ht==NULL)
 		return -1;
+	if (ht->dmqreplicate>0) {
+		isval.s.s = sre->s;
+		isval.s.len = sre->len;
+		if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, hname, NULL, AVP_VAL_STR, &isval, mode)!=0) {
+			LM_ERR("dmq relication failed\n");
+		}
+	}
 	if(ht_rm_cell_re(sre, ht, mode /* 0 - name; 1 - value */)<0)
 		return -1;
 	return 0;
diff --git a/modules/htable/doc/htable_admin.xml b/modules/htable/doc/htable_admin.xml
index d652c8f..3279738 100644
--- a/modules/htable/doc/htable_admin.xml
+++ b/modules/htable/doc/htable_admin.xml
@@ -31,6 +31,10 @@
 		be adjusted per itme via assignment operation at runtime.
 	</para>
 	<para>
+		Replication between multiple servers is performed automatically (if 
+		enabled) via the DMQ module.
+	</para>
+	<para>
 		You can read more about hash tables at:
 		http://en.wikipedia.org/wiki/Hash_table.
 	</para>
@@ -121,7 +125,7 @@ if(is_present_hf("Authorization"))
 			<itemizedlist>
 			<listitem>
 			<para>
-				<emphasis>No dependencies on other &kamailio; modules</emphasis>.
+				<emphasis>If DMQ replication is enabled, the DMQ module must be loaded first.</emphasis>.
 			</para>
 			</listitem>
 			</itemizedlist>
@@ -236,8 +240,8 @@ if(is_present_hf("Authorization"))
 			<emphasis>size</emphasis> - number specifying the size of hash
 			table.  Larger value means less collisions. The number of entries
 			(aka slots or buckets) in the table is 2^size. The possible range
-			for this value is from 2 to 14, smaller or larger values will be
-			increased or decreased respectivly.
+			for this value is from 2 to 31, smaller or larger values will be
+			increased to 3 (8 slots) or decreased to 14 (16384 slots).
 		</para>
 		</listitem>
 		<listitem>
@@ -272,6 +276,11 @@ if(is_present_hf("Authorization"))
 			<emphasis>updateexpire</emphasis> - if set to 1 (default), the time until expiration of an item is reset when that item is updated.  Certain uses of htable may dictate that updates should not reset the expiration timeout, however, in which case this attribute can be set to 0.
 		</para>
 		</listitem>
+		<listitem>
+		<para>
+			<emphasis>dmqreplicate</emphasis> - if set to 1, any actions (set, update, delete etc.) performed upon entries in this table will be replicated to other nodes (htable peers). Please note, module parameter "enable_dmq" must also be set in order for this to apply (see below). Default is 0 (no replication).
+		</para>
+		</listitem>
 		</itemizedlist>
 		<para>
 		<emphasis>
@@ -284,7 +293,7 @@ if(is_present_hf("Authorization"))
 ...
 modparam("htable", "htable", "a=>size=4;autoexpire=7200;dbtable=htable_a;")
 modparam("htable", "htable", "b=>size=5;")
-modparam("htable", "htable", "c=>size=4;autoexpire=7200;initval=1;")
+modparam("htable", "htable", "c=>size=4;autoexpire=7200;initval=1;dmqreplicate=1;")
 ...
 </programlisting>
 		</example>
@@ -504,6 +513,33 @@ modparam("htable", "db_expires", 1)
 </programlisting>
 		</example>
 	</section>
+	<section>
+		<title><varname>enable_dmq</varname> (integer)</title>
+		<para>
+			If set to 1, will enable DMQ replication of actions performed upon 
+			entries in all tables having "dmqreplicate" parameter set. Any update 
+			action performed via psuedo-variables, MI and RPC commands will be 
+			repeated on all other nodes. Therefore, it is important to ensure the
+			table definition (size, autoexpire etc.) is identical across all instances.
+		</para>
+		<para>
+			Currently, values are not replicated on load from DB as it is expected 
+			that in these cases, all servers will load their values from the same DB.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>enable_dmq</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("htable", "enable_dmq", 1)
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 	<section>
 	<title>Functions</title>
@@ -570,6 +606,46 @@ sht_rm_value_re("ha=>.*");
 </programlisting>
 		</example>
 	</section>
+	<section id="htable.f.sht_lock">
+		<title>
+		<function moreinfo="none">sht_lock(htable=>key)</function>
+		</title>
+		<para>
+			Lock the slot in htable corespoding to the key item.
+		</para>
+		<para>
+			This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>sht_lock</function> usage</title>
+		<programlisting format="linespecific">
+...
+sht_lock("ha=>test");
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="htable.f.sht_unlock">
+		<title>
+		<function moreinfo="none">sht_unlock(htable=>key)</function>
+		</title>
+		<para>
+			Unlock the slot in htable corespoding to the key item.
+		</para>
+		<para>
+			This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>sht_unlock</function> usage</title>
+		<programlisting format="linespecific">
+...
+sht_lock("ha=>test");
+$sht(ha=>test) = $sht(ha=>test) + 10;
+sht_unlock("ha=>test");
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 		<section>
 		<title>Exported pseudo-variables</title>
@@ -733,6 +809,66 @@ kamcmd htable.get students anna
 ...
 </programlisting>
 	</section>
+       <section>
+                <title>
+                <function moreinfo="none">htable.sets htable key value</function>
+                </title>
+                <para>
+					Set an item in hash table to string value.
+                </para>
+                <para>
+                Name: <emphasis>htable.sets</emphasis>
+                </para>
+                <para>Parameters:</para>
+                <itemizedlist>
+                        <listitem><para>htable : Name of the hash table</para>
+                        </listitem>
+                        <listitem><para>key : Key name in the hash table</para>
+                        </listitem>
+                        <listitem><para>Value : String value for the item</para>
+                        </listitem>
+
+                </itemizedlist>
+                <para>
+                Example:
+                </para>
+<programlisting  format="linespecific">
+...
+# Set $sht(test=>x)
+kamcmd htable.sets test x abc
+...
+</programlisting>
+	</section>
+       <section>
+                <title>
+                <function moreinfo="none">htable.seti htable key value</function>
+                </title>
+                <para>
+					Set an item in hash table to integer value.
+                </para>
+                <para>
+                Name: <emphasis>htable.seti</emphasis>
+                </para>
+                <para>Parameters:</para>
+                <itemizedlist>
+                        <listitem><para>htable : Name of the hash table</para>
+                        </listitem>
+                        <listitem><para>key : Key name in the hash table</para>
+                        </listitem>
+                        <listitem><para>Value : Integer value for the item</para>
+                        </listitem>
+
+                </itemizedlist>
+                <para>
+                Example:
+                </para>
+<programlisting  format="linespecific">
+...
+# Set $sht(test=>x)
+kamcmd htable.sets test x 123
+...
+</programlisting>
+	</section>
         <section>
                 <title>
                 <function moreinfo="none">htable.dump htable</function>
@@ -760,13 +896,38 @@ kamcmd htable.dump ipban
 	</section>
         <section>
                 <title>
+                <function moreinfo="none">htable.reload htable</function>
+                </title>
+                <para>
+		Reload hash table from database.
+                </para>
+                <para>
+                Name: <emphasis>dhtable.reload</emphasis>
+                </para>
+                <para>Parameters:</para>
+                <itemizedlist>
+                        <listitem><para>htable : Name of the hash table to reload</para>
+                        </listitem>
+
+                </itemizedlist>
+                <para>
+                Example:
+                </para>
+<programlisting  format="linespecific">
+...
+kamcmd htable.reload ipban
+...
+</programlisting>
+	</section>
+        <section>
+                <title>
                 <function moreinfo="none">htable.listTables</function>
                 </title>
                 <para>
 		Lists all defined tables
                 </para>
                 <para>
-                Name: <emphasis>dhtable.listTables</emphasis>
+                Name: <emphasis>htable.listTables</emphasis>
                 </para>
                 <para>Parameters:</para>
                 <itemizedlist>
@@ -783,6 +944,33 @@ kamcmd htable.listTables
 ...
 </programlisting>
 	</section>
+    <section>
+          <title>
+                <function moreinfo="none">htable.stats</function>
+          </title>
+          <para>
+			  Get statistics for hash tables - name, number of slots,
+			  number of items, max number of items per slot, min number
+			  of items per slot.
+          </para>
+                <para>
+                Name: <emphasis>htable.stats</emphasis>
+                </para>
+                <para>Parameters:</para>
+                <itemizedlist>
+                        <listitem><para>None</para>
+                        </listitem>
+
+                </itemizedlist>
+                <para>
+                Example:
+                </para>
+<programlisting  format="linespecific">
+...
+kamcmd htable.stats
+...
+</programlisting>
+	</section>
 
 	</section><!-- RPC commands -->
 
diff --git a/modules/htable/ht_api.c b/modules/htable/ht_api.c
index 6a74793..f55e784 100644
--- a/modules/htable/ht_api.c
+++ b/modules/htable/ht_api.c
@@ -36,10 +36,6 @@
 #include "ht_db.h"
 
 
-#define ht_compute_hash(_s)        core_case_hash(_s,0,0)
-#define ht_get_entry(_h,_size)    (_h)&((_size)-1)
-
-
 ht_t *_ht_root = NULL;
 
 typedef struct _keyvalue {
@@ -222,7 +218,7 @@ ht_t* ht_get_table(str *name)
 }
 
 int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode,
-		int itype, int_str *ival, int updateexpire)
+		int itype, int_str *ival, int updateexpire, int dmqreplicate)
 {
 	unsigned int htid;
 	ht_t *ht;
@@ -252,7 +248,7 @@ int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode,
 
 	if(size<=1)
 		ht->htsize = 8;
-	else if(size>14)
+	else if(size>31)
 		ht->htsize = 1<<14;
 	else ht->htsize = 1<<size;
 	ht->htid = htid;
@@ -265,7 +261,7 @@ int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode,
 	ht->flags = itype;
 	if(ival!=NULL)
 		ht->initval = *ival;
-
+	ht->dmqreplicate = dmqreplicate;
 	ht->next = _ht_root;
 	_ht_root = ht;
 	return 0;
@@ -765,6 +761,7 @@ int ht_table_spec(char *spec)
 	unsigned int size = 4;
 	unsigned int dbmode = 0;
 	unsigned int updateexpire = 1;
+	unsigned int dmqreplicate = 0;
 	str in;
 	str tok;
 	param_t *pit=NULL;
@@ -821,11 +818,16 @@ int ht_table_spec(char *spec)
 				goto error;
 
 			LM_DBG("htable [%.*s] - updateexpire [%u]\n", name.len, name.s, updateexpire); 
+		} else if(pit->name.len == 12 && strncmp(pit->name.s, "dmqreplicate", 12) == 0) {
+			if(str2int(&tok, &dmqreplicate) != 0)
+				goto error;
+
+			LM_DBG("htable [%.*s] - dmqreplicate [%u]\n", name.len, name.s, dmqreplicate); 
 		} else { goto error; }
 	}
 
 	return ht_add_table(&name, autoexpire, &dbtable, size, dbmode,
-			itype, &ival, updateexpire);
+			itype, &ival, updateexpire, dmqreplicate);
 
 error:
 	LM_ERR("invalid htable parameter [%.*s]\n", in.len, in.s);
diff --git a/modules/htable/ht_api.h b/modules/htable/ht_api.h
index c8b88f7..f1b504b 100644
--- a/modules/htable/ht_api.h
+++ b/modules/htable/ht_api.h
@@ -29,6 +29,9 @@
 #include "../../locking.h"
 #include "../../pvar.h"
 
+#define ht_compute_hash(_s)        core_case_hash(_s,0,0)
+#define ht_get_entry(_h,_size)    (_h)&((_size)-1)
+
 typedef struct _ht_cell
 {
     unsigned int cellid;
@@ -59,6 +62,7 @@ typedef struct _ht
 	int_str initval;
 	int updateexpire;
 	unsigned int htsize;
+	int dmqreplicate;
 	ht_entry_t *entries;
 	struct _ht *next;
 } ht_t;
@@ -70,7 +74,7 @@ typedef struct _ht_pv {
 } ht_pv_t, *ht_pv_p;
 
 int ht_add_table(str *name, int autoexp, str *dbtable, int size, int dbmode,
-		int itype, int_str *ival, int updateexpire);
+		int itype, int_str *ival, int updateexpire, int dmqreplicate);
 int ht_init_tables(void);
 int ht_destroy(void);
 int ht_set_cell(ht_t *ht, str *name, int type, int_str *val, int mode);
diff --git a/modules/htable/ht_dmq.c b/modules/htable/ht_dmq.c
new file mode 100644
index 0000000..c2cf7a5
--- /dev/null
+++ b/modules/htable/ht_dmq.c
@@ -0,0 +1,277 @@
+/**
+ * 
+ * Copyright (C) 2013 Charles Chance (Sipcentric Ltd)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include "ht_dmq.h"
+#include "ht_api.h"
+
+static str ht_dmq_content_type = str_init("application/json");
+static str dmq_200_rpl  = str_init("OK");
+static str dmq_400_rpl  = str_init("Bad Request");
+static str dmq_500_rpl  = str_init("Server Internal Error");
+
+typedef struct _ht_dmq_repdata {
+	int action;
+	str htname;
+	str cname;
+	int type;
+	int intval;
+	str strval;
+	int expire;
+} ht_dmq_repdata_t;
+
+dmq_api_t ht_dmqb;
+dmq_peer_t* ht_dmq_peer = NULL;
+dmq_resp_cback_t ht_dmq_resp_callback = {&ht_dmq_resp_callback_f, 0};
+
+/**
+ * @brief add notification peer
+ */
+int ht_dmq_initialize()
+{
+	dmq_peer_t not_peer;
+
+        /* load the DMQ API */
+        if (dmq_load_api(&ht_dmqb)!=0) {
+                LM_ERR("cannot load dmq api\n");
+                return -1;
+        } else {
+                LM_DBG("loaded dmq api\n");
+        }
+
+	not_peer.callback = ht_dmq_handle_msg;
+	not_peer.description.s = "htable";
+	not_peer.description.len = 6;
+	not_peer.peer_id.s = "htable";
+	not_peer.peer_id.len = 6;
+	ht_dmq_peer = ht_dmqb.register_dmq_peer(&not_peer);
+	if(!ht_dmq_peer) {
+		LM_ERR("error in register_dmq_peer\n");
+		goto error;
+	} else {
+		LM_DBG("dmq peer registered\n");
+	}
+	return 0;
+error:
+	return -1;
+}
+
+int ht_dmq_broadcast(str* body) {
+        if (!ht_dmq_peer) {
+                LM_ERR("ht_dmq_peer is null!\n");
+                return -1;
+        }
+        LM_DBG("sending broadcast...\n");
+        ht_dmqb.bcast_message(ht_dmq_peer, body, 0, &ht_dmq_resp_callback, 1, &ht_dmq_content_type);
+        return 0;
+}
+
+/**
+ * @brief ht dmq callback
+ */
+int ht_dmq_handle_msg(struct sip_msg* msg, peer_reponse_t* resp)
+{
+	int content_length;
+	str body;
+	ht_dmq_action_t action = HT_DMQ_NONE;
+	str htname, cname;
+	int type = 0, mode = 0;
+	int_str val;
+	srjson_doc_t jdoc;
+	srjson_t *it = NULL;
+
+	/* received dmq message */
+	LM_DBG("dmq message received\n");
+	
+	if(!msg->content_length) {
+		LM_ERR("no content length header found\n");
+		goto invalid;
+	}
+	content_length = get_content_length(msg);
+	if(!content_length) {
+		LM_DBG("content length is 0\n");
+		goto invalid;
+	}
+
+	body.s = get_body(msg);
+	body.len = content_length;
+
+	if (!body.s) {
+		LM_ERR("unable to get body\n");
+		goto error;
+	}
+
+	/* parse body */
+	LM_DBG("body: %.*s\n", body.len, body.s);	
+
+	srjson_InitDoc(&jdoc, NULL);
+	jdoc.buf = body;
+
+	if(jdoc.root == NULL) {
+		jdoc.root = srjson_Parse(&jdoc, jdoc.buf.s);
+		if(jdoc.root == NULL)
+		{
+			LM_ERR("invalid json doc [[%s]]\n", jdoc.buf.s);
+			goto invalid;
+		}
+	}
+
+	for(it=jdoc.root->child; it; it = it->next)
+	{
+		LM_DBG("found field: %s\n", it->string);
+		if (strcmp(it->string, "action")==0) {
+			action = it->valueint;
+		} else if (strcmp(it->string, "htname")==0) {
+			htname.s = it->valuestring;
+			htname.len = strlen(htname.s);
+		} else if (strcmp(it->string, "cname")==0) {
+			cname.s = it->valuestring;
+			cname.len = strlen(cname.s);
+		} else if (strcmp(it->string, "type")==0) {
+			type = it->valueint;
+		} else if (strcmp(it->string, "strval")==0) {
+			val.s.s = it->valuestring;
+			val.s.len = strlen(val.s.s);
+		} else if (strcmp(it->string, "intval")==0) {
+			val.n = it->valueint;
+		} else if (strcmp(it->string, "mode")==0) {
+			mode = it->valueint;
+		} else {
+			LM_ERR("unrecognized field in json object\n");
+			goto invalid;
+		}
+	}	
+
+	if (ht_dmq_replay_action(action, &htname, &cname, type, &val, mode)!=0) {
+		LM_ERR("failed to replay action\n");
+		goto error;
+	}
+
+	srjson_DestroyDoc(&jdoc);
+	resp->reason = dmq_200_rpl;
+	resp->resp_code = 200;
+	return 0;
+
+invalid:
+	srjson_DestroyDoc(&jdoc);
+	resp->reason = dmq_400_rpl;
+	resp->resp_code = 400;
+	return 0;
+
+error:
+	srjson_DestroyDoc(&jdoc);
+	resp->reason = dmq_500_rpl;
+	resp->resp_code = 500;	
+	return 0;
+}
+
+int ht_dmq_replicate_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode) {
+
+	srjson_doc_t jdoc;
+
+        LM_DBG("replicating action to dmq peers...\n");
+
+	srjson_InitDoc(&jdoc, NULL);
+
+	jdoc.root = srjson_CreateObject(&jdoc);
+	if(jdoc.root==NULL) {
+		LM_ERR("cannot create json root\n");
+		goto error;
+	}
+
+	srjson_AddNumberToObject(&jdoc, jdoc.root, "action", action);
+	srjson_AddStrToObject(&jdoc, jdoc.root, "htname", htname->s, htname->len);
+	if (cname!=NULL) {
+		srjson_AddStrToObject(&jdoc, jdoc.root, "cname", cname->s, cname->len);
+	}
+
+	if (action==HT_DMQ_SET_CELL || action==HT_DMQ_SET_CELL_EXPIRE || action==HT_DMQ_RM_CELL_RE) {
+		srjson_AddNumberToObject(&jdoc, jdoc.root, "type", type);
+		if (type&AVP_VAL_STR) {
+			srjson_AddStrToObject(&jdoc, jdoc.root, "strval", val->s.s, val->s.len);
+		} else {
+			srjson_AddNumberToObject(&jdoc, jdoc.root, "intval", val->n);
+		}
+	}
+
+	srjson_AddNumberToObject(&jdoc, jdoc.root, "mode", mode);	
+
+	jdoc.buf.s = srjson_PrintUnformatted(&jdoc, jdoc.root);
+	if(jdoc.buf.s!=NULL) {
+		jdoc.buf.len = strlen(jdoc.buf.s);
+		LM_DBG("sending serialized data %.*s\n", jdoc.buf.len, jdoc.buf.s);
+		if (ht_dmq_broadcast(&jdoc.buf)!=0) {
+			goto error;
+		}
+		jdoc.free_fn(jdoc.buf.s);
+		jdoc.buf.s = NULL;
+	} else {
+		LM_ERR("unable to serialize data\n");
+		goto error;
+	}
+
+	srjson_DestroyDoc(&jdoc);
+	return 0;
+
+error:
+	if(jdoc.buf.s!=NULL) {
+		jdoc.free_fn(jdoc.buf.s);
+		jdoc.buf.s = NULL;
+	}
+	srjson_DestroyDoc(&jdoc);
+	return -1;
+}
+
+int ht_dmq_replay_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode) {
+
+	ht_t* ht;
+	ht = ht_get_table(htname);
+	if(ht==NULL) {
+		LM_ERR("unable to get table\n");
+		return -1;
+	}
+
+        LM_DBG("replaying action %d on %.*s=>%.*s...\n", action, htname->len, htname->s, cname->len, cname->s);
+
+	if (action==HT_DMQ_SET_CELL) {
+		return ht_set_cell(ht, cname, type, val, mode);
+	} else if (action==HT_DMQ_SET_CELL_EXPIRE) {
+		return ht_set_cell_expire(ht, cname, 0, val);
+	} else if (action==HT_DMQ_DEL_CELL) {
+		return ht_del_cell(ht, cname);
+	} else if (action==HT_DMQ_RM_CELL_RE) {
+		return ht_rm_cell_re(&val->s, ht, mode);
+	} else {
+		LM_ERR("unrecognized action");
+		return -1;
+	}
+}
+
+/**
+ * @brief dmq response callback
+ */
+int ht_dmq_resp_callback_f(struct sip_msg* msg, int code,
+		dmq_node_t* node, void* param)
+{
+	LM_DBG("dmq response callback triggered [%p %d %p]\n", msg, code, param);
+	return 0;
+}
diff --git a/modules/htable/ht_dmq.h b/modules/htable/ht_dmq.h
new file mode 100644
index 0000000..6acea93
--- /dev/null
+++ b/modules/htable/ht_dmq.h
@@ -0,0 +1,48 @@
+/**
+ *
+ * Copyright (C) 2013 Charles Chance (Sipcentric Ltd)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _HT_DMQ_H_
+#define _HT_DMQ_H_
+
+#include "../dmq/bind_dmq.h"
+#include "../../lib/srutils/srjson.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/parse_content.h"
+
+extern dmq_api_t ht_dmqb;
+extern dmq_peer_t* ht_dmq_peer;
+extern dmq_resp_cback_t ht_dmq_resp_callback;
+
+typedef enum {
+		HT_DMQ_NONE,
+        HT_DMQ_SET_CELL,
+        HT_DMQ_SET_CELL_EXPIRE,
+        HT_DMQ_DEL_CELL,
+        HT_DMQ_RM_CELL_RE
+} ht_dmq_action_t;
+
+int ht_dmq_initialize();
+int ht_dmq_handle_msg(struct sip_msg* msg, peer_reponse_t* resp);
+int ht_dmq_replicate_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode);
+int ht_dmq_replay_action(ht_dmq_action_t action, str* htname, str* cname, int type, int_str* val, int mode);
+int ht_dmq_resp_callback_f(struct sip_msg* msg, int code, dmq_node_t* node, void* param);
+
+#endif
diff --git a/modules/htable/ht_var.c b/modules/htable/ht_var.c
index 87f85c9..4ef38be 100644
--- a/modules/htable/ht_var.c
+++ b/modules/htable/ht_var.c
@@ -22,6 +22,7 @@
 		       
 #include "ht_api.h"
 #include "ht_var.h"
+#include "ht_dmq.h"
 
 /* pkg copy */
 ht_cell_t *_htc_local=NULL;
@@ -90,6 +91,9 @@ int pv_set_ht_cell(struct sip_msg* msg, pv_param_t *param,
 	if((val==NULL) || (val->flags&PV_VAL_NULL))
 	{
 		/* delete it */
+		if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, &hpv->htname, &htname, 0, NULL, 0)!=0) {
+			LM_ERR("dmq relication failed\n");
+		}
 		ht_del_cell(hpv->ht, &htname);
 		return 0;
 	}
@@ -97,6 +101,9 @@ int pv_set_ht_cell(struct sip_msg* msg, pv_param_t *param,
 	if(val->flags&PV_TYPE_INT)
 	{
 		isval.n = val->ri;
+		if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &hpv->htname, &htname, 0, &isval, 1)!=0) {
+			LM_ERR("dmq relication failed\n");
+		}
 		if(ht_set_cell(hpv->ht, &htname, 0, &isval, 1)!=0)
 		{
 			LM_ERR("cannot set $ht(%.*s)\n", htname.len, htname.s);
@@ -104,6 +111,9 @@ int pv_set_ht_cell(struct sip_msg* msg, pv_param_t *param,
 		}
 	} else {
 		isval.s = val->rs;
+		if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &hpv->htname, &htname, AVP_VAL_STR, &isval, 1)!=0) {
+			LM_ERR("dmq relication failed\n");
+		}
 		if(ht_set_cell(hpv->ht, &htname, AVP_VAL_STR, &isval, 1)!=0)
 		{
 			LM_ERR("cannot set $ht(%.*s)\n", htname.len, htname.s);
@@ -229,6 +239,9 @@ int pv_set_ht_cell_expire(struct sip_msg* msg, pv_param_t *param,
 		if(val->flags&PV_TYPE_INT)
 			isval.n = val->ri;
 	}
+	if (hpv->ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL_EXPIRE, &hpv->htname, &htname, 0, &isval, 0)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}	
 	if(ht_set_cell_expire(hpv->ht, &htname, 0, &isval)!=0)
 	{
 		LM_ERR("cannot set $ht(%.*s)\n", htname.len, htname.s);
@@ -327,6 +340,11 @@ int pv_get_ht_add(struct sip_msg *msg,  pv_param_t *param,
 		return pv_get_null(msg, param, res);
 
 	/* integer */
+	if (hpv->ht->dmqreplicate>0) {
+		if (ht_dmq_replicate_action(HT_DMQ_SET_CELL, &hpv->htname, &htname, 0, &htc->value, 1)!=0) {
+			LM_ERR("dmq relication failed\n");
+		}
+	}	
 	return pv_get_sintval(msg, param, res, htc->value.n);
 }
 
diff --git a/modules/htable/htable.c b/modules/htable/htable.c
index 2b22542..1900ec5 100644
--- a/modules/htable/htable.c
+++ b/modules/htable/htable.c
@@ -32,6 +32,7 @@
 #include "../../timer.h"
 #include "../../route.h"
 #include "../../dprint.h"
+#include "../../hashes.h"
 #include "../../ut.h"
 #include "../../rpc.h"
 #include "../../rpc_lookup.h"
@@ -43,12 +44,14 @@
 #include "ht_db.h"
 #include "ht_var.h"
 #include "api.h"
+#include "ht_dmq.h"
 
 
 MODULE_VERSION
 
 int  ht_timer_interval = 20;
 int  ht_db_expires_flag = 0;
+int  ht_enable_dmq = 0;
 
 static int htable_init_rpc(void);
 
@@ -58,9 +61,11 @@ static int mod_init(void);
 static int child_init(int rank);
 static void destroy(void);
 
-static int fixup_ht_rm(void** param, int param_no);
+static int fixup_ht_key(void** param, int param_no);
 static int ht_rm_name_re(struct sip_msg* msg, char* key, char* foo);
 static int ht_rm_value_re(struct sip_msg* msg, char* key, char* foo);
+static int ht_slot_lock(struct sip_msg* msg, char* key, char* foo);
+static int ht_slot_unlock(struct sip_msg* msg, char* key, char* foo);
 
 int ht_param(modparam_t type, void* val);
 
@@ -96,9 +101,13 @@ static mi_export_t mi_cmds[] = {
 static cmd_export_t cmds[]={
 	{"sht_print",       (cmd_function)ht_print,        0, 0, 0,
 		ANY_ROUTE},
-	{"sht_rm_name_re",  (cmd_function)ht_rm_name_re,   1, fixup_ht_rm, 0,
+	{"sht_rm_name_re",  (cmd_function)ht_rm_name_re,   1, fixup_ht_key, 0,
 		ANY_ROUTE},
-	{"sht_rm_value_re", (cmd_function)ht_rm_value_re,  1, fixup_ht_rm, 0,
+	{"sht_rm_value_re", (cmd_function)ht_rm_value_re,  1, fixup_ht_key, 0,
+		ANY_ROUTE},
+	{"sht_lock",        (cmd_function)ht_slot_lock,    1, fixup_ht_key, 0,
+		ANY_ROUTE},
+	{"sht_unlock",      (cmd_function)ht_slot_unlock,  1, fixup_ht_key, 0,
 		ANY_ROUTE},
 	{"bind_htable",     (cmd_function)bind_htable,     0, 0, 0,
 		ANY_ROUTE},
@@ -117,6 +126,7 @@ static param_export_t params[]={
 	{"fetch_rows",         INT_PARAM, &ht_fetch_rows},
 	{"timer_interval",     INT_PARAM, &ht_timer_interval},
 	{"db_expires",         INT_PARAM, &ht_db_expires_flag},
+	{"enable_dmq",         INT_PARAM, &ht_enable_dmq},
 	{0,0,0}
 };
 
@@ -181,6 +191,12 @@ static int mod_init(void)
 			return -1;
 		}
 	}
+
+	if (ht_enable_dmq>0 && ht_dmq_initialize()!=0) {
+		LM_ERR("failed to initialize dmq integration\n");
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -245,7 +261,7 @@ static int ht_print(struct sip_msg *msg, char *s1, char *s2)
 	return 1;
 }
 
-static int fixup_ht_rm(void** param, int param_no)
+static int fixup_ht_key(void** param, int param_no)
 {
 	pv_spec_t *sp;
 	str s;
@@ -279,6 +295,7 @@ static int ht_rm_name_re(struct sip_msg* msg, char* key, char* foo)
 	str sre;
 	pv_spec_t *sp;
 	sp = (pv_spec_t*)key;
+	int_str isval;
 
 	hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
 
@@ -293,6 +310,12 @@ static int ht_rm_name_re(struct sip_msg* msg, char* key, char* foo)
 		LM_ERR("cannot get $ht expression\n");
 		return -1;
 	}
+	if (hpv->ht->dmqreplicate>0) {
+		isval.s = sre;
+		if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, &hpv->htname, NULL, AVP_VAL_STR, &isval, 0)!=0) {
+			LM_ERR("dmq relication failed\n");
+		}
+	}
 	if(ht_rm_cell_re(&sre, hpv->ht, 0)<0)
 		return -1;
 	return 1;
@@ -304,6 +327,7 @@ static int ht_rm_value_re(struct sip_msg* msg, char* key, char* foo)
 	str sre;
 	pv_spec_t *sp;
 	sp = (pv_spec_t*)key;
+	int_str isval;
 
 	hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
 
@@ -319,11 +343,100 @@ static int ht_rm_value_re(struct sip_msg* msg, char* key, char* foo)
 		return -1;
 	}
 
+	if (hpv->ht->dmqreplicate>0) {
+		isval.s = sre;
+		if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, &hpv->htname, NULL, AVP_VAL_STR, &isval, 1)!=0) {
+			LM_ERR("dmq relication failed\n");
+		}
+	}
 	if(ht_rm_cell_re(&sre, hpv->ht, 1)<0)
 		return -1;
 	return 1;
 }
 
+/**
+ * lock the slot for a given key in a hash table
+ */
+static int ht_slot_lock(struct sip_msg* msg, char* key, char* foo)
+{
+	ht_pv_t *hpv;
+	str skey;
+	pv_spec_t *sp;
+	unsigned int hid;
+	unsigned int idx;
+
+	sp = (pv_spec_t*)key;
+
+	hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
+
+	if(hpv->ht==NULL)
+	{
+		hpv->ht = ht_get_table(&hpv->htname);
+		if(hpv->ht==NULL) {
+			LM_ERR("cannot get $ht root\n");
+			return -11;
+		}
+	}
+	if(pv_printf_s(msg, hpv->pve, &skey)!=0)
+	{
+		LM_ERR("cannot get $ht key\n");
+		return -1;
+	}
+
+	hid = ht_compute_hash(&skey);
+
+	idx = ht_get_entry(hid, hpv->ht->htsize);
+
+	LM_DBG("unlocking slot %.*s[%u] for key %.*s\n",
+			hpv->htname.len, hpv->htname.s,
+			idx, skey.len, skey.s);
+
+	lock_get(&hpv->ht->entries[idx].lock);
+
+	return 1;
+}
+
+/**
+ * unlock the slot for a given key in a hash table
+ */
+static int ht_slot_unlock(struct sip_msg* msg, char* key, char* foo)
+{
+	ht_pv_t *hpv;
+	str skey;
+	pv_spec_t *sp;
+	unsigned int hid;
+	unsigned int idx;
+
+	sp = (pv_spec_t*)key;
+
+	hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
+
+	if(hpv->ht==NULL)
+	{
+		hpv->ht = ht_get_table(&hpv->htname);
+		if(hpv->ht==NULL) {
+			LM_ERR("cannot get $ht root\n");
+			return -11;
+		}
+	}
+	if(pv_printf_s(msg, hpv->pve, &skey)!=0)
+	{
+		LM_ERR("cannot get $ht key\n");
+		return -1;
+	}
+
+	hid = ht_compute_hash(&skey);
+
+	idx = ht_get_entry(hid, hpv->ht->htsize);
+
+	LM_DBG("unlocking slot %.*s[%u] for key %.*s\n",
+			hpv->htname.len, hpv->htname.s,
+			idx, skey.len, skey.s);
+
+	lock_release(&hpv->ht->entries[idx].lock);
+
+	return 1;
+}
 
 int ht_param(modparam_t type, void *val)
 {
@@ -441,6 +554,10 @@ static struct mi_root* ht_mi_delete(struct mi_root* cmd_tree, void* param) {
 	if (!ht)
 		return init_mi_tree(404, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
 
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, &ht->name, key, 0, NULL, 0)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}
+
 	ht_del_cell(ht, key);
 
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
@@ -530,10 +647,26 @@ static const char* htable_get_doc[2] = {
 	"Get one key from a hash table.",
 	0
 };
+static const char* htable_sets_doc[2] = {
+	"Set one key in a hash table to a string value.",
+	0
+};
+static const char* htable_seti_doc[2] = {
+	"Set one key in a hash table to an integer value.",
+	0
+};
 static const char* htable_list_doc[2] = {
 	"List all htables.",
 	0
 };
+static const char* htable_stats_doc[2] = {
+	"Statistics about htables.",
+	0
+};
+static const char* htable_reload_doc[2] = {
+	"Reload hash table.",
+	0
+};
 
 static void htable_rpc_delete(rpc_t* rpc, void* c) {
 	str htname, keyname;
@@ -549,6 +682,10 @@ static void htable_rpc_delete(rpc_t* rpc, void* c) {
 		return;
 	}
 
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_DEL_CELL, &ht->name, &keyname, 0, NULL, 0)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}
+
 	ht_del_cell(ht, &keyname);
 }
 
@@ -612,6 +749,75 @@ error:
 	return;
 }
 
+/*! \brief RPC htable.sets command to set one item to string value */
+static void htable_rpc_sets(rpc_t* rpc, void* c) {
+	str htname, keyname;
+	int_str keyvalue;
+	ht_t *ht;
+
+	if (rpc->scan(c, "SS.S", &htname, &keyname, &keyvalue.s) < 3) {
+		rpc->fault(c, 500,
+				"Not enough parameters (htable name, key name and value)");
+		return;
+	}
+
+	/* Find the htable */
+	ht = ht_get_table(&htname);
+	if (!ht) {
+		rpc->fault(c, 500, "No such htable");
+		return;
+	}
+	
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &ht->name, &keyname, AVP_VAL_STR, &keyvalue, 1)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}
+
+	if(ht_set_cell(ht, &keyname, AVP_VAL_STR, &keyvalue, 1)!=0)
+	{
+		LM_ERR("cannot set $ht(%.*s=>%.*s)\n", htname.len, htname.s,
+				keyname.len, keyname.s);
+		rpc->fault(c, 500, "Failed to set the item");
+		return;
+	}
+
+	return;
+}
+
+/*! \brief RPC htable.seti command to set one item to integer value */
+static void htable_rpc_seti(rpc_t* rpc, void* c) {
+	str htname, keyname;
+	int_str keyvalue;
+	ht_t *ht;
+
+	if (rpc->scan(c, "SS.d", &htname, &keyname, &keyvalue.n) < 3) {
+		rpc->fault(c, 500,
+				"Not enough parameters (htable name, key name and value)");
+		return;
+	}
+
+	/* Find the htable */
+	ht = ht_get_table(&htname);
+	if (!ht) {
+		rpc->fault(c, 500, "No such htable");
+		return;
+	}
+
+	if (ht->dmqreplicate>0 && ht_dmq_replicate_action(HT_DMQ_SET_CELL, &ht->name, &keyname, 0, &keyvalue, 1)!=0) {
+		LM_ERR("dmq relication failed\n");
+	}
+	
+	if(ht_set_cell(ht, &keyname, 0, &keyvalue, 1)!=0)
+	{
+		LM_ERR("cannot set $ht(%.*s=>%.*s)\n", htname.len, htname.s,
+				keyname.len, keyname.s);
+		rpc->fault(c, 500, "Failed to set the item");
+		return;
+	}
+
+	return;
+}
+
+/*! \brief RPC htable.dump command to print content of a hash table */
 static void  htable_rpc_dump(rpc_t* rpc, void* c)
 {
 	str htname;
@@ -719,13 +925,14 @@ static void  htable_rpc_list(rpc_t* rpc, void* c)
 			dbname[0] = '\0';
 		}
 
-		if(rpc->struct_add(th, "Ssdddd",
+		if(rpc->struct_add(th, "Ssddddd",
 						"name", &ht->name,	/* String */
 						"dbtable", &dbname ,	/* Char * */
 						"dbmode", (int)  ht->dbmode,		/* u int */
 						"expire", (int) ht->htexpire,		/* u int */
 						"updateexpire", ht->updateexpire,	/* int */
-						"size", (int) ht->htsize		/* u int */
+						"size", (int) ht->htsize,			/* u int */
+						"dmqreplicate", ht->dmqreplicate	/* int */
 						) < 0) {
 			rpc->fault(c, 500, "Internal error creating data rpc");
 			goto error;
@@ -737,11 +944,147 @@ error:
 	return;
 }
 
+static void  htable_rpc_stats(rpc_t* rpc, void* c)
+{
+	ht_t *ht;
+	void* th;
+	unsigned int min;
+	unsigned int max;
+	unsigned int all;
+	unsigned int i;
+
+	ht = ht_get_root();
+	if(ht==NULL)
+	{
+		rpc->fault(c, 500, "No htables");
+		return;
+	}
+	while (ht != NULL)
+	{
+		/* add entry node */
+		if (rpc->add(c, "{", &th) < 0)
+		{
+			rpc->fault(c, 500, "Internal error creating structure rpc");
+			goto error;
+		}
+		all = 0;
+		max = 0;
+		min = 4294967295U;
+		for(i=0; i<ht->htsize; i++) {
+			lock_get(&ht->entries[i].lock);
+			if(ht->entries[i].esize<min)
+				min = ht->entries[i].esize;
+			if(ht->entries[i].esize>max)
+				max = ht->entries[i].esize;
+			all += ht->entries[i].esize;
+			lock_release(&ht->entries[i].lock);
+		}
+
+		if(rpc->struct_add(th, "Sddd",
+						"name", &ht->name,	/* str */
+						"slots", (int)ht->htsize,	/* uint */
+						"all", (int)all,	/* uint */
+						"min", (int)min,	/* uint */
+						"max", (int)max		/* uint */
+						) < 0) {
+			rpc->fault(c, 500, "Internal error creating rpc structure");
+			goto error;
+		}
+		ht = ht->next;
+	}
+
+error:
+	return;
+}
+
+
+/*! \brief RPC htable.reload command to reload content of a hash table */
+static void htable_rpc_reload(rpc_t* rpc, void* c)
+{
+	str htname;
+	ht_t *ht;
+	ht_t nht;
+	ht_cell_t *first;
+	ht_cell_t *it;
+	int i;
+
+	if(ht_db_url.len<=0) {
+		rpc->fault(c, 500, "No htable db_url");
+		return;
+	}
+	if(ht_db_init_con()!=0) {
+		rpc->fault(c, 500, "Failed to init htable db connection");
+		return;
+	}
+	if(ht_db_open_con()!=0) {
+		rpc->fault(c, 500, "Failed to open htable db connection");
+		return;
+	}
+
+	if (rpc->scan(c, "S", &htname) < 1)
+	{
+		rpc->fault(c, 500, "No htable name given");
+		return;
+	}
+	ht = ht_get_table(&htname);
+	if(ht==NULL)
+	{
+		rpc->fault(c, 500, "No such htable");
+		return;
+	}
+
+
+	memcpy(&nht, ht, sizeof(ht_t));
+	nht.entries = (ht_entry_t*)shm_malloc(nht.htsize*sizeof(ht_entry_t));
+	if(nht.entries == NULL)
+	{
+		ht_db_close_con();
+		rpc->fault(c, 500, "Mtree reload failed");
+		return;
+	}
+	memset(nht.entries, 0, nht.htsize*sizeof(ht_entry_t));
+
+	if(ht_db_load_table(&nht, &ht->dbtable, 0)<0)
+	{
+		ht_db_close_con();
+		rpc->fault(c, 500, "Mtree reload failed");
+		return;
+	}
+
+	/* replace old entries */
+	for(i=0; i<nht.htsize; i++)
+	{
+		lock_get(&ht->entries[i].lock);
+		first = ht->entries[i].first;
+		ht->entries[i].first = nht.entries[i].first;
+		ht->entries[i].esize = nht.entries[i].esize;
+		lock_release(&ht->entries[i].lock);
+		nht.entries[i].first = first;
+	}
+	/* free old entries */
+	for(i=0; i<nht.htsize; i++)
+	{
+		first = nht.entries[i].first;
+		while(first)
+		{
+			it = first;
+			first = first->next;
+			ht_cell_free(it);
+		}
+	}
+	ht_db_close_con();
+	return;
+}
+
 rpc_export_t htable_rpc[] = {
 	{"htable.dump", htable_rpc_dump, htable_dump_doc, 0},
 	{"htable.delete", htable_rpc_delete, htable_delete_doc, 0},
 	{"htable.get", htable_rpc_get, htable_get_doc, 0},
+	{"htable.sets", htable_rpc_sets, htable_sets_doc, 0},
+	{"htable.seti", htable_rpc_seti, htable_seti_doc, 0},
 	{"htable.listTables", htable_rpc_list, htable_list_doc, 0},
+	{"htable.reload", htable_rpc_reload, htable_reload_doc, 0},
+	{"htable.stats", htable_rpc_stats, htable_stats_doc, 0},
 	{0, 0, 0, 0}
 };
 
diff --git a/modules/imc/README b/modules/imc/README
index d64d373..c6220be 100644
--- a/modules/imc/README
+++ b/modules/imc/README
@@ -232,7 +232,7 @@ modparam("imc", "extra_hdrs", "P-Flags: 3\r\n")
 
    4.1. imc_manager()
 
-4.1. imc_manager()
+4.1.  imc_manager()
 
    Handles Message method.It detects if the body of the message is a
    conference command.If so it executes it, otherwise it sends the message
@@ -261,7 +261,7 @@ if(is_method("MESSAGE)
    5.1. imc_list_rooms
    5.2. imc_list_members
 
-5.1. imc_list_rooms
+5.1.  imc_list_rooms
 
    Lists of the IM Conferencing rooms.
 
@@ -273,7 +273,7 @@ if(is_method("MESSAGE)
                 :imc_list_rooms:_reply_fifo_file_
                 _empty_line_
 
-5.2. imc_list_members
+5.2.  imc_list_members
 
    Listing of the members in IM Conferencing rooms.
 
@@ -291,7 +291,7 @@ if(is_method("MESSAGE)
 
    6.1. active_rooms
 
-6.1. active_rooms
+6.1.  active_rooms
 
    Number of active IM Conferencing rooms.
 
diff --git a/modules/ims_auth/authims_mod.c b/modules/ims_auth/authims_mod.c
index 12070c6..b245d85 100644
--- a/modules/ims_auth/authims_mod.c
+++ b/modules/ims_auth/authims_mod.c
@@ -67,7 +67,8 @@ static void destroy(void);
 static int mod_init(void);
 
 static int auth_fixup(void** param, int param_no);
-static int challenge_fixup(void** param, int param_no);
+static int auth_fixup_async(void** param, int param_no);
+static int challenge_fixup_async(void** param, int param_no);
 
 struct cdp_binds cdpb;
 
@@ -86,6 +87,7 @@ int av_request_at_once = 1; /**< how many auth vectors to request in a MAR 				*
 int av_request_at_sync = 1; /**< how many auth vectors to request in a sync MAR 		*/
 char *registration_qop = "auth,auth-int"; /**< the qop options to put in the authorization challenges */
 str registration_qop_str = {0, 0}; /**< the qop options to put in the authorization challenges */
+int av_check_only_impu = 0; /**< Should we check IMPU (0) or IMPU and IMPI (1), when searching for authentication vectors? */
 static str s_qop_s = {", qop=\"", 7};
 static str s_qop_e = {"\"", 1};
 
@@ -108,7 +110,7 @@ str cxdx_forced_peer;
 /* fixed parameter storage */
 str scscf_name_str; /**< fixed name of the S-CSCF 							*/
 
-/* used mainly in testing - load balancing with SIPP where we dont want to worry about auth */
+/* used mainly in testing - load balancing with SIPP where we don't want to worry about auth */
 int ignore_failed_auth = 0;
 
 /*
@@ -116,9 +118,9 @@ int ignore_failed_auth = 0;
  */
 static cmd_export_t cmds[] = {
     {"ims_www_authenticate", (cmd_function) www_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
-    {"ims_www_challenge", (cmd_function) www_challenge, 1, challenge_fixup, 0, REQUEST_ROUTE},
+    {"ims_www_challenge", (cmd_function) www_challenge, 2, challenge_fixup_async, 0, REQUEST_ROUTE},
     {"ims_proxy_authenticate", (cmd_function) proxy_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
-    {"ims_proxy_challenge", (cmd_function) proxy_challenge, 1, auth_fixup, 0, REQUEST_ROUTE},
+    {"ims_proxy_challenge", (cmd_function) proxy_challenge, 2, auth_fixup_async, 0, REQUEST_ROUTE},
     {"bind_ims_auth", (cmd_function) bind_ims_auth, 0, 0, 0, 0},
     {0, 0, 0, 0, 0, 0}
 };
@@ -139,6 +141,7 @@ static param_export_t params[] = {
     {"registration_default_algorithm", STR_PARAM, &registration_default_algorithm},
     {"registration_qop", STR_PARAM, &registration_qop},
     {"ignore_failed_auth", INT_PARAM, &ignore_failed_auth},
+    {"av_check_only_impu", INT_PARAM, &av_check_only_impu},
     {"cxdx_forced_peer", STR_PARAM, &cxdx_forced_peer_s},
     {"cxdx_dest_realm", STR_PARAM, &cxdx_dest_realm_s},
     {0, 0, 0}
@@ -266,30 +269,22 @@ static void destroy(void) {
 /*
  * Convert the char* parameters
  */
-static int challenge_fixup(void** param, int param_no) {
+static int challenge_fixup_async(void** param, int param_no) {
 
     if (strlen((char*) *param) <= 0) {
         LM_ERR("empty parameter %d not allowed\n", param_no);
         return -1;
     }
 
-    if (param_no == 1) {
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0)
+            return -1;
+        return 0;
+    } else if (param_no == 2) {
         if (fixup_var_str_12(param, 1) == -1) {
             LM_ERR("Erroring doing fixup on challenge");
             return -1;
         }
-        mar_param_t *ap;
-        ap = (mar_param_t*) pkg_malloc(sizeof (mar_param_t));
-        if (ap == NULL) {
-            LM_ERR("no more pkg\n");
-            return -1;
-        }
-        memset(ap, 0, sizeof (mar_param_t));
-        ap->paction = get_action_from_param(param, param_no);
-
-        ap->param = (char*) *param;
-
-        *param = (void*) ap;
     }
 
     return 0;
@@ -305,7 +300,29 @@ static int auth_fixup(void** param, int param_no) {
     }
 
     if (param_no == 1) {
-        //return fixup_var_str_12(param, 1);
+        if (fixup_var_str_12(param, 1) == -1) {
+            LM_ERR("Erroring doing fixup on auth");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Convert the char* parameters
+ */
+static int auth_fixup_async(void** param, int param_no) {
+    if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+    }
+
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0)
+            return -1;
+        return 0;
+    } else if (param_no == 2) {
         if (fixup_var_str_12(param, 1) == -1) {
             LM_ERR("Erroring doing fixup on auth");
             return -1;
diff --git a/modules/ims_auth/authorize.c b/modules/ims_auth/authorize.c
index 8b1904d..026e3b5 100644
--- a/modules/ims_auth/authorize.c
+++ b/modules/ims_auth/authorize.c
@@ -47,6 +47,7 @@
 #include "../../ut.h"
 #include "../../str.h"
 #include "../../basex.h"
+#include "../../hashes.h"
 #include "../../lib/srdb1/db.h"
 #include "../../lib/srdb1/db_ut.h"
 #include "../../dprint.h"
@@ -85,6 +86,7 @@ extern int add_authinfo_hdr;
 extern int max_nonce_reuse;
 extern str scscf_name_str;
 extern int ignore_failed_auth;
+extern int av_check_only_impu;
 
 auth_hash_slot_t *auth_data; /**< Authentication vector hash table */
 extern int auth_data_hash_size; /**< authentication vector hash table size */
@@ -268,22 +270,38 @@ int proxy_authenticate(struct sip_msg* _m, char* _realm, char* _table) {
     return digest_authenticate(_m, &srealm, &stable, HDR_PROXYAUTH_T);
 }
  */
-int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth) {
+int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, char *route) {
 
     str realm = {0, 0};
     unsigned int aud_hash;
     str private_identity, public_identity, auts = {0, 0}, nonce = {0, 0};
     auth_vector *av = 0;
     int algo_type;
+    
+    str route_name;
 
     saved_transaction_t* saved_t;
     tm_cell_t *t = 0;
     cfg_action_t* cfg_action;
 
-    mar_param_t* ap = (mar_param_t*) str1;
-    cfg_action = ap->paction->next;
+    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
 
-    if (get_str_fparam(&realm, msg, (fparam_t*) ap->param) < 0) {
+    if (get_str_fparam(&realm, msg, (fparam_t*) str1) < 0) {
         LM_ERR("failed to get realm value\n");
         return CSCF_RETURN_ERROR;
     }
@@ -453,12 +471,12 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth) {
     return CSCF_RETURN_BREAK;
 }
 
-int www_challenge(struct sip_msg* msg, char* str1, char* str2) {
-    return challenge(msg, str1, str2, 0);
+int www_challenge(struct sip_msg* msg, char* _route, char* str1, char* str2) {
+    return challenge(msg, str1, str2, 0, _route);
 }
 
-int proxy_challenge(struct sip_msg* msg, char* str1, char* str2) {
-    return challenge(msg, str1, str2, 1);
+int proxy_challenge(struct sip_msg* msg, char* _route, char* str1, char* str2) {
+    return challenge(msg, str1, str2, 1, _route);
 }
 
 /**
@@ -648,7 +666,7 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
         LM_ERR("no matching auth vector found - maybe timer expired\n");
 
         if (ignore_failed_auth) {
-            LM_WARN("NB: Ignoring all failed auth - check your config if you dont expect this\n");
+            LM_WARN("NB: Ignoring all failed auth - check your config if you don't expect this\n");
             ret = AUTH_OK;
         }
 
@@ -783,7 +801,7 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
     }
 
     if (ignore_failed_auth) {
-        LM_WARN("NB: Ignoring all failed auth - check your config if you dont expect this\n");
+        LM_WARN("NB: Ignoring all failed auth - check your config if you don't expect this\n");
         ret = AUTH_OK;
     }
 
@@ -1162,6 +1180,12 @@ void free_auth_userdata(auth_userdata * aud) {
  * @returns the hash % Auth_data->size
  */
 inline unsigned int get_hash_auth(str private_identity, str public_identity) {
+if (av_check_only_impu)
+	return core_hash(&public_identity, 0, auth_data_hash_size);
+else
+	return core_hash(&public_identity, 0, auth_data_hash_size);
+/*
+
 
 #define h_inc h+=v^(v>>3)
     char* p;
@@ -1192,6 +1216,7 @@ inline unsigned int get_hash_auth(str private_identity, str public_identity) {
     h = ((h)+(h >> 11))+((h >> 13)+(h >> 23));
     return (h) % auth_data_hash_size;
 #undef h_inc
+*/
 }
 
 /**
@@ -1209,13 +1234,29 @@ auth_userdata * get_auth_userdata(str private_identity, str public_identity) {
     hash = get_hash_auth(private_identity, public_identity);
     auth_data_lock(hash);
     aud = auth_data[hash].head;
+    if (av_check_only_impu)
+      LM_DBG("Searching auth_userdata for IMPU %.*s (Hash %d)\n", public_identity.len, public_identity.s, hash);
+    else
+      LM_DBG("Searching auth_userdata for IMPU %.*s / IMPI %.*s (Hash %d)\n", public_identity.len, public_identity.s,
+        private_identity.len, private_identity.s, hash);
+
     while (aud) {
-        if (aud->private_identity.len == private_identity.len &&
-                aud->public_identity.len == public_identity.len &&
-                memcmp(aud->private_identity.s, private_identity.s, private_identity.len) == 0 &&
-                memcmp(aud->public_identity.s, public_identity.s, public_identity.len) == 0) {
-            return aud;
-        }
+	if (av_check_only_impu) {
+		if (aud->public_identity.len == public_identity.len &&
+		        memcmp(aud->public_identity.s, public_identity.s, public_identity.len) == 0) {
+                    LM_DBG("Found auth_userdata\n");
+		    return aud;
+		}
+	} else {
+		if (aud->private_identity.len == private_identity.len &&
+		        aud->public_identity.len == public_identity.len &&
+		        memcmp(aud->private_identity.s, private_identity.s, private_identity.len) == 0 &&
+		        memcmp(aud->public_identity.s, public_identity.s, public_identity.len) == 0) {
+                    LM_DBG("Found auth_userdata\n");
+		    return aud;
+		}
+	}
+
         aud = aud->next;
     }
     /* if we get here, there is no auth_userdata for this user */
@@ -1408,6 +1449,11 @@ int add_auth_vector(str private_identity, str public_identity, auth_vector * av)
     aud = get_auth_userdata(private_identity, public_identity);
     if (!aud) goto error;
 
+     LM_DBG("Adding auth_vector (status %d) for IMPU %.*s / IMPI %.*s (Hash %d)\n", av->status,
+	public_identity.len, public_identity.s,
+        private_identity.len, private_identity.s, aud->hash);
+
+
     av->prev = aud->tail;
     av->next = 0;
 
diff --git a/modules/ims_auth/authorize.h b/modules/ims_auth/authorize.h
index 084fe60..7f4beef 100644
--- a/modules/ims_auth/authorize.h
+++ b/modules/ims_auth/authorize.h
@@ -133,13 +133,13 @@ void auth_db_close(void);
  * Authorize using Proxy-Authorization header field
  */
 int proxy_authenticate(struct sip_msg* _msg, char* _realm, char* _table);
-int proxy_challenge(struct sip_msg* msg, char* _realm, char* str2);
+int proxy_challenge(struct sip_msg* msg, char* route, char* _realm, char* str2);
 
 /*
  * Authorize using WWW-Authorization header field
  */
 int www_authenticate(struct sip_msg* _msg, char* _realm, char* _table);
-int www_challenge(struct sip_msg* msg, char* _realm, char* str2);
+int www_challenge(struct sip_msg* msg, char* route, char* _realm, char* str2);
 
 
 /*
diff --git a/modules/ims_auth/cxdx_avp.c b/modules/ims_auth/cxdx_avp.c
index 85f7771..12bcf29 100644
--- a/modules/ims_auth/cxdx_avp.c
+++ b/modules/ims_auth/cxdx_avp.c
@@ -136,7 +136,7 @@ static inline str cxdx_get_avp(AAAMessage *msg,int avp_code,int vendor_id,
 	
 	avp = cdpb.AAAFindMatchingAVP(msg,0,avp_code,vendor_id,0);
 	if (avp==0){
-		LM_INFO("%s: Failed finding avp\n",func);
+		LM_INFO("%s: Failed finding avp (avp_code = %d, vendor_id = %d)\n",func, avp_code, vendor_id);
 		return r;
 	}
 	else 
diff --git a/modules/ims_auth/cxdx_mar.c b/modules/ims_auth/cxdx_mar.c
index 7fea383..f48927b 100644
--- a/modules/ims_auth/cxdx_mar.c
+++ b/modules/ims_auth/cxdx_mar.c
@@ -154,7 +154,6 @@ void async_cdp_callback(int is_timeout, void *param, AAAMessage *maa, long elaps
         goto error;
     }
 
-
     //get each individual element from the MAA
     cxdx_get_result_code(maa, &rc);
     cxdx_get_experimental_result_code(maa, &experimental_rc);
@@ -388,6 +387,8 @@ success:
         //TODO need to confirm that removing this has done no problems
         //tmp->auth_data->code = -tmp->auth_data->code;
 
+	LM_DBG("Added new auth-vector.\n");
+
         tmp = tmp->next;
     }
 
diff --git a/modules/ims_auth/cxdx_mar.h b/modules/ims_auth/cxdx_mar.h
index 7f1733a..9a930ec 100644
--- a/modules/ims_auth/cxdx_mar.h
+++ b/modules/ims_auth/cxdx_mar.h
@@ -57,12 +57,6 @@ extern str cxdx_forced_peer; /**< FQDN of the Diameter peer to send requests to
 extern str cxdx_dest_realm;
 extern struct tm_binds tmb;
 
-typedef struct mar_param {
-	int type;
-        char* param;
-	cfg_action_t *paction;
-} mar_param_t;
-
 typedef struct saved_transaction {
 	unsigned int tindex;
 	unsigned int tlabel;
diff --git a/modules/ims_auth/doc/ims_auth.xml b/modules/ims_auth/doc/ims_auth.xml
index eb61566..3a7a399 100644
--- a/modules/ims_auth/doc/ims_auth.xml
+++ b/modules/ims_auth/doc/ims_auth.xml
@@ -44,6 +44,17 @@
 
         <email>richard.good at smilecoms.com</email>
       </author>
+
+      <editor>
+        <firstname>Carsten</firstname>
+        <surname>Bock</surname>
+        <affiliation>
+          <orgname>ng-voice GmbH</orgname>
+        </affiliation>
+        <address>
+          <email>carsten at ng-voice.com</email>
+        </address>
+      </editor>
     </authorgroup>
 
     <copyright>
diff --git a/modules/ims_auth/doc/ims_auth_admin.xml b/modules/ims_auth/doc/ims_auth_admin.xml
index 18834cd..240c3ef 100644
--- a/modules/ims_auth/doc/ims_auth_admin.xml
+++ b/modules/ims_auth/doc/ims_auth_admin.xml
@@ -210,11 +210,11 @@ modparam("ims_auth", "registration_default_algorithm", "HSS-Selected")
       <quote>auth,auth-int</quote>.</para>
 
       <example>
-        <title><varname>load_credentials</varname> parameter usage</title>
+        <title><varname>registration_qop</varname> parameter usage</title>
 
         <programlisting format="linespecific">
 ...
-modparam("ims_auth", "load_credentials", "auth-int")
+modparam("ims_auth", "registration_qop", "auth-int")
 ...
 </programlisting>
       </example>
@@ -246,7 +246,7 @@ modparam("ims_auth", "cxdx_forced_peer", "hss.ims.smilecoms.com")
       <para>Default value is <quote>ims.smilecoms.com</quote>.</para>
 
       <example>
-        <title><varname>version_table</varname> parameter usage</title>
+        <title><varname>cxdx_dest_realm</varname> parameter usage</title>
 
         <programlisting format="linespecific">
 ...
@@ -255,6 +255,83 @@ modparam("ims_auth", "cxdx_dest_realm", "ims.smilecoms.com")
 </programlisting>
       </example>
     </section>
+
+    <section>
+      <title><varname>max_nonce_reuse</varname> (integer)</title>
+
+      <para>Defines, how many times a nonce can be reused (provided nc is incremented)</para>
+
+      <para>Default value is <quote>0</quote> (don't allow reuse).</para>
+
+      <example>
+        <title><varname>max_nonce_reuse</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("ims_auth", "max_nonce_reuse", 1)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>add_authinfo_hdr</varname> (integer)</title>
+
+      <para>Should an Authentication-Info header be added on 200 OK responses?</para>
+
+      <para>Default value is <quote>1</quote> (add Authentication-Info header).</para>
+
+      <example>
+        <title><varname>add_authinfo_hdr</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("ims_auth", "add_authinfo_hdr", 0)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>ignore_failed_auth</varname> (integer)</title>
+
+      <para>Ignore invalid passwords (only IMPI/IMPU is checked).</para>
+      <para>It should be used only for testing, e.g. load balancing with SIPP where we don't want to worry about auth.</para>
+
+      <para>Default value is <quote>0</quote> (don't ingnore the failed authentication).</para>
+
+      <example>
+        <title><varname>ignore_failed_auth</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("ims_auth", "ignore_failed_auth", 1)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>av_check_only_impu</varname> (integer)</title>
+
+      <para>When storing the authentication vectors for an account, use either IMPI/IMPU (=0, default) or IMPU (=1).</para>
+      <para>In case the IMPI is different from the IMPU, this option needs to be enabled to allow registration from
+        classic "SIP-clients", such as Snom phones and others, as they do not send an authentication username in the first REGISTER.</para>
+      <para>Default value is <quote>0</quote> (store authentication vectors based on IMPI/IMPU).</para>
+
+      <example>
+        <title><varname>av_check_only_impu</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("ims_auth", "av_check_only_impu", 1)
+...
+</programlisting>
+      </example>
+    </section>
+
+
+
   </section>
 
   <section>
@@ -325,8 +402,8 @@ modparam("ims_auth", "cxdx_dest_realm", "ims.smilecoms.com")
         <programlisting format="linespecific">
 ...
 if (!www_authorize("kamailio.org", "subscriber")) {
-	www_challenge("kamailio.org", "1");
-};
+	www_challenge(""REG_MAR_REPLY"", "kamailio.org", "1");
+};         
 ...
 </programlisting>
       </example>
@@ -342,7 +419,7 @@ if (!www_authorize("kamailio.org", "subscriber")) {
     </section>
 
     <section>
-      <title><function moreinfo="none">ims_www_challenge(realm,
+      <title><function moreinfo="none">ims_www_challenge(route_block, realm,
       table)</function></title>
 
       <para>Name alias: proxy_authorize(realm, table)</para>
@@ -363,6 +440,9 @@ if (!www_authorize("kamailio.org", "subscriber")) {
 
       <itemizedlist>
         <listitem>
+          <para>Route block to resume after async MAR Diameter reply.</para>
+        </listitem>
+        <listitem>
           <para><emphasis>realm</emphasis> - Realm is a opaque string that the
           user agent should present to the user so he can decide what username
           and password to use. Usually this is domain of the host the server
@@ -393,15 +473,39 @@ if (!www_authorize("kamailio.org", "subscriber")) {
         <programlisting format="linespecific">
 ...
 if (!proxy_authorize("$fd", "subscriber)) {
-	proxy_challenge("$fd", "1");  # Realm will be autogenerated
+	proxy_challenge(""REG_MAR_REPLY","$fd");  # Realm will be autogenerated
 };
 ...
+            ...
+route[REG_MAR_REPLY]
+{
+     #this is async so to know status we have to check the reply avp
+     xlog("L_DBG","maa_return code is $avp(s:maa_return_code)\n");   
+
+     switch ($avp(s:maa_return_code)){
+             case 1: #success
+                     xlog("L_DBG", "MAR success - 401/407 response sent from module\n");
+                     break;
+             case -1: #failure
+                     xlog("L_ERR", "MAR failure - error response sent from module\n");
+                     break;
+             case -2: #error
+                     xlog("L_ERR", "MAR error - sending error response now\n");
+                     t_reply("500", "MAR failed");
+                     break;
+             default:
+                     xlog("L_ERR", "Unknown return code from MAR, value is [$avp(s:uaa_return_code)]\n");
+                     t_reply("500", "Unknown response code from MAR");
+                     break;
+     }
+     exit;           
+}               
 </programlisting>
       </example>
     </section>
 
     <section>
-      <title><function moreinfo="none">ims_proxy_challenge(realm,
+      <title><function moreinfo="none">ims_proxy_challenge(route_block, realm,
       table)</function></title>
 
       <para>Name alias: proxy_authorize(realm, table)</para>
@@ -422,6 +526,9 @@ if (!proxy_authorize("$fd", "subscriber)) {
 
       <itemizedlist>
         <listitem>
+          <para>Route block to resume after async MAR Diameter reply.</para>
+        </listitem>
+        <listitem>
           <para><emphasis>realm</emphasis> - Realm is a opaque string that the
           user agent should present to the user so he can decide what username
           and password to use. Usually this is domain of the host the server
@@ -452,9 +559,33 @@ if (!proxy_authorize("$fd", "subscriber)) {
         <programlisting format="linespecific">
 ...
 if (!proxy_authorize("$fd", "subscriber)) {
-	proxy_challenge("$fd", "1");  # Realm will be autogenerated
+	proxy_challenge("REG_MAR_REPLY","$fd", "1");  # Realm will be autogenerated
 };
 ...
+route[REG_MAR_REPLY]
+{
+     #this is async so to know status we have to check the reply avp
+     xlog("L_DBG","maa_return code is $avp(s:maa_return_code)\n");   
+
+     switch ($avp(s:maa_return_code)){
+             case 1: #success
+                     xlog("L_DBG", "MAR success - 401/407 response sent from module\n");
+                     break;
+             case -1: #failure
+                     xlog("L_ERR", "MAR failure - error response sent from module\n");
+                     break;
+             case -2: #error
+                     xlog("L_ERR", "MAR error - sending error response now\n");
+                     t_reply("500", "MAR failed");
+                     break;
+             default:
+                     xlog("L_ERR", "Unknown return code from MAR, value is [$avp(s:uaa_return_code)]\n");
+                     t_reply("500", "Unknown response code from MAR");
+                     break;
+     }
+     exit;           
+}            
+...
 </programlisting>
       </example>
     </section>
diff --git a/modules/ims_charging/Makefile b/modules/ims_charging/Makefile
new file mode 100644
index 0000000..0dbcd19
--- /dev/null
+++ b/modules/ims_charging/Makefile
@@ -0,0 +1,22 @@
+# $Id$
+#
+# ims_ro make file
+#
+# 
+
+include ../../Makefile.defs
+auto_gen=
+NAME=ims_charging.so
+LIBS=
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/ims/kamailio_ims
+
+ifneq ($(OS),darwin)
+	LIBS += -lrt
+endif
+
+include ../../Makefile.modules
diff --git a/modules/ims_charging/README b/modules/ims_charging/README
new file mode 100644
index 0000000..d6abf37
--- /dev/null
+++ b/modules/ims_charging/README
@@ -0,0 +1,714 @@
+The IMS Charging Module
+
+Jason Penton
+
+   Smile Communications
+   <jason.penton at smilecoms.com>
+
+Carsten Bock
+
+   ng-voice GmbH
+   <carsten at ng-voice.com>
+
+Carlos Ruiz Diaz
+
+   ng-voice GmbH
+   <carlos at ng-voice.com>
+
+   Copyright © 2013 Smile Communications
+
+   Copyright © 2013 ng-voice GmbH
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Understanding Charging in the IP-Multimedia-Subsystem (IMS)
+
+              3.1. Offline Charging (Rf)
+              3.2. Online Charging (Ro)
+              3.3. Online Charging (Ro): A practical example
+
+        4. Parameters
+
+              4.1. hash_size(int)
+              4.2. interim_update_credits(int)
+              4.3. timer_buffer(int)
+              4.4. ro_forced_peer(string)
+              4.5. ro_auth_expiry(integer)
+              4.6. ro_auth_expiry(integer)
+              4.7. cdp_event_latency(integer)
+              4.8. cdp_event_threshold(integer)
+              4.9. cdp_event_latency_log(integer)
+              4.10. origin_host(string)
+              4.11. origin_realm(string)
+              4.12. destination_host(string)
+              4.13. destination_realm(string)
+              4.14. service_context_id_root(string)
+              4.15. service_context_id_ext(string)
+              4.16. service_context_id_mnc(string)
+              4.17. service_context_id_mcc(string)
+              4.18. service_context_id_release(string)
+
+        5. Functions
+
+              5.1. Ro_CCR(route_name, direction, charge_type, unit_type,
+                      reservation_units)
+
+        6. Statistics
+
+              6.1. Initial CCRs (initial_ccrs)
+              6.2. Interim CCRs (interim_ccrs)
+              6.3. Final CCRs (final_ccrs)
+              6.4. Sucessful initial CCRs (successful_initial_ccrs)
+              6.5. Sucessful interim CCRs (successful_interim_ccrs)
+              6.6. Sucessful final CCRs (successful_final_ccrs)
+              6.7. Failed initial CCRs (failed_initial_ccrs)
+              6.8. Failed interim CCRs (failed_interim_ccrs)
+              6.9. Failed final CCRs (failed_final_ccrs)
+              6.10. CCRs average response time (ccr_avg_response_time)
+              6.11. CCRs responses time (ccr_responses_time)
+              6.12. CCRs requests, which ended with a timeout
+                      (ccr_timeouts)
+
+              6.13. Billed seconds (billed_secs)
+              6.14. Killed calls (killed_calls)
+
+   List of Examples
+
+   1.1. hash_sizeparameter usage
+   1.2. interim_update_creditsparameter usage
+   1.3. timer_bufferparameter usage
+   1.4. ro_forced_peerparameter usage
+   1.5. ro_auth_expiryparameter usage
+   1.6. ro_auth_expiryparameter usage
+   1.7. cdp_event_latencyparameter usage
+   1.8. cdp_event_thresholdparameter usage
+   1.9. cdp_event_latency_logparameter usage
+   1.10. origin_hostparameter usage
+   1.11. origin_realmparameter usage
+   1.12. destination_hostparameter usage
+   1.13. destination_realmparameter usage
+   1.14. service_context_id_rootparameter usage
+   1.15. service_context_id_extparameter usage
+   1.16. service_context_id_mncparameter usage
+   1.17. service_context_id_mccparameter usage
+   1.18. service_context_id_releaseparameter usage
+   1.19. Ro_CCR
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Understanding Charging in the IP-Multimedia-Subsystem (IMS)
+
+        3.1. Offline Charging (Rf)
+        3.2. Online Charging (Ro)
+        3.3. Online Charging (Ro): A practical example
+
+   4. Parameters
+
+        4.1. hash_size(int)
+        4.2. interim_update_credits(int)
+        4.3. timer_buffer(int)
+        4.4. ro_forced_peer(string)
+        4.5. ro_auth_expiry(integer)
+        4.6. ro_auth_expiry(integer)
+        4.7. cdp_event_latency(integer)
+        4.8. cdp_event_threshold(integer)
+        4.9. cdp_event_latency_log(integer)
+        4.10. origin_host(string)
+        4.11. origin_realm(string)
+        4.12. destination_host(string)
+        4.13. destination_realm(string)
+        4.14. service_context_id_root(string)
+        4.15. service_context_id_ext(string)
+        4.16. service_context_id_mnc(string)
+        4.17. service_context_id_mcc(string)
+        4.18. service_context_id_release(string)
+
+   5. Functions
+
+        5.1. Ro_CCR(route_name, direction, charge_type, unit_type,
+                reservation_units)
+
+   6. Statistics
+
+        6.1. Initial CCRs (initial_ccrs)
+        6.2. Interim CCRs (interim_ccrs)
+        6.3. Final CCRs (final_ccrs)
+        6.4. Sucessful initial CCRs (successful_initial_ccrs)
+        6.5. Sucessful interim CCRs (successful_interim_ccrs)
+        6.6. Sucessful final CCRs (successful_final_ccrs)
+        6.7. Failed initial CCRs (failed_initial_ccrs)
+        6.8. Failed interim CCRs (failed_interim_ccrs)
+        6.9. Failed final CCRs (failed_final_ccrs)
+        6.10. CCRs average response time (ccr_avg_response_time)
+        6.11. CCRs responses time (ccr_responses_time)
+        6.12. CCRs requests, which ended with a timeout (ccr_timeouts)
+        6.13. Billed seconds (billed_secs)
+        6.14. Killed calls (killed_calls)
+
+1. Overview
+
+   This module contains all methods related to the IMS charging control
+   functions performed by an network element (e.g. a S-CSCF) over the Ro
+   interface. This module is dependent on the CDP (C Diameter Peer)
+   modules for communicating with a Charging-Server as specified in 3GPP
+   specification TS xx.xxx.
+
+   Please also refer to RFC 4006 (Diameter Credit-Control Application)
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The Following mouldes must be loaded before this module:
+     * Dialog_ng
+     * TM - Transaction Manager
+     * CDP - C Diameter Peer
+     * CDP_AVP - CDP AVP Applications
+
+2.2. External Libraries or Applications
+
+   This modules requires the internal IMS library.
+
+3. Understanding Charging in the IP-Multimedia-Subsystem (IMS)
+
+   3.1. Offline Charging (Rf)
+   3.2. Online Charging (Ro)
+   3.3. Online Charging (Ro): A practical example
+
+   Before each service usage, the charging system must be asked for
+   permission (credit authorization). The charging server must make a
+   decision: Either authorize or deny the session. For postpaid scenarios
+   this is fairly easy: The charging-server only needs to collect the
+   usage data for processing it at the end of the month. As no realtime
+   account updating is needed, this is often called "offline-charging".
+   For prepaid scenarios the charging server needs to know the user's
+   account balance and it will need to update the account in real-time.
+   This is often referred to as "online-charging".
+
+   Question: What is the double of the Radius? Answer: It's the Diameter!
+
+   As quite often, we use the Diameter-Protocol to do the Charging in the
+   IMS. And as quite often, IMS uses a huge bunch of acronyms to describe
+   the different interfaces: We call the diameter-interface for
+   offline-charging the "Rf"-interface and the interface for online
+   charging the "Ro"-interface.
+
+   Each system, that needs this credit authorization, have to be equipped
+   with a proper charging trigger, a so-called charging-trigger-function
+   (CTF) in order to communicate with the charging-server (also called
+   charging-function):
+   [charging1.png]
+
+3.1. Offline Charging (Rf)
+
+   For the offlinc charging (Rf), we have the following two
+   diameter-messages:
+     * ACR - Accounting Request
+     * ACA - Accounting Answer
+
+   Each request can have the following Accounting-Record-Type:
+     * START_RECORD - used to start an accounting session, typically when
+       the application receives a SIP 200 OK acknowledging an initial SIP
+       INVITE.
+     * INTERIM_RECORD - used to update a session, for example, in the case
+       of SIP RE-INVITE and/or UPDATE in the current SIP dialog.
+     * STOP_RECORD - used to stop an accounting session, for example, when
+       the application receives a SIP BYE message.
+     * EVENT_RECORD - used for event-based accounting, e.g. a short
+       message or similar
+
+3.2. Online Charging (Ro)
+
+   For online charging (Ro), this get's a little bit more complicated. The
+   charging function needs to perform credit control before allowing
+   resource usage. The prepaid subscriber needs to exist in the
+   charging-server and all activities must be monitored by the
+   charging-server. We must distinguish between the following two cases:
+     * Direct debiting - the amount is immediately deducted from the
+       user's account in one single transaction. This could be for example
+       a SMS or the ordering of a movie in case of Video-on-Demand.
+     * Unit reservation - an amount is reserved by the charging-server.
+       This is done, because the charging-server does not know yet, how
+       many units are needed to provide the service. During the session,
+       the used amount may be deducted and more units can be requested; at
+       the end of the session the used sessions are reported in the final
+       request. These sessions could be typically a voice- or video-call
+       or a Pay-TV session, if you pay per usage.
+
+   As a result, we have the following three scenarios:
+     * Immediate Event Charging (IEC) - used for simple Event-based
+       charging
+     * Event Charging with Unit Reservation (ECUR) (of type Event-based
+       charging)
+     * Session Charging with Unit Reservation (SCUR) (of type
+       Session-based charging)
+
+3.3. Online Charging (Ro): A practical example
+
+   But how does it look in reality? Let us make a more practical example:
+
+   Let us assume we have a subscriber, who has sufficient credit for 75
+   seconds of talking. The subscriber initiates a call; as we do not know,
+   how long the call will take, we start with requesting credit for 30
+   seconds (CCR-Request, we could request any duration, e.g. 2 hours, but
+   it would probably block other calls if we reserve all the required
+   credit).
+
+   The call proceeds, so after 30 seconds we send another CCR-Request with
+   the indication that we used the reserved 30 seconds and that we request
+   another 30 seconds. We reduce the account of the subscriber by 30
+   seconds, so he has a credit of 45 seconds. Since 45 seconds is more
+   than the requested 30 seconds, this second request can also easily be
+   accepted and another 30 seconds can be granted. After this request, the
+   account is at 45 seconds and we still (or again) have 30 seconds
+   reserved.
+
+   Meanwhile the subscriber initiates a second call. We try to request
+   again 30 seconds from the charging-server, but as our account is at 45
+   seconds of speaking time and since we reserved another 30 seconds for
+   the first call, we can only grant 15 seconds for the second call. The
+   last 15 seconds are now reserved for this subscriber; we have 45
+   seconds on the account of which 45 seconds are reserved.
+
+   Now the first call gets terminated: We only used 20 seconds from the
+   granted 30 seconds. So we decrease the account of the subscriber by 20
+   seconds and we reduce the amount of reserved units by 30. We have 25
+   seconds in the account and we have still reserved 15 seconds for the
+   second call.
+
+   As the second call is still proceeding, we will try to request another
+   30 seconds and we indicate, that we used the granted 15 seconds. The
+   account is deducted by 15 seconds (the used units) and we can grant
+   another 10 seconds for the second call, as this is the remains on the
+   account.
+
+   After 10 seconds, no more units can be granted, so the call is teared
+   down.
+
+   The following diagram is a graphical representation of the above
+   example:
+   [charging2.png]
+
+4. Parameters
+
+   4.1. hash_size(int)
+   4.2. interim_update_credits(int)
+   4.3. timer_buffer(int)
+   4.4. ro_forced_peer(string)
+   4.5. ro_auth_expiry(integer)
+   4.6. ro_auth_expiry(integer)
+   4.7. cdp_event_latency(integer)
+   4.8. cdp_event_threshold(integer)
+   4.9. cdp_event_latency_log(integer)
+   4.10. origin_host(string)
+   4.11. origin_realm(string)
+   4.12. destination_host(string)
+   4.13. destination_realm(string)
+   4.14. service_context_id_root(string)
+   4.15. service_context_id_ext(string)
+   4.16. service_context_id_mnc(string)
+   4.17. service_context_id_mcc(string)
+   4.18. service_context_id_release(string)
+
+4.1.  hash_size(int)
+
+   The size of the hash table internally used to keep the
+   Diameter-Ro-Session. A larger table is much faster but consumes more
+   memory. The hash size must be a power of two number.
+
+   IMPORTANT: If Ro-Session's information should be stored in a database,
+   a constant hash_size should be used, otherwise the restoring process
+   will not take place. If you really want to modify the hash_size you
+   must delete all table's rows before restarting the server.
+
+   Default value is 4096.
+
+   Example 1.1.  hash_sizeparameter usage
+...
+modparam("ims_charging", "hash_size", 1024)
+...
+
+4.2.  interim_update_credits(int)
+
+   How much credit should be requested interim request? At the start of
+   the call, we request the amout of seconds as per Command. For each
+   interim request, we would request credit for "interim_update_credits".
+
+   Default value is 30.
+
+   Example 1.2.  interim_update_creditsparameter usage
+...
+modparam("ims_charging", "interim_update_credits", 600)
+...
+
+4.3.  timer_buffer(int)
+
+   How many seconds before expiry of our credit should we request more
+   credit?
+
+   Default value is 8.
+
+   Example 1.3.  timer_bufferparameter usage
+...
+modparam("ims_charging", "timer_buffer", 10)
+...
+
+4.4.  ro_forced_peer(string)
+
+   This is the optional name of the origin host of the Diameter server
+   (typically a Charging Server). If not set then realm routing is used.
+
+   Default value is ''.
+
+   Example 1.4.  ro_forced_peerparameter usage
+...
+modparam("ims_charging", "ro_forced_peer", "ocs.ims.smilecoms.com")
+...
+
+4.5.  ro_auth_expiry(integer)
+
+   This is the expiry length in seconds of the initiated Diameter
+   sessions.
+
+   Default value is 7200.
+
+   Example 1.5.  ro_auth_expiryparameter usage
+...
+modparam("ims_charging", "ro_auth_expiry", 14400)
+...
+
+4.6.  ro_auth_expiry(integer)
+
+   This is the expiry length in seconds of the initiated Diameter
+   sessions.
+
+   Default value is 7200.
+
+   Example 1.6.  ro_auth_expiryparameter usage
+...
+modparam("ims_charging", "ro_auth_expiry", 14400)
+...
+
+4.7.  cdp_event_latency(integer)
+
+   This is a flag to determine whether or slow CDP responses should be
+   reported in the log file. 1 is enabled and 0 is disabled.
+
+   Default value is 1.
+
+   Example 1.7.  cdp_event_latencyparameter usage
+...
+modparam("ims_charging", "cdp_event_latency", 1)
+...
+
+4.8.  cdp_event_threshold(integer)
+
+   This time in milliseconds is the limit we should report a CDP response
+   as slow. i.e. if a CDP response exceeds this limit it will be reported
+   in the log file. This is only relevant is cdp_event_latency is enabled
+   (set to 0).
+
+   Default value is 500.
+
+   Example 1.8.  cdp_event_thresholdparameter usage
+...
+modparam("ims_charging", "cdp_event_threshold", 500)
+...
+
+4.9.  cdp_event_latency_log(integer)
+
+   This time log level at which we should report slow CDP responses. 0 is
+   ERROR, 1 is WARN, 2 is INFO and 3 is DEBUG. This is only relevant is
+   cdp_event_latency is enabled (set to 0)
+
+   Default value is 0.
+
+   Example 1.9.  cdp_event_latency_logparameter usage
+...
+modparam("ims_charging", "cdp_event_latency_log", 1)
+...
+
+4.10.  origin_host(string)
+
+   Origin host to be used in Diameter messages to charging-server.
+
+   Default value is "scscf.ims.smilecoms.com".
+
+   Example 1.10.  origin_hostparameter usage
+...
+modparam("ims_charging", "origin_host", "scscf.kamailio-ims.org")
+...
+
+4.11.  origin_realm(string)
+
+   Origin Realm to be used in Diameter messages to charging-server.
+
+   Default value is "ims.smilecome.com".
+
+   Example 1.11.  origin_realmparameter usage
+...
+modparam("ims_charging", "origin_realm", "kamailio-ims.org")
+...
+
+4.12.  destination_host(string)
+
+   Destination host to be used in Diameter messages to charging-server.
+
+   Default value is 5s.
+
+   Example 1.12.  destination_hostparameter usage
+...
+modparam("ims_charging", "destination_host", "ocs.kamailio-ims.org")
+...
+
+4.13.  destination_realm(string)
+
+   Destination realm to be used in Diameter messages to charging-server.
+
+   Default value is "ims.smilecoms.com".
+
+   Example 1.13.  destination_realmparameter usage
+...
+modparam("ims_charging", "destination_realm", "kamailio-ims.org")
+...
+
+4.14.  service_context_id_root(string)
+
+   This defines a root-element of the Service-Context-Id AVP used in the
+   diameter-message
+
+   The Service-Context-Id AVP is of type UTF8String (AVP Code 461) and
+   contains a unique identifier of the Diameter credit-control service
+   specific document that applies to the request (as defined in section
+   RFC 4006 4.1.2). This is an identifier allocated by the service
+   provider, by the service element manufacturer, or by a standardization
+   body, and MUST uniquely identify a given Diameter credit-control
+   service specific document. The format of the Service-Context-Id is:
+"service-context" "@" "domain" service-context = Token
+
+   The Token is an arbitrary string of characters and digits.
+
+   'domain' represents the entity that allocated the Service-Context-Id.
+   It can be ietf.org, 3gpp.org, etc., if the identifier is allocated by a
+   standardization body, or it can be the FQDN of the service provider
+   (e.g., provider.example.com) or of the vendor (e.g.,
+   vendor.example.com) if the identifier is allocated by a private entity.
+
+   Service-specific documents that are for private use only (i.e., to one
+   provider's own use, where no interoperability is deemed useful) may
+   define private identifiers without need of coordination. However, when
+   interoperability is wanted, coordination of the identifiers via, for
+   example, publication of an informational RFC is RECOMMENDED in order to
+   make Service-Context-Id globally available.
+
+   Default value is "32260 at 3gpp.org".
+
+   Example 1.14.  service_context_id_rootparameter usage
+...
+modparam("ims_charging", "service_context_id_root", "calls at kamailio-ims.org")
+...
+
+4.15.  service_context_id_ext(string)
+
+   This defines the extension of the Service-Context-Id AVP used in the
+   diameter-message.
+
+   Default value is "ext".
+
+   Example 1.15.  service_context_id_extparameter usage
+...
+modparam("ims_charging", "service_context_id_ext", "ext2")
+...
+
+4.16.  service_context_id_mnc(string)
+
+   This defines Mobile-Network-Code (MNC) of the Service-Context-Id AVP
+   used in the diameter-message.
+
+   Default value is "01".
+
+   Example 1.16.  service_context_id_mncparameter usage
+...
+modparam("ims_charging", "service_context_id_mnc", "42")
+...
+
+4.17.  service_context_id_mcc(string)
+
+   This defines Mobile-Country-Code (MCC) of the Service-Context-Id AVP
+   used in the diameter-message.
+
+   see https://en.wikipedia.org/wiki/Mobile_country_code_(MCC) for
+   details.
+
+   Default value is "001".
+
+   Example 1.17.  service_context_id_mccparameter usage
+...
+modparam("ims_charging", "service_context_id_mcc", "262")
+...
+
+4.18.  service_context_id_release(string)
+
+   This defines Release of the Service-Context-Id AVP used in the
+   diameter-message.
+
+   Default value is "8" (Release 8).
+
+   Example 1.18.  service_context_id_releaseparameter usage
+...
+modparam("ims_charging", "service_context_id_release", "262")
+...
+
+5. Functions
+
+   5.1. Ro_CCR(route_name, direction, charge_type, unit_type,
+          reservation_units)
+
+5.1.  Ro_CCR(route_name, direction, charge_type, unit_type,
+reservation_units)
+
+   Perform a CCR on Diameter Ro interface for Charging
+
+   Meaning of the parameters is as follows:
+     * route_nameroute to be executed upon reception of charging requests
+     * direction"orig"inating or "term"inating
+     * charge_type"IEC" = Immediate Event Charging, "ECUR" - Event
+       Charging with Unit Reservation or "SCUR" - Session Charging with
+       Unit Reservation.
+       (Note: At the moment only SCUR is supported)
+     * unit_typeTypes of the unit to be requested
+       (unused at the moment)
+     * reservation_unitshow many units (at the moment seconds) should be
+       reservated at the moment.
+
+   This function can be used from REQUEST_ROUTE.
+
+   This method is executed asynchronously. See example on how to retrieve
+   return value.
+
+   Example 1.19. Ro_CCR
+...
+  xlog("L_DBG","Sending initial CCR Request for call\n");
+  Ro_CCR("CHARGING_CCR_REPLY", "orig", "SCUR", "", "30");
+}
+
+route[CHARGING_CCR_REPLY]
+  xlog("L_DBG","cca_return code is $avp(s:cca_return_code)\n");
+  switch ($avp(s:cca_return_code)) {
+    case 1: #success
+        xlog("L_DBG", "CCR success - will route message\n");
+        route(Finalize_Orig);
+        break;
+    case -1: #failure
+        xlog("L_ERR", "CCR failure - error response sent from module\n");
+        sl_send_reply("402","Payment required");
+        break;
+    case -2: #error
+        xlog("L_ERR", "CCR error - error response sent from module\n");
+        sl_send_reply("500", "Charging Error");
+        break;
+    default:
+        xlog("L_ERR", "Unknown return code from CCR: [$avp(s:cca_return_code)] \
+n");
+        break;
+  }
+  exit;
+  }
+...
+
+6. Statistics
+
+   6.1. Initial CCRs (initial_ccrs)
+   6.2. Interim CCRs (interim_ccrs)
+   6.3. Final CCRs (final_ccrs)
+   6.4. Sucessful initial CCRs (successful_initial_ccrs)
+   6.5. Sucessful interim CCRs (successful_interim_ccrs)
+   6.6. Sucessful final CCRs (successful_final_ccrs)
+   6.7. Failed initial CCRs (failed_initial_ccrs)
+   6.8. Failed interim CCRs (failed_interim_ccrs)
+   6.9. Failed final CCRs (failed_final_ccrs)
+   6.10. CCRs average response time (ccr_avg_response_time)
+   6.11. CCRs responses time (ccr_responses_time)
+   6.12. CCRs requests, which ended with a timeout (ccr_timeouts)
+   6.13. Billed seconds (billed_secs)
+   6.14. Killed calls (killed_calls)
+
+6.1. Initial CCRs (initial_ccrs)
+
+   The number of initial CCRs, i.e., the CCRs that were sent for the
+   initial INVITEs.
+
+6.2. Interim CCRs (interim_ccrs)
+
+   The number of CCRs sent within established sessions.
+
+6.3. Final CCRs (final_ccrs)
+
+   The number of CCRs sent to terminate a session.
+
+6.4. Sucessful initial CCRs (successful_initial_ccrs)
+
+   Initial CCRs that ended with DIAMETER_SUCCESS response code.
+
+6.5. Sucessful interim CCRs (successful_interim_ccrs)
+
+   Interim CCRs that ended with DIAMETER_SUCCESS response code.
+
+6.6. Sucessful final CCRs (successful_final_ccrs)
+
+   Final CCRs that ended with DIAMETER_SUCCESS response code.
+
+6.7. Failed initial CCRs (failed_initial_ccrs)
+
+   Initial CCRs that ended with no DIAMETER_SUCCESS response or with some
+   other error during processing.
+
+6.8. Failed interim CCRs (failed_interim_ccrs)
+
+   Interim CCRs that ended with no DIAMETER_SUCCESS response or with some
+   other error during processing.
+
+6.9. Failed final CCRs (failed_final_ccrs)
+
+   Final CCRs that ended with no DIAMETER_SUCCESS response or with some
+   other error during processing.
+
+6.10. CCRs average response time (ccr_avg_response_time)
+
+   Average CCA arrival time in milliseconds.
+
+6.11. CCRs responses time (ccr_responses_time)
+
+   Total CCA arrival time in milliseconds.
+
+6.12. CCRs requests, which ended with a timeout (ccr_timeouts)
+
+   Number of CCR-Requests, which ran into an timeout.
+
+6.13. Billed seconds (billed_secs)
+
+   Number of seconds billed in total.
+
+6.14. Killed calls (killed_calls)
+
+   Number of calls that were killed due to lack of credit.
diff --git a/modules/ims_charging/Ro_data.c b/modules/ims_charging/Ro_data.c
new file mode 100644
index 0000000..6504c54
--- /dev/null
+++ b/modules/ims_charging/Ro_data.c
@@ -0,0 +1,289 @@
+#include "Ro_data.h"
+#include "config.h"
+
+
+#define str_dup(dst,src,mem) \
+do {\
+	if ((src).len) {\
+		(dst).s = mem##_malloc((src).len);\
+		if (!(dst).s){\
+			LM_ERR("Error allocating %d bytes in %s!\n",(src).len,#mem);\
+			(dst).len = 0;\
+			goto out_of_memory;\
+		}\
+		memcpy((dst).s,(src).s,(src).len);\
+		(dst).len = (src).len;\
+	}else{\
+		(dst).s=0;(dst).len=0;\
+	}\
+} while (0)
+
+/**
+ * Frees a str content.
+ * @param x - the str to free
+ * @param mem - type of memory that the content is using (shm/pkg)
+ */
+#define str_free(x,mem) \
+do {\
+	if ((x).s) mem##_free((x).s);\
+	(x).s=0;(x).len=0;\
+} while(0)
+
+extern client_ro_cfg cfg;
+
+event_type_t * new_event_type(str * sip_method, str * event, uint32_t * expires) {
+    event_type_t * x = 0;
+
+    mem_new(x, sizeof (event_type_t), pkg);
+    if (sip_method && sip_method->s)
+        str_dup_ptr(x->sip_method, *sip_method, pkg);
+    if (event && event->s)
+        str_dup_ptr(x->event, *event, pkg);
+    if (expires && *expires != 0) {
+        mem_new(x->expires, sizeof (uint32_t), pkg);
+        *(x->expires) = *expires;
+    }
+    return x;
+
+out_of_memory:
+    LM_ERR("out of pkg memory\n");
+    event_type_free(x);
+    return NULL;
+}
+
+time_stamps_t * new_time_stamps(time_t *sip_request_timestamp, uint32_t *sip_request_timestamp_fraction, time_t *sip_response_timestamp, uint32_t *sip_response_timestamp_fraction) {
+
+    time_stamps_t * x = 0;
+
+    mem_new(x, sizeof (time_stamps_t), pkg);
+
+    if (sip_request_timestamp && *sip_request_timestamp > 0) {
+        mem_new(x->sip_request_timestamp, sizeof (time_t), pkg);
+        *(x->sip_request_timestamp) = *sip_request_timestamp;
+    }
+
+    if (sip_request_timestamp_fraction && *sip_request_timestamp_fraction > 0) {
+        mem_new(x->sip_request_timestamp_fraction, sizeof (uint32_t), pkg);
+        *(x->sip_request_timestamp_fraction) = *sip_request_timestamp_fraction;
+    }
+
+    if (sip_response_timestamp && *sip_response_timestamp > 0) {
+        mem_new(x->sip_response_timestamp, sizeof (time_t), pkg);
+        *(x->sip_response_timestamp) = *sip_response_timestamp;
+    }
+
+    if (sip_response_timestamp_fraction && *sip_response_timestamp_fraction > 0) {
+        mem_new(x->sip_response_timestamp_fraction, sizeof (uint32_t), pkg);
+        *(x->sip_response_timestamp_fraction) = *sip_response_timestamp_fraction;
+    }
+
+
+    return x;
+
+out_of_memory:
+    LM_ERR("out of pkg memory\n");
+    time_stamps_free(x);
+    return 0;
+}
+
+ims_information_t * new_ims_information(event_type_t * event_type, time_stamps_t * time_stamps, str * user_session_id, str * outgoing_session_id, str * calling_party, str * called_party, str * icid, str * orig_ioi, str * term_ioi, int node_role) {
+
+    str_list_slot_t *sl = 0;
+    ims_information_t *x = 0;
+    ioi_list_element_t * ioi_elem = 0;
+
+    mem_new(x, sizeof (ims_information_t), pkg);
+
+    x->event_type = event_type;
+    x->time_stamps = time_stamps;
+
+    mem_new(x->role_of_node, sizeof (int32_t), pkg);
+    *(x->role_of_node) = node_role;
+
+    //x->node_functionality = cfg.node_func;
+
+    if (outgoing_session_id && outgoing_session_id->s)
+        str_dup_ptr(x->outgoing_session_id, *outgoing_session_id, pkg);
+
+    if (user_session_id && user_session_id->s)
+        str_dup_ptr(x->user_session_id, *user_session_id, pkg);
+
+    if (calling_party && calling_party->s) {
+        mem_new(sl, sizeof (str_list_slot_t), pkg);
+        str_dup(sl->data, *calling_party, pkg);
+        WL_APPEND(&(x->calling_party_address), sl);
+    }
+
+    if (called_party && called_party->s)
+        str_dup_ptr(x->called_party_address, *called_party, pkg);
+
+    //WL_FREE_ALL(&(x->called_asserted_identity),str_list_t,pkg);
+    //str_free_ptr(x->requested_party_address,pkg);
+
+    if ((orig_ioi && orig_ioi->s) || (term_ioi && term_ioi->s)) {
+        mem_new(ioi_elem, sizeof (ioi_list_element_t), pkg);
+        if (orig_ioi)
+            str_dup_ptr_ptr(ioi_elem->info.originating_ioi, orig_ioi, pkg);
+        if (term_ioi)
+            str_dup_ptr_ptr(ioi_elem->info.terminating_ioi, term_ioi, pkg);
+    }
+
+    if (icid && icid->s)
+        str_dup_ptr(x->icid, *icid, pkg);
+
+    return x;
+
+out_of_memory:
+    LM_ERR("out of pkg memory\n");
+    ims_information_free(x);
+    return NULL;
+}
+
+service_information_t * new_service_information(ims_information_t * ims_info, subscription_id_t * subscription) {
+    service_information_t * x = 0;
+    subscription_id_list_element_t * sl = 0;
+
+    mem_new(x, sizeof (service_information_t), pkg);
+
+    x->ims_information = ims_info;
+    if (subscription) {
+        mem_new(sl, sizeof (subscription_id_list_element_t), pkg);
+        subscription_id_list_t_copy(&(sl->s), subscription, pkg);
+        WL_APPEND(&(x->subscription_id), sl);
+    }
+
+    return x;
+
+out_of_memory:
+    LM_ERR("new service information: out of pkg memory\n");
+    service_information_free(x);
+    return 0;
+}
+
+Ro_CCR_t * new_Ro_CCR(int32_t acc_record_type, str * user_name, ims_information_t * ims_info, subscription_id_t * subscription) {
+
+
+    Ro_CCR_t *x = 0;
+
+    service_information_t * service_info = 0;
+
+    mem_new(x, sizeof (Ro_CCR_t), pkg);
+
+    str_dup(x->origin_host, cfg.origin_host, pkg);
+    str_dup(x->origin_realm, cfg.origin_realm, pkg);
+    str_dup(x->destination_realm, cfg.destination_realm, pkg);
+    x->acct_record_type = acc_record_type;
+
+    if (user_name) {
+        str_dup_ptr_ptr(x->user_name, user_name, pkg);
+    }
+
+    if (cfg.service_context_id && cfg.service_context_id->s)
+        str_dup_ptr(x->service_context_id, *(cfg.service_context_id), pkg);
+
+    if (ims_info)
+        if (!(service_info = new_service_information(ims_info, subscription)))
+            goto error;
+
+    x->service_information = service_info;
+    service_info = 0;
+
+    return x;
+
+out_of_memory:
+    LM_ERR("out of pkg memory\n");
+error:
+    Ro_free_CCR(x);
+    service_information_free(service_info);
+
+    return 0;
+}
+
+void event_type_free(event_type_t *x) {
+    if (!x) return;
+    str_free_ptr(x->sip_method, pkg);
+    str_free_ptr(x->event, pkg);
+    mem_free(x->expires, pkg);
+    mem_free(x, pkg);
+}
+
+void time_stamps_free(time_stamps_t *x) {
+    if (!x) return;
+    mem_free(x->sip_request_timestamp, pkg);
+    mem_free(x->sip_request_timestamp_fraction, pkg);
+    mem_free(x->sip_response_timestamp, pkg);
+    mem_free(x->sip_response_timestamp_fraction, pkg);
+    mem_free(x, pkg);
+}
+
+void ims_information_free(ims_information_t *x) {
+    if (!x) return;
+
+    event_type_free(x->event_type);
+
+    mem_free(x->role_of_node, pkg);
+    str_free_ptr(x->user_session_id, pkg);
+    str_free_ptr(x->outgoing_session_id, pkg);
+
+    WL_FREE_ALL(&(x->calling_party_address), str_list_t, pkg);
+    str_free_ptr(x->called_party_address, pkg);
+    WL_FREE_ALL(&(x->called_asserted_identity), str_list_t, pkg);
+    str_free_ptr(x->requested_party_address, pkg);
+
+    time_stamps_free(x->time_stamps);
+
+    WL_FREE_ALL(&(x->as_info), as_info_list_t, pkg);
+
+    WL_FREE_ALL(&(x->ioi), ioi_list_t, pkg);
+    str_free_ptr(x->icid, pkg);
+
+    str_free_ptr(x->service_id, pkg);
+
+    WL_FREE_ALL(&(x->service_specific_info), service_specific_info_list_t, pkg);
+
+    mem_free(x->cause_code, pkg);
+
+    mem_free(x, pkg);
+}
+
+void service_information_free(service_information_t *x) {
+    if (!x) return;
+
+    WL_FREE_ALL(&(x->subscription_id), subscription_id_list_t, pkg);
+    ims_information_free(x->ims_information);
+
+    mem_free(x, pkg);
+}
+
+void Ro_free_CCR(Ro_CCR_t *x) {
+    if (!x) return;
+
+    str_free(x->origin_host, pkg);
+    str_free(x->origin_realm, pkg);
+    str_free(x->destination_realm, pkg);
+
+    str_free_ptr(x->user_name, pkg);
+    mem_free(x->acct_interim_interval, pkg);
+    mem_free(x->origin_state_id, pkg);
+    mem_free(x->event_timestamp, pkg);
+
+    str_free_ptr(x->service_context_id, pkg);
+
+    service_information_free(x->service_information);
+
+    mem_free(x, pkg);
+}
+
+void Ro_free_CCA(Ro_CCA_t *x) {
+    if (!x) return;
+
+    if (x->mscc->final_unit_action) {
+        mem_free(x->mscc->final_unit_action, pkg);
+    }
+    mem_free(x->mscc->granted_service_unit, pkg);
+    mem_free(x->mscc, pkg);
+    mem_free(x, pkg);
+}
+
+
+
diff --git a/modules/ims_charging/Ro_data.h b/modules/ims_charging/Ro_data.h
new file mode 100644
index 0000000..c469582
--- /dev/null
+++ b/modules/ims_charging/Ro_data.h
@@ -0,0 +1,408 @@
+#ifndef __CDF_Ro_data_H
+#define __CDF_Ro_data_H
+
+#include "../cdp/diameter.h"
+#include "../cdp/diameter_epc.h"
+
+
+/**
+ * Allocate and blank a memory area
+ */
+#define mem_new(dst,len,mem) \
+do {\
+	if (!(len)) (dst)=0;\
+	else {\
+		(dst) = mem##_malloc(len);\
+		if (!(dst)) {\
+			LM_ERR("Error allocating %ld bytes in %s!\n",(long int)len,#mem);\
+			goto out_of_memory;\
+		}\
+		bzero((dst),(len));\
+	}\
+} while(0)
+
+#define struct_new(dst,type,mem) \
+		men_new(dst,sizeof(type),mem)
+
+
+/**
+ * Duplicate an arbitrary memory area
+ */
+#define mem_dup(dst,src,len,mem) \
+do {\
+	if (!(src)||!(len)) (dst)=0;\
+	else {\
+		(dst) = mem##_malloc(len);\
+		if (!(dst)) {\
+			LM_ERR("Error allocating %ld bytes in %s!\n",(long int)len,#mem);\
+			goto out_of_memory;\
+		}\
+		memcpy((dst),(src),len);\
+	}\
+} while(0)
+
+
+/**
+ * Free an arbitrary memory area
+ */
+#define mem_free(x,mem) \
+do {\
+	if (x) {\
+		mem##_free(x);\
+		x=0;\
+	}\
+} while(0)
+
+
+#define str_dup_ptr(dst,src,mem) \
+do {\
+	dst = mem##_malloc(sizeof(str));\
+	if ((src).len) {\
+		(dst)->s = mem##_malloc((src).len);\
+		if (!(dst)->s){\
+			LM_ERR("Error allocating %d bytes in %s!\n",(src).len,#mem);\
+			mem##_free(dst);\
+			goto out_of_memory;\
+		}\
+		memcpy((dst)->s,(src).s,(src).len);\
+		(dst)->len = (src).len;\
+	}else{\
+		(dst)->s=0;(dst)->len=0;\
+	}\
+} while (0)
+
+#define str_dup_ptr_ptr(dst,src,mem) \
+do {\
+	dst = mem##_malloc(sizeof(str));\
+	if ((src) && (src)->len) {\
+		(dst)->s = mem##_malloc((src)->len);\
+		if (!(dst)->s){\
+			LM_ERR("Error allocating %d bytes in %s!\n",(src)->len,#mem);\
+			mem##_free(dst);\
+			goto out_of_memory;\
+		}\
+		memcpy((dst)->s,(src)->s,(src)->len);\
+		(dst)->len = (src)->len;\
+	}else{\
+		(dst)->s=0;(dst)->len=0;\
+	}\
+} while (0)
+
+
+#define str_free_ptr(x,mem) \
+do {\
+	if (x) {\
+		if ((x)->s) mem##_free((x)->s);\
+		mem##_free((x));\
+	}\
+} while(0)
+
+/**
+ * list operations 
+ */
+
+#define WL_APPEND(list,add)                                                      \
+do {                                                                             \
+  (add)->next = NULL;															 \
+  (add)->prev = (list)->tail;													 \
+  if ((list)->tail) ((list)->tail)->next=(add);									 \
+  else (list)->head = (add);                                                     \
+  (list)->tail=(add);                                                        	 \
+} while (0)
+
+#define WL_FREE(el,list_type,mem)												\
+	list_type##_free(el,mem)
+
+#define WL_FREE_ALL(list,list_type,mem)\
+do {\
+	struct _##list_type##_slot *el,*nel;\
+	for(el=(list)->head;el;el=nel){\
+		nel = el->next;\
+		WL_FREE(el,list_type,mem);\
+	}\
+	(list)->head=0;\
+	(list)->tail=0;\
+} while(0)
+
+/* List of str */
+
+typedef struct _str_list_t_slot {
+    str data;
+    struct _str_list_t_slot *prev, *next;
+} str_list_slot_t;
+
+typedef struct {
+    str_list_slot_t *head, *tail;
+} str_list_t;
+
+#define str_list_t_free(x,mem) \
+do{\
+	if (x) {\
+		str_free((x)->data,mem);\
+		mem##_free(x);\
+		(x)=0;\
+	}\
+}while(0)
+
+
+#define str_list_t_copy(dst,src,mem) \
+	str_dup((dst)->data,(src)->data,mem)
+
+typedef struct {
+    str *sip_method;
+    str *event;
+    uint32_t *expires;
+} event_type_t;
+
+typedef struct {
+    time_t *sip_request_timestamp;
+    uint32_t *sip_request_timestamp_fraction;
+    time_t *sip_response_timestamp;
+    uint32_t *sip_response_timestamp_fraction;
+} time_stamps_t;
+
+typedef struct {
+    str *application_server;
+    str_list_t application_provided_called_party_address;
+} as_info_t;
+
+typedef struct _as_info_list_t_slot {
+    as_info_t info;
+    struct _as_info_list_t_slot *next, *prev;
+} as_info_list_element_t;
+
+typedef struct {
+    as_info_list_element_t *head, *tail;
+} as_info_list_t;
+
+
+#define as_info_list_t_free(x,mem) \
+do{\
+	str_list_slot_t *y=0,*z;\
+	if (x) {\
+		str_free_ptr((x)->info.application_server,mem);\
+		for(y=(x)->info.application_provided_called_party_address.head;y;y=z){\
+			z=y->next;\
+			str_free(y->data,mem);\
+			mem_free(y,mem);\
+		}\
+		mem##_free(x);\
+		(x) = 0;\
+	}\
+}while(0)
+
+#define as_info_list_t_copy(dst,src,mem) \
+do {\
+	str_dup_ptr_ptr((dst)->info.application_server,(src)->info.application_server,mem);\
+	WL_DUP_ALL(&((dst)->info.application_provided_called_party_address),&((src)->info.application_provided_called_party_address),str_list_t,mem);\
+} while(0)
+
+typedef struct {
+    str *originating_ioi;
+    str *terminating_ioi;
+} ioi_t;
+
+typedef struct _ioi_list_t_slot {
+    ioi_t info;
+    struct _ioi_list_t_slot *next, *prev;
+} ioi_list_element_t;
+
+typedef struct {
+    ioi_list_element_t *head, *tail;
+} ioi_list_t;
+
+
+#define ioi_list_t_free(x,mem) \
+do{\
+	if (x) {\
+		str_free_ptr((x)->info.originating_ioi,mem);\
+		str_free_ptr((x)->info.terminating_ioi,mem);\
+		mem##_free(x);\
+		(x) = 0;\
+	}\
+}while(0)
+
+#define ioi_list_t_copy(dst,src,mem) \
+do {\
+	str_dup_ptr_ptr((dst)->info.originating_ioi,(src)->info.originating_ioi,mem);\
+	str_dup_ptr_ptr((dst)->info.terminating_ioi,(src)->info.terminating_ioi,mem);\
+} while(0)
+
+typedef struct {
+    str *data;
+    uint32_t *type;
+} service_specific_info_t;
+
+typedef struct _service_specific_info_list_t_slot {
+    service_specific_info_t info;
+    struct _service_specific_info_list_t_slot *next, *prev;
+} service_specific_info_list_element_t;
+
+typedef struct {
+    service_specific_info_list_element_t *head, *tail;
+} service_specific_info_list_t;
+
+
+#define service_specific_info_list_t_free(x,mem) \
+do{\
+	if (x) {\
+		str_free_ptr((x)->info.data,mem);\
+		mem_free((x)->info.type,mem);\
+		mem##_free(x);\
+		(x) = 0;\
+	}\
+}while(0)
+
+#define service_specific_info_list_t_copy(dst,src,mem) \
+do {\
+	str_dup_ptr_ptr((dst)->info.data,(src)->info.data,mem);\
+	mem_dup((dst)->info.type,(src)->info.type,sizeof(uint32_t),mem);\
+} while(0)
+
+typedef struct {
+    event_type_t *event_type;
+
+    int32_t *role_of_node;
+    int32_t node_functionality;
+
+    str *user_session_id;
+    str *outgoing_session_id;
+
+    str_list_t calling_party_address;
+    str *called_party_address;
+    str_list_t called_asserted_identity;
+    str * requested_party_address;
+
+    time_stamps_t *time_stamps;
+
+    as_info_list_t as_info;
+
+    ioi_list_t ioi;
+    str *icid;
+
+    str *service_id;
+
+    service_specific_info_list_t service_specific_info;
+
+    int32_t *cause_code;
+
+} ims_information_t;
+
+typedef enum {
+    Subscription_Type_MSISDN = AVP_EPC_Subscription_Id_Type_End_User_E164,
+    Subscription_Type_IMSI = AVP_EPC_Subscription_Id_Type_End_User_IMSI,
+    Subscription_Type_IMPU = AVP_EPC_Subscription_Id_Type_End_User_SIP_URI,
+    Subscription_Type_NAI = AVP_EPC_Subscription_Id_Type_End_User_NAI,
+    Subscription_Type_IMPI = AVP_EPC_Subscription_Id_Type_End_User_Private,
+} subscription_id_type_e;
+
+typedef struct _subscription_id_t {
+    int32_t type;
+    str id;
+} subscription_id_t;
+
+typedef struct _subscription_id_list_t_slot {
+    subscription_id_t s;
+    struct _subscription_id_list_t_slot *next, *prev;
+} subscription_id_list_element_t;
+
+typedef struct {
+    subscription_id_list_element_t *head, *tail;
+} subscription_id_list_t;
+
+
+#define subscription_id_list_t_free(x,mem) \
+do{\
+	if (x) {\
+		str_free((x)->s.id,mem);\
+		mem##_free(x);\
+		(x) = 0;\
+	}\
+}while(0)
+
+#define subscription_id_list_t_copy(dst,src,mem) \
+do {\
+	(dst)->type = (src)->type;\
+	str_dup((dst)->id,(src)->id,mem);\
+} while(0)
+
+typedef struct {
+    subscription_id_list_t subscription_id;
+
+    ims_information_t *ims_information;
+
+} service_information_t;
+
+typedef struct {
+    str origin_host;
+    str origin_realm;
+    str destination_realm;
+
+    int32_t acct_record_type;
+    uint32_t acct_record_number;
+
+    str *user_name;
+    uint32_t *acct_interim_interval;
+    uint32_t *origin_state_id;
+    time_t *event_timestamp;
+
+    str *service_context_id;
+
+    service_information_t *service_information;
+} Ro_CCR_t;
+
+typedef struct {
+    uint32_t cc_time;
+    uint32_t cc_total_octets;
+    uint32_t cc_input_octets;
+    uint32_t cc_output_octets;
+} granted_services_unit_t;
+
+typedef struct {
+    uint32_t action;
+} final_unit_indication_t;
+
+typedef struct {
+    granted_services_unit_t *granted_service_unit;
+    uint32_t validity_time;
+    final_unit_indication_t *final_unit_action;
+} multiple_services_credit_control_t;
+
+typedef struct {
+    uint32_t resultcode;
+    uint32_t cc_request_type;
+    uint32_t cc_request_number;
+    multiple_services_credit_control_t *mscc;
+} Ro_CCA_t;
+
+event_type_t * new_event_type(str * sip_method,
+        str * event,
+        uint32_t * expires);
+
+time_stamps_t * new_time_stamps(time_t *sip_request_timestamp,
+        uint32_t *sip_request_timestamp_fraction,
+        time_t *sip_response_timestamp,
+        uint32_t *sip_response_timestamp_fraction);
+
+ims_information_t * new_ims_information(event_type_t * event_type,
+        time_stamps_t * time_stamps,
+        str * user_session_id,
+        str * outgoing_session_id,
+        str * calling_party,
+        str * called_party,
+        str * icid,
+        str * orig_ioi,
+        str * term_ioi,
+        int node_role);
+
+void event_type_free(event_type_t *x);
+void time_stamps_free(time_stamps_t *x);
+void ims_information_free(ims_information_t *x);
+void service_information_free(service_information_t *x);
+
+Ro_CCR_t * new_Ro_CCR(int32_t acc_record_type, str * user_name, ims_information_t * ims_info, subscription_id_t * subscription);
+void Ro_free_CCR(Ro_CCR_t *x);
+void Ro_free_CCA(Ro_CCA_t *x);
+
+
+#endif /* __CDF_Ro_data_H */
diff --git a/modules/ims_charging/ccr.c b/modules/ims_charging/ccr.c
new file mode 100644
index 0000000..51a8bf7
--- /dev/null
+++ b/modules/ims_charging/ccr.c
@@ -0,0 +1,328 @@
+#include "../cdp_avp/mod_export.h"
+
+#include "ccr.h"
+#include "Ro_data.h"
+
+extern cdp_avp_bind_t *cdp_avp;
+
+int Ro_write_event_type_avps(AAA_AVP_LIST * avp_list, event_type_t * x) {
+    AAA_AVP_LIST aList = {0, 0};
+
+    if (x->sip_method) {
+        if (!cdp_avp->epcapp.add_SIP_Method(&aList, *(x->sip_method), AVP_DUPLICATE_DATA))
+            goto error;
+    }
+
+    if (x->event)
+        if (!cdp_avp->epcapp.add_Event(&aList, *(x->event), 0))
+            goto error;
+
+    if (x->expires)
+        if (!cdp_avp->epcapp.add_Expires(avp_list, *(x->expires)))
+            goto error;
+
+    if (!cdp_avp->epcapp.add_Event_Type(avp_list, &aList, AVP_FREE_DATA))	//TODO: used to be DONT FREE
+        goto error;
+
+    return 1;
+error:
+    cdp_avp->cdp->AAAFreeAVPList(&aList);
+    LM_ERR("error while adding event type avps\n");
+    return 0;
+}
+
+int Ro_write_time_stamps_avps(AAA_AVP_LIST * avp_list, time_stamps_t* x) {
+    AAA_AVP_LIST aList = {0, 0};
+
+    if (x->sip_request_timestamp)
+        if (!cdp_avp->epcapp.add_SIP_Request_Timestamp(&aList, *(x->sip_request_timestamp)))
+            goto error;
+
+    if (x->sip_request_timestamp_fraction)
+        if (!cdp_avp->epcapp.add_SIP_Request_Timestamp_Fraction(&aList,
+                *(x->sip_request_timestamp_fraction)))
+            goto error;
+
+    if (x->sip_response_timestamp)
+        if (!cdp_avp->epcapp.add_SIP_Response_Timestamp(&aList, *(x->sip_response_timestamp)))
+            goto error;
+
+    if (x->sip_response_timestamp_fraction)
+        if (!cdp_avp->epcapp.add_SIP_Response_Timestamp_Fraction(&aList,
+                *(x->sip_response_timestamp_fraction)))
+            goto error;
+
+    if (!cdp_avp->epcapp.add_Time_Stamps(avp_list, &aList, AVP_FREE_DATA))	//used to be DONT FREE
+        goto error;
+
+
+    return 1;
+error:
+    cdp_avp->cdp->AAAFreeAVPList(&aList);
+    LM_ERR("error while adding time stamps avps\n");
+
+    return 0;
+}
+
+int Ro_write_ims_information_avps(AAA_AVP_LIST * avp_list, ims_information_t* x) {
+    str_list_slot_t * sl = 0;
+    AAA_AVP_LIST aList = {0, 0};
+    AAA_AVP_LIST aList2 = {0, 0};
+    service_specific_info_list_element_t * info = 0;
+    ioi_list_element_t * ioi_elem = 0;
+
+    if (x->event_type)
+        if (!Ro_write_event_type_avps(&aList2, x->event_type))
+            goto error;
+    if (x->role_of_node)
+        if (!cdp_avp->epcapp.add_Role_Of_Node(&aList2, *(x->role_of_node))) goto error;
+
+    if (!cdp_avp->epcapp.add_Node_Functionality(&aList2, x->node_functionality))
+        goto error;
+
+    if (x->user_session_id)
+        if (!cdp_avp->epcapp.add_User_Session_Id(&aList2, *(x->user_session_id), 0))
+            goto error;
+
+    for (sl = x->calling_party_address.head; sl; sl = sl->next) {
+        if (!cdp_avp->epcapp.add_Calling_Party_Address(&aList2, sl->data, 0))
+            goto error;
+    }
+
+    if (x->called_party_address)
+        if (!cdp_avp->epcapp.add_Called_Party_Address(&aList2, *(x->called_party_address), 0))
+            goto error;
+
+    for (sl = x->called_asserted_identity.head; sl; sl = sl->next) {
+        if (!cdp_avp->epcapp.add_Called_Asserted_Identity(&aList2, sl->data, 0))
+            goto error;
+    }
+
+    if (x->requested_party_address)
+        if (!cdp_avp->epcapp.add_Requested_Party_Address(&aList2, *(x->requested_party_address), 0))
+            goto error;
+    if (x->time_stamps)
+        if (!Ro_write_time_stamps_avps(&aList2, x->time_stamps))
+            goto error;
+
+    for (ioi_elem = x->ioi.head; ioi_elem; ioi_elem = ioi_elem->next) {
+
+        if (ioi_elem->info.originating_ioi)
+            if (!cdp_avp->epcapp.add_Originating_IOI(&aList, *(ioi_elem->info.originating_ioi), 0))
+                goto error;
+
+        if (ioi_elem->info.terminating_ioi)
+            if (!cdp_avp->epcapp.add_Terminating_IOI(&aList, *(ioi_elem->info.terminating_ioi), 0))
+                goto error;
+
+        if (!cdp_avp->epcapp.add_Inter_Operator_Identifier(&aList2, &aList, 0))
+            goto error;
+        aList.head = aList.tail = 0;
+    }
+
+    if (x->icid)
+        if (!cdp_avp->epcapp.add_IMS_Charging_Identifier(&aList2, *(x->icid), 0))
+            goto error;
+
+    if (x->service_id)
+        if (!cdp_avp->epcapp.add_Service_ID(&aList2, *(x->service_id), 0))
+            goto error;
+
+    for (info = x->service_specific_info.head; info; info = info->next) {
+
+        if (info->info.data)
+            if (!cdp_avp->epcapp.add_Service_Specific_Data(&aList, *(info->info.data), 0))
+                goto error;
+        if (info->info.type)
+            if (!cdp_avp->epcapp.add_Service_Specific_Type(&aList, *(info->info.type)))
+                goto error;
+
+        if (!cdp_avp->epcapp.add_Service_Specific_Info(&aList2, &aList, 0))
+            goto error;
+        aList.head = aList.tail = 0;
+    }
+
+    if (x->cause_code)
+        if (!cdp_avp->epcapp.add_Cause_Code(&aList2, *(x->cause_code)))
+            goto error;
+
+    if (!cdp_avp->epcapp.add_IMS_Information(avp_list, &aList2, AVP_FREE_DATA))//TODO check why not DONT FREE DATA
+        goto error;
+
+    return 1;
+error:
+    /*free aList*/
+    cdp_avp->cdp->AAAFreeAVPList(&aList);
+    cdp_avp->cdp->AAAFreeAVPList(&aList2);
+    LM_ERR("could not add ims information avps\n");
+    return 0;
+}
+
+int Ro_write_service_information_avps(AAA_AVP_LIST * avp_list, service_information_t* x) {
+    subscription_id_list_element_t * elem = 0;
+    AAA_AVP_LIST aList = {0, 0};
+
+    for (elem = x->subscription_id.head; elem; elem = elem->next) {
+
+        if (!cdp_avp->ccapp.add_Subscription_Id_Group(&aList, elem->s.type, elem->s.id, 0))
+            goto error;
+
+    }
+
+    if (x->ims_information)
+        if (!Ro_write_ims_information_avps(&aList, x->ims_information))
+            goto error;
+
+    if (!cdp_avp->epcapp.add_Service_Information(avp_list, &aList, AVP_FREE_DATA)) //TODO: use to be dont free
+        goto error;
+
+    return 1;
+error:
+    cdp_avp->cdp->AAAFreeAVPList(&aList);
+    return 0;
+}
+
+AAAMessage * Ro_write_CCR_avps(AAAMessage * ccr, Ro_CCR_t* x) {
+
+    if (!ccr) return 0;
+
+    if (!cdp_avp->base.add_Origin_Host(&(ccr->avpList), x->origin_host, 0)) goto error;
+
+    if (!cdp_avp->base.add_Origin_Realm(&(ccr->avpList), x->origin_realm, 0)) goto error;
+    if (!cdp_avp->base.add_Destination_Realm(&(ccr->avpList), x->destination_realm, 0)) goto error;
+
+    if (!cdp_avp->base.add_Accounting_Record_Type(&(ccr->avpList), x->acct_record_type)) goto error;
+    if (!cdp_avp->base.add_Accounting_Record_Number(&(ccr->avpList), x->acct_record_number)) goto error;
+
+    if (x->user_name)
+        if (!cdp_avp->base.add_User_Name(&(ccr->avpList), *(x->user_name), AVP_DUPLICATE_DATA)) goto error;
+
+    if (x->acct_interim_interval)
+        if (!cdp_avp->base.add_Acct_Interim_Interval(&(ccr->avpList), *(x->acct_interim_interval))) goto error;
+
+    if (x->origin_state_id)
+        if (!cdp_avp->base.add_Origin_State_Id(&(ccr->avpList), *(x->origin_state_id))) goto error;
+
+    if (x->event_timestamp)
+        if (!cdp_avp->base.add_Event_Timestamp(&(ccr->avpList), *(x->event_timestamp))) goto error;
+
+    if (x->service_context_id)
+        if (!cdp_avp->ccapp.add_Service_Context_Id(&(ccr->avpList), *(x->service_context_id), 0)) goto error;
+
+    if (x->service_information)
+        if (!Ro_write_service_information_avps(&(ccr->avpList), x->service_information))
+            goto error;
+    return ccr;
+error:
+    cdp_avp->cdp->AAAFreeMessage(&ccr);
+    return 0;
+}
+
+AAAMessage *Ro_new_ccr(AAASession * session, Ro_CCR_t * ro_ccr_data) {
+
+    AAAMessage * ccr = 0;
+    ccr = cdp_avp->cdp->AAACreateRequest(IMS_Ro, Diameter_CCR, Flag_Proxyable, session);
+    if (!ccr) {
+        LM_ERR("could not create CCR\n");
+        return 0;
+    }
+  
+    ccr = Ro_write_CCR_avps(ccr, ro_ccr_data);
+
+    return ccr;
+}
+
+Ro_CCA_t *Ro_parse_CCA_avps(AAAMessage *cca) {
+    if (!cca)
+        return 0;
+
+    Ro_CCA_t *ro_cca_data = 0;
+    mem_new(ro_cca_data, sizeof (Ro_CCR_t), pkg);
+    multiple_services_credit_control_t *mscc = 0;
+    mem_new(mscc, sizeof (multiple_services_credit_control_t), pkg);
+    granted_services_unit_t *gsu = 0;
+    mem_new(gsu, sizeof (granted_services_unit_t), pkg);
+    final_unit_indication_t *fui = 0;
+    mem_new(fui, sizeof (final_unit_indication_t), pkg);
+    mscc->granted_service_unit = gsu;
+    mscc->final_unit_action = fui;
+
+    mscc->final_unit_action->action = -1;
+
+    AAA_AVP_LIST* avp_list = &cca->avpList;
+    AAA_AVP_LIST mscc_avp_list;
+    AAA_AVP_LIST* mscc_avp_list_ptr;
+
+    AAA_AVP *avp = avp_list->head;
+    unsigned int x;
+    while (avp != NULL) {
+        switch (avp->code) {
+            case AVP_CC_Request_Type:
+                x = get_4bytes(avp->data.s);
+                ro_cca_data->cc_request_type = x;
+                break;
+            case AVP_CC_Request_Number:
+                x = get_4bytes(avp->data.s);
+                ro_cca_data->cc_request_number = x;
+                break;
+            case AVP_Multiple_Services_Credit_Control:
+                mscc_avp_list = cdp_avp->cdp->AAAUngroupAVPS(avp->data);
+                mscc_avp_list_ptr = &mscc_avp_list;
+                AAA_AVP *mscc_avp = mscc_avp_list_ptr->head;
+                while (mscc_avp != NULL) {
+                    LM_DBG("MSCC AVP code is [%i] and data length is [%i]", mscc_avp->code, mscc_avp->data.len);
+                    switch (mscc_avp->code) {
+                            AAA_AVP_LIST y;
+                            AAA_AVP *z;
+                        case AVP_Granted_Service_Unit:
+                            y = cdp_avp->cdp->AAAUngroupAVPS(mscc_avp->data);
+                            z = y.head;
+                            while (z) {
+                                switch (z->code) {
+                                    case AVP_CC_Time:
+                                        mscc->granted_service_unit->cc_time = get_4bytes(z->data.s);
+                                        break;
+                                    default:
+                                        LM_ERR("Unsupported Granted Service Unit with code:[%d]\n", z->code);
+                                }
+                                z = z->next;
+                            }
+                            cdp_avp->cdp->AAAFreeAVPList(&y);
+                            break;
+                        case AVP_Validity_Time:
+                            mscc->validity_time = get_4bytes(mscc_avp->data.s);
+                            break;
+                        case AVP_Final_Unit_Indication:
+                            y = cdp_avp->cdp->AAAUngroupAVPS(mscc_avp->data);
+                            z = y.head;
+                            while (z) {
+                                switch (z->code) {
+                                    case AVP_Final_Unit_Action:
+                                        mscc->final_unit_action->action = get_4bytes(z->data.s);
+                                        break;
+                                    default:
+                                        LM_ERR("Unsupported Final Unit Indication AVP.\n");
+                                }
+                                z = z->next;
+                            }
+                            cdp_avp->cdp->AAAFreeAVPList(&y);
+                    }
+                    mscc_avp = mscc_avp->next;
+                }
+                cdp_avp->cdp->AAAFreeAVPList(mscc_avp_list_ptr);
+                break;
+            case AVP_Result_Code:
+                x = get_4bytes(avp->data.s);
+                ro_cca_data->resultcode = x;
+                break;
+        }
+        avp = avp->next;
+    }
+    ro_cca_data->mscc = mscc;
+    return ro_cca_data;
+
+out_of_memory:
+    LM_ERR("out of pkg memory\n");
+    Ro_free_CCA(ro_cca_data);
+    return 0;
+}
diff --git a/modules/ims_charging/ccr.h b/modules/ims_charging/ccr.h
new file mode 100644
index 0000000..508c0f4
--- /dev/null
+++ b/modules/ims_charging/ccr.h
@@ -0,0 +1,10 @@
+#ifndef _Client_Ro_CCR_H
+#define _Client_Ro_CCR_H
+
+#include "../cdp/diameter.h"
+#include "Ro_data.h"
+
+AAAMessage *Ro_new_ccr(AAASession * session, Ro_CCR_t *);
+Ro_CCA_t *Ro_parse_CCA_avps(AAAMessage *cca);
+
+#endif
diff --git a/modules/ims_charging/config.h b/modules/ims_charging/config.h
new file mode 100644
index 0000000..d3868b5
--- /dev/null
+++ b/modules/ims_charging/config.h
@@ -0,0 +1,12 @@
+#ifndef __CLIENT_RO_CONFIG_H
+#define __CLIENT_RO_CONFIG_H
+
+typedef struct {
+    str origin_host;
+    str origin_realm;
+    str destination_realm;
+    str destination_host;
+    str * service_context_id;
+} client_ro_cfg;
+
+#endif
diff --git a/modules/ims_charging/dialog.c b/modules/ims_charging/dialog.c
new file mode 100644
index 0000000..1b2453b
--- /dev/null
+++ b/modules/ims_charging/dialog.c
@@ -0,0 +1,161 @@
+#include "dialog.h"
+#include "ro_session_hash.h"
+
+struct cdp_binds cdpb;
+
+void dlg_reply(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
+	struct sip_msg *reply = _params->rpl;
+	struct ro_session* session = 0;
+	struct ro_session_entry* ro_session_entry;
+	time_t now = time(0);
+	time_t time_since_last_event;
+
+	LM_DBG("dlg_reply callback entered\n");
+
+//	if (reply != FAKED_REPLY && reply->REPLY_STATUS == 200) {
+//		//get CC session from callback param
+//		char* cdp_session_id = (char*)*_params->param;
+//		LM_INFO("Call answered\n");
+//		LM_DBG("Call answered and we have a session id of [%s]\n", cdp_session_id);
+//
+//		str session_id;
+//		session_id.s = cdp_session_id;
+//		session_id.len = strlen(cdp_session_id);
+//		AAASession* cdp_session = cdpb.AAAGetCCAccSession(session_id);
+//		if (!cdp_session) {
+//			LM_ERR("could not find find CC App CDP session\n");
+//			return;
+//		}
+//
+//		cdpb.AAAStartChargingCCAccSession(cdp_session);
+//		cdpb.AAASessionsUnlock(cdp_session->hash);
+//	}
+
+	if (reply != FAKED_REPLY && reply->REPLY_STATUS == 200) {
+		LM_DBG("Call answered on dlg [%p] - search for Ro Session and initialise timers.\n", dlg);
+
+		session = (struct ro_session*)*_params->param;
+		if (!session) {
+			LM_ERR("Ro Session object is NULL...... aborting\n");
+			return;
+		}
+
+		ro_session_entry = &(ro_session_table->entries[session->h_entry]);
+
+		ro_session_lock(ro_session_table, ro_session_entry);
+
+		if (session->active) {
+			LM_CRIT("Why the heck am i receiving a double confirmation of the dialog? Ignoring... ");
+			ro_session_unlock(ro_session_table, ro_session_entry);
+			return;
+		}
+	
+		time_since_last_event = now - session->last_event_timestamp;
+		session->start_time = session->last_event_timestamp = now;
+		session->event_type = answered;
+		session->active = 1;
+		
+
+		/* check to make sure that the validity of the credit is enough for the bundle */
+		int ret = 0;
+		if (session->reserved_secs < (session->valid_for - time_since_last_event)) {
+			if (session->reserved_secs > ro_timer_buffer/*TIMEOUTBUFFER*/) {
+				ret = insert_ro_timer(&session->ro_tl, session->reserved_secs - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
+			} else {
+				ret = insert_ro_timer(&session->ro_tl, session->reserved_secs);
+			}
+		} else {
+			if (session->valid_for > ro_timer_buffer) {
+				ret = insert_ro_timer(&session->ro_tl, session->valid_for - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
+			} else {
+				ret = insert_ro_timer(&session->ro_tl, session->valid_for);
+			}
+		}
+
+
+		if (ret != 0) {
+			LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s); 
+		} else {
+			ref_ro_session_unsafe(session, 1); // lock already acquired
+		}
+				
+		ro_session_unlock(ro_session_table, ro_session_entry);
+
+		AAASession* cdp_session = cdpb.AAAGetCCAccSession(session->ro_session_id);
+		if (!cdp_session) {
+			LM_ERR("could not find find CC App CDP session for session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s);
+//			ro_session_unlock(ro_session_table, ro_session_entry);
+			return;
+		}
+		
+//		ro_session_unlock(ro_session_table, ro_session_entry);
+
+		cdpb.AAAStartChargingCCAccSession(cdp_session);
+		cdpb.AAASessionsUnlock(cdp_session->hash);		
+		
+//		unref_ro_session(session, 1);	DONT need this anymore because we don't do lookup so no addition to ref counter
+	}
+}
+
+/* this may be called for a number of callbacks related to tearing down a dialog so beware. */
+void dlg_terminated(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
+	int i;
+	int unref = 0;
+	struct ro_session *ro_session = 0;
+	struct ro_session_entry *ro_session_entry;
+
+	LM_DBG("dialog [%p] terminated, lets send stop record\n", dlg);
+
+	if (!_params) {
+		return;
+	}
+
+	struct sip_msg *request = _params->req;
+	if (!request) {
+		LM_WARN("dlg_terminated has no SIP request associated.\n");
+	}
+
+	if (dlg && (dlg->callid.s && dlg->callid.len > 0)) {
+		/* find the session for this call, possibly both for orig and term*/
+		for (i=0; i<2; i++) {
+			//TODO: try and get the Ro session specifically for terminating dialog or originating one
+			//currently the way we are doing is a hack.....
+			if ((ro_session = lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0))) {
+				ro_session_entry =
+						&(ro_session_table->entries[ro_session->h_entry]);
+
+				//if the Ro session is not active we don't need to do anything. This prevents
+				//double processing for various dialog_terminated callback events.
+				//If however, the call was never answered, then we can continue as normal
+				if (!ro_session->active && (ro_session->start_time != 0)) {
+					unref_ro_session(ro_session,1);
+					LM_ERR("Ro Session is not active, but may have been answered [%d]\n", (int)ro_session->start_time);
+					continue;
+				}
+			
+	
+				ro_session_lock(ro_session_table, ro_session_entry);
+
+				if (ro_session->active) { // if the call was never activated, there's no timer to remove
+					int ret = remove_ro_timer(&ro_session->ro_tl);
+					if (ret < 0) {
+						LM_CRIT("unable to unlink the timer on ro_session %p [%.*s]\n", 
+							ro_session, ro_session->cdp_session_id.len, ro_session->cdp_session_id.s);
+					} else if (ret > 0) {
+						LM_WARN("inconsistent ro timer data on ro_session %p [%.*s]\n",
+							ro_session, ro_session->cdp_session_id.len, ro_session->cdp_session_id.s);						
+					} else {
+						unref++;
+					}
+				}
+
+				LM_DBG("Sending CCR STOP on Ro_Session [%p]\n", ro_session);
+				send_ccr_stop(ro_session);
+				ro_session->active = 0;
+				//ro_session->start_time;
+				unref_ro_session_unsafe(ro_session, 2+unref, ro_session_entry); //lock already acquired
+				ro_session_unlock(ro_session_table, ro_session_entry);
+			}
+		}
+	}
+}
diff --git a/modules/ims_charging/dialog.h b/modules/ims_charging/dialog.h
new file mode 100644
index 0000000..06778e9
--- /dev/null
+++ b/modules/ims_charging/dialog.h
@@ -0,0 +1,14 @@
+#ifndef __DIALOG_H
+#define __DIALOG_H
+
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../../modules/dialog_ng/dlg_hash.h"
+#include "../cdp/cdp_load.h"
+#include "ims_ro.h"
+
+extern int ro_timer_buffer;
+
+void dlg_terminated(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
+void dlg_reply(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
+
+#endif
diff --git a/modules/ims_charging/diameter_ro.c b/modules/ims_charging/diameter_ro.c
new file mode 100644
index 0000000..2261ba8
--- /dev/null
+++ b/modules/ims_charging/diameter_ro.c
@@ -0,0 +1,40 @@
+#include "../cdp/diameter_epc.h"
+#include "Ro_data.h"
+#include "diameter_ro.h"
+
+int AAASendCCR(AAASession *session) {
+
+    return 1;
+}
+
+/**
+ * Handler for incoming Diameter requests.
+ * @param request - the received request
+ * @param param - generic pointer
+ * @returns the answer to this request
+ */
+void RoChargingResponseHandler(AAAMessage *response, void *param) {
+    switch (response->applicationId) {
+        case IMS_Ro:
+            switch (response->commandCode) {
+                case Diameter_CCA:
+                    break;
+                default:
+                    LM_ERR("ERR:"M_NAME":RoChargingResponseHandler: - "
+                            "Received unknown response for Ro command %d, flags %#1x endtoend %u hopbyhop %u\n",
+                            response->commandCode, response->flags,
+                            response->endtoendId, response->hopbyhopId);
+                    return;
+            }
+            break;
+        default:
+            LM_ERR("DBG:"M_NAME":RoChargingResponseHandler(): - Received unknown response for app %d command %d\n",
+                    response->applicationId,
+                    response->commandCode);
+            LM_ERR("Reponse is [%s]", response->buf.s);
+            return;
+
+    }
+    return;
+}
+
diff --git a/modules/ims_charging/diameter_ro.h b/modules/ims_charging/diameter_ro.h
new file mode 100644
index 0000000..6d320b3
--- /dev/null
+++ b/modules/ims_charging/diameter_ro.h
@@ -0,0 +1,11 @@
+#ifndef __CLIENT_RF_DIAMETER_RO_H
+#define __CLIENT_RF_DIAMETER_RO_H
+
+#include "../cdp/cdp_load.h"
+#include "../cdp_avp/mod_export.h"
+
+int AAASendCCR(AAASession * session);
+
+void RoChargingResponseHandler(AAAMessage *response, void *param);
+
+#endif /* __CLIENT_RF_DIAMETER_RO_H */
diff --git a/modules/ims_charging/doc/Makefile b/modules/ims_charging/doc/Makefile
new file mode 100644
index 0000000..56be612
--- /dev/null
+++ b/modules/ims_charging/doc/Makefile
@@ -0,0 +1,4 @@
+docs = ims_charging.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/ims_charging/doc/images/charging1.png b/modules/ims_charging/doc/images/charging1.png
new file mode 100644
index 0000000..300f082
Binary files /dev/null and b/modules/ims_charging/doc/images/charging1.png differ
diff --git a/modules/ims_charging/doc/images/charging2.png b/modules/ims_charging/doc/images/charging2.png
new file mode 100644
index 0000000..a4d4698
Binary files /dev/null and b/modules/ims_charging/doc/images/charging2.png differ
diff --git a/modules/ims_charging/doc/ims_charging.xml b/modules/ims_charging/doc/ims_charging.xml
new file mode 100644
index 0000000..f1f2285
--- /dev/null
+++ b/modules/ims_charging/doc/ims_charging.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+ "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"
+[
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+]>
+<book>
+  <bookinfo>
+    <title>The IMS Charging Module</title>
+    <authorgroup>
+      <author>
+        <firstname>Jason</firstname>
+        <surname>Penton</surname>
+        <affiliation>
+          <orgname>Smile Communications</orgname>
+        </affiliation>
+        <email>jason.penton at smilecoms.com</email>
+      </author>
+      <author>
+        <firstname>Carsten</firstname>
+        <surname>Bock</surname>
+        <affiliation>
+          <orgname>ng-voice GmbH</orgname>
+        </affiliation>
+        <email>carsten at ng-voice.com</email>
+      </author>
+      <author>
+        <firstname>Carlos</firstname>
+        <surname>Ruiz Diaz</surname>
+        <affiliation>
+          <orgname>ng-voice GmbH</orgname>
+        </affiliation>
+        <email>carlos at ng-voice.com</email>
+      </author>
+    </authorgroup>
+    <copyright>
+      <year>2013</year>
+      <holder>Smile Communications</holder>
+    </copyright>
+    <copyright>
+      <year>2013</year>
+      <holder>ng-voice GmbH</holder>
+    </copyright>
+  </bookinfo>
+  <toc />
+  <xi:include href="ims_charging_admin.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</book>
+
diff --git a/modules/ims_charging/doc/ims_charging_admin.xml b/modules/ims_charging/doc/ims_charging_admin.xml
new file mode 100644
index 0000000..a6ef005
--- /dev/null
+++ b/modules/ims_charging/doc/ims_charging_admin.xml
@@ -0,0 +1,651 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module Admin Guide -->
+<chapter>
+  <title>Admin Guide</title>
+  <section>
+    <title>Overview</title>
+    <para>This module contains all methods related to the IMS charging control functions performed
+    by an network element (e.g. a S-CSCF) over the Ro interface. This module is dependent on the
+    CDP (C Diameter Peer) modules for communicating with a Charging-Server as specified in 3GPP
+    specification TS xx.xxx.</para>
+    <para>Please also refer to RFC 4006 (Diameter Credit-Control Application)</para>
+  </section>
+  <section>
+    <title>Dependencies</title>
+    <section>
+      <title>Kamailio Modules</title>
+      <para>The Following mouldes must be loaded before this module:</para>
+      <itemizedlist>
+        <listitem>
+          <para>Dialog_ng</para>
+        </listitem>
+        <listitem>
+          <para>TM - Transaction Manager</para>
+        </listitem>
+        <listitem>
+          <para>CDP - C Diameter Peer</para>
+        </listitem>
+        <listitem>
+          <para>CDP_AVP - CDP AVP Applications</para>
+        </listitem>
+      </itemizedlist>
+    </section>
+    <section>
+      <title>External Libraries or Applications</title>
+      <para>This modules requires the internal IMS library.</para>
+    </section>
+  </section>
+  <section>
+    <title>Understanding Charging in the IP-Multimedia-Subsystem (IMS)</title>
+    <para>Before each service usage, the charging system must be asked for permission (credit
+    authorization). The charging server must make a decision: Either authorize or deny the session.
+    For postpaid scenarios this is fairly easy: The charging-server only needs to collect the usage
+    data for processing it at the end of the month. As no realtime account updating is needed, this
+    is often called "offline-charging". For prepaid scenarios the charging server needs to know the
+    user's account balance and it will need to update the account in real-time. This is often
+    referred to as "online-charging".</para>
+    <para>Question: What is the double of the Radius? Answer: It's the Diameter!</para>
+    <para>As quite often, we use the Diameter-Protocol to do the Charging in the IMS. And as quite
+    often, IMS uses a huge bunch of acronyms to describe the different interfaces: We call the
+    diameter-interface for offline-charging the "Rf"-interface and the interface for online
+    charging the "Ro"-interface.</para>
+    <para>Each system, that needs this credit authorization, have to be equipped with a proper
+    charging trigger, a so-called charging-trigger-function (CTF) in order to communicate with the
+    charging-server (also called charging-function):</para>
+    <mediaobject>
+      <imageobject>
+        <imagedata fileref="./images/charging1.png" />
+      </imageobject>
+    </mediaobject>
+    <section>
+      <title>Offline Charging (Rf)</title>
+      <para>For the offlinc charging (Rf), we have the following two diameter-messages:</para>
+      <itemizedlist>
+        <listitem>
+          <para>ACR - Accounting Request</para>
+        </listitem>
+        <listitem>
+          <para>ACA - Accounting Answer</para>
+        </listitem>
+      </itemizedlist>
+      <para>Each request can have the following Accounting-Record-Type:</para>
+      <itemizedlist>
+        <listitem>
+          <para>START_RECORD - used to start an accounting session, typically when the application
+          receives a SIP 200 OK acknowledging an initial SIP INVITE.</para>
+        </listitem>
+        <listitem>
+          <para>INTERIM_RECORD - used to update a session, for example, in the case of SIP
+          RE-INVITE and/or UPDATE in the current SIP dialog.</para>
+        </listitem>
+        <listitem>
+          <para>STOP_RECORD - used to stop an accounting session, for example, when the application
+          receives a SIP BYE message.</para>
+        </listitem>
+        <listitem>
+          <para>EVENT_RECORD - used for event-based accounting, e.g. a short message or
+          similar</para>
+        </listitem>
+      </itemizedlist>
+    </section>
+    <section>
+      <title>Online Charging (Ro)</title>
+      <para>For online charging (Ro), this get's a little bit more complicated. The charging
+      function needs to perform credit control before allowing resource usage. The prepaid
+      subscriber needs to exist in the charging-server and all activities must be monitored by the
+      charging-server. We must distinguish between the following two cases:</para>
+      <itemizedlist>
+        <listitem>
+          <para>Direct debiting - the amount is immediately deducted from the user's account in one
+          single transaction. This could be for example a SMS or the ordering of a movie in case of
+          Video-on-Demand.</para>
+        </listitem>
+        <listitem>
+          <para>Unit reservation - an amount is reserved by the charging-server. This is done,
+          because the charging-server does not know yet, how many units are needed to provide the
+          service. During the session, the used amount may be deducted and more units can be
+          requested; at the end of the session the used sessions are reported in the final request.
+          These sessions could be typically a voice- or video-call or a Pay-TV session, if you pay
+          per usage.</para>
+        </listitem>
+      </itemizedlist>
+      <para>As a result, we have the following three scenarios:</para>
+      <itemizedlist>
+        <listitem>
+          <para>Immediate Event Charging (IEC) - used for simple Event-based charging</para>
+        </listitem>
+        <listitem>
+          <para>Event Charging with Unit Reservation (ECUR) (of type Event-based charging)</para>
+        </listitem>
+        <listitem>
+          <para>Session Charging with Unit Reservation (SCUR) (of type Session-based
+          charging)</para>
+        </listitem>
+      </itemizedlist>
+    </section>
+    <section>
+      <title>Online Charging (Ro): A practical example</title>
+      <para>But how does it look in reality? Let us make a more practical example:</para>
+      <para>Let us assume we have a subscriber, who has sufficient credit for 75 seconds of
+      talking. The subscriber initiates a call; as we do not know, how long the call will take, we
+      start with requesting credit for 30 seconds (CCR-Request, we could request any duration, e.g.
+      2 hours, but it would probably block other calls if we reserve all the required
+      credit).</para>
+      <para>The call proceeds, so after 30 seconds we send another CCR-Request with the indication
+      that we used the reserved 30 seconds and that we request another 30 seconds. We reduce the
+      account of the subscriber by 30 seconds, so he has a credit of 45 seconds. Since 45 seconds
+      is more than the requested 30 seconds, this second request can also easily be accepted and
+      another 30 seconds can be granted. After this request, the account is at 45 seconds and we
+      still (or again) have 30 seconds reserved.</para>
+      <para>Meanwhile the subscriber initiates a second call. We try to request again 30 seconds
+      from the charging-server, but as our account is at 45 seconds of speaking time and since we
+      reserved another 30 seconds for the first call, we can only grant 15 seconds for the second
+      call. The last 15 seconds are now reserved for this subscriber; we have 45 seconds on the
+      account of which 45 seconds are reserved.</para>
+      <para>Now the first call gets terminated: We only used 20 seconds from the granted 30
+      seconds. So we decrease the account of the subscriber by 20 seconds and we reduce the amount
+      of reserved units by 30. We have 25 seconds in the account and we have still reserved 15
+      seconds for the second call.</para>
+      <para>As the second call is still proceeding, we will try to request another 30 seconds and
+      we indicate, that we used the granted 15 seconds. The account is deducted by 15 seconds (the
+      used units) and we can grant another 10 seconds for the second call, as this is the remains
+      on the account.</para>
+      <para>After 10 seconds, no more units can be granted, so the call is teared down.</para>
+      <para>The following diagram is a graphical representation of the above example:</para>
+      <mediaobject>
+        <imageobject>
+          <imagedata fileref="./images/charging2.png" />
+        </imageobject>
+      </mediaobject>
+    </section>
+  </section>
+  <section>
+    <title>Parameters</title>
+    <section>
+      <title>
+      <varname>hash_size</varname>(int)</title>
+      <para>The size of the hash table internally used to keep the Diameter-Ro-Session. A larger
+      table is much faster but consumes more memory. The hash size must be a power of two
+      number.</para>
+      <para>IMPORTANT: If Ro-Session's information should be stored in a database, a constant
+      hash_size should be used, otherwise the restoring process will not take place. If you really
+      want to modify the hash_size you must delete all table's rows before restarting the
+      server.</para>
+      <para>
+        <emphasis>Default value is 4096.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>hash_size</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "hash_size", 1024)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>interim_update_credits</varname>(int)</title>
+      <para>How much credit should be requested interim request? At the start of the call, we
+      request the amout of seconds as per Command. For each interim request, we would request
+      credit for "interim_update_credits".</para>
+      <para>
+        <emphasis>Default value is 30.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>interim_update_credits</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "interim_update_credits", 600)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>timer_buffer</varname>(int)</title>
+      <para>How many seconds before expiry of our credit should we request more credit?</para>
+      <para>
+        <emphasis>Default value is 8.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>timer_buffer</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "timer_buffer", 10)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>ro_forced_peer</varname>(string)</title>
+      <para>This is the optional name of the origin host of the Diameter server (typically a
+      Charging Server). If not set then realm routing is used.</para>
+      <para>
+        <emphasis>Default value is ''.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>ro_forced_peer</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "ro_forced_peer", "ocs.ims.smilecoms.com")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>ro_auth_expiry</varname>(integer)</title>
+      <para>This is the expiry length in seconds of the initiated Diameter sessions.</para>
+      <para>
+        <emphasis>Default value is 7200.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>ro_auth_expiry</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "ro_auth_expiry", 14400)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>ro_auth_expiry</varname>(integer)</title>
+      <para>This is the expiry length in seconds of the initiated Diameter sessions.</para>
+      <para>
+        <emphasis>Default value is 7200.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>ro_auth_expiry</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "ro_auth_expiry", 14400)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>cdp_event_latency</varname>(integer)</title>
+      <para>This is a flag to determine whether or slow CDP responses should be reported in the log
+      file. 1 is enabled and 0 is disabled.</para>
+      <para>
+        <emphasis>Default value is 1.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>cdp_event_latency</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "cdp_event_latency", 1)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>cdp_event_threshold</varname>(integer)</title>
+      <para>This time in milliseconds is the limit we should report a CDP response as slow. i.e. if
+      a CDP response exceeds this limit it will be reported in the log file. This is only relevant
+      is cdp_event_latency is enabled (set to 0).</para>
+      <para>
+        <emphasis>Default value is 500.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>cdp_event_threshold</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "cdp_event_threshold", 500)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>cdp_event_latency_log</varname>(integer)</title>
+      <para>This time log level at which we should report slow CDP responses. 0 is ERROR, 1 is
+      WARN, 2 is INFO and 3 is DEBUG. This is only relevant is cdp_event_latency is enabled (set to
+      0)</para>
+      <para>
+        <emphasis>Default value is 0.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>cdp_event_latency_log</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "cdp_event_latency_log", 1)
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>origin_host</varname>(string)</title>
+      <para>Origin host to be used in Diameter messages to charging-server.</para>
+      <para>
+        <emphasis>Default value is "scscf.ims.smilecoms.com".</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>origin_host</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "origin_host", "scscf.kamailio-ims.org")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>origin_realm</varname>(string)</title>
+      <para>Origin Realm to be used in Diameter messages to charging-server.</para>
+      <para>
+        <emphasis>Default value is "ims.smilecome.com".</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>origin_realm</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "origin_realm", "kamailio-ims.org")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>destination_host</varname>(string)</title>
+      <para>Destination host to be used in Diameter messages to charging-server.</para>
+      <para>
+        <emphasis>Default value is 5s.</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>destination_host</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "destination_host", "ocs.kamailio-ims.org")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>destination_realm</varname>(string)</title>
+      <para>Destination realm to be used in Diameter messages to charging-server.</para>
+      <para>
+        <emphasis>Default value is "ims.smilecoms.com".</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>destination_realm</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "destination_realm", "kamailio-ims.org")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>service_context_id_root</varname>(string)</title>
+      <para>This defines a root-element of the Service-Context-Id AVP used in the
+      diameter-message</para>
+      <para>The Service-Context-Id AVP is of type UTF8String (AVP Code 461) and contains a unique
+      identifier of the Diameter credit-control service specific document that applies to the
+      request (as defined in section RFC 4006 4.1.2). This is an identifier allocated by the
+      service provider, by the service element manufacturer, or by a standardization body, and MUST
+      uniquely identify a given Diameter credit-control service specific document. The format of
+      the Service-Context-Id is:</para>
+      <programlisting format="linespecific">
+"service-context" "@" "domain" service-context = Token
+      </programlisting>
+      <para>The Token is an arbitrary string of characters and digits.</para>
+      <para>'domain' represents the entity that allocated the Service-Context-Id. It can be
+      ietf.org, 3gpp.org, etc., if the identifier is allocated by a standardization body, or it can
+      be the FQDN of the service provider (e.g., provider.example.com) or of the vendor (e.g.,
+      vendor.example.com) if the identifier is allocated by a private entity.</para>
+      <para>Service-specific documents that are for private use only (i.e., to one provider's own
+      use, where no interoperability is deemed useful) may define private identifiers without need
+      of coordination. However, when interoperability is wanted, coordination of the identifiers
+      via, for example, publication of an informational RFC is RECOMMENDED in order to make
+      Service-Context-Id globally available.</para>
+      <para>
+        <emphasis>Default value is "32260 at 3gpp.org".</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>service_context_id_root</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "service_context_id_root", "calls at kamailio-ims.org")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>service_context_id_ext</varname>(string)</title>
+      <para>This defines the extension of the Service-Context-Id AVP used in the
+      diameter-message.</para>
+      <para>
+        <emphasis>Default value is "ext".</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>service_context_id_ext</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "service_context_id_ext", "ext2")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>service_context_id_mnc</varname>(string)</title>
+      <para>This defines Mobile-Network-Code (MNC) of the Service-Context-Id AVP used in the
+      diameter-message.</para>
+      <para>
+        <emphasis>Default value is "01".</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>service_context_id_mnc</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "service_context_id_mnc", "42")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>service_context_id_mcc</varname>(string)</title>
+      <para>This defines Mobile-Country-Code (MCC) of the Service-Context-Id AVP used in the
+      diameter-message.</para>
+      <para>see https://en.wikipedia.org/wiki/Mobile_country_code_(MCC) for details.</para>
+      <para>
+        <emphasis>Default value is "001".</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>service_context_id_mcc</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "service_context_id_mcc", "262")
+...
+        </programlisting>
+      </example>
+    </section>
+    <section>
+      <title>
+      <varname>service_context_id_release</varname>(string)</title>
+      <para>This defines Release of the Service-Context-Id AVP used in the diameter-message.</para>
+      <para>
+        <emphasis>Default value is "8" (Release 8).</emphasis>
+      </para>
+      <example>
+        <title>
+        <varname>service_context_id_release</varname>parameter usage</title>
+        <programlisting format="linespecific">
+...
+modparam("ims_charging", "service_context_id_release", "262")
+...
+        </programlisting>
+      </example>
+    </section>
+  </section>
+  <section>
+    <title>Functions</title>
+    <section>
+      <title>
+        <function moreinfo="none">Ro_CCR(route_name, direction, charge_type, unit_type,
+        reservation_units)</function>
+      </title>
+      <para>Perform a CCR on Diameter Ro interface for Charging</para>
+      <para>Meaning of the parameters is as follows:</para>
+      <itemizedlist>
+        <listitem>
+          <para>
+          <emphasis>route_name</emphasis>route to be executed upon reception of charging
+          requests</para>
+        </listitem>
+        <listitem>
+          <para>
+          <emphasis>direction</emphasis>"orig"inating or "term"inating</para>
+        </listitem>
+        <listitem>
+          <para>
+          <emphasis>charge_type</emphasis>"IEC" = Immediate Event Charging, "ECUR" - Event Charging
+          with Unit Reservation or "SCUR" - Session Charging with Unit Reservation.</para>
+          <emphasis>(Note: At the moment only SCUR is supported)</emphasis>
+        </listitem>
+        <listitem>
+          <para>
+          <emphasis>unit_type</emphasis>Types of the unit to be requested</para>
+          <emphasis>(unused at the moment)</emphasis>
+        </listitem>
+        <listitem>
+          <para>
+          <emphasis>reservation_units</emphasis>how many units (at the moment seconds) should be
+          reservated at the moment.</para>
+        </listitem>
+      </itemizedlist>
+      <para>This function can be used from REQUEST_ROUTE.</para>
+      <para>This method is executed asynchronously. See example on how to retrieve return
+      value.</para>
+      <example>
+        <title>Ro_CCR</title>
+        <programlisting format="linespecific">
+...
+  xlog("L_DBG","Sending initial CCR Request for call\n");
+  Ro_CCR("CHARGING_CCR_REPLY", "orig", "SCUR", "", "30");
+}
+
+route[CHARGING_CCR_REPLY] 
+  xlog("L_DBG","cca_return code is $avp(s:cca_return_code)\n");
+  switch ($avp(s:cca_return_code)) {
+    case 1: #success
+        xlog("L_DBG", "CCR success - will route message\n");
+        route(Finalize_Orig);
+        break;
+    case -1: #failure
+        xlog("L_ERR", "CCR failure - error response sent from module\n");
+        sl_send_reply("402","Payment required");
+        break;
+    case -2: #error
+        xlog("L_ERR", "CCR error - error response sent from module\n");
+        sl_send_reply("500", "Charging Error");
+        break;
+    default:
+        xlog("L_ERR", "Unknown return code from CCR: [$avp(s:cca_return_code)] \n");
+        break;
+  }
+  exit;
+  }
+...
+        </programlisting>
+      </example>
+    </section>
+  </section>
+  <section>
+    <title>Statistics</title>
+    <section>
+      <title>Initial CCRs (initial_ccrs)</title>
+      <para>The number of initial CCRs, i.e., the CCRs that were sent for the initial INVITEs.</para>
+    </section>
+    <section>
+      <title>Interim CCRs (interim_ccrs)</title>
+      <para>The number of CCRs sent within established sessions.</para>
+    </section>
+    <section>
+      <title>Final CCRs (final_ccrs)</title>
+      <para>The number of CCRs sent to terminate a session.</para>
+    </section>
+    <section>
+      <title>Sucessful initial CCRs (successful_initial_ccrs)</title>
+      <para>Initial CCRs that ended with DIAMETER_SUCCESS response code.</para>
+    </section>
+    <section>
+      <title>Sucessful interim CCRs (successful_interim_ccrs)</title>
+      <para>Interim CCRs that ended with DIAMETER_SUCCESS response code.</para>
+    </section>
+    <section>
+      <title>Sucessful final CCRs (successful_final_ccrs)</title>
+      <para>Final CCRs that ended with DIAMETER_SUCCESS response code.</para>
+    </section>
+    <section>
+      <title>Failed initial CCRs (failed_initial_ccrs)</title>
+      <para>Initial CCRs that ended with no DIAMETER_SUCCESS response or with some other error during processing.</para>
+    </section>
+    <section>
+      <title>Failed interim CCRs (failed_interim_ccrs)</title>
+      <para>Interim CCRs that ended with no DIAMETER_SUCCESS response or with some other error during processing.</para>
+    </section>
+    <section>
+      <title>Failed final CCRs (failed_final_ccrs)</title>
+      <para>Final CCRs that ended with no DIAMETER_SUCCESS response or with some other error during processing.</para>
+    </section>
+    <section>
+      <title>CCRs average response time (ccr_avg_response_time)</title>
+      <para>Average CCA arrival time in milliseconds.</para>
+    </section>
+    <section>
+      <title>CCRs responses time (ccr_responses_time)</title>
+      <para>Total CCA arrival time in milliseconds.</para>
+    </section>
+    <section>
+      <title>CCRs requests, which ended with a timeout (ccr_timeouts)</title>
+      <para>Number of CCR-Requests, which ran into an timeout.</para>
+    </section>
+    <section>
+      <title>Billed seconds (billed_secs)</title>
+      <para>Number of seconds billed in total.</para>
+    </section>
+    <section>
+      <title>Killed calls (killed_calls)</title>
+      <para>Number of calls that were killed due to lack of credit.</para>
+    </section>
+
+  </section>
+</chapter>
+
diff --git a/modules/ims_charging/ims_ro.c b/modules/ims_charging/ims_ro.c
new file mode 100644
index 0000000..72a6fe5
--- /dev/null
+++ b/modules/ims_charging/ims_ro.c
@@ -0,0 +1,1209 @@
+#include "mod.h"
+
+#include "../../parser/msg_parser.h"
+#include "../../parser/parse_uri.h"
+#include "../../sr_module.h"
+#include "../../socket_info.h"
+#include "../../timer.h"
+#include "../../locking.h"
+#include "../../modules/tm/tm_load.h"
+
+#include "../../modules/dialog_ng/dlg_hash.h"
+#include "../../modules/dialog_ng/dlg_load.h"
+
+
+#include "../cdp/cdp_load.h"
+#include "../../mod_fix.h"
+
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
+
+#include "../../lib/ims/ims_getters.h"
+
+#include "diameter_ro.h"
+#include "ims_ro.h"
+#include "Ro_data.h"
+#include "dialog.h"
+
+#include "ccr.h"
+#include "config.h"
+#include "ro_session_hash.h"
+#include "stats.h"
+
+extern struct tm_binds tmb;
+extern struct cdp_binds cdpb;
+extern client_ro_cfg cfg;
+extern struct dlg_binds dlgb;
+extern cdp_avp_bind_t *cdp_avp;
+
+struct session_setup_data {
+	struct ro_session *ro_session;
+
+	cfg_action_t* action;
+	unsigned int tindex;
+	unsigned int tlabel;
+};
+
+struct dlg_binds* dlgb_p;
+extern struct tm_binds tmb;
+
+int interim_request_credits;
+
+static int create_cca_return_code(int result);
+static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs);
+static void resume_on_interim_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs);
+static void resume_on_termination_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs);
+static int get_mac_avp_value(struct sip_msg *msg, str *value);
+
+void credit_control_session_callback(int event, void* session) {
+	switch (event) {
+		case AUTH_EV_SESSION_DROP:
+			LM_DBG("Received notification of CC App session drop - we must free the generic data\n");
+			break;
+		default:
+			LM_DBG("Received unhandled event [%d] in credit control session callback from CDP\n", event);
+	}
+}
+
+int get_direction_as_int(str* direction);
+
+/**
+ * Retrieves the SIP request that generated a diameter transaction
+ * @param hash - the tm hash value for this request
+ * @param label - the tm label value for this request
+ * @returns the SIP request
+ */
+struct sip_msg * trans_get_request_from_current_reply() {
+    struct cell *t;
+    t = tmb.t_gett();
+    if (!t || t == (void*) - 1) {
+        LM_ERR("trans_get_request_from_current_reply: Reply without transaction\n");
+        return 0;
+    }
+    if (t) return t->uas.request;
+    else return 0;
+}
+
+/**
+ * Create and add an AVP to a Diameter message.
+ * @param m - Diameter message to add to
+ * @param d - the payload data
+ * @param len - length of the payload data
+ * @param avp_code - the code of the AVP
+ * @param flags - flags for the AVP
+ * @param vendorid - the value of the vendor id or 0 if none
+ * @param data_do - what to do with the data when done
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns 1 on success or 0 on failure
+ */
+static inline int Ro_add_avp(AAAMessage *m, char *d, int len, int avp_code, int flags, int vendorid, int data_do, const char *func) {
+    AAA_AVP *avp;
+    if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
+    avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
+    if (!avp) {
+        LM_ERR("%s: Failed creating avp\n", func);
+        return 0;
+    }
+    if (cdpb.AAAAddAVPToMessage(m, avp, m->avpList.tail) != AAA_ERR_SUCCESS) {
+        LM_ERR("%s: Failed adding avp to message\n", func);
+       cdpb.AAAFreeAVP(&avp);
+        return 0;
+    }
+    return 1;
+}
+
+/**
+ * Create and add an AVP to a list of AVPs.
+ * @param list - the AVP list to add to
+ * @param d - the payload data
+ * @param len - length of the payload data
+ * @param avp_code - the code of the AVP
+ * @param flags - flags for the AVP
+ * @param vendorid - the value of the vendor id or 0 if none
+ * @param data_do - what to do with the data when done
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns 1 on success or 0 on failure
+ */
+static inline int Ro_add_avp_list(AAA_AVP_LIST *list, char *d, int len, int avp_code,
+        int flags, int vendorid, int data_do, const char *func) {
+    AAA_AVP *avp;
+    if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
+    avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
+    if (!avp) {
+        LM_ERR("%s: Failed creating avp\n", func);
+        return 0;
+    }
+    if (list->tail) {
+        avp->prev = list->tail;
+        avp->next = 0;
+        list->tail->next = avp;
+        list->tail = avp;
+    } else {
+        list->head = avp;
+        list->tail = avp;
+        avp->next = 0;
+        avp->prev = 0;
+    }
+
+    return 1;
+}
+
+/**
+ * Creates and adds a Destination-Realm AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int ro_add_destination_realm_avp(AAAMessage *msg, str data) {
+    return
+    Ro_add_avp(msg, data.s, data.len,
+            AVP_Destination_Realm,
+            AAA_AVP_FLAG_MANDATORY,
+            0,
+            AVP_DUPLICATE_DATA,
+            __FUNCTION__);
+}
+
+inline int Ro_add_cc_request(AAAMessage *msg, unsigned int cc_request_type, unsigned int cc_request_number) {
+    char x[4];
+    set_4bytes(x, cc_request_type);
+    int success = Ro_add_avp(msg, x, 4, AVP_CC_Request_Type, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    char y[4];
+    set_4bytes(y, cc_request_number);
+
+    return success && Ro_add_avp(msg, y, 4, AVP_CC_Request_Number, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+}
+
+inline int Ro_add_event_timestamp(AAAMessage *msg, time_t now) {
+    char x[4];
+    str s = {x, 4};
+    uint32_t ntime = htonl(now + EPOCH_UNIX_TO_EPOCH_NTP);
+    memcpy(x, &ntime, sizeof (uint32_t));
+
+    return Ro_add_avp(msg, s.s, s.len, AVP_Event_Timestamp, AAA_AVP_FLAG_NONE, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+}
+
+inline int Ro_add_user_equipment_info(AAAMessage *msg, unsigned int type, str value) {
+    AAA_AVP_LIST list;
+    str group;
+    char x[4];
+
+    list.head = 0;
+    list.tail = 0;
+
+    set_4bytes(x, type);
+    Ro_add_avp_list(&list, x, 4, AVP_User_Equipment_Info_Type, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    Ro_add_avp_list(&list, value.s, value.len, AVP_User_Equipment_Info_Value, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    group = cdpb.AAAGroupAVPS(list);
+
+    cdpb.AAAFreeAVPList(&list);
+
+    return Ro_add_avp(msg, group.s, group.len, AVP_User_Equipment_Info, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+}
+
+inline int Ro_add_termination_cause(AAAMessage *msg, unsigned int term_code) {
+    char x[4];
+    str s = {x, 4};
+    uint32_t code = htonl(term_code);
+    memcpy(x, &code, sizeof (uint32_t));
+
+    return Ro_add_avp(msg, s.s, s.len, AVP_Termination_Cause, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+}
+
+/* called only when building stop record AVPS */
+inline int Ro_add_multiple_service_credit_Control_stop(AAAMessage *msg, int used_unit) {
+    AAA_AVP_LIST used_list, mscc_list;
+    str used_group;
+    char x[4];
+
+    unsigned int service_id = 1000; //VOICE TODO FIX as config item
+
+    used_list.head = 0;
+    used_list.tail = 0;
+    mscc_list.head = 0;
+    mscc_list.tail = 0;
+
+    /* if we must Used-Service-Unit */
+    if (used_unit >= 0) {
+        set_4bytes(x, used_unit);
+        Ro_add_avp_list(&used_list, x, 4, AVP_CC_Time, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+        used_group = cdpb.AAAGroupAVPS(used_list);
+        cdpb.AAAFreeAVPList(&used_list);
+        Ro_add_avp_list(&mscc_list, used_group.s, used_group.len, AVP_Used_Service_Unit, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+    }
+
+    set_4bytes(x, service_id);
+    Ro_add_avp_list(&mscc_list, x, 4, AVP_Service_Identifier, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    used_group = cdpb.AAAGroupAVPS(mscc_list);
+    cdpb.AAAFreeAVPList(&mscc_list);
+
+    return Ro_add_avp(msg, used_group.s, used_group.len, AVP_Multiple_Services_Credit_Control, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+}
+
+inline int Ro_add_multiple_service_credit_Control(AAAMessage *msg, unsigned int requested_unit, int used_unit) {
+    AAA_AVP_LIST list, used_list, mscc_list;
+    str group, used_group;
+    unsigned int service_id = 1000; //VOICE TODO FIX as config item - should be a MAP that can be identified based on SDP params
+    char x[4];
+
+    list.head = 0;
+    list.tail = 0;
+    used_list.head = 0;
+    used_list.tail = 0;
+    mscc_list.head = 0;
+    mscc_list.tail = 0;
+
+    set_4bytes(x, requested_unit);
+    Ro_add_avp_list(&list, x, 4, AVP_CC_Time, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+    group = cdpb.AAAGroupAVPS(list);
+    cdpb.AAAFreeAVPList(&list);
+
+    Ro_add_avp_list(&mscc_list, group.s, group.len, AVP_Requested_Service_Unit, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+
+    set_4bytes(x, service_id);
+    Ro_add_avp_list(&mscc_list, x, 4, AVP_Service_Identifier, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    /* if we must Used-Service-Unit */
+    if (used_unit >= 0) {
+        set_4bytes(x, used_unit);
+        Ro_add_avp_list(&used_list, x, 4, AVP_CC_Time, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+        used_group = cdpb.AAAGroupAVPS(used_list);
+        cdpb.AAAFreeAVPList(&used_list);
+        Ro_add_avp_list(&mscc_list, used_group.s, used_group.len, AVP_Used_Service_Unit, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+    }
+
+    group = cdpb.AAAGroupAVPS(mscc_list);
+    cdpb.AAAFreeAVPList(&mscc_list);
+
+    return Ro_add_avp(msg, group.s, group.len, AVP_Multiple_Services_Credit_Control, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+}
+
+inline int Ro_add_subscription_id(AAAMessage *msg, unsigned int type, str *subscription_id)//, struct sip_msg* sip_msg)
+{
+    AAA_AVP_LIST list;
+    str group;
+    char x[4];
+
+    list.head = 0;
+    list.tail = 0;
+
+    set_4bytes(x, type);
+    Ro_add_avp_list(&list, x, 4, AVP_Subscription_Id_Type, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    Ro_add_avp_list(&list, subscription_id->s, subscription_id->len, AVP_Subscription_Id_Data, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    group = cdpb.AAAGroupAVPS(list);
+
+    cdpb.AAAFreeAVPList(&list);
+
+    return Ro_add_avp(msg, group.s, group.len, AVP_Subscription_Id, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+}
+
+/**
+ * Creates and adds a Vendor-Specifig-Application-ID AVP.
+ * @param msg - the Diameter message to add to.
+ * @param vendor_id - the value of the vendor_id,
+ * @param auth_id - the authorization application id
+ * @param acct_id - the accounting application id
+ * @returns 1 on success or 0 on error
+ */
+inline int Ro_add_vendor_specific_appid(AAAMessage *msg, unsigned int vendor_id, unsigned int auth_id, unsigned int acct_id) {
+    AAA_AVP_LIST list;
+    str group;
+    char x[4];
+
+    list.head = 0;
+    list.tail = 0;
+
+    set_4bytes(x, vendor_id);
+    Ro_add_avp_list(&list, x, 4, AVP_Vendor_Id, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+
+    if (auth_id) {
+        set_4bytes(x, auth_id);
+        Ro_add_avp_list(&list, x, 4, AVP_Auth_Application_Id, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+    }
+    if (acct_id) {
+        set_4bytes(x, acct_id);
+        Ro_add_avp_list(&list, x, 4, AVP_Acct_Application_Id, AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__);
+    }
+
+    group = cdpb.AAAGroupAVPS(list);
+
+    cdpb.AAAFreeAVPList(&list);
+
+    return Ro_add_avp(msg, group.s, group.len, AVP_Vendor_Specific_Application_Id, AAA_AVP_FLAG_MANDATORY, 0, AVP_FREE_DATA, __FUNCTION__);
+}
+
+int get_sip_header_info(struct sip_msg * req,
+        struct sip_msg * reply,
+        int32_t * acc_record_type,
+        str * sip_method,
+        str * event, uint32_t * expires,
+        str * callid, str * asserted_id_uri, str * to_uri) {
+
+    sip_method->s = req->first_line.u.request.method.s;
+    sip_method->len = req->first_line.u.request.method.len;
+
+    if (strncmp(sip_method->s, "INVITE", 6) == 0)
+        *acc_record_type = AAA_ACCT_START;
+    else if (strncmp(sip_method->s, "BYE", 3) == 0)
+        *acc_record_type = AAA_ACCT_STOP;
+    else
+        *acc_record_type = AAA_ACCT_EVENT;
+
+    *event = cscf_get_event(req);
+    *expires = cscf_get_expires_hdr(req, 0);
+    *callid = cscf_get_call_id(req, NULL);
+
+    if ((*asserted_id_uri = cscf_get_asserted_identity(req)).len == 0) {
+    	LM_DBG("No P-Asserted-Identity hdr found. Using From hdr");
+
+    	if (!cscf_get_from_uri(req, asserted_id_uri)) {
+    		LM_ERR("Error assigning P-Asserted-Identity using From hdr");
+    		goto error;
+    	}
+    }
+
+    *to_uri	= req->first_line.u.request.uri;
+
+    LM_DBG("retrieved sip info : sip_method %.*s acc_record_type %i, event %.*s expires %u "
+            "call_id %.*s from_uri %.*s to_uri %.*s\n",
+            sip_method->len, sip_method->s, *acc_record_type, event->len, event->s, *expires,
+            callid->len, callid->s, asserted_id_uri->len, asserted_id_uri->s, to_uri->len, to_uri->s);
+
+    return 1;
+error:
+    return 0;
+}
+
+int get_ims_charging_info(struct sip_msg *req, struct sip_msg * reply, str * icid, str * orig_ioi, str * term_ioi) {
+
+    LM_DBG("get ims charging info\n");
+    if (req)
+        cscf_get_p_charging_vector(req, icid, orig_ioi, term_ioi);
+    if (reply)
+        cscf_get_p_charging_vector(reply, icid, orig_ioi, term_ioi);
+
+    return 1;
+}
+
+int get_timestamps(struct sip_msg * req, struct sip_msg * reply, time_t * req_timestamp, time_t * reply_timestamp) {
+
+    if (reply)
+        *reply_timestamp = time(NULL);
+    if (req)
+        *req_timestamp = time(NULL);
+    return 1;
+}
+
+/*
+ * creates the ro session for a session establishment
+ *
+ */
+
+Ro_CCR_t * dlg_create_ro_session(struct sip_msg * req, struct sip_msg * reply, AAASession ** authp, int dir) {
+
+    Ro_CCR_t * ro_ccr_data = 0;
+    AAASession * auth = NULL;
+    str user_name/* ={0,0}*/, sip_method = {0, 0}, event = {0, 0};
+    uint32_t expires = 0;
+    str callid = {0, 0}, to_uri = {0, 0}, from_uri = {0, 0},
+    icid = {0, 0}, orig_ioi = {0, 0}, term_ioi = {0, 0};
+
+    event_type_t * event_type = 0;
+    ims_information_t * ims_info = 0;
+    time_stamps_t * time_stamps = 0;
+    time_t req_timestamp = 0, reply_timestamp = 0;
+    int32_t acc_record_type;
+    subscription_id_t subscr;
+
+    *authp = 0;
+
+    if (!get_sip_header_info(req, reply, &acc_record_type, &sip_method, &event, &expires, &callid, &from_uri, &to_uri))
+        goto error;
+    if (dir == RO_ORIG_DIRECTION) {
+        user_name.s = from_uri.s;
+        user_name.len = from_uri.len;
+    } else if (dir == RO_TERM_DIRECTION){
+        user_name.s = to_uri.s;
+        user_name.len = to_uri.len;
+    } else {
+    	LM_CRIT("don't know what to do in unknown mode - should we even get here\n");
+    	goto error;
+    }
+
+    /*	if(!get_ims_charging_info(req, reply, &icid, &orig_ioi, &term_ioi))
+                    goto error;
+     */
+    LM_DBG("retrieved ims charging info icid:[%.*s] orig_ioi:[%.*s] term_ioi:[%.*s]\n",
+    		icid.len, icid.s, orig_ioi.len, orig_ioi.s, term_ioi.len, term_ioi.s);
+
+    if (!get_timestamps(req, reply, &req_timestamp, &reply_timestamp))
+        goto error;
+
+    if (!(event_type = new_event_type(&sip_method, &event, &expires)))
+        goto error;
+
+    if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, &reply_timestamp, NULL)))
+        goto error;
+
+    if (!(ims_info = new_ims_information(event_type, time_stamps, &callid, &callid, &from_uri, &to_uri, &icid, &orig_ioi, &term_ioi, dir)))
+        goto error;
+    event_type = 0;
+    time_stamps = 0;
+
+    subscr.type = Subscription_Type_IMPU;
+    subscr.id.s = from_uri.s;
+    subscr.id.len = from_uri.len;
+
+    ro_ccr_data = new_Ro_CCR(acc_record_type, &user_name, ims_info, &subscr);
+    if (!ro_ccr_data) {
+        LM_ERR("dlg_create_ro_session: no memory left for generic\n");
+        goto out_of_memory;
+    }
+    ims_info = 0;
+
+    if (strncmp(req->first_line.u.request.method.s, "INVITE", 6) == 0) {
+    	//create CDP CC Accounting session
+    	auth = cdpb.AAACreateCCAccSession(credit_control_session_callback, 1/*is_session*/, NULL ); //must unlock session hash when done
+    	LM_DBG("Created Ro Session with id Session ID [%.*s]\n", auth->id.len, auth->id.s);
+        //save_session = auth->id;
+
+    }
+    /*if (strncmp(req->first_line.u.request.method.s, "BYE", 3) == 0) {
+        auth = cdp_avp->cdp->AAAGetAuthSession(save_session);
+    }*/
+
+
+    if (!auth) {
+        LM_ERR("unable to create the Ro Session\n");
+        goto error;
+    }
+
+    *authp = auth;
+    return ro_ccr_data;
+
+out_of_memory:
+error :
+    time_stamps_free(time_stamps);
+    event_type_free(event_type);
+    ims_information_free(ims_info);
+    Ro_free_CCR(ro_ccr_data);
+
+    return NULL;
+}
+
+int sip_create_ro_ccr_data(struct sip_msg * msg, int dir, Ro_CCR_t ** ro_ccr_data, AAASession ** auth) {
+
+    if (msg->first_line.type == SIP_REQUEST) {
+        /*end of session*/
+        if (strncmp(msg->first_line.u.request.method.s, "INVITE", 6) == 0) {
+            if (!(*ro_ccr_data = dlg_create_ro_session(msg, NULL, auth, dir)))
+                goto error;
+        }
+    } else {
+        goto error; //We only support Request (INVITE) messages on this interface
+    }
+
+    return 1;
+error:
+    return 0;
+}
+
+void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned int reserve) {
+    AAASession * auth = 0;
+
+    AAAMessage * ccr = 0;
+    Ro_CCR_t *ro_ccr_data = 0;
+    ims_information_t *ims_info = 0;
+    int32_t acc_record_type;
+    subscription_id_t subscr;
+    time_stamps_t *time_stamps;
+	struct interim_ccr *i_req = shm_malloc(sizeof(struct interim_ccr));
+
+    event_type_t *event_type;
+    int node_role = 0;
+
+	memset(i_req, 0, sizeof(sizeof(struct interim_ccr)));
+    i_req->ro_session	= ro_session;
+
+    str sip_method = str_init("dummy");
+    str sip_event = str_init("dummy");
+
+    time_t req_timestamp;
+
+    event_type = new_event_type(&sip_method, &sip_event, 0);
+
+    LM_DBG("Sending interim CCR request for (usage:new) [%i:%i] seconds for user [%.*s] using session id [%.*s]",
+    						used,
+    						reserve,
+    						ro_session->from_uri.len, ro_session->from_uri.s,
+    						ro_session->ro_session_id.len, ro_session->ro_session_id.s);
+
+    req_timestamp = time(0);
+
+    if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, NULL, NULL)))
+        goto error;
+
+    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->from_uri, &ro_session->to_uri, 0, 0, 0, node_role)))
+        goto error;
+
+    LM_DBG("Created IMS information\n");
+
+    event_type = 0;
+
+    subscr.type = Subscription_Type_IMPU;
+    //TODO: need to check which direction. for ORIG we use from_uri. for TERM we use to_uri
+    subscr.id.s = ro_session->from_uri.s;
+    subscr.id.len = ro_session->from_uri.len;
+
+    acc_record_type = AAA_ACCT_INTERIM;
+
+    ro_ccr_data = new_Ro_CCR(acc_record_type, &ro_session->from_uri, ims_info, &subscr);
+    if (!ro_ccr_data) {
+        LM_ERR("dlg_create_ro_session: no memory left for generic\n");
+        goto error;
+    }
+    ims_info = NULL;
+
+    auth = cdpb.AAAGetCCAccSession(ro_session->ro_session_id);
+    if (!auth) {
+        LM_DBG("Diameter Auth Session has timed out.... creating a new one.\n");
+        /* lets try and recreate this session */
+        //TODO: make a CC App session auth = cdpb.AAASession(ro_session->auth_appid, ro_session->auth_session_type, ro_session->ro_session_id); //TODO: would like this session to last longer (see session timeout in cdp
+        //BUG("Oh shit, session timed out and I don't know how to create a new one.");
+
+        auth = cdpb.AAAMakeSession(ro_session->auth_appid, ro_session->auth_session_type, ro_session->ro_session_id); //TODO: would like this session to last longer (see session timeout in cdp
+        if (!auth)
+            goto error;
+    }
+
+    //don't send INTERIM record if session is not in OPEN state (it could already be waiting for a previous response, etc)
+    if (auth->u.cc_acc.state != ACC_CC_ST_OPEN) {
+	    LM_WARN("ignoring interim update on CC session not in correct state, currently in state [%d]\n", auth->u.cc_acc.state);
+	    goto error;
+    }
+
+    if (!(ccr = Ro_new_ccr(auth, ro_ccr_data)))
+        goto error;
+
+    if (!Ro_add_vendor_specific_appid(ccr, IMS_vendor_id_3GPP, IMS_Ro, 0/*acct id*/)) {
+        LM_ERR("Problem adding Vendor specific ID\n");
+    }
+    ro_session->hop_by_hop += 1;
+    if (!Ro_add_cc_request(ccr, RO_CC_INTERIM, ro_session->hop_by_hop)) {
+        LM_ERR("Problem adding CC-Request data\n");
+    }
+    if (!Ro_add_event_timestamp(ccr, time(NULL))) {
+        LM_ERR("Problem adding Event-Timestamp data\n");
+    }
+
+    if (!Ro_add_user_equipment_info(ccr, AVP_EPC_User_Equipment_Info_Type_MAC, ro_session->avp_value.mac)) {
+        LM_ERR("Problem adding User-Equipment data\n");
+    }
+
+    if (!Ro_add_subscription_id(ccr, AVP_EPC_Subscription_Id_Type_End_User_SIP_URI, &(subscr.id))) {
+        LM_ERR("Problem adding Subscription ID data\n");
+    }
+
+    if (!Ro_add_multiple_service_credit_Control(ccr, interim_request_credits/*INTERIM_CREDIT_REQ_AMOUNT*/, used)) {
+        LM_ERR("Problem adding Multiple Service Credit Control data\n");
+    }
+
+    LM_DBG("Sending CCR Diameter message.\n");
+
+    cdpb.AAASessionsUnlock(auth->hash);
+
+    //AAAMessage *cca = cdpb.AAASendRecvMessageToPeer(ccr, &cfg.destination_host);
+    cdpb.AAASendMessageToPeer(ccr, &cfg.destination_host, resume_on_interim_ccr, (void *) i_req);
+
+//    cdpb.AAASessionsUnlock(auth->hash);
+
+    Ro_free_CCR(ro_ccr_data);
+
+    update_stat(interim_ccrs, 1);
+    return;
+error:
+	LM_ERR("error trying to reserve interim credit\n");
+
+	if (ro_ccr_data)
+		Ro_free_CCR(ro_ccr_data);
+
+	if (ccr)
+		cdpb.AAAFreeMessage(&ccr);
+
+    if (auth) {
+    	cdpb.AAASessionsUnlock(auth->hash);
+    	cdpb.AAADropCCAccSession(auth);
+    }
+
+    shm_free(i_req);
+    //
+    // since callback function will be never called because of the error, we need to release the lock on the session
+    // to it can be reused later.
+    //
+    struct ro_session_entry *ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
+    unref_ro_session_unsafe(ro_session, 1, ro_session_entry);//unref from the initial timer that fired this event.
+    ro_session_unlock(ro_session_table, ro_session_entry);
+
+    return;
+}
+
+static void resume_on_interim_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs) {
+	struct interim_ccr *i_req	= (struct interim_ccr *) param;
+	Ro_CCA_t * ro_cca_data = NULL;
+
+    if (is_timeout) {
+        update_stat(ccr_timeouts, 1);
+        LM_ERR("Transaction timeout - did not get CCA\n");
+        goto error;
+    }
+
+    update_stat(ccr_responses_time, elapsed_msecs);
+
+	if (!i_req) {
+		LM_ERR("This is so wrong: ro session is NULL\n");
+		goto error;
+	}
+
+	if (cca == NULL) {
+		LM_ERR("Error reserving credit for CCA.\n");
+		goto error;
+	}
+
+	ro_cca_data = Ro_parse_CCA_avps(cca);
+
+	if (ro_cca_data == NULL) {
+		LM_ERR("Could not parse CCA message response.\n");
+		goto error;
+	}
+
+	if (ro_cca_data->resultcode != 2001) {
+		LM_ERR("Got bad CCA result code [%d] - reservation failed", ro_cca_data->resultcode);
+		goto error;
+	} else {
+		LM_DBG("Valid CCA response with time chunk of [%i] and validity [%i].\n", ro_cca_data->mscc->granted_service_unit->cc_time, ro_cca_data->mscc->validity_time);
+	}
+
+	i_req->new_credit = ro_cca_data->mscc->granted_service_unit->cc_time;
+	i_req->credit_valid_for = ro_cca_data->mscc->validity_time;
+	i_req->is_final_allocation	= 0;
+
+	if (ro_cca_data->mscc->final_unit_action && (ro_cca_data->mscc->final_unit_action->action == 0))
+		i_req->is_final_allocation = 1;
+
+	Ro_free_CCA(ro_cca_data);
+	cdpb.AAAFreeMessage(&cca);
+
+	update_stat(successful_interim_ccrs, 1);
+	goto success;
+
+error:
+	if (ro_cca_data)
+		Ro_free_CCA(ro_cca_data);
+
+//	if (ro_cca_data)
+	cdpb.AAAFreeMessage(&cca);
+
+	if (i_req) {
+		i_req->credit_valid_for = 0;
+		i_req->new_credit = 0;
+	}
+
+success:
+	resume_ro_session_ontimeout(i_req);
+}
+
+void send_ccr_stop(struct ro_session *ro_session) {
+    AAASession * auth = 0;
+    Ro_CCR_t * ro_ccr_data = 0;
+    AAAMessage * ccr = 0;
+    ims_information_t *ims_info = 0;
+    int32_t acc_record_type;
+    subscription_id_t subscr;
+    time_stamps_t *time_stamps;
+    unsigned int used = 0;
+
+    if (ro_session->event_type != pending) {
+        used = time(0) - ro_session->last_event_timestamp;
+    }
+
+    update_stat(billed_secs, used);
+
+    event_type_t *event_type;
+    int node_role = 0;
+
+    str sip_method = str_init("dummy");
+    str sip_event = str_init("dummy");
+
+    time_t req_timestamp;
+
+    event_type = new_event_type(&sip_method, &sip_event, 0);
+
+    LM_DBG("Sending CCR STOP request for for user:[%.*s] using session id:[%.*s] and units:[%d]\n",
+    		ro_session->from_uri.len, ro_session->from_uri.s, ro_session->ro_session_id.len, ro_session->ro_session_id.s, used);
+
+    req_timestamp = time(0);
+
+    if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, NULL, NULL)))
+        goto error0;
+
+    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->from_uri, &ro_session->to_uri, 0, 0, 0, node_role)))
+        goto error0;
+    
+    event_type = 0;
+
+    subscr.type = Subscription_Type_IMPU;
+    subscr.id = ro_session->from_uri;
+
+    acc_record_type = AAA_ACCT_STOP;
+
+    ro_ccr_data = new_Ro_CCR(acc_record_type, &ro_session->from_uri, ims_info, &subscr);
+    if (!ro_ccr_data) {
+        LM_ERR("dlg_create_ro_session: no memory left for generic\n");
+        goto error0;
+    }
+    ims_info = 0;
+
+    LM_DBG("Created Ro data\n");
+
+    auth = cdpb.AAAGetCCAccSession(ro_session->ro_session_id);
+
+    if (!auth) {
+        LM_DBG("Diameter Auth Session has timed out.... creating a new one.\n");
+        /* lets try and recreate this session */
+        auth = cdpb.AAAMakeSession(ro_session->auth_appid, ro_session->auth_session_type, ro_session->ro_session_id); //TODO: would like this session to last longer (see session timeout in cdp
+        if (!auth)
+            goto error1;
+    }
+
+
+    if (!(ccr = Ro_new_ccr(auth, ro_ccr_data)))
+        goto error1;
+
+    LM_DBG("Created new CCR\n");
+
+    if (!Ro_add_vendor_specific_appid(ccr, IMS_vendor_id_3GPP, IMS_Ro, 0)) {
+        LM_ERR("Problem adding Vendor specific ID\n");
+    }
+   
+    ro_session->hop_by_hop += 1;
+    if (!Ro_add_cc_request(ccr, RO_CC_STOP, ro_session->hop_by_hop)) {
+        LM_ERR("Problem adding CC-Request data\n");
+    }
+   
+    if (!Ro_add_event_timestamp(ccr, time(NULL))) {
+        LM_ERR("Problem adding Event-Timestamp data\n");
+    }
+
+    if (!Ro_add_user_equipment_info(ccr, AVP_EPC_User_Equipment_Info_Type_MAC, ro_session->avp_value.mac)) {
+        LM_ERR("Problem adding User-Equipment data\n");
+    }
+    
+    if (!Ro_add_subscription_id(ccr, AVP_EPC_Subscription_Id_Type_End_User_SIP_URI, &ro_session->from_uri)) {
+        LM_ERR("Problem adding Subscription ID data\n");
+    }
+    
+    if (!Ro_add_multiple_service_credit_Control_stop(ccr, used)) {
+        LM_ERR("Problem adding Multiple Service Credit Control data\n");
+    }
+    
+    if (!Ro_add_termination_cause(ccr, TERM_CAUSE_LOGOUT)) {
+        LM_ERR("problem add Termination cause AVP to STOP record.\n");
+    }
+
+    cdpb.AAASessionsUnlock(auth->hash);
+    cdpb.AAASendMessageToPeer(ccr, &cfg.destination_host, resume_on_termination_ccr, NULL);
+
+    Ro_free_CCR(ro_ccr_data);
+
+    update_stat(final_ccrs, 1);
+    return;
+
+error1:
+    LM_ERR("error on Ro STOP record\n");
+    Ro_free_CCR(ro_ccr_data);
+
+    if (auth) {
+    	cdpb.AAASessionsUnlock(auth->hash);
+    	cdpb.AAADropCCAccSession(auth);
+    }
+
+error0:
+    return;
+
+}
+
+static void resume_on_termination_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs) {
+    Ro_CCA_t *ro_cca_data = NULL;
+
+    if (is_timeout) {
+        update_stat(ccr_timeouts, 1);
+        LM_ERR("Transaction timeout - did not get CCA\n");
+        goto error;
+    }
+
+    update_stat(ccr_responses_time, elapsed_msecs);
+
+    if (!cca) {
+    	LM_ERR("Error in termination CCR.\n");
+        return;
+    }
+
+    ro_cca_data = Ro_parse_CCA_avps(cca);
+
+    if (ro_cca_data == NULL) {
+    	LM_DBG("Could not parse CCA message response.\n");
+    	return;
+    }
+
+    if (ro_cca_data->resultcode != 2001) {
+    	LM_ERR("Got bad CCA result code for STOP record - [%d]\n", ro_cca_data->resultcode);
+        goto error;
+    }
+    else {
+    	LM_DBG("Valid CCA response for STOP record\n");
+    }
+
+//   Ro_free_CCA(ro_cca_data);
+//   cdpb.AAAFreeMessage(&cca);
+
+    update_stat(successful_final_ccrs, 1);
+
+error:
+	Ro_free_CCA(ro_cca_data);
+    cdpb.AAAFreeMessage(&cca);
+}
+
+
+
+/**
+ * Send a CCR to the OCS based on the SIP message (INVITE ONLY)
+ * @param msg - SIP message
+ * @param direction - orig|term
+ * @param charge_type - IEC (Immediate Event Charging), ECUR (Event Charging with Unit Reservation), SCUR (Session Charging with Unit Reservation)
+ * @param unit_type - unused
+ * @param reservation_units - units to try to reserve
+ * @param reservation_units - config route to call when receiving a CCA
+ * @param tindex - transaction index
+ * @param tindex - transaction label
+ *
+ * @returns #CSCF_RETURN_TRUE if OK, #CSCF_RETURN_ERROR on error
+ */
+int Ro_Send_CCR(struct sip_msg *msg, str* direction, str* charge_type, str* unit_type, int reservation_units,
+						cfg_action_t* action, unsigned int tindex, unsigned int tlabel) {
+	str session_id = { 0, 0 },
+		asserted_id_uri	= { 0, 0 };
+	AAASession* cc_acc_session = NULL;
+    Ro_CCR_t * ro_ccr_data = 0;
+    AAAMessage * ccr = 0;
+    int dir = 0;
+    struct ro_session *new_session = 0;
+    struct session_setup_data *ssd = shm_malloc(sizeof(struct session_setup_data)); // lookup structure used to load session info from cdp callback on CCA
+
+    int cc_event_number = 0;						//According to IOT tests this should start at 0
+    int cc_event_type = RO_CC_START;
+
+    //make sure we can get the dialog! if not, we can't continue
+	struct dlg_cell* dlg = dlgb.get_dlg(msg);
+	if (!dlg) {
+		LM_DBG("Unable to find dialog and cannot do Ro charging without it\n");
+		goto error;
+	}
+
+	if ((asserted_id_uri = cscf_get_asserted_identity(msg)).len == 0) {
+		LM_DBG("No P-Asserted-Identity hdr found. Using From hdr");
+
+		asserted_id_uri	= dlg->from_uri;
+	}
+
+	dir = get_direction_as_int(direction);
+
+    str mac	= {0,0};
+    if (get_mac_avp_value(msg, &mac) != 0)
+    	LM_DBG(RO_MAC_AVP_NAME" was not set. Using default.");
+
+	//create a session object without auth and diameter session id - we will add this later.
+	new_session = build_new_ro_session(dir, 0, 0, &session_id, &dlg->callid,
+			&asserted_id_uri, &msg->first_line.u.request.uri, &mac, dlg->h_entry, dlg->h_id,
+			reservation_units, 0);
+
+	if (!new_session) {
+		LM_ERR("Couldn't create new Ro Session - this is BAD!\n");
+		goto error;
+	}
+
+	ssd->action	= action;
+	ssd->tindex	= tindex;
+	ssd->tlabel	= tlabel;
+	ssd->ro_session	= new_session;
+
+    if (!sip_create_ro_ccr_data(msg, dir, &ro_ccr_data, &cc_acc_session))
+        goto error;
+
+    if (!ro_ccr_data)
+        goto error;
+
+    if (!cc_acc_session)
+    	goto error;
+
+    if (!(ccr = Ro_new_ccr(cc_acc_session, ro_ccr_data)))
+        goto error;
+
+    if (!Ro_add_vendor_specific_appid(ccr, IMS_vendor_id_3GPP, IMS_Ro, 0)) {
+        LM_ERR("Problem adding Vendor specific ID\n");
+        goto error;
+    }
+
+    if (!Ro_add_cc_request(ccr, cc_event_type, cc_event_number)) {
+        LM_ERR("Problem adding CC-Request data\n");
+        goto error;
+    }
+
+    if (!Ro_add_event_timestamp(ccr, time(NULL))) {
+        LM_ERR("Problem adding Event-Timestamp data\n");
+        goto error;
+    }
+
+    if (!Ro_add_user_equipment_info(ccr, AVP_EPC_User_Equipment_Info_Type_MAC, mac)) {
+        LM_ERR("Problem adding User-Equipment data\n");
+        goto error;
+    }
+
+    if (!Ro_add_subscription_id(ccr, AVP_EPC_Subscription_Id_Type_End_User_SIP_URI, &asserted_id_uri)) {
+        LM_ERR("Problem adding Subscription ID data\n");
+        goto error;
+    }
+    if (!Ro_add_multiple_service_credit_Control(ccr, reservation_units, -1)) {
+        LM_ERR("Problem adding Multiple Service Credit Control data\n");
+        goto error;
+    }
+
+    /* before we send, update our session object with CC App session ID and data */
+    new_session->auth_appid = cc_acc_session->application_id;
+    new_session->auth_session_type = cc_acc_session->type;
+    new_session->ro_session_id.s = (char*) shm_malloc(cc_acc_session->id.len);
+    new_session->ro_session_id.len = cc_acc_session->id.len;
+    memcpy(new_session->ro_session_id.s, cc_acc_session->id.s, cc_acc_session->id.len);
+    
+    LM_DBG("new CC Ro Session ID: [%.*s]\n", cc_acc_session->id.len, cc_acc_session->id.s);
+
+    LM_DBG("Sending CCR Diameter message.\n");
+    cdpb.AAASessionsUnlock(cc_acc_session->hash);
+    cdpb.AAASendMessageToPeer(ccr, &cfg.destination_host, resume_on_initial_ccr, (void *) ssd);
+
+    Ro_free_CCR(ro_ccr_data);
+
+    //TODO: if the following fail, we should clean up the Ro session.......
+    if (dlgb.register_dlgcb(dlg, /* DLGCB_RESPONSE_FWDED */ DLGCB_CONFIRMED, dlg_reply, (void*)new_session ,NULL ) != 0) {
+    	LM_CRIT("cannot register callback for dialog confirmation\n");
+    	goto error;
+    }
+
+    if (dlgb.register_dlgcb(dlg, DLGCB_TERMINATED | DLGCB_FAILED | DLGCB_EXPIRED /*| DLGCB_DESTROY */
+    		, dlg_terminated, (void*)new_session, NULL ) != 0) {
+    	LM_CRIT("cannot register callback for dialog termination\n");
+    	goto error;
+    }
+
+    update_stat(initial_ccrs, 1);
+
+    return RO_RETURN_TRUE;
+
+error:
+    Ro_free_CCR(ro_ccr_data);
+    if (cc_acc_session) {
+        	cdpb.AAASessionsUnlock(cc_acc_session->hash);
+        	cdpb.AAADropSession(cc_acc_session);
+    }
+
+    if (ssd)
+    	pkg_free(ssd);
+
+    LM_DBG("Trying to reserve credit on initial INVITE failed.\n");
+    return RO_RETURN_ERROR;
+}
+
+static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs) {
+    Ro_CCA_t *ro_cca_data = NULL;
+    struct cell *t = NULL;
+    struct session_setup_data *ssd = (struct session_setup_data *) param;
+    int error_code	= RO_RETURN_ERROR;
+
+    if (is_timeout) {
+        update_stat(ccr_timeouts, 1);
+        LM_ERR("Transaction timeout - did not get CCA\n");
+        error_code =  RO_RETURN_ERROR;
+        goto error0;
+    }
+
+    update_stat(ccr_responses_time, elapsed_msecs);
+
+    if (!cca) {
+    	LM_ERR("Error reserving credit for CCA.\n");
+    	error_code	= RO_RETURN_ERROR;
+        goto error0;
+    }
+
+    if (!ssd) {
+    	LM_ERR("Session lookup data is NULL.\n");
+    	error_code	= RO_RETURN_ERROR;
+    	goto error0;
+    }
+
+    // we make sure the transaction exists
+	if (tmb.t_lookup_ident(&t, ssd->tindex, ssd->tlabel) < 0) {
+		LM_ERR("t_continue: transaction not found\n");
+		error_code	= RO_RETURN_ERROR;
+		goto error0;
+	}
+
+	// we bring the list of AVPs of the transaction to the current context
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
+
+    ro_cca_data = Ro_parse_CCA_avps(cca);
+
+    if (!ro_cca_data) {
+    	LM_ERR("Could not parse CCA message response.\n");
+    	error_code	= RO_RETURN_ERROR;
+        goto error0;
+    }
+
+    if (ro_cca_data->resultcode != 2001) {
+    	LM_ERR("Got bad CCA result code - reservation failed");
+    	error_code	= RO_RETURN_FALSE;
+        goto error1;
+    }
+
+    LM_DBG("Valid CCA response with time chunk of [%i] and validity [%i]\n",
+    			ro_cca_data->mscc->granted_service_unit->cc_time,
+    			ro_cca_data->mscc->validity_time);
+
+    ssd->ro_session->last_event_timestamp = time(0);
+    ssd->ro_session->event_type = pending;
+    ssd->ro_session->reserved_secs = ro_cca_data->mscc->granted_service_unit->cc_time;
+    ssd->ro_session->valid_for = ro_cca_data->mscc->validity_time;
+
+    Ro_free_CCA(ro_cca_data);
+
+    LM_DBG("Freeing CCA message\n");
+    cdpb.AAAFreeMessage(&cca);
+
+    link_ro_session(ssd->ro_session, 1);            //create extra ref for the fact that dialog has a handle in the callbacks
+    unref_ro_session(ssd->ro_session, 1);
+
+    create_cca_return_code(RO_RETURN_TRUE);
+
+    if (t)
+    	tmb.unref_cell(t);
+
+    tmb.t_continue(ssd->tindex, ssd->tlabel, ssd->action);
+    shm_free(ssd);
+
+    update_stat(successful_initial_ccrs, 1);
+    return;
+
+error1:
+	Ro_free_CCA(ro_cca_data);
+
+error0:
+    LM_DBG("Trying to reserve credit on initial INVITE failed on cdp callback\n");
+    create_cca_return_code(error_code);
+
+    cdpb.AAAFreeMessage(&cca);
+
+    if (t)
+    	tmb.unref_cell(t);
+
+    tmb.t_continue(ssd->tindex, ssd->tlabel, ssd->action);
+    shm_free(ssd);
+}
+
+void remove_aaa_session(str *session_id) {
+    AAASession *session;
+
+    if ((session = cdpb.AAAGetCCAccSession(*session_id))) {
+        LM_DBG("Found AAA CC App Auth session to delete.\n");
+        cdpb.AAASessionsUnlock(session->hash);
+        cdpb.AAADropCCAccSession(session);
+    }
+}
+
+int get_direction_as_int(str* direction) {
+	char* p = direction->s;
+
+	if (direction->len > 0 && p) {
+		if (p[0]=='O' || p[0]=='o'){
+			return RO_ORIG_DIRECTION;
+		} else if (p[0]=='T' || p[0]=='t') {
+			return RO_TERM_DIRECTION;
+		}
+	}
+	return RO_UNKNOWN_DIRECTION;
+}
+
+static int create_cca_return_code(int result) {
+    int rc;
+    int_str avp_val, avp_name;
+    avp_name.s.s = RO_AVP_CCA_RETURN_CODE;
+    avp_name.s.len = RO_AVP_CCA_RETURN_CODE_LENGTH;
+
+    avp_val.n = result;
+    avp_val.s.s = RO_RETURN_TRUE_STR;	//assume true
+    avp_val.s.len = 1;
+
+    switch(result) {
+    case RO_RETURN_FALSE:
+    	avp_val.s.s = RO_RETURN_FALSE_STR;
+    	break;
+    case RO_RETURN_ERROR:
+    	avp_val.s.s = RO_RETURN_ERROR_STR;
+    	break;
+    default:
+    	if (result >= 0)
+    		break;
+
+    	LM_ERR("Unknown result code: %d", result);
+    	avp_val.s.s = "??";
+    }
+
+    if (result < 0)	
+        avp_val.s.len = 2;
+
+    rc = add_avp(AVP_NAME_STR|AVP_VAL_STR, avp_name, avp_val);
+
+    if (rc < 0)
+        LM_ERR("Couldn't create ["RO_AVP_CCA_RETURN_CODE"] AVP\n");
+    else
+    	LM_DBG("Created AVP ["RO_AVP_CCA_RETURN_CODE"] successfully: value=[%d]\n", result);
+
+    return 1;
+}
+
+static int get_mac_avp_value(struct sip_msg *msg, str *value) {
+	str mac_avp_name_str = str_init(RO_MAC_AVP_NAME);
+	pv_spec_t avp_spec;
+	pv_value_t val;
+
+	pv_parse_spec2(&mac_avp_name_str, &avp_spec, 1);
+	if (pv_get_spec_value(msg, &avp_spec, &val) != 0 || val.rs.len == 0) {
+
+		value->s	= "00:00:00:00:00:00";
+		value->len	= sizeof("00:00:00:00:00:00") - 1;
+		return -1;
+	}
+
+	*value = val.rs;
+	return 0;
+}
diff --git a/modules/ims_charging/ims_ro.h b/modules/ims_charging/ims_ro.h
new file mode 100644
index 0000000..d0481ed
--- /dev/null
+++ b/modules/ims_charging/ims_ro.h
@@ -0,0 +1,23 @@
+#ifndef CLIENT_RF_IMS_RO_H
+#define CLIENT_RF_IMS_RO_H
+
+#include "../../mod_fix.h"
+#include "../cdp/diameter_api.h"
+#include "ro_session_hash.h"
+
+struct interim_ccr {
+	struct ro_session* ro_session;
+	int new_credit;
+	int credit_valid_for;
+	unsigned int is_final_allocation;
+};
+
+void credit_control_session_callback(int event, void* session);
+void remove_aaa_session(str *session_id);
+int Ro_Send_CCR(struct sip_msg *msg, str* direction, str* charge_type, str* unit_type, int reservation_units, cfg_action_t* action, unsigned int tindex, unsigned int tlabel);
+//void send_ccr_interim(struct ro_session *ro_session, str* from_uri, str *to_uri, int *new_credit, int *credit_valid_for, unsigned int used, unsigned int reserve, unsigned int *is_final_allocation);
+void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned int reserve);
+void send_ccr_stop(struct ro_session *ro_session);
+
+
+#endif /* CLIENT_RF_IMS_RO_H */
diff --git a/modules/ims_charging/mod.c b/modules/ims_charging/mod.c
new file mode 100644
index 0000000..9e60c7d
--- /dev/null
+++ b/modules/ims_charging/mod.c
@@ -0,0 +1,358 @@
+/*
+ * mod.c
+ *
+ *  Created on: 21 Feb 2013
+ *      Author: jaybeepee
+ */
+
+#include "mod.h"
+#include "../../sr_module.h"
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../../modules/dialog_ng/dlg_hash.h"
+#include "../cdp/cdp_load.h"
+#include "../cdp_avp/mod_export.h"
+#include "../../parser/parse_to.h"
+#include "stats.h"
+#include "ro_timer.h"
+#include "ro_session_hash.h"
+#include "ims_ro.h"
+#include "config.h"
+#include "dialog.h"
+
+MODULE_VERSION
+
+/* parameters */
+char* ro_origin_host_s = "scscf.ims.smilecoms.com";
+char* ro_origin_realm_s = "ims.smilecoms.com";
+char* ro_destination_realm_s = "ims.smilecoms.com";
+char* ro_destination_host_s = "hss.ims.smilecoms.com";
+char* ro_service_context_id_root_s = "32260 at 3gpp.org";
+char* ro_service_context_id_ext_s = "ext";
+char* ro_service_context_id_mnc_s = "01";
+char* ro_service_context_id_mcc_s = "001";
+char* ro_service_context_id_release_s = "8";
+static int ro_session_hash_size = 4096;
+int ro_timer_buffer = 5;
+int interim_request_credits = 30;
+client_ro_cfg cfg;
+
+struct cdp_binds cdpb;
+struct dlg_binds dlgb;
+cdp_avp_bind_t *cdp_avp;
+struct tm_binds tmb;
+
+char* rx_dest_realm_s = "ims.smilecoms.com";
+str rx_dest_realm;
+/* Only used if we want to force the Ro peer usually this is configured at a stack level and the first request uses realm routing */
+//char* rx_forced_peer_s = "";
+str ro_forced_peer;
+int ro_auth_expiry = 7200;
+int cdp_event_latency = 1; /*flag: report slow processing of CDP callback events or not - default enabled */
+int cdp_event_threshold = 500; /*time in ms above which we should report slow processing of CDP callback event - default 500ms*/
+int cdp_event_latency_loglevel = 0; /*log-level to use to report slow processing of CDP callback event - default ERROR*/
+
+stat_var *initial_ccrs;
+stat_var *interim_ccrs;
+stat_var *final_ccrs;
+stat_var *successful_initial_ccrs;
+stat_var *successful_interim_ccrs;
+stat_var *successful_final_ccrs;
+stat_var *ccr_responses_time;
+stat_var *billed_secs;
+stat_var *killed_calls;
+stat_var *ccr_timeouts;
+
+/** module functions */
+static int mod_init(void);
+static int mod_child_init(int);
+static void mod_destroy(void);
+static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units);
+//void ro_session_ontimeout(struct ro_tl *tl);
+
+static int ro_fixup(void **param, int param_no);
+
+static cmd_export_t cmds[] = {
+		{ "Ro_CCR", 	(cmd_function) w_ro_ccr, 5, ro_fixup, 0, REQUEST_ROUTE },
+		{ 0, 0, 0, 0, 0, 0 }
+};
+
+static param_export_t params[] = {
+		{ "hash_size", 				INT_PARAM,			&ro_session_hash_size 		},
+		{ "interim_update_credits",	INT_PARAM,			&interim_request_credits 	},
+		{ "timer_buffer", 			INT_PARAM,			&ro_timer_buffer 			},
+		{ "ro_forced_peer", 		STR_PARAM, 			&ro_forced_peer.s 			},
+		{ "ro_auth_expiry",			INT_PARAM, 			&ro_auth_expiry 			},
+		{ "cdp_event_latency", 		INT_PARAM,			&cdp_event_latency 			}, /*flag: report slow processing of CDP
+																						callback events or not */
+		{ "cdp_event_threshold", 	INT_PARAM, 			&cdp_event_threshold 		}, /*time in ms above which we should
+																						report slow processing of CDP callback event*/
+		{ "cdp_event_latency_log", 	INT_PARAM, 			&cdp_event_latency_loglevel },/*log-level to use to report
+																						slow processing of CDP callback event*/
+		{ "origin_host", 			STR_PARAM, 			&ro_origin_host_s 			},
+		{ "origin_realm", 			STR_PARAM,			&ro_origin_realm_s 			},
+		{ "destination_realm", 		STR_PARAM,			&ro_destination_realm_s 	},
+		{ "destination_host", 		STR_PARAM,			&ro_destination_host_s 		},
+		{ "service_context_id_root",STR_PARAM,			&ro_service_context_id_root_s 	},
+		{ "service_context_id_ext", STR_PARAM,			&ro_service_context_id_ext_s 	},
+		{ "service_context_id_mnc", STR_PARAM,			&ro_service_context_id_mnc_s 	},
+		{ "service_context_id_mcc", STR_PARAM,			&ro_service_context_id_mcc_s 	},
+		{ "service_context_id_release",	STR_PARAM, 		&ro_service_context_id_release_s},
+		{ 0, 0, 0 }
+};
+
+stat_export_t charging_stats[] = {
+    {"initial_ccrs", STAT_NO_RESET, &initial_ccrs},
+    {"interim_ccrs", STAT_NO_RESET, &interim_ccrs},
+    {"final_ccrs", STAT_NO_RESET, &final_ccrs},
+    {"successful_initial_ccrs", STAT_NO_RESET, &successful_initial_ccrs},
+    {"successful_interim_ccr", STAT_NO_RESET, &successful_interim_ccrs},
+    {"successful_final_ccrs", STAT_NO_RESET, &successful_final_ccrs},
+    {"failed_initial_ccrs", STAT_IS_FUNC, (stat_var**) get_failed_initial_ccrs},
+    {"failed_interim_ccr", STAT_IS_FUNC, (stat_var**) get_failed_interim_ccrs},
+    {"failed_final_ccrs", STAT_IS_FUNC, (stat_var**) get_failed_final_ccrs},
+    {"ccr_avg_response_time", STAT_IS_FUNC, (stat_var**) get_ccr_avg_response_time},
+    {"ccr_responses_time", STAT_NO_RESET, &ccr_responses_time},
+    {"billed_secs", STAT_NO_RESET, &billed_secs},
+    {"killed_calls", STAT_NO_RESET, &killed_calls},
+    {"ccr_timeouts", STAT_NO_RESET, &ccr_timeouts},
+    {0, 0, 0}
+};
+
+/** module exports */
+struct module_exports exports = { MOD_NAME, DEFAULT_DLFLAGS, /* dlopen flags */
+		cmds, 		/* Exported functions */
+		params, 	/* Exported params */
+		charging_stats,	/* exported statistics */
+		0, 			/* exported MI functions */
+		0, 			/* exported pseudo-variables */
+		0, 			/* extra processes */
+		mod_init, 	/* module initialization function */
+		0,
+		mod_destroy, 	/* module destroy functoin */
+		mod_child_init 	/* per-child init function */
+};
+
+int fix_parameters() {
+	cfg.origin_host.s = ro_origin_host_s;
+	cfg.origin_host.len = strlen(ro_origin_host_s);
+
+	cfg.origin_realm.s = ro_origin_realm_s;
+	cfg.origin_realm.len = strlen(ro_origin_realm_s);
+
+	cfg.destination_realm.s = ro_destination_realm_s;
+	cfg.destination_realm.len = strlen(ro_destination_realm_s);
+
+	cfg.destination_host.s = ro_destination_host_s;
+	cfg.destination_host.len = strlen(ro_destination_host_s);
+
+	cfg.service_context_id = shm_malloc(sizeof(str));
+	if (!cfg.service_context_id) {
+		LM_ERR("fix_parameters:not enough shm memory\n");
+		return 0;
+	}
+	cfg.service_context_id->len = strlen(ro_service_context_id_ext_s)
+			+ strlen(ro_service_context_id_mnc_s)
+			+ strlen(ro_service_context_id_mcc_s)
+			+ strlen(ro_service_context_id_release_s)
+			+ strlen(ro_service_context_id_root_s) + 5;
+	cfg.service_context_id->s =
+			pkg_malloc(cfg.service_context_id->len * sizeof (char));
+	if (!cfg.service_context_id->s) {
+		LM_ERR("fix_parameters: not enough memory!\n");
+		return 0;
+	}
+	cfg.service_context_id->len = sprintf(cfg.service_context_id->s,
+			"%s.%s.%s.%s.%s", ro_service_context_id_ext_s,
+			ro_service_context_id_mnc_s, ro_service_context_id_mcc_s,
+			ro_service_context_id_release_s, ro_service_context_id_root_s);
+	if (cfg.service_context_id->len < 0) {
+		LM_ERR("fix_parameters: error while creating service_context_id\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int mod_init(void) {
+	int n;
+	load_dlg_f load_dlg;
+	load_tm_f load_tm;
+
+	if (!fix_parameters()) {
+		LM_ERR("unable to set Ro configuration parameters correctly\n");
+		goto error;
+	}
+
+	/* bind to the tm module */
+	if (!(load_tm = (load_tm_f) find_export("load_tm", NO_SCRIPT, 0))) {
+		LM_ERR("Can not import load_tm. This module requires tm module\n");
+		goto error;
+	}
+	if (load_tm(&tmb) == -1)
+		goto error;
+
+	if (!(load_dlg = (load_dlg_f) find_export("load_dlg", 0, 0))) { /* bind to dialog module */
+		LM_ERR("can not import load_dlg. This module requires Kamailio dialog module.\n");
+	}
+	if (load_dlg(&dlgb) == -1) {
+		goto error;
+	}
+
+	if (load_cdp_api(&cdpb) != 0) { /* load the CDP API */
+		LM_ERR("can't load CDP API\n");
+		goto error;
+	}
+
+	if (load_dlg_api(&dlgb) != 0) { /* load the dialog API */
+		LM_ERR("can't load Dialog API\n");
+		goto error;
+	}
+
+	cdp_avp = load_cdp_avp(); /* load CDP_AVP API */
+	if (!cdp_avp) {
+		LM_ERR("can't load CDP_AVP API\n");
+		goto error;
+	}
+
+	/* init timer lists*/
+	if (init_ro_timer(ro_session_ontimeout) != 0) {
+		LM_ERR("cannot init timer list\n");
+		return -1;
+	}
+
+	/* initialized the hash table */
+	for (n = 0; n < (8 * sizeof(n)); n++) {
+		if (ro_session_hash_size == (1 << n))
+			break;
+		if (ro_session_hash_size < (1 << n)) {
+			LM_WARN("hash_size is not a power of 2 as it should be -> rounding from %d to %d\n", ro_session_hash_size, 1 << (n - 1));
+			ro_session_hash_size = 1 << (n - 1);
+		}
+	}
+
+	if (init_ro_session_table(ro_session_hash_size) < 0) {
+		LM_ERR("failed to create ro session hash table\n");
+		return -1;
+	}
+
+	/* register global timer */
+	if (register_timer(ro_timer_routine, 0/*(void*)ro_session_list*/, 1) < 0) {
+		LM_ERR("failed to register timer \n");
+		return -1;
+	}
+
+	 /* register statistics */
+	if (register_module_stats(exports.name, charging_stats) != 0) {
+		LM_ERR("failed to register core statistics\n");
+		return -1;
+	}
+
+	/*if (register_stat(MOD_NAME, "ccr_responses_time", &ccr_responses_time, 0)) {
+		LM_ERR("failed to register core statistics\n");
+		return -1;
+	}*/
+
+	return 0;
+
+error:
+	LM_ERR("Failed to initialise ims_qos module\n");
+	return RO_RETURN_FALSE;
+
+}
+
+static int mod_child_init(int rank) {
+	return 0;
+}
+
+static void mod_destroy(void) {
+
+}
+
+static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units) {
+	/* PSEUDOCODE/NOTES
+	 * 1. What mode are we in - terminating or originating
+	 * 2. check request type - 	IEC - Immediate Event Charging
+	 * 							ECUR - Event Charging with Unit Reservation
+	 * 							SCUR - Session Charging with Unit Reservation
+	 * 3. probably only do SCUR in this module for now - can see event based charging in another component instead (AS for SMS for example, etc)
+	 * 4. Check a dialog exists for call, if not we fail
+	 * 5. make sure we dont already have an Ro Session for this dialog
+	 * 6. create new Ro Session
+	 * 7. register for DLG callback passing new Ro session as parameter - (if dlg torn down we know which Ro session it is associated with)
+	 *
+	 *
+	 */
+	cfg_action_t* cfg_action;
+	tm_cell_t *t;
+	unsigned int tindex = 0,
+				 tlabel = 0;
+
+	LM_DBG("Ro CCR initiated: direction:%.*s, charge_type:%.*s, unit_type:%.*s, reservation_units:%i, route_name:%.*s",
+			direction->len, direction->s,
+			charge_type->len, charge_type->s,
+			unit_type->len, unit_type->s,
+			reservation_units,
+			route_name->len, route_name->s);
+
+    if (msg->first_line.type != SIP_REQUEST) {
+    	LM_ERR("Ro_CCR() called from SIP reply.");
+    	return -1;
+    }
+
+	LM_DBG("Looking for route block [%.*s]\n", route_name->len, route_name->s);
+
+	int ri = route_get(&main_rt, route_name->s);
+	if (ri < 0) {
+		LM_ERR("unable to find route block [%.*s]\n", route_name->len, route_name->s);
+		return RO_RETURN_ERROR;
+	}
+	
+	cfg_action = main_rt.rlist[ri];
+	if (!cfg_action) {
+		LM_ERR("empty action lists in route block [%.*s]\n", route_name->len, route_name->s);
+		return RO_RETURN_ERROR;
+    }
+
+	//before we send lets suspend the transaction
+	t = tmb.t_gett();
+	if (t == NULL || t == T_UNDEFINED) {
+		if (tmb.t_newtran(msg) < 0) {
+			LM_ERR("cannot create the transaction for CCR async\n");
+			return RO_RETURN_ERROR;
+		}
+		t = tmb.t_gett();
+		if (t == NULL || t == T_UNDEFINED) {
+			LM_ERR("cannot lookup the transaction\n");
+			return RO_RETURN_ERROR;
+		}
+	}
+
+	LM_DBG("Suspending SIP TM transaction\n");
+	if (tmb.t_suspend(msg, &tindex, &tlabel) < 0) {
+		LM_ERR("failed to suspend the TM processing\n");
+		return RO_RETURN_ERROR;
+	}
+
+	return Ro_Send_CCR(msg, direction, charge_type, unit_type, reservation_units, cfg_action, tindex, tlabel);
+}
+
+static int ro_fixup(void **param, int param_no) {
+	str s;
+	unsigned int num;
+
+	if (param_no > 0 && param_no <= 4) {
+		return fixup_var_str_12(param, param_no);
+	} else if (param_no == 5) {
+		/*convert to int */
+		s.s = (char*)*param;
+		s.len = strlen(s.s);
+		if (str2int(&s, &num)==0) {
+			pkg_free(*param);
+			*param = (void*)(unsigned long)num;
+			return 0;
+		}
+		LM_ERR("Bad reservation units: <%s>n", (char*)(*param));
+		return E_CFG;
+	}
+	return 0;
+}
diff --git a/modules/ims_charging/mod.h b/modules/ims_charging/mod.h
new file mode 100644
index 0000000..9c0bc82
--- /dev/null
+++ b/modules/ims_charging/mod.h
@@ -0,0 +1,50 @@
+/*
+ * mod.h
+ *
+ *  Created on: 21 Feb 2013
+ *      Author: jaybeepee
+ */
+
+#ifndef MOD_H_
+#define MOD_H_
+
+#define MOD_NAME "ims_charging"
+
+#define RO_CC_START 	1
+#define RO_CC_INTERIM 	2
+#define RO_CC_STOP 		3
+
+#define RO_UNKNOWN_DIRECTION 0
+#define RO_ORIG_DIRECTION 1
+#define RO_TERM_DIRECTION 2
+
+/** Return and break the execution of routing script */
+#define RO_RETURN_BREAK	0
+/** Return true in the routing script */
+#define RO_RETURN_TRUE	1
+#define RO_RETURN_TRUE_STR "1"
+/** Return false in the routing script */
+#define RO_RETURN_FALSE -1
+#define RO_RETURN_FALSE_STR "-1"
+/** Return error in the routing script */
+#define RO_RETURN_ERROR -2
+#define RO_RETURN_ERROR_STR "-2"
+
+/** Diameter Termination Cause Codes */
+#define TERM_CAUSE_LOGOUT 1
+#define TERM_CAUSE_SERVICE_NOT_PROVIDED 2
+#define TERM_CAUSE_BAD_ANSWER 3
+#define TERM_CAUSE_ADMINISTRATIVE 4
+#define TERM_CAUSE_LINK_BROKEN 5
+#define TERM_CAUSE_AUTH_EXPIRED 6
+#define TERM_CAUSE_USER_MOVED 7
+#define TERM_CAUSE_SESSION_TIMEOUT 8
+
+
+
+#define RO_AVP_CCA_RETURN_CODE "cca_return_code"
+#define RO_AVP_CCA_RETURN_CODE_LENGTH 15
+
+#define RO_MAC_AVP_NAME	"$avp(ro_mac_value)"
+
+#endif /* MOD_H_ */
diff --git a/modules/ims_charging/ro_fixup.c b/modules/ims_charging/ro_fixup.c
new file mode 100644
index 0000000..f0e18f7
--- /dev/null
+++ b/modules/ims_charging/ro_fixup.c
@@ -0,0 +1,19 @@
+/* 
+ * File:   ro_fixup.c
+ * Author: Jason Penton
+ *
+ * Created on 06 April 2011, 9:52 PM
+ */
+
+#include "ro_fixup.h"
+#include "../../mod_fix.h"
+
+int ro_send_ccr_fixup(void** param, int param_no) {
+    if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+    }
+
+    return fixup_var_int_12(param, 1);
+}
+
diff --git a/modules/ims_charging/ro_fixup.h b/modules/ims_charging/ro_fixup.h
new file mode 100644
index 0000000..3f20d13
--- /dev/null
+++ b/modules/ims_charging/ro_fixup.h
@@ -0,0 +1,14 @@
+/* 
+ * File:   ro_fixup.h
+ * Author: root
+ *
+ * Created on 06 April 2011, 9:51 PM
+ */
+
+#ifndef RO_FIXUP_H
+#define	RO_FIXUP_H
+
+int ro_send_ccr_fixup(void** param, int param_no);
+
+#endif	/* RO_FIXUP_H */
+
diff --git a/modules/ims_charging/ro_session_hash.c b/modules/ims_charging/ro_session_hash.c
new file mode 100644
index 0000000..c79d3b2
--- /dev/null
+++ b/modules/ims_charging/ro_session_hash.c
@@ -0,0 +1,284 @@
+/* 
+ * File:   ro_session_hash.c
+ * Author: Jason Penton
+ *
+ * Created on 08 April 2011, 1:10 PM
+ */
+
+#include "ro_session_hash.h"
+
+#define MAX_LDG_LOCKS  2048
+#define MIN_LDG_LOCKS  2
+
+/*! global ro_session table */
+struct ro_session_table *ro_session_table = 0;
+
+/*!
+ * \brief Link a ro_session structure
+ * \param ro_session Ro Session
+ * \param n extra increments for the reference counter
+ */
+void link_ro_session(struct ro_session *ro_session, int n) {
+    struct ro_session_entry *ro_session_entry;
+
+    ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
+
+    ro_session_lock(ro_session_table, ro_session_entry);
+
+    ro_session->h_id = ro_session_entry->next_id++;
+    if (ro_session_entry->first == 0) {
+        ro_session_entry->first = ro_session_entry->last = ro_session;
+    } else {
+        ro_session_entry->last->next = ro_session;
+        ro_session->prev = ro_session_entry->last;
+        ro_session_entry->last = ro_session;
+    }
+
+    ro_session->ref += 1 + n;
+    
+    ro_session_unlock(ro_session_table, ro_session_entry);
+
+    return;
+}
+
+/*!
+ * \brief Refefence an ro_session with locking
+ * \see ref_ro_session_unsafe
+ * \param ro_session Ro Session
+ * \param cnt increment for the reference counter
+ */
+void ref_ro_session(struct ro_session *ro_session, unsigned int cnt) {
+    struct ro_session_entry *ro_session_entry;
+
+    ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
+
+    ro_session_lock(ro_session_table, ro_session_entry);
+    ref_ro_session_unsafe(ro_session, cnt);
+    ro_session_unlock(ro_session_table, ro_session_entry);
+}
+
+/*!
+ * \brief Unreference an ro_session with locking
+ * \see unref_ro_session_unsafe
+ * \param ro_session Ro Session
+ * \param cnt decrement for the reference counter
+ */
+void unref_ro_session(struct ro_session *ro_session, unsigned int cnt) {
+    struct ro_session_entry *ro_session_entry;
+
+    ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
+
+    ro_session_lock(ro_session_table, ro_session_entry);
+    unref_ro_session_unsafe(ro_session, cnt, ro_session_entry);
+    ro_session_unlock(ro_session_table, ro_session_entry);
+}
+
+/*!
+ * \brief Initialize the global ro_session table
+ * \param size size of the table
+ * \return 0 on success, -1 on failure
+ */
+int init_ro_session_table(unsigned int size) {
+    unsigned int n;
+    unsigned int i;
+
+    ro_session_table = (struct ro_session_table*) shm_malloc(sizeof (struct ro_session_table) +size * sizeof (struct ro_session_entry));
+    if (ro_session_table == 0) {
+        LM_ERR("no more shm mem (1)\n");
+        goto error0;
+    }
+
+    memset(ro_session_table, 0, sizeof (struct ro_session_table));
+    ro_session_table->size = size;
+    ro_session_table->entries = (struct ro_session_entry*) (ro_session_table + 1);
+
+    n = (size < MAX_LDG_LOCKS) ? size : MAX_LDG_LOCKS;
+    for (; n >= MIN_LDG_LOCKS; n--) {
+        ro_session_table->locks = lock_set_alloc(n);
+        if (ro_session_table->locks == 0)
+            continue;
+        if (lock_set_init(ro_session_table->locks) == 0) {
+            lock_set_dealloc(ro_session_table->locks);
+            ro_session_table->locks = 0;
+            continue;
+        }
+        ro_session_table->locks_no = n;
+        break;
+    }
+
+    if (ro_session_table->locks == 0) {
+        LM_ERR("unable to allocted at least %d locks for the hash table\n",
+                MIN_LDG_LOCKS);
+        goto error1;
+    }
+
+    for (i = 0; i < size; i++) {
+        memset(&(ro_session_table->entries[i]), 0, sizeof (struct ro_session_entry));
+        ro_session_table->entries[i].next_id = rand();
+        ro_session_table->entries[i].lock_idx = i % ro_session_table->locks_no;
+    }
+
+    return 0;
+error1:
+    shm_free(ro_session_table);
+error0:
+    return -1;
+}
+
+/*!
+ * \brief Destroy an ro_session and free memory
+ * \param ro_session destroyed Ro Session
+ */
+inline void destroy_ro_session(struct ro_session *ro_session) {
+
+    LM_DBG("destroying Ro Session %p\n", ro_session);
+
+    remove_ro_timer(&ro_session->ro_tl);
+    
+    if (ro_session->ro_session_id.s && (ro_session->ro_session_id.len > 0)) {
+        shm_free(ro_session->ro_session_id.s);
+    }
+
+
+    shm_free(ro_session);
+}
+
+/*!
+ * \brief Destroy the global Ro session table
+ */
+void destroy_dlg_table(void) {
+    struct ro_session *ro_session, *l_ro_session;
+    unsigned int i;
+
+    if (ro_session_table == 0)
+        return;
+
+    if (ro_session_table->locks) {
+        lock_set_destroy(ro_session_table->locks);
+        lock_set_dealloc(ro_session_table->locks);
+    }
+
+    for (i = 0; i < ro_session_table->size; i++) {
+        ro_session = ro_session_table->entries[i].first;
+        while (ro_session) {
+            l_ro_session = ro_session;
+            ro_session = ro_session->next;
+            destroy_ro_session(l_ro_session);
+        }
+
+    }
+
+    shm_free(ro_session_table);
+    ro_session_table = 0;
+
+    return;
+}
+
+struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_session_type, str *session_id, str *callid, str *from_uri, str* to_uri, str* mac, unsigned int dlg_h_entry, unsigned int dlg_h_id, unsigned int requested_secs, unsigned int validity_timeout){
+    LM_DBG("Building Ro Session **********");
+    char *p;
+    unsigned int len = session_id->len + callid->len + from_uri->len + to_uri->len + mac->len + sizeof (struct ro_session);
+    struct ro_session *new_ro_session = (struct ro_session*) shm_malloc(len);
+
+    if (!new_ro_session) {
+        LM_ERR("no more shm mem.\n");
+        shm_free(new_ro_session);
+        return 0;
+    }
+    
+    LM_DBG("New Ro Session given memory at address [%p]\n", new_ro_session);
+
+    memset(new_ro_session, 0, len);
+
+    new_ro_session->direction = direction;
+    new_ro_session->auth_appid = auth_appid;
+    new_ro_session->auth_session_type = auth_session_type;
+
+    new_ro_session->ro_tl.next = new_ro_session->ro_tl.prev;
+    new_ro_session->ro_tl.timeout = 0; //requested_secs;
+
+    new_ro_session->reserved_secs = requested_secs;
+    new_ro_session->valid_for = validity_timeout;
+
+    new_ro_session->hop_by_hop = 1;
+    new_ro_session->next = 0;
+    new_ro_session->dlg_h_entry = dlg_h_entry;
+    new_ro_session->dlg_h_id = dlg_h_id;
+
+    new_ro_session->h_entry = dlg_h_entry; /* we will use the same entry ID as the dlg - saves us using our own hash function */
+    new_ro_session->h_id = 0;
+    new_ro_session->ref = 0;
+
+    p = (char*) (new_ro_session + 1);
+    new_ro_session->callid.s = p;
+    new_ro_session->callid.len = callid->len;
+    memcpy(p, callid->s, callid->len);
+    p += callid->len;
+
+    new_ro_session->ro_session_id.s = p;
+    new_ro_session->ro_session_id.len = session_id->len;
+    memcpy(p, session_id->s, session_id->len);
+    p += session_id->len;
+
+    new_ro_session->from_uri.s = p;
+    new_ro_session->from_uri.len = from_uri->len;
+    memcpy(p, from_uri->s, from_uri->len);
+    p += from_uri->len;
+
+    new_ro_session->to_uri.s = p;
+    new_ro_session->to_uri.len = to_uri->len;
+    memcpy(p, to_uri->s, to_uri->len);
+    p += to_uri->len;
+
+    new_ro_session->avp_value.mac.s		= p;
+    new_ro_session->avp_value.mac.len	= mac->len;
+    memcpy(p, mac->s, mac->len);
+
+    p += mac->len;
+
+    if (p != (((char*) new_ro_session) + len)) {
+        LM_ERR("buffer overflow\n");
+        shm_free(new_ro_session);
+        return 0;
+    }
+
+    return new_ro_session;
+
+}
+
+/*!
+ * \brief Lookup an Ro session in the global list
+ * \param h_entry number of the hash table entry
+ * \param h_id id of the hash table entry
+ * \return ro_session on success, NULL on failure
+ */
+struct ro_session* lookup_ro_session(unsigned int h_entry, str* callid, int direction, unsigned int *del) {
+    struct ro_session *ro_session;
+    struct ro_session_entry *ro_session_entry;
+
+    if (del != NULL)
+        *del = 0;
+
+    if (h_entry >= ro_session_table->size)
+        goto not_found;
+    ro_session_entry = &(ro_session_table->entries[h_entry]);
+
+    ro_session_lock(ro_session_table, ro_session_entry);
+
+    for (ro_session = ro_session_entry->first; ro_session; ro_session = ro_session->next) {
+        if ((direction==0 || direction==ro_session->direction) && (strncmp(ro_session->callid.s, callid->s, callid->len)==0)) {
+		ref_ro_session_unsafe(ro_session,1);
+            LM_DBG("ref ro_session %p with 1 -> %d\n", ro_session, ro_session->ref);
+            ro_session_unlock(ro_session_table, ro_session_entry);
+            LM_DBG("ro_session id=%u found on entry %u\n", ro_session->h_id, h_entry);
+            return ro_session;
+        }
+    }
+
+    ro_session_unlock(ro_session_table, ro_session_entry);
+not_found:
+    LM_DBG("no ro_session for callid=%.*s found on entry %u\n", callid->len, callid->s, h_entry);
+    return 0;
+}
+
+
diff --git a/modules/ims_charging/ro_session_hash.h b/modules/ims_charging/ro_session_hash.h
new file mode 100644
index 0000000..105bd37
--- /dev/null
+++ b/modules/ims_charging/ro_session_hash.h
@@ -0,0 +1,195 @@
+/* 
+ * File:   ro_session_hash.h
+ * Author: Jason Penton
+ *
+ * Created on 07 April 2011, 4:12 PM
+ */
+
+#ifndef RO_SESSION_HASH_H
+#define	RO_SESSION_HASH_H
+
+#include "ro_timer.h"
+#include "../../mem/shm_mem.h"
+#include <stdlib.h>
+
+enum ro_session_event_type {
+    pending,
+    answered,
+    no_more_credit,
+    unknown_error
+};
+
+struct diameter_avp_value {
+	str mac;
+};
+
+struct ro_session {
+	str cdp_session_id;
+    volatile int ref;
+    int direction;
+    struct ro_session* next;
+    struct ro_session* prev;
+    str ro_session_id;
+    str callid;
+    str from_uri;
+    str to_uri;
+    unsigned int hop_by_hop;
+    struct ro_tl ro_tl;
+    unsigned int reserved_secs;
+    unsigned int valid_for;
+    unsigned int dlg_h_entry;
+    unsigned int dlg_h_id;
+    unsigned int h_entry;
+    unsigned int h_id;
+    time_t start_time;
+    time_t last_event_timestamp;
+    enum ro_session_event_type event_type;
+    int auth_appid;
+    int auth_session_type;
+    int active;
+
+    struct diameter_avp_value avp_value;
+};
+
+/*! entries in the main ro_session table */
+struct ro_session_entry {
+    struct ro_session *first; /*!< dialog list */
+    struct ro_session *last; /*!< optimisation, end of the dialog list */
+    unsigned int next_id; /*!< next id */
+    unsigned int lock_idx; /*!< lock index */
+};
+
+/*! main ro_sesion table */
+struct ro_session_table {
+    unsigned int size; /*!< size of the dialog table */
+    struct ro_session_entry *entries; /*!< dialog hash table */
+    unsigned int locks_no; /*!< number of locks */
+    gen_lock_set_t *locks; /*!< lock table */
+};
+
+
+/*! global ro_session table */
+extern struct ro_session_table *ro_session_table;
+
+
+/*!
+ * \brief Set a ro_session lock
+ * \param _table ro_session table
+ * \param _entry locked entry
+ */
+#define ro_session_lock(_table, _entry) \
+		{ LM_DBG("LOCKING %d", (_entry)->lock_idx); lock_set_get( (_table)->locks, (_entry)->lock_idx); LM_DBG("LOCKED %d", (_entry)->lock_idx);}
+
+
+/*!
+ * \brief Release a ro_session lock
+ * \param _table ro_session table
+ * \param _entry locked entry
+ */
+#define ro_session_unlock(_table, _entry) \
+		{ LM_DBG("UNLOCKING %d", (_entry)->lock_idx); lock_set_release( (_table)->locks, (_entry)->lock_idx); LM_DBG("UNLOCKED %d", (_entry)->lock_idx); }
+
+/*!
+ * \brief Reference an ro_session without locking
+ * \param _ro_session Ro Session
+ * \param _cnt increment for the reference counter
+ */
+#define ref_ro_session_unsafe(_session,_cnt)     \
+	do { \
+		(_session)->ref += (_cnt); \
+		LM_DBG("ref ro_session %p with %d -> %d (tl=%p)\n", \
+			(_session),(_cnt),(_session)->ref,&(_session)->ro_tl); \
+	}while(0)
+
+
+/*!
+ * \brief Unreference an ro_session without locking
+ * \param _ro_session Ro Session
+ * \param _cnt decrement for the reference counter
+ */
+#define unref_ro_session_unsafe(_ro_session,_cnt,_ro_session_entry)   \
+	do { \
+		(_ro_session)->ref -= (_cnt); \
+		LM_DBG("unref ro_session %p with %d -> %d (tl=%p)\n",\
+			(_ro_session),(_cnt),(_ro_session)->ref,&(_ro_session)->ro_tl);\
+		if ((_ro_session)->ref<0) {\
+			LM_CRIT("bogus ref for session id < 0 [%d]\n",(_ro_session)->ref);\
+		}\
+		if ((_ro_session)->ref<=0) { \
+			unlink_unsafe_ro_session( _ro_session_entry, _ro_session);\
+			LM_DBG("ref <=0 for ro_session %p\n",_ro_session);\
+			destroy_ro_session(_ro_session);\
+		}\
+	}while(0)
+
+/*!
+ * \brief Unlink a ro_session from the list without locking
+ * \see unref_ro_session_unsafe
+ * \param ro_session_entry unlinked entry
+ * \param ro_session unlinked ro_session
+ */
+static inline void unlink_unsafe_ro_session(struct ro_session_entry *ro_session_entry, struct ro_session *ro_session) {
+    if (ro_session->next)
+        ro_session->next->prev = ro_session->prev;
+    else
+        ro_session_entry->last = ro_session->prev;
+    if (ro_session->prev)
+        ro_session->prev->next = ro_session->next;
+    else
+        ro_session_entry->first = ro_session->next;
+
+    ro_session->next = ro_session->prev = 0;
+
+    return;
+}
+
+/*!
+ * \brief Initialize the global ro_session table
+ * \param size size of the table
+ * \return 0 on success, -1 on failure
+ */
+int init_ro_session_table(unsigned int size);
+
+/*!
+ * \brief Destroy a ro_session and free memory
+ * \param ro_session destroyed Ro Session
+ */
+inline void destroy_ro_session(struct ro_session *ro_session);
+
+/*!
+ * \brief Destroy the ro_session dialog table
+ */
+void destroy_ro_session_table(void);
+
+/*!
+ * \brief Link a ro_session structure
+ * \param ro_session Ro Session
+ * \param n extra increments for the reference counter
+ */
+void link_ro_session(struct ro_session *ro_session, int n);
+
+void remove_aaa_session(str *session_id);
+
+struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_session_type, str *session_id, str *callid, str *from_uri, str* to_uri, str* mac, unsigned int dlg_h_entry, unsigned int dlg_h_id, unsigned int requested_secs, unsigned int validity_timeout);
+
+/*!
+ * \brief Refefence a ro_session with locking
+ * \see ref_ro_session_unsafe
+ * \param ro_session Ro Session
+ * \param cnt increment for the reference counter
+ */
+void ref_ro_session(struct ro_session *ro_session, unsigned int cnt);
+
+/*!
+ * \brief Unreference a ro_session with locking
+ * \see unref_ro_session_unsafe
+ * \param ro_session Ro Session
+ * \param cnt decrement for the reference counter
+ */
+void unref_ro_session(struct ro_session *ro_session, unsigned int cnt);
+
+struct ro_session* lookup_ro_session(unsigned int h_entry, str *callid, int direction, unsigned int *del);
+
+
+#endif	/* RO_SESSION_HASH_H */
+
diff --git a/modules/ims_charging/ro_timer.c b/modules/ims_charging/ro_timer.c
new file mode 100644
index 0000000..248e4db
--- /dev/null
+++ b/modules/ims_charging/ro_timer.c
@@ -0,0 +1,466 @@
+/* 
+ * File:   ro_timer.c
+ * Author: Jason Penton
+ *
+ * Created on 06 April 2011, 1:37 PM
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "../../mem/shm_mem.h"
+#include "../dialog_ng/dlg_load.h"
+#include "ro_timer.h"
+#include "ro_session_hash.h"
+#include "ims_ro.h"
+#include "stats.h"
+
+extern int interim_request_credits;
+extern int ro_timer_buffer;
+
+extern struct dlg_binds dlgb;
+
+/*! global dialog timer */
+struct ro_timer *roi_timer = 0;
+/*! global dialog timer handler */
+ro_timer_handler timer_hdl = 0;
+
+/*!
+ * \brief Initialize the ro_session timer handler
+ * Initialize the ro_session timer handler, allocate the lock and a global
+ * timer in shared memory. The global timer handler will be set on success.
+ * \param hdl ro_session timer handler
+ * \return 0 on success, -1 on failure
+ */
+int init_ro_timer(ro_timer_handler hdl) {
+    roi_timer = (struct ro_timer*) shm_malloc(sizeof (struct ro_timer));
+    if (roi_timer == 0) {
+        LM_ERR("no more shm mem\n");
+        return -1;
+    }
+    memset(roi_timer, 0, sizeof (struct ro_timer));
+
+    roi_timer->first.next = roi_timer->first.prev = &(roi_timer->first);
+
+    roi_timer->lock = lock_alloc();
+    if (roi_timer->lock == 0) {
+        LM_ERR("failed to alloc lock\n");
+        goto error0;
+    }
+
+    if (lock_init(roi_timer->lock) == 0) {
+        LM_ERR("failed to init lock\n");
+        goto error1;
+    }
+
+    timer_hdl = hdl;
+    return 0;
+error1:
+    lock_dealloc(roi_timer->lock);
+error0:
+    shm_free(roi_timer);
+    roi_timer = 0;
+    return -1;
+}
+
+/*!
+ * \brief Destroy global ro_session timer
+ */
+void destroy_ro_timer(void) {
+    if (roi_timer == 0)
+        return;
+
+    lock_destroy(roi_timer->lock);
+    lock_dealloc(roi_timer->lock);
+
+    shm_free(roi_timer);
+    roi_timer = 0;
+}
+
+/*!
+ * \brief Helper function for insert_ro_session_timer
+ * \see insert_ro_session_timer
+ * \param tl ro_session timer list
+ */
+static inline void insert_ro_timer_unsafe(struct ro_tl *tl) {
+    struct ro_tl* ptr;
+
+    /* insert in sorted order */
+    for (ptr = roi_timer->first.prev; ptr != &roi_timer->first; ptr = ptr->prev) {
+        if (ptr->timeout <= tl->timeout)
+            break;
+    }
+
+    LM_DBG("inserting %p for %d\n", tl, tl->timeout);
+    tl->prev = ptr;
+    tl->next = ptr->next;
+    tl->prev->next = tl;
+    tl->next->prev = tl;
+}
+
+/*!
+ * \brief Insert a ro_session timer to the list
+ * \param tl ro_session timer list
+ * \param interval timeout value in seconds
+ * \return 0 on success, -1 when the input timer list is invalid
+ */
+int insert_ro_timer(struct ro_tl *tl, int interval) {
+    lock_get(roi_timer->lock);
+
+    LM_DBG("inserting timer for interval [%i]\n", interval);
+    if (tl->next != 0 || tl->prev != 0) {
+        lock_release(roi_timer->lock);
+        LM_CRIT("Trying to insert a bogus ro tl=%p tl->next=%p tl->prev=%p\n",
+                tl, tl->next, tl->prev);
+        return -1;
+    }
+    tl->timeout = get_ticks() + interval;
+    insert_ro_timer_unsafe(tl);
+
+
+    LM_DBG("TIMER inserted");
+    lock_release(roi_timer->lock);
+
+    return 0;
+}
+
+/*!
+ * \brief Helper function for remove_ro_session_timer
+ * \param tl ro_session timer list
+ * \see remove_ro_session_timer
+ */
+static inline void remove_ro_timer_unsafe(struct ro_tl *tl) {
+    tl->prev->next = tl->next;
+    tl->next->prev = tl->prev;
+}
+
+/*!
+ * \brief Remove a ro_session timer from the list
+ * \param tl ro_session timer that should be removed
+ * \return 1 when the input timer is empty, 0 when the timer was removed,
+ * -1 when the input timer list is invalid
+ */
+int remove_ro_timer(struct ro_tl *tl) {
+    lock_get(roi_timer->lock);
+	
+    if (tl->prev == NULL && tl->timeout == 0) {
+        lock_release(roi_timer->lock);
+        return 1;
+    }
+
+    if (tl->prev == NULL || tl->next == NULL) {
+        LM_CRIT("bogus tl=%p tl->prev=%p tl->next=%p\n",
+                tl, tl->prev, tl->next);
+        lock_release(roi_timer->lock);
+        return -1;
+    }
+    LM_DBG("TIMER REMOVED");
+    remove_ro_timer_unsafe(tl);
+    tl->next = NULL;
+    tl->prev = NULL;
+    tl->timeout = 0;
+
+    lock_release(roi_timer->lock);
+    return 0;
+}
+
+/*!
+ * \brief Update a ro_session timer on the list
+ * \param tl dialog timer
+ * \param timeout new timeout value in seconds
+ * \return 0 on success, -1 when the input list is invalid
+ * \note the update is implemented as a remove, insert
+ */
+int update_ro_timer(struct ro_tl *tl, int timeout) {
+    lock_get(roi_timer->lock);
+
+    if (tl->next) {
+        if (tl->prev == 0) {
+            lock_release(roi_timer->lock);
+            return -1;
+        }
+        remove_ro_timer_unsafe(tl);
+    }
+
+    tl->timeout = get_ticks() + timeout;
+    insert_ro_timer_unsafe(tl);
+
+    lock_release(roi_timer->lock);
+    return 0;
+}
+
+/*!
+ * \brief Helper function for ro_timer_routine
+ * \param time time for expiration check
+ * \return list of expired credit reservations on sessions on success, 0 on failure
+ */
+static inline struct ro_tl* get_expired_ro_sessions(unsigned int time) {
+    struct ro_tl *tl, *end, *ret;
+
+    lock_get(roi_timer->lock);
+
+    if (roi_timer->first.next == &(roi_timer->first) || roi_timer->first.next->timeout > time) {
+        lock_release(roi_timer->lock);
+        return 0;
+    }
+
+    end = &roi_timer->first;
+    tl = roi_timer->first.next;
+    LM_DBG("start with tl=%p tl->prev=%p tl->next=%p (%d) at %d and end with end=%p end->prev=%p end->next=%p\n", tl, tl->prev, tl->next, tl->timeout, time, end, end->prev, end->next);
+    while (tl != end && tl->timeout <= time) {
+        LM_DBG("getting tl=%p tl->prev=%p tl->next=%p with %d\n", tl, tl->prev, tl->next, tl->timeout);
+        tl->prev = 0;
+        tl->timeout = 0;
+        tl = tl->next;
+    }
+    LM_DBG("end with tl=%p tl->prev=%p tl->next=%p and d_timer->first.next->prev=%p\n", tl, tl->prev, tl->next, roi_timer->first.next->prev);
+
+    if (tl == end && roi_timer->first.next->prev) {
+        ret = 0;
+    } else {
+        ret = roi_timer->first.next;
+        tl->prev->next = 0;
+        roi_timer->first.next = tl;
+        tl->prev = &roi_timer->first;
+    }
+
+    lock_release(roi_timer->lock);
+
+    return ret;
+}
+
+/*!
+ * \brief Timer routine for expiration of credit reservations
+ * Timer handler for expiration of credit reservations on a session, runs the global timer handler on them.
+ * \param time for expiration checks
+ * \param attr unused
+ */
+void ro_timer_routine(unsigned int ticks, void * attr) {
+
+    struct ro_tl *tl, *ctl;
+    LM_DBG("getting expired ro-sessions");
+
+    tl = get_expired_ro_sessions(ticks);
+
+    while (tl) {
+        ctl = tl;
+        tl = tl->next;
+        ctl->next = NULL;
+        LM_DBG("Ro Session Timer firing: tl=%p next=%p\n", ctl, tl);
+        timer_hdl(ctl);
+    }
+}
+
+void resume_ro_session_ontimeout(struct interim_ccr *i_req) {
+	time_t now = time(0);
+	time_t used_secs;
+	struct ro_session_entry *ro_session_entry = NULL;
+	int call_terminated = 0;
+
+	if (!i_req) {
+		LM_ERR("This is so wrong: i_req is NULL\n");
+		return;
+	}
+
+	ro_session_entry = &(ro_session_table->entries[i_req->ro_session->h_entry]);
+
+	LM_DBG("credit=%d credit_valid_for=%d", i_req->new_credit, i_req->credit_valid_for);
+
+	used_secs = now - i_req->ro_session->last_event_timestamp;
+
+	/* check to make sure diameter server is giving us sane values */
+	if (i_req->new_credit > i_req->credit_valid_for) {
+		LM_WARN("That's weird, Diameter server gave us credit with a lower validity period :D. Setting reserved time to validity period instead \n");
+		i_req->new_credit = i_req->credit_valid_for;
+	}
+
+	if (i_req->new_credit > 0) {
+		//now insert the new timer
+		i_req->ro_session->last_event_timestamp = time(0);
+		i_req->ro_session->event_type = answered;
+		i_req->ro_session->valid_for = i_req->credit_valid_for;
+
+		int ret = 0;
+		if (i_req->is_final_allocation) {
+			LM_DBG("This is a final allocation and call will end in %i seconds\n", i_req->new_credit);
+			i_req->ro_session->event_type = no_more_credit;
+			ret = insert_ro_timer(&i_req->ro_session->ro_tl, i_req->new_credit);
+		}
+		else {
+			int timer_timeout = i_req->new_credit;
+
+			if (i_req->new_credit > ro_timer_buffer /*TIMEOUTBUFFER*/) {
+
+				// We haven't finished using our 1st block of units, and we need to set the timer to
+				// (new_credit - ro_timer_buffer[5 secs]) to ensure we get new credit before our previous
+				// reservation is exhausted. This will only be done the first time, because the timer
+				// will always be fired 5 seconds before we run out of time thanks to this operation
+
+				if ((now - i_req->ro_session->start_time) /* call time */ < i_req->ro_session->reserved_secs)
+					timer_timeout = i_req->new_credit - ro_timer_buffer;
+				else
+					timer_timeout = i_req->new_credit;
+			}
+
+			ret = insert_ro_timer(&i_req->ro_session->ro_tl, timer_timeout);
+
+		}
+
+		// update to the new block of units we got
+		i_req->ro_session->reserved_secs = i_req->new_credit;
+
+		if (ret != 0) {
+			LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
+					i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
+		}
+		else {
+			ref_ro_session_unsafe(i_req->ro_session, 1);
+		}
+	}
+	else {
+		/* just put the timer back in with however many seconds are left (if any!!! in which case we need to kill */
+		/* also update the event type to no_more_credit to save on processing the next time we get here */
+		i_req->ro_session->event_type = no_more_credit;
+		int whatsleft = i_req->ro_session->reserved_secs - used_secs;
+		if (whatsleft <= 0) {
+			// TODO we need to handle this situation more precisely.
+			// in case CCR times out, we get a call shutdown but the error message assumes it was due to a lack of credit.
+			//
+			LM_WARN("Immediately killing call due to no more credit *OR* no CCA received (timeout) after reservation request\n");
+
+			//
+			// we need to unlock the session or else we might get a deadlock on dlg_terminated() dialog callback.
+			// Do not unref the session because it will be made inside the dlg_terminated() function.
+			//
+
+			//unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);
+			ro_session_unlock(ro_session_table, ro_session_entry);
+
+			dlgb.lookup_terminate_dlg(i_req->ro_session->dlg_h_entry, i_req->ro_session->dlg_h_id, NULL );
+			call_terminated = 1;
+		}
+		else {
+			LM_DBG("No more credit for user - letting call run out of money in [%i] seconds", whatsleft);
+			int ret = insert_ro_timer(&i_req->ro_session->ro_tl, whatsleft);
+			if (ret != 0) {
+				LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
+						i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
+			}
+			else {
+				ref_ro_session_unsafe(i_req->ro_session, 1);
+			}
+		}
+	}
+
+	//
+	// if call was forcefully terminated, the lock was released before dlgb.lookup_terminate_dlg() function call.
+	//
+	if (!call_terminated) {
+		unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);//unref from the initial timer that fired this event.
+		ro_session_unlock(ro_session_table, ro_session_entry);
+	}
+
+	shm_free(i_req);
+	LM_DBG("Exiting async ccr interim nicely");
+}
+
+/* this is the function called when a we need to request more funds/credit. We need to try and reserve more credit.
+ * If we cant we need to put a new timer to kill the call at the appropriate time
+ */
+void ro_session_ontimeout(struct ro_tl *tl) {
+	time_t now, used_secs, call_time;
+
+	LM_DBG("We have a fired timer [p=%p] and tl=[%i].\n", tl, tl->timeout);
+
+	/* find the session id for this timer*/
+	struct ro_session_entry *ro_session_entry = NULL;
+	struct ro_session* ro_session = ((struct ro_session*) ((char *) (tl) - (unsigned long) (&((struct ro_session*) 0)->ro_tl)));
+
+	if (!ro_session) {
+		LM_ERR("Can't find a session. This is bad");
+		return;
+	}
+
+	ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
+	ro_session_lock(ro_session_table, ro_session_entry);
+	
+	LM_DBG("event-type=%d", ro_session->event_type);
+	
+//	if (!ro_session->active) {
+//		LM_ALERT("Looks like this session was terminated while requesting more units");
+//		goto exit;
+//		return;
+//	}
+	
+	switch (ro_session->event_type) {
+	case answered:
+		now = time(0);
+		used_secs = now - ro_session->last_event_timestamp;
+		call_time = now - ro_session->start_time;
+
+		update_stat(billed_secs, used_secs);
+
+		if (ro_session->callid.s != NULL
+				&& ro_session->dlg_h_entry	>= 0
+				&& ro_session->dlg_h_id > 0
+				&& ro_session->ro_session_id.s != NULL)
+		{
+			LM_DBG("Found a session to re-apply for timing [%.*s] and user is [%.*s]\n",
+					ro_session->ro_session_id.len,
+					ro_session->ro_session_id.s,
+					ro_session->from_uri.len,
+					ro_session->from_uri.s);
+
+			LM_DBG("Call session has been active for %i seconds. The last reserved secs was [%i] and the last event was [%i seconds] ago",
+					(unsigned int) call_time,
+					(unsigned int) ro_session->reserved_secs,
+					(unsigned int) used_secs);
+
+			LM_DBG("Call session [p=%p]: we will now make a request for another [%i] of credit with a usage of [%i] seconds from the last bundle.\n",
+					ro_session,
+					interim_request_credits/* new reservation request amount */,
+					(unsigned int) used_secs/* charged seconds from previous reservation */);
+
+			// Apply for more credit.
+			//
+			// The function call will return immediately and we will receive the reply asynchronously via a callback
+			send_ccr_interim(ro_session, (unsigned int) used_secs, interim_request_credits);
+			return;
+		}
+		else {
+			LM_ERR("Hmmm, the session we have either doesn't have all the data or something else has gone wrong.\n");
+			/* put the timer back so the call will be killed according to previous timeout. */
+			ro_session->event_type = unknown_error;
+			int ret = insert_ro_timer(&ro_session->ro_tl,
+					ro_session->reserved_secs - used_secs);
+			if (ret != 0) {
+				LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", 
+					ro_session->ro_session_id.len, ro_session->ro_session_id.s); 
+			}
+			else {
+				ref_ro_session_unsafe(ro_session, 1);
+			}
+			LM_ERR("Immediately killing call due to unknown error\n");
+		}
+
+		break;
+	default:
+		LM_ERR("Diameter call session - event [%d]\n", ro_session->event_type);
+
+		if (ro_session->event_type == no_more_credit)
+			LM_INFO("Call/session must be ended - no more funds.\n");
+		else if (ro_session->event_type == unknown_error)
+			LM_ERR("last event caused an error. We will now tear down this session.\n");
+	}
+
+
+	update_stat(killed_calls, 1);
+
+	//unref_ro_session_unsafe(ro_session, 1, ro_session_entry); //unref from the initial timer that fired this event.
+	ro_session_unlock(ro_session_table, ro_session_entry);
+
+	dlgb.lookup_terminate_dlg(ro_session->dlg_h_entry, ro_session->dlg_h_id, NULL);
+	return;
+}
+
diff --git a/modules/ims_charging/ro_timer.h b/modules/ims_charging/ro_timer.h
new file mode 100644
index 0000000..398e0b6
--- /dev/null
+++ b/modules/ims_charging/ro_timer.h
@@ -0,0 +1,93 @@
+/* 
+ * File:   ro_timer.h
+ * Author: Jason Penton
+ *
+ * Created on 06 April 2011, 1:39 PM
+ */
+
+#ifndef RO_TIMER_H
+#define	RO_TIMER_H
+
+#include "../../locking.h"
+#include "../../timer.h"
+
+extern struct interim_ccr *i_req;
+
+/*! ro timeout list */
+struct ro_tl {
+    struct ro_tl *next;
+    struct ro_tl *prev;
+    volatile unsigned int timeout; /*!< timeout in seconds */
+};
+
+/*! ro_session timer */
+struct ro_timer {
+    struct ro_tl first; /*!< ro session timeout list */
+    gen_lock_t *lock; /*!< lock for the list */
+};
+
+/*! ro_session timer handler */
+typedef void (*ro_timer_handler)(struct ro_tl *);
+
+
+/*!
+ * \brief Initialize the ro_session timer handler
+ * Initialize the ro_session timer handler, allocate the lock and a global
+ * timer in shared memory. The global timer handler will be set on success.
+ * \param hdl dialog timer handler
+ * \return 0 on success, -1 on failure
+ */
+int init_ro_timer(ro_timer_handler);
+
+
+/*!
+ * \brief Destroy ro_session dialog timer
+ */
+void destroy_ro_timer(void);
+
+
+/*!
+ * \brief Insert a ro_session timer to the list
+ * \param tl ro_session timer list
+ * \param interval timeout value in seconds
+ * \return 0 on success, -1 when the input timer list is invalid
+ */
+int insert_ro_timer(struct ro_tl *tl, int interval);
+
+
+/*!
+ * \brief Remove a ro_session timer from the list
+ * \param tl ro_session timer that should be removed
+ * \return 1 when the input timer is empty, 0 when the timer was removed,
+ * -1 when the input timer list is invalid
+ */
+int remove_ro_timer(struct ro_tl *tl);
+
+
+/*!
+ * \brief Update a ro_session timer on the list
+ * \param tl ro_session timer
+ * \param timeout new timeout value in seconds
+ * \return 0 on success, -1 when the input list is invalid
+ * \note the update is implemented as a remove, insert
+ */
+int update_ro_timer(struct ro_tl *tl, int timeout);
+
+
+/*!
+ * \brief Timer routine for expiration of ro_session credit reservations
+ * Timer handler for expiration of ro_session credit reservations, runs the global timer handler on them.
+ * \param time for expiration checks on credit reservations
+ * \param attr unused
+ */
+void ro_timer_routine(unsigned int ticks, void * attr);
+
+/* this is the function called when a we need to request more funds/credit. We need to try and reserve more credit.
+ * If we cant we need to put a new timer to kill the call at the appropriate time
+ */
+void ro_session_ontimeout(struct ro_tl *tl);
+
+void resume_ro_session_ontimeout(struct interim_ccr *i_req);
+
+#endif	/* RO_TIMER_H */
+
diff --git a/modules/ims_charging/stats.c b/modules/ims_charging/stats.c
new file mode 100644
index 0000000..93627d8
--- /dev/null
+++ b/modules/ims_charging/stats.c
@@ -0,0 +1,45 @@
+/*
+ * stats.c
+ *
+ *  Created on: Sep 30, 2013
+ *      Author: carlos
+ */
+
+#include "stats.h"
+
+unsigned long get_failed_initial_ccrs() {
+
+	unsigned long success_number = get_stat_val(successful_initial_ccrs),
+		 total_number	= get_stat_val(initial_ccrs);
+
+	return total_number - success_number;
+}
+
+unsigned long get_failed_interim_ccrs() {
+
+	unsigned long success_number = get_stat_val(successful_interim_ccrs),
+		 total_number	= get_stat_val(interim_ccrs);
+
+	return total_number - success_number;
+}
+
+unsigned long get_failed_final_ccrs() {
+
+	unsigned long success_number = get_stat_val(successful_final_ccrs),
+		 total_number	= get_stat_val(final_ccrs);
+
+	return total_number - success_number;
+}
+
+unsigned long get_ccr_avg_response_time() {
+
+	unsigned long responses_time = get_stat_val(ccr_responses_time),
+				  ccrs	= get_stat_val(initial_ccrs)
+				  	  	  + get_stat_val(interim_ccrs)
+				  	  	  + get_stat_val(final_ccrs);
+
+	if (responses_time == 0 || ccrs == 0)
+		return 0;
+
+	return responses_time / ccrs;
+}
diff --git a/modules/ims_charging/stats.h b/modules/ims_charging/stats.h
new file mode 100644
index 0000000..9b0e3fc
--- /dev/null
+++ b/modules/ims_charging/stats.h
@@ -0,0 +1,29 @@
+/*
+ * stats.h
+ *
+ *  Created on: Sep 30, 2013
+ *      Author: carlos
+ */
+
+#ifndef STATS_H_
+#define STATS_H_
+
+#include "../../lib/kcore/statistics.h"
+
+extern stat_var *initial_ccrs;
+extern stat_var *interim_ccrs;
+extern stat_var *final_ccrs;
+extern stat_var *successful_initial_ccrs;
+extern stat_var *successful_interim_ccrs;
+extern stat_var *successful_final_ccrs;
+extern stat_var *ccr_responses_time;
+extern stat_var *billed_secs;
+extern stat_var *killed_calls;
+extern stat_var *ccr_timeouts;
+
+unsigned long get_failed_initial_ccrs();
+unsigned long get_failed_interim_ccrs();
+unsigned long get_failed_final_ccrs();
+unsigned long get_ccr_avg_response_time();
+
+#endif /* STATS_H_ */
diff --git a/modules/ims_icscf/cxdx_lir.h b/modules/ims_icscf/cxdx_lir.h
index 6e43923..6389d46 100644
--- a/modules/ims_icscf/cxdx_lir.h
+++ b/modules/ims_icscf/cxdx_lir.h
@@ -57,11 +57,6 @@ extern str cxdx_dest_realm;
 struct sip_msg;
 
 
-typedef struct lir_param {
-	int type;
-	cfg_action_t *paction;
-} lir_param_t;
-
 typedef struct saved_lir_transaction {
 	unsigned int tindex;
 	unsigned int tlabel;
diff --git a/modules/ims_icscf/cxdx_uar.h b/modules/ims_icscf/cxdx_uar.h
index c2f20f4..1a00557 100644
--- a/modules/ims_icscf/cxdx_uar.h
+++ b/modules/ims_icscf/cxdx_uar.h
@@ -52,12 +52,6 @@ extern struct cdp_binds cdpb; /**< Structure with pointers to cdp funcs 		*/
 extern str cxdx_forced_peer; /**< FQDN of the Diameter peer to send requests to */
 extern str cxdx_dest_realm;
 
-typedef struct uar_param {
-	int type;
-	gparam_t *ivalue;
-	cfg_action_t *paction;
-} uar_param_t;
-
 typedef struct saved_transaction {
 	unsigned int tindex;
 	unsigned int tlabel;
diff --git a/modules/ims_icscf/db.c b/modules/ims_icscf/db.c
index 343d92d..05c81ad 100644
--- a/modules/ims_icscf/db.c
+++ b/modules/ims_icscf/db.c
@@ -343,7 +343,7 @@ int ims_icscf_db_get_capabilities(scscf_capabilities *cap[],int cap_cnt)
 	}
 
 	if (res->n == 0) {
-		LM_DBG("DBG:ims_icscf_db_get_capabilities: No Capabilites found... not critical...\n");
+		LM_DBG("DBG:ims_icscf_db_get_capabilities: No Capabilities found... not critical...\n");
 		return 1;
 	}
 	else {
diff --git a/modules/ims_icscf/doc/ims_icscf_admin.xml b/modules/ims_icscf/doc/ims_icscf_admin.xml
index fdb0b98..aa5573d 100644
--- a/modules/ims_icscf/doc/ims_icscf_admin.xml
+++ b/modules/ims_icscf/doc/ims_icscf_admin.xml
@@ -189,7 +189,7 @@ if (I_scscf_select("0")) {
      t_relay();
 }
 ...
-</programlisting>
+        </programlisting>
       </example>
     </section>
 
@@ -215,7 +215,7 @@ I_scscf_drop();
 
     <section>
       <title><function
-      moreinfo="none">I_perform_user_authorization_request(capabalities)</function></title>
+      moreinfo="none">I_perform_user_authorization_request(route_block, capabalities)</function></title>
 
       <para>Perform a UAR on Diameter CXDX interface. This function will build
       a list of SCSCFs to be used and populate the SCSCF list for the request.
@@ -224,6 +224,9 @@ I_scscf_drop();
 
       <itemizedlist>
         <listitem>
+          <para>Route block to resume after async UAR Diameter reply.</para>
+        </listitem>
+        <listitem>
           <para>capabilities - whether to request capabilities or not "1" -
           with capabilities, "0" - no capabilities.</para>
         </listitem>
@@ -239,58 +242,98 @@ I_scscf_drop();
 
         <programlisting format="linespecific">
 ...
-            I_perform_user_authorization_request("0"); #0=REG/DEREG; 1=REG+Capabilities
-            #this is async so to know status we have to check the reply avp
-            switch ($avp(s:uaa_return_code)){
-                case 1: #success
+I_perform_user_authorization_request("REG_UAR_REPLY","0"); #0=REG/DEREG; 1=REG+Capabilities
+exit;
+...
+route[REG_UAR_REPLY]
+{
+    #this is async so to know status we have to check the reply avp
+    switch ($avp(s:uaa_return_code)){
+            case 1: #success
                     if (I_scscf_select("0")){
-                        t_on_failure("register_failure");
-                        t_on_reply("register_reply");
-                        if (!t_relay()) {
-                            t_reply("500", "Error forwarding to SCSCF");
-                        }
+                            t_on_failure("register_failure");
+                            t_on_reply("register_reply");
+                            #now relay to appropriate SCSCF
+                            if (!t_relay()) {
+                                    t_reply("500", "Error forwarding to SCSCF");
+                            }
                     } else {#select failed
-                        I_scscf_drop();
-                        t_reply("500", "Server error on SCSCF Select (UAR)");
-                    }
+                            I_scscf_drop();
+                            t_reply("500", "Server error on SCSCF Select (UAR)");
+                    }       
+                    break;          
+            case -1: #failure
+                    xlog("L_ERR", "UAR failure - error response sent from module\n");
                     break;
-                case -1: #failure
-                    xlog("L_ERR", "UAR failure - error response sent from module");
-                    break;
-                case -2: #error
-                    xlog("L_ERR", "UAR error - sending error response now");
+            case -2: #error
+                    xlog("L_ERR", "UAR error - sending error response now\n");
                     t_reply("500", "UAR failed");
                     break;
-                default:
-                    xlog("L_ERR", "Unknown return code from UAR, value is [$avp(s:uaa_return_code)]");
-                    t_reply("500", "Unknown response code from UAR"); 
+            default:
+                    xlog("L_ERR", "Unknown return code from UAR, value is [$avp(s:uaa_return_code)]\n");
+                    t_reply("500", "Unknown response code from UAR");
                     break;
-            }
-...
-</programlisting>
+    }
+}
+...          
+        </programlisting>
       </example>
     </section>
 
     <section>
       <title><function
-      moreinfo="none">I_perform_location_information_request()</function></title>
+      moreinfo="none">I_perform_location_information_request(route_block)</function></title>
+
+      <para>Perform a LIR on Diameter CXDX interface.</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>Route block to resume after async LIR Diameter reply.</para>
+        </listitem>
+      </itemizedlist>
 
       <para>This function can be used from REQUEST_ROUTE.</para>
 
+      <para>p.s. this is executed asynchronously. See example on how to
+      retrieve return value</para>
+
       <example>
-        <title>proxy_authorize usage</title>
+        <title>I_perform_location_information_request()</title>
 
         <programlisting format="linespecific">
 ...
-if (!proxy_authorize("$fd", "subscriber)) {
-proxy_challenge("$fd", "1");  # Realm will be autogenerated
-};
+I_perform_location_information_request("SESSION_LIR_REPLY","0");
+exit;
 ...
-</programlisting>
+route[SESSION_LIR_REPLY]
+{
+    if ($avp(lia_return_code) == 1) {
+            if (I_scscf_select("0")) {
+                    append_branch();
+                    t_on_reply("initial_request_reply");
+                    t_on_failure("initial_request_failure");
+                    if (!t_relay()) {
+                            t_reply("500","Error forwarding towards S-CSCF");
+                            break;
+                    }
+                    break;
+            } else {
+                    xlog("L_DBG", "dropping scscf list on initial request\n");
+                    I_scscf_drop();
+                    t_reply("500", "Server error on LIR select S-CSCF");
+                    break;
+            }
+    } else {
+            t_reply("500", "Server error on LIR");
+            break;
+    }
+    break;
+}
+...          
+        </programlisting>
       </example>
     </section>
   </section>
-
   <section>
     <title>Statistics</title>
 
diff --git a/modules/ims_icscf/location.c b/modules/ims_icscf/location.c
index 92d50cb..3d0f09a 100644
--- a/modules/ims_icscf/location.c
+++ b/modules/ims_icscf/location.c
@@ -45,6 +45,7 @@
 
 #include "location.h"
 #include "../../action.h" /* run_actions */
+#include "../../mod_fix.h"
 #include "cxdx_lir.h"
 
 extern int route_lir_user_unknown_no; 
@@ -54,17 +55,33 @@ extern int route_lir_user_unknown_no;
  * @param msg - sip message
  * @returns 1 on success or 0 on failure
  */
-int I_perform_location_information_request(struct sip_msg* msg, char* str1, char* str2) {
+int I_perform_location_information_request(struct sip_msg* msg, char* route, char* str1, char* str2) {
     str public_identity = {0, 0};
     int orig = 0;
     
     tm_cell_t *t = 0;
     saved_lir_transaction_t* saved_t;
     
+    str route_name;
+    
      cfg_action_t* cfg_action;
 
-    lir_param_t* ap = (lir_param_t*) str1;
-    cfg_action = ap->paction->next;
+     if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
     
     LM_DBG("DBG:I_LIR: Starting ...\n");
     /* check if we received what we should */
diff --git a/modules/ims_icscf/location.h b/modules/ims_icscf/location.h
index 8ccc7bc..eccd734 100644
--- a/modules/ims_icscf/location.h
+++ b/modules/ims_icscf/location.h
@@ -60,7 +60,7 @@ extern struct cdp_binds cdpb;//cdp binds functions
  * @param msg - sip message
  * @returns 1 on success or 0 on failure
  */
-int I_perform_location_information_request(struct sip_msg* msg, char* str1, char* str2);
+int I_perform_location_information_request(struct sip_msg* msg, char* route, char* str1, char* str2);
 
 
 #endif
diff --git a/modules/ims_icscf/mod.c b/modules/ims_icscf/mod.c
index 6066741..f9d0fe8 100644
--- a/modules/ims_icscf/mod.c
+++ b/modules/ims_icscf/mod.c
@@ -106,8 +106,8 @@ static int fixup_uar(void** param, int param_no);
 static int fixup_lir(void** param, int param_no);
 
 static cmd_export_t cmds[] = {
-    {"I_perform_user_authorization_request", (cmd_function) I_perform_user_authorization_request, 1, fixup_uar, 0, REQUEST_ROUTE},
-    {"I_perform_location_information_request", (cmd_function) I_perform_location_information_request, 1, fixup_lir, 0, REQUEST_ROUTE},
+    {"I_perform_user_authorization_request", (cmd_function) I_perform_user_authorization_request, 2, fixup_uar, 0, REQUEST_ROUTE},
+    {"I_perform_location_information_request", (cmd_function) I_perform_location_information_request, 2, fixup_lir, 0, REQUEST_ROUTE},
     {"I_scscf_select", (cmd_function) I_scscf_select, 1, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
     {"I_scscf_drop", (cmd_function) I_scscf_drop, 0, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
     { 0, 0, 0, 0, 0, 0}
@@ -274,38 +274,35 @@ static int mod_init(void) {
 
 static int fixup_uar(void** param, int param_no)
 {
-	uar_param_t *ap;
-	if(param_no!=1)
-		return 0;
-	ap = (uar_param_t*)pkg_malloc(sizeof(uar_param_t));
-	if(ap==NULL)
-	{
-		LM_ERR("no more pkg\n");
-		return -1;
-	}
-	memset(ap, 0, sizeof(uar_param_t));
-	ap->paction = get_action_from_param(param, param_no);
-	if(fixup_igp_null(param, param_no)<0)
-		return -1;
-	ap->ivalue = (gparam_t*)(*param);
-	*param = (void*)ap;
-	return 0;
+    if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+    }
+
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0){
+            LM_ERR("fixup spve failed on %d\n", param_no);
+            return -1;
+        }
+        return 0;
+    }
+    return 0;
+    
 }
 
 static int fixup_lir(void** param, int param_no)
 {
-	lir_param_t *ap;
-	if(param_no!=1)
-		return 0;
-	ap = (lir_param_t*)pkg_malloc(sizeof(lir_param_t));
-	if(ap==NULL)
-	{
-		LM_ERR("no more pkg\n");
-		return -1;
-	}
-	memset(ap, 0, sizeof(lir_param_t));
-	ap->paction = get_action_from_param(param, param_no);
-	*param = (void*)ap;
-	return 0;
+	if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+        }
+
+        if (param_no == 1) {        //route name - static or dynamic string (config vars)
+            if (fixup_spve_null(param, param_no) < 0)
+                return -1;
+            return 0;
+        } 
+        return 0;
+    
 }
 
diff --git a/modules/ims_icscf/registration.c b/modules/ims_icscf/registration.c
index 6a6fe57..9412511 100644
--- a/modules/ims_icscf/registration.c
+++ b/modules/ims_icscf/registration.c
@@ -46,6 +46,7 @@
 
 #include "registration.h"
 #include "../../action.h" /* run_actions */
+#include "../../mod_fix.h"
 #include "cxdx_uar.h"
 
 extern int route_uar_user_unknown_no;
@@ -54,11 +55,9 @@ extern int route_uar_user_unknown_no;
  * Perform User Authorization Request.
  * creates and send the user authorization query
  * @param msg - the SIP message
- * @param str1 - the realm
- * @param str2 - if to do capabilities
  * @returns true if OK, false if not
  */
-int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2) {
+int I_perform_user_authorization_request(struct sip_msg* msg, char* route, char* str1, char* str2) {
     str private_identity, public_identity, visited_network_id;
     int authorization_type = AVP_IMS_UAR_REGISTRATION;
     int expires = 3600;
@@ -72,13 +71,30 @@ int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char*
     tm_cell_t *t = 0;
     int intvalue_param;
     cfg_action_t* cfg_action;
+    
+    str route_name;
 
-    uar_param_t* ap = (uar_param_t*) str1;
-    if (fixup_get_ivalue(msg, ap->ivalue, &intvalue_param) != 0) {
+    if (fixup_get_ivalue(msg, (gparam_t*) str1, &intvalue_param) != 0) {
         LM_ERR("no int value param passed\n");
         return CSCF_RETURN_ERROR;
     }
-    cfg_action = ap->paction->next;
+    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+
 
     realm = cscf_get_realm_from_ruri(msg);
 
diff --git a/modules/ims_icscf/registration.h b/modules/ims_icscf/registration.h
index 6cf52cd..b7ebbc6 100644
--- a/modules/ims_icscf/registration.h
+++ b/modules/ims_icscf/registration.h
@@ -61,7 +61,7 @@ extern struct cdp_binds cdpb;
  * @param str2 - if to do capabilities
  * @returns true if OK, false if not
  */
-int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2);
+int I_perform_user_authorization_request(struct sip_msg* msg, char* route, char* str1, char* str2);
 
 
 
diff --git a/modules/ims_icscf/scscf_list.c b/modules/ims_icscf/scscf_list.c
index 8b6b79c..c65a963 100644
--- a/modules/ims_icscf/scscf_list.c
+++ b/modules/ims_icscf/scscf_list.c
@@ -384,7 +384,7 @@ int I_scscf_select(struct sip_msg* msg, char* str1, char* str2) {
         } else {
             /* subsequent */
             req = msg;
-            append_branch(req, &scscf_name, 0, 0, Q_UNSPECIFIED, 0, 0, 0, 0);
+            append_branch(req, &scscf_name, 0, 0, Q_UNSPECIFIED, 0, 0, 0, 0, 0, 0);
             result = CSCF_RETURN_TRUE;
         }
     } else {
diff --git a/modules/ims_isc/doc/ims_isc_admin.xml b/modules/ims_isc/doc/ims_isc_admin.xml
index adc6f5e..33dac0a 100644
--- a/modules/ims_isc/doc/ims_isc_admin.xml
+++ b/modules/ims_isc/doc/ims_isc_admin.xml
@@ -126,6 +126,26 @@ modparam("ims_isc", "isc_fr_inv_timeout", 20000)
         </programlisting>
       </example>
     </section>
+
+    <section>
+      <title><varname>add_p_served_user</varname> (integer)</title>
+
+      <para>This boolean indicates if a P-Served-User should be added on the ISC
+      interface, according to RFC 5502.</para>
+
+      <para><emphasis> Default value is 0 (false)</emphasis></para>
+
+      <example>
+        <title><varname>add_p_served_user</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("ims_isc", "add_p_served_user", 1)
+# p-served user header will be enabled
+...
+        </programlisting>
+      </example>
+    </section>
     </section>
 
     <section>
diff --git a/modules/ims_isc/isc.c b/modules/ims_isc/isc.c
index f6d02d1..ea9428e 100644
--- a/modules/ims_isc/isc.c
+++ b/modules/ims_isc/isc.c
@@ -76,7 +76,7 @@ int isc_forward(struct sip_msg *msg, isc_match *m, isc_mark *mark) {
 
 	/* append branch if last trigger failed */
 	if (is_route_type(FAILURE_ROUTE))
-		append_branch(msg, &(msg->first_line.u.request.uri), &(msg->dst_uri), 0, Q_UNSPECIFIED, 0, 0, 0, 0);
+		append_branch(msg, &(msg->first_line.u.request.uri), &(msg->dst_uri), 0, Q_UNSPECIFIED, 0, 0, 0, 0, 0, 0);
 
 	// Determines the tm transaction identifiers.
 	// If no transaction, then creates one
diff --git a/modules/ims_isc/mark.c b/modules/ims_isc/mark.c
index a1a73e4..470a20d 100644
--- a/modules/ims_isc/mark.c
+++ b/modules/ims_isc/mark.c
@@ -44,6 +44,16 @@
  */
 
 #include "mark.h"
+#include "../../str.h"
+#include "../../data_lump.h"
+
+const str psu_hdr_s = str_init("P-Served-User: <%.*s>;sescase=%.*s;regstate=%.*s\r\n");
+const str sescase_orig = str_init("orig");
+const str sescase_term = str_init("term");
+const str regstate_reg = str_init("reg");
+const str regstate_unreg = str_init("unreg");
+
+extern int add_p_served_user;
 
 /** base16 char constants */
 char *hexchars = "0123456789abcdef";
@@ -155,7 +165,7 @@ void isc_mark_get(str x, isc_mark *mark) {
 				}
 				break;
 			default:
-				LM_ERR("isc_mark_get: unkown parameter found: %c !\n", x.s[i]);
+				LM_ERR("isc_mark_get: unknown parameter found: %c !\n", x.s[i]);
 			}
 			i = j + 1;
 		} else
@@ -243,6 +253,9 @@ int isc_mark_set(struct sip_msg *msg, isc_match *match, isc_mark *mark) {
 	if (match)
 		as = match->server_name;
 	isc_mark_write_route(msg, &as, &route);
+	if (add_p_served_user) {
+	    isc_mark_write_psu(msg, mark);
+	}
 	LM_DBG("isc_mark_set: NEW mark <%s>\n", chr_mark);
 
 	return 1;
@@ -291,3 +304,60 @@ inline int isc_mark_write_route(struct sip_msg *msg, str *as, str *iscmark) {
 	return 1;
 }
 
+/**
+ *  Inserts the P-Served-User header on a SIP message
+ *  as specified in RFC 5502
+ *  @param msg - SIP message
+ *  @param mark - the mark containing all required information
+ *  @returns 1 on success, else 0
+ */
+int isc_mark_write_psu(struct sip_msg *msg, isc_mark *mark) {
+    struct lump *l = msg->add_rm;
+    int hlen;
+    char * hstr = NULL;
+    const str *regstate, *sescase;
+
+    switch(mark->direction) {
+    case IFC_ORIGINATING_SESSION:
+        regstate = &regstate_reg;
+        sescase = &sescase_orig;
+        break;
+    case IFC_TERMINATING_SESSION:
+        regstate = &regstate_reg;
+        sescase = &sescase_term;
+        break;
+    case IFC_TERMINATING_UNREGISTERED:
+        regstate = &regstate_unreg;
+        sescase = &sescase_term;
+        break;
+    default:
+        LM_ERR("isc_mark_write_psu: unknown direction: %d\n", mark->direction);
+        return 0;
+    }
+
+    hlen = psu_hdr_s.len - /* 3 "%.*s" */ 12 + mark->aor.len + regstate->len + sescase->len + 1;
+    hstr = pkg_malloc(hlen);
+    if (hstr == NULL) {
+        LM_ERR("isc_mark_write_psu: could not allocate %zu bytes\n", hlen);
+        return 0;
+    }
+
+    int ret = snprintf(hstr, hlen, psu_hdr_s.s,
+            mark->aor.len, mark->aor.s,
+            sescase->len, sescase->s,
+            regstate->len, regstate->s);
+    if (ret >= hlen) {
+        LM_ERR("isc_mark_write_psu: invalid string buffer size: %zu, required: %d\n", hlen, ret);
+        pkg_free(hstr);
+        return 0;
+    }
+
+    LM_DBG("isc_mark_write_psu: %.*s\n", (int)hlen - 3 /* don't print \r\n\0 */, hstr);
+    if (append_new_lump(&l, hstr, hlen - 1, HDR_OTHER_T) == 0) {
+        LM_ERR("isc_mark_write_psu: append_new_lump(%p, \"%.*s\\\r\\n\", %zu, 0) failed\n", &l, (int)hlen - 3 /* don't print \r\n\0 */, hstr, hlen - 1);
+        pkg_free(hstr);
+        return 0;
+    }
+    /* hstr will be deallocated when msg will be destroyed */
+    return 1;
+}
diff --git a/modules/ims_isc/mark.h b/modules/ims_isc/mark.h
index e6912f3..9121eaa 100644
--- a/modules/ims_isc/mark.h
+++ b/modules/ims_isc/mark.h
@@ -76,6 +76,7 @@ int base16_to_bin(char *from,int len, char *to);
 inline int isc_mark_drop_route(struct sip_msg *msg);
 int isc_mark_set(struct sip_msg *msg, isc_match *match, isc_mark *mark);
 inline int isc_mark_write_route(struct sip_msg *msg,str *as,str *iscmark);
+int isc_mark_write_psu(struct sip_msg *msg, isc_mark *mark);
 int bin_to_base16(char *from,int len, char *to);
 
 #endif
diff --git a/modules/ims_isc/mod.c b/modules/ims_isc/mod.c
index 3b69bbd..5c54453 100644
--- a/modules/ims_isc/mod.c
+++ b/modules/ims_isc/mod.c
@@ -62,6 +62,7 @@ str isc_my_uri_sip = {0, 0}; /**< Uri of myself to loop the message in str with
 int isc_expires_grace = 120; /**< expires value to add to the expires in the 3rd party register*/
 int isc_fr_timeout = 5000; /**< default ISC response timeout in ms */
 int isc_fr_inv_timeout = 20000; /**< default ISC invite response timeout in ms */
+int add_p_served_user = 0; /**< should the P-Served-User header be inserted? */
 
 /** module functions */
 static int mod_init(void);
@@ -92,6 +93,7 @@ static param_export_t params[] = {
  	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 consider it dead. Has to be lower than SIP transaction timeout
  	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 to prevent downstream timeouts. Not too small though because
  	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 AS are usually slow as hell... */
+    { "add_p_served_user", INT_PARAM, &add_p_served_user}, /**< boolean indicating if the P-Served-User (RFC5502) should be added on the ISC interface or not */
     { 0, 0, 0}
 };
 
diff --git a/modules/ims_qos/cdpeventprocessor.c b/modules/ims_qos/cdpeventprocessor.c
index 3a70ba2..8cb8751 100644
--- a/modules/ims_qos/cdpeventprocessor.c
+++ b/modules/ims_qos/cdpeventprocessor.c
@@ -200,40 +200,37 @@ void cdp_cb_event_process() {
         switch (ev->event) {
             case AUTH_EV_SESSION_TIMEOUT:
             case AUTH_EV_SESSION_GRACE_TIMEOUT:
-            case AUTH_EV_SESSION_LIFETIME_TIMEOUT:
-                LM_DBG("Rx CDP Session: AUTH EV SESSION TIMEOUT or GRACE TIMEOUT or LIFE TIMEOUT\n");
+            case AUTH_EV_RECV_ASR:
+                LM_DBG("Received notification of ASR from transport plane or CDP timeout for CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                        " and domain [%.*s]\n",
+                        rx_session_id->len, rx_session_id->s,
+                        p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                        p_session_data->domain.len, p_session_data->domain.s);
+
 
                 if (p_session_data->subscribed_to_signaling_path_status) {
-                    LM_DBG("Received notification of CDP timeout of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a subscription to signalling bearer session");
+                    //nothing to do here - just wait for AUTH_EV_SERVICE_TERMINATED event
                 } else {
-                    LM_DBG("Received notification of CDP timeout of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a media bearer session session");
+                    //this is a media bearer session that was terminated from the transport plane - we need to terminate the associated dialog
+                    //so we set p_session_data->must_terminate_dialog to 1 and when we receive AUTH_EV_SERVICE_TERMINATED event we will terminate the dialog
+                    p_session_data->must_terminate_dialog = 1;
                 }
                 break;
 
             case AUTH_EV_SERVICE_TERMINATED:
-                LM_DBG("Rx CDP Session: Service terminated\n");
-                
+                LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                        " and domain [%.*s]\n",
+                        rx_session_id->len, rx_session_id->s,
+                        p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                        p_session_data->domain.len, p_session_data->domain.s);
+
                 if (p_session_data->subscribed_to_signaling_path_status) {
-                    LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a subscription to signalling bearer session");
-                    
                     //instead of removing the contact from usrloc_pcscf we just change the state of the contact to TERMINATE_PENDING_NOTIFY
                     //pcscf_registrar sees this, sends a SIP PUBLISH and on SIP NOTIFY the contact is deleted
-                    
+
                     if (ul.register_udomain(p_session_data->domain.s, &domain)
                             < 0) {
                         LM_DBG("Unable to register usrloc domain....aborting\n");
@@ -251,21 +248,21 @@ void cdp_cb_event_process() {
                     }
                     ul.unlock_udomain(domain, &p_session_data->registration_aor);
                 } else {
-                    LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a media bearer session session");
-                    LM_DBG("Terminating dialog with callid, ftag, ttag: [%.*s], [%.*s], [%.*s]\n",
-                            p_session_data->callid.len, p_session_data->callid.s,
-                            p_session_data->ftag.len, p_session_data->ftag.s,
-                            p_session_data->ttag.len, p_session_data->ttag.s);
-                    dlgb.terminate_dlg(&p_session_data->callid,
-                            &p_session_data->ftag, &p_session_data->ttag, NULL,
-                            &release_reason);
+                    
+                    //we only terminate the dialog if this was triggered from the transport plane or timeout - i.e. if must_terminate_dialog is set
+                    //if this was triggered from the signalling plane (i.e. someone hanging up) then we don'y need to terminate the dialog
+                    if (p_session_data->must_terminate_dialog) {
+                        LM_DBG("Terminating dialog with callid, ftag, ttag: [%.*s], [%.*s], [%.*s]\n",
+                                p_session_data->callid.len, p_session_data->callid.s,
+                                p_session_data->ftag.len, p_session_data->ftag.s,
+                                p_session_data->ttag.len, p_session_data->ttag.s);
+                        dlgb.terminate_dlg(&p_session_data->callid,
+                                &p_session_data->ftag, &p_session_data->ttag, NULL,
+                                &release_reason);
+                    }
                 }
-                
+
                 //free callback data
                 if (p_session_data) {
                     shm_free(p_session_data);
diff --git a/modules/ims_qos/doc/ims_qos_admin.xml b/modules/ims_qos/doc/ims_qos_admin.xml
index 1770bb8..913d558 100644
--- a/modules/ims_qos/doc/ims_qos_admin.xml
+++ b/modules/ims_qos/doc/ims_qos_admin.xml
@@ -193,7 +193,7 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
     <section>
       <title><function
-      moreinfo="none">Rx_AAR_Register(domain)</function></title>
+      moreinfo="none">Rx_AAR_Register(route_block, domain)</function></title>
 
       <para>Perform a AAR on Diameter RX interface to subscribe to signalling 
       status. This purpose of this is tell a Diameter server (typically a PCRF)
@@ -205,6 +205,9 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
       <itemizedlist>
         <listitem>
+          <para>Route block to resume after async UAR Diameter reply.</para>
+        </listitem>
+        <listitem>
           <para><emphasis>domain</emphasis> that usrloc_pcscf uses to store 
           user information.</para>
         </listitem>
@@ -220,8 +223,12 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
         <programlisting format="linespecific">
 ...
-    Rx_AAR_Register("location");
-    
+if(Rx_AAR_Register("REG_AAR_REPLY","location")==0){
+    exit;
+}
+...
+route[REG_AAR_REPLY]
+{
     switch ($avp(s:aar_return_code)) {
         case 1:
             xlog("L_DBG", "Diameter: AAR success on subscription to signalling\n");
@@ -231,7 +238,6 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
             t_reply("403", "Can't register to QoS for signalling");
             exit;
     }
-
 ...
 </programlisting>
       </example>
@@ -239,7 +245,7 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
     
     <section>
       <title><function
-      moreinfo="none">Rx_AAR(domain)</function></title>
+      moreinfo="none">Rx_AAR(route_block, direction)</function></title>
 
       <para>Perform a AAR on Diameter RX interface to request resource 
       authorisation from a Diameter server (typically a PCRF). For more details 
@@ -249,8 +255,11 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
       <itemizedlist>
         <listitem>
-          <para><emphasis>domain</emphasis> that usrloc_pcscf uses to store 
-          user information.</para>
+          <para>Route block to resume after async UAR Diameter reply.</para>
+        </listitem>
+        <listitem>
+          <para><emphasis>direction</emphasis>the direction of this message - 
+          orig, term, etc.</para>
         </listitem>
       </itemizedlist>
 
@@ -264,18 +273,19 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
         <programlisting format="linespecific">
 ...
-    Rx_AAR("location");
-    
-    switch ($avp(s:aar_return_code)) {
-        case 1:
-            xlog("L_DBG", "Diameter: AAR success\n");
-            break;
-        default:
-            xlog("L_ERR", "Diameter: AAR failed\n");
-            t_reply("403", "QoS not authorized");
-            exit;
-    }
-
+if(Rx_AAR("ORIG_SESSION_AAR_REPLY","orig")==0){
+    exit;
+}
+...
+route[ORIGN_SESSION_AAR_REPLY]
+{
+    if ($avp(s:aar_return_code) != 1) {
+        xlog("L_ERR", "IMS: AAR failed Orig\n");
+        dlg_terminate("all", "Sorry no QoS available");
+    } else {
+        xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n");
+    } 
+}
 ...
 </programlisting>
       </example>
diff --git a/modules/ims_qos/mod.c b/modules/ims_qos/mod.c
index c6aea4b..16d522e 100644
--- a/modules/ims_qos/mod.c
+++ b/modules/ims_qos/mod.c
@@ -75,7 +75,7 @@
 
 MODULE_VERSION
 
-extern gen_lock_t* process_lock; /* lock on the process table */
+        extern gen_lock_t* process_lock; /* lock on the process table */
 
 str orig_session_key = {"originating", 11};
 str term_session_key = {"terminating", 11};
@@ -101,8 +101,7 @@ static int mod_child_init(int);
 static void mod_destroy(void);
 
 static int fixup_aar_register(void** param, int param_no);
-
-static void free_dialog_data(void *data);
+static int fixup_aar(void** param, int param_no);
 
 int * callback_singleton; /*< Callback singleton */
 
@@ -114,12 +113,12 @@ char* rx_forced_peer_s = "";
 str rx_forced_peer;
 
 /* commands wrappers and fixups */
-static int w_rx_aar(struct sip_msg *msg, char* direction, char *bar);
-static int w_rx_aar_register(struct sip_msg *msg, char* str1, char *bar);
+static int w_rx_aar(struct sip_msg *msg, char *route, char* direction, char *bar);
+static int w_rx_aar_register(struct sip_msg *msg, char *route, char* str1, char *bar);
 
 static cmd_export_t cmds[] = {
-    { "Rx_AAR", (cmd_function) w_rx_aar, 1, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE},
-    { "Rx_AAR_Register", (cmd_function) w_rx_aar_register, 1, fixup_aar_register, 0, REQUEST_ROUTE},
+    { "Rx_AAR", (cmd_function) w_rx_aar, 2, fixup_aar, 0, REQUEST_ROUTE | ONREPLY_ROUTE},
+    { "Rx_AAR_Register", (cmd_function) w_rx_aar_register, 2, fixup_aar_register, 0, REQUEST_ROUTE},
     { 0, 0, 0, 0, 0, 0}
 };
 
@@ -134,9 +133,9 @@ static param_export_t params[] = {
 };
 
 stat_export_t mod_stats[] = {
-	{"aar_avg_response_time" ,  STAT_IS_FUNC, 	(stat_var**)get_avg_aar_response_time	},
-	{"aar_timeouts" ,  			0, 				(stat_var**)&stat_aar_timeouts  		},
-	{0,0,0}
+    {"aar_avg_response_time", STAT_IS_FUNC, (stat_var**) get_avg_aar_response_time},
+    {"aar_timeouts", 0, (stat_var**) & stat_aar_timeouts},
+    {0, 0, 0}
 };
 
 /** module exports */
@@ -156,7 +155,7 @@ int fix_parameters() {
     rx_forced_peer.s = rx_forced_peer_s;
     rx_forced_peer.len = strlen(rx_forced_peer_s);
 
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 }
 
 /**
@@ -169,16 +168,16 @@ static int mod_init(void) {
         goto error;
 
 #ifdef STATISTICS
-	/* register statistics */
-	if (register_module_stats( exports.name, mod_stats)!=0 ) {
-		LM_ERR("failed to register core statistics\n");
-		goto error;
-	}
-
-	if (!register_stats()){
-		LM_ERR("Unable to register statistics\n");
-		goto error;
-	}
+    /* register statistics */
+    if (register_module_stats(exports.name, mod_stats) != 0) {
+        LM_ERR("failed to register core statistics\n");
+        goto error;
+    }
+
+    if (!register_stats()) {
+        LM_ERR("Unable to register statistics\n");
+        goto error;
+    }
 #endif
 
     callback_singleton = shm_malloc(sizeof (int));
@@ -216,12 +215,12 @@ static int mod_init(void) {
     bind_usrloc = (bind_usrloc_t) find_export("ul_bind_ims_usrloc_pcscf", 1, 0);
     if (!bind_usrloc) {
         LM_ERR("can't bind usrloc_pcscf\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     if (bind_usrloc(&ul) < 0) {
         LM_ERR("can't bind to usrloc pcscf\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
     LM_DBG("Successfully bound to PCSCF Usrloc module\n");
 
@@ -236,7 +235,7 @@ static int mod_init(void) {
     return 0;
 error:
     LM_ERR("Failed to initialise ims_qos module\n");
-    return RX_RETURN_FALSE;
+    return CSCF_RETURN_FALSE;
 }
 
 /**
@@ -294,7 +293,7 @@ void callback_for_cdp_session(int event, void *session) {
     //only put the events we care about on the event stack
     if (event == AUTH_EV_SESSION_TIMEOUT ||
             event == AUTH_EV_SESSION_GRACE_TIMEOUT ||
-            event == AUTH_EV_SESSION_LIFETIME_TIMEOUT ||
+            event == AUTH_EV_RECV_ASR ||
             event == AUTH_EV_SERVICE_TERMINATED) {
 
         LOG(L_DBG, "callback_for_cdp session(): called with event %d and session id [%.*s]\n", event, rx_session_id->len, rx_session_id->s);
@@ -349,19 +348,6 @@ AAAMessage* callback_cdp_request(AAAMessage *request, void *param) {
     return 0;
 }
 
-static void free_dialog_data(void *data) {
-    str *rx_session_id = (str*) data;
-    if (rx_session_id) {
-        if (rx_session_id->s) {
-            shm_free(rx_session_id->s);
-            rx_session_id->s = 0;
-        }
-        shm_free(rx_session_id);
-        rx_session_id = 0;
-    }
-
-}
-
 void callback_dialog_terminated(struct dlg_cell* dlg, int type, struct dlg_cb_params * params) {
     LM_DBG("Dialog has ended - we need to terminate Rx bearer session\n");
 
@@ -405,28 +391,56 @@ void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param) {
 /* Wrapper to send AAR from config file - this only allows for AAR for calls - not register, which uses r_rx_aar_register
  * return: 1 - success, <=0 failure. 2 - message not a AAR generating message (ie proceed without PCC if you wish)
  */
-static int w_rx_aar(struct sip_msg *msg, char* direction, char* bar) {
+static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
+
+    int ret = CSCF_RETURN_ERROR;
     struct cell *t;
-    AAAMessage* resp;
+
     AAASession* auth_session;
     rx_authsessiondata_t* rx_authdata_p = 0;
-    unsigned int result = AAA_SUCCESS;
     str *rx_session_id;
     str callid = {0, 0};
     str ftag = {0, 0};
     str ttag = {0, 0};
+    
+    str route_name;
+
+    cfg_action_t* cfg_action = 0;
+    saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
+    char* direction = str1;
+    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+
+    LM_DBG("Rx AAR called\n");
+    //create the default return code AVP
+    create_return_code(ret);
 
     //We don't ever do AAR on request for calling scenario...
     if (msg->first_line.type != SIP_REPLY) {
         LM_DBG("Can't do AAR for call session in request\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
 
     //is it appropriate to send AAR at this stage?
     t = tmb.t_gett();
-    if (!t) {
+    if (t == NULL || t == T_UNDEFINED) {
         LM_WARN("Cannot get transaction for AAR based on SIP Request\n");
-        goto aarna;
+        //goto aarna;
+        return CSCF_RETURN_ERROR;
     }
 
     //we dont apply QoS if its not a reply to an INVITE! or UPDATE or PRACK!
@@ -435,34 +449,85 @@ static int w_rx_aar(struct sip_msg *msg, char* direction, char* bar) {
             || memcmp(t->method.s, "UPDATE", 6) == 0))) {
         if (cscf_get_content_length(msg) == 0
                 || cscf_get_content_length(t->uas.request) == 0) {
-            goto aarna; //AAR na if we dont have offer/answer pair
+            LM_DBG("No SDP offer answer -> therefore we can not do Rx AAR");
+            //goto aarna; //AAR na if we dont have offer/answer pair
+            return CSCF_RETURN_ERROR;
         }
     } else {
-        goto aarna;
+        LM_DBG("Message is not response to INVITE, PRACK or UPDATE -> therefore we do not Rx AAR");
+        return CSCF_RETURN_ERROR;
     }
 
     /* get callid, from and to tags to be able to identify dialog */
     callid = cscf_get_call_id(msg, 0);
     if (callid.len <= 0 || !callid.s) {
         LM_ERR("unable to get callid\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
     if (!cscf_get_from_tag(msg, &ftag)) {
         LM_ERR("Unable to get ftag\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
     if (!cscf_get_to_tag(msg, &ttag)) {
         LM_ERR("Unable to get ttag\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
 
     //check to see that this is not a result of a retransmission in reply route only
     if (msg->cseq == NULL
             && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || (msg->cseq == NULL))) {
         LM_ERR("No Cseq header found - aborting\n");
-        goto error;
-    }
-
+        return CSCF_RETURN_ERROR;
+    }
+
+    saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t));
+    if (!saved_t_data) {
+        LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data, 0, sizeof (saved_transaction_t));
+    saved_t_data->act = cfg_action;
+    //OTHER parms need after async response set here
+    //store call id
+    saved_t_data->callid.s = (char*) shm_malloc(callid.len + 1);
+    if (!saved_t_data->callid.s) {
+        LM_ERR("no more memory trying to save transaction state : callid\n");
+        shm_free(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data->callid.s, 0, callid.len + 1);
+    memcpy(saved_t_data->callid.s, callid.s, callid.len);
+    saved_t_data->callid.len = callid.len;
+
+    //store ttag
+    saved_t_data->ttag.s = (char*) shm_malloc(ttag.len + 1);
+    if (!saved_t_data->ttag.s) {
+        LM_ERR("no more memory trying to save transaction state : ttag\n");
+        shm_free(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data->ttag.s, 0, ttag.len + 1);
+    memcpy(saved_t_data->ttag.s, ttag.s, ttag.len);
+    saved_t_data->ttag.len = ttag.len;
+
+    //store ftag
+    saved_t_data->ftag.s = (char*) shm_malloc(ftag.len + 1);
+    if (!saved_t_data->ftag.s) {
+        LM_ERR("no more memory trying to save transaction state : ftag\n");
+        shm_free(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data->ftag.s, 0, ftag.len + 1);
+    memcpy(saved_t_data->ftag.s, ftag.s, ftag.len);
+    saved_t_data->ftag.len = ftag.len;
+
+    //store branch
+    int branch;
+    if (tmb.t_check( msg  , &branch )==-1){
+        LOG(L_ERR, "ERROR: t_suspend: failed find UAC branch\n");
+        return CSCF_RETURN_ERROR;
+    }
+    
     //Check that we dont already have an auth session for this specific dialog
     //if not we create a new one and attach it to the dialog (via session ID).
     enum dialog_direction dlg_direction = get_dialog_direction(direction);
@@ -504,62 +569,44 @@ static int w_rx_aar(struct sip_msg *msg, char* direction, char* bar) {
         LM_DBG("Attached CDP auth session [%.*s] for Rx to dialog in %s mode\n", auth_session->id.len, auth_session->id.s, direction);
     } else {
         LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
-        //TODO - what to do on updates - reinvites, etc
-        goto aarna; //TODO: for now we ignore
+        if (saved_t_data)
+                free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
+        create_return_code(CSCF_RETURN_TRUE);
+        return CSCF_RETURN_TRUE;
     }
 
-    resp = rx_send_aar(t->uas.request, msg, auth_session, &callid, &ftag, &ttag,
-            direction, &rx_authdata_p);
-
-    if (!resp) {
-        LM_ERR("No response received for AAR request\n");
-        goto error;
+    LM_DBG("Suspending SIP TM transaction\n");
+    if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
+        LM_ERR("failed to suspend the TM processing\n");
+        free_saved_transaction_global_data(saved_t_data);
+        return CSCF_RETURN_ERROR;
     }
 
-    if (!rx_authdata_p) {
-        LM_ERR("Rx: mod.c: error creating new rx_auth_data\n");
-        goto error;
-    }
-    //
-    //    /* Process the response to AAR, retrieving result code and associated Rx session ID */
-    if (rx_process_aaa(resp, &result) < 0) {
-        LM_DBG("Failed to process AAA from PCRF\n");
-        cdpb.AAAFreeMessage(&resp);
-        goto error;
-    }
-    cdpb.AAAFreeMessage(&resp);
-
+    LM_DBG("Sending Rx AAR");
+    ret = rx_send_aar(t->uas.request, msg, auth_session, direction, saved_t_data);
 
-    if (result >= 2000 && result < 3000) {
-        LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", result);
-
-        str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
+    if (!ret) {
+        LM_ERR("Failed to send AAR\n");
+        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
+        goto error;
 
-        passed_rx_session_id->s = 0;
-        passed_rx_session_id->len = 0;
-        STR_SHM_DUP(*passed_rx_session_id, auth_session->id, "cb_passed_rx_session_id");
 
-        LM_DBG("passed rx session id %.*s", passed_rx_session_id->len, passed_rx_session_id->s);
+    } else {
+        LM_DBG("Successful async send of AAR\n");
+        return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
+    }
 
-        dlgb.register_dlgcb_nodlg(&callid, &ftag, &ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED, callback_dialog_terminated, (void*) (passed_rx_session_id), free_dialog_data);
+error:
+    LM_ERR("Error trying to send AAR (calling)\n");
+    if (saved_t_data)
+        free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
+    //otherwise the callback will segfault
 
-        return RX_RETURN_TRUE;
-    } else {
-        LM_DBG("Received negative reply from PCRF for AAR Request\n");
-        //we don't free rx_authdata_p here - it is free-ed when the CDP session expires
-        goto error; // if its not a success then that means i want to reject this call!
-    }
-out_of_memory:
-    error :
-            LM_ERR("Error trying to send AAR (calling)\n");
-    return RX_RETURN_FALSE;
-aarna:
-    LM_DBG("Policy and Charging Control non-applicable\n");
-    return RX_RETURN_AAR_NA;
+     return CSCF_RETURN_ERROR;
 }
 
 /* Wrapper to send AAR from config file - only used for registration */
-static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
+static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char* bar) {
 
     int ret = CSCF_RETURN_ERROR;
     struct pcontact_info ci;
@@ -571,14 +618,32 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
     AAASession* auth;
     rx_authsessiondata_t* rx_regsession_data_p;
     cfg_action_t* cfg_action = 0;
+    str route_name;
     char* p;
     int aar_sent = 0;
-    saved_transaction_local_t* local_data = 0;		//data to be shared across all async calls
-    saved_transaction_t* saved_t_data = 0;			//data specific to each contact's AAR async call
-    aar_param_t* ap = (aar_param_t*) str1;
-    udomain_t* domain_t = ap->domain;
-    cfg_action = ap->paction->next;
-    int is_rereg = 0;								//is this a reg/re-reg
+    saved_transaction_local_t* local_data = 0; //data to be shared across all async calls
+    saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
+    
+    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    
+    udomain_t* domain_t = (udomain_t*) str1;
+    
+    int is_rereg = 0; //is this a reg/re-reg
 
     LM_DBG("Rx AAR Register called\n");
 
@@ -619,60 +684,60 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
             //if ((cscf_get_expires(msg) == 0)) {
             LM_DBG("This is a de registration\n");
             LM_DBG("We ignore it as these are dealt with by usrloc callbacks \n");
-            create_return_code(RX_RETURN_TRUE);
-            return RX_RETURN_TRUE;
+            create_return_code(CSCF_RETURN_TRUE);
+            return CSCF_RETURN_TRUE;
         }
     }
 
     //before we continue, make sure we have a transaction to work with (viz. cdp async)
-	t = tmb.t_gett();
-	if (t == NULL || t == T_UNDEFINED) {
-		if (tmb.t_newtran(msg) < 0) {
-			LM_ERR("cannot create the transaction for UAR async\n");
-			return CSCF_RETURN_ERROR;
-		}
-		t = tmb.t_gett();
-		if (t == NULL || t == T_UNDEFINED) {
-			LM_ERR("cannot lookup the transaction\n");
-			return CSCF_RETURN_ERROR;
-		}
-	}
-
-	saved_t_data = (saved_transaction_t*)shm_malloc(sizeof(saved_transaction_t));
-	if (!saved_t_data){
-		LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
-		return CSCF_RETURN_ERROR;
-	}
-	memset(saved_t_data,0,sizeof(saved_transaction_t));
-	saved_t_data->act = cfg_action;
-	saved_t_data->domain = domain_t;
-	saved_t_data->lock = lock_alloc();
-	if (saved_t_data->lock == NULL) {
-		LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n");
-		return CSCF_RETURN_ERROR;
-	}
-	if (lock_init(saved_t_data->lock) == NULL) {
-		LM_ERR("unable to init lock for saved_t_transaction reply counter\n");
-		return CSCF_RETURN_ERROR;
-	}
-
-	LM_DBG("Suspending SIP TM transaction\n");
-	if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
-		LM_ERR("failed to suspend the TM processing\n");
-		free_saved_transaction_global_data(saved_t_data);
-		return CSCF_RETURN_ERROR;
-	}
-
-	LM_DBG("Successfully suspended transaction\n");
-
-	//now get the contacts in the REGISTER and do AAR for each one.
+    t = tmb.t_gett();
+    if (t == NULL || t == T_UNDEFINED) {
+        if (tmb.t_newtran(msg) < 0) {
+            LM_ERR("cannot create the transaction for UAR async\n");
+            return CSCF_RETURN_ERROR;
+        }
+        t = tmb.t_gett();
+        if (t == NULL || t == T_UNDEFINED) {
+            LM_ERR("cannot lookup the transaction\n");
+            return CSCF_RETURN_ERROR;
+        }
+    }
+
+    saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t));
+    if (!saved_t_data) {
+        LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data, 0, sizeof (saved_transaction_t));
+    saved_t_data->act = cfg_action;
+    saved_t_data->domain = domain_t;
+    saved_t_data->lock = lock_alloc();
+    if (saved_t_data->lock == NULL) {
+        LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n");
+        return CSCF_RETURN_ERROR;
+    }
+    if (lock_init(saved_t_data->lock) == NULL) {
+        LM_ERR("unable to init lock for saved_t_transaction reply counter\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    LM_DBG("Suspending SIP TM transaction\n");
+    if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
+        LM_ERR("failed to suspend the TM processing\n");
+        free_saved_transaction_global_data(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+
+    LM_DBG("Successfully suspended transaction\n");
+
+    //now get the contacts in the REGISTER and do AAR for each one.
     cb = cscf_parse_contacts(msg);
     if (!cb || (!cb->contacts && !cb->star)) {
         LM_DBG("No contact headers in Register message\n");
         goto error;
     }
 
-    lock_get(saved_t_data->lock);		//we lock here to make sure we send all requests before processing replies asynchronously
+    lock_get(saved_t_data->lock); //we lock here to make sure we send all requests before processing replies asynchronously
     for (h = msg->contact; h; h = h->next) {
         if (h->type == HDR_CONTACT_T && h->parsed) {
             for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
@@ -685,7 +750,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                 } else if (pcontact->reg_state == PCONTACT_REG_PENDING
                         || pcontact->reg_state == PCONTACT_REGISTERED) { //NEW reg request
                     LM_DBG("Contact [%.*s] exists and is in state PCONTACT_REG_PENDING or PCONTACT_REGISTERED\n"
-                    		, pcontact->aor.len, pcontact->aor.s);
+                            , pcontact->aor.len, pcontact->aor.s);
 
                     //get IP address from contact
                     struct sip_uri puri;
@@ -745,12 +810,12 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                     }
 
                     //we are ready to send the AAR async. lets save the local data data
-                    int local_data_len = sizeof(saved_transaction_local_t) + c->uri.len + auth->id.len;
+                    int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len;
                     local_data = shm_malloc(local_data_len);
                     if (!local_data) {
-                    	LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n");
-                    	lock_release(saved_t_data->lock);
-                    	goto error;
+                        LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n");
+                        lock_release(saved_t_data->lock);
+                        goto error;
                     }
                     memset(local_data, 0, local_data_len);
 
@@ -761,32 +826,36 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                     local_data->contact.s = p;
                     local_data->contact.len = c->uri.len;
                     memcpy(p, c->uri.s, c->uri.len);
-                    p+=c->uri.len;
+                    p += c->uri.len;
 
                     local_data->auth_session_id.s = p;
                     local_data->auth_session_id.len = auth->id.len;
                     memcpy(p, auth->id.s, auth->id.len);
-                    p+=auth->id.len;
+                    p += auth->id.len;
 
-                    if (p!=( ((char*)local_data) + local_data_len) ) {
-                    	LM_CRIT("buffer overflow\n");
-                    	free_saved_transaction_data(local_data);
-                    	goto error;
+                    if (p != (((char*) local_data) + local_data_len)) {
+                        LM_CRIT("buffer overflow\n");
+                        free_saved_transaction_data(local_data);
+                        goto error;
                     }
 
                     LM_DBG("Calling send aar register");
-                    ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object
+
+                    //TODOD remove - no longer user AOR parm
+                    //ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object
+                    ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, local_data); //returns a locked rx auth object
+
                     ul.unlock_udomain(domain_t, &c->uri);
 
                     if (!ret) {
-                    	LM_ERR("Failed to send AAR\n");
-                    	lock_release(saved_t_data->lock);
-                    	free_saved_transaction_data(local_data);	//free the local data becuase the CDP async request was not successful (we must free here)
-                    	goto error;
+                        LM_ERR("Failed to send AAR\n");
+                        lock_release(saved_t_data->lock);
+                        free_saved_transaction_data(local_data); //free the local data becuase the CDP async request was not successful (we must free here)
+                        goto error;
                     } else {
-                    	aar_sent = 1;
-                    	//before we send - bump up the reply counter
-			saved_t_data->answers_not_received++;		//we dont need to lock as we already hold the lock above
+                        aar_sent = 1;
+                        //before we send - bump up the reply counter
+                        saved_t_data->answers_not_received++; //we dont need to lock as we already hold the lock above
                     }
                 } else {
                     //contact exists - this is a re-registration, for now we just ignore this
@@ -796,11 +865,11 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                 }
             }
         } else {
-        	if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error
-        		LM_ERR("Failed to parse contact header\n");
-        		lock_release(saved_t_data->lock);
-        		goto error;
-        	}
+            if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error
+                LM_ERR("Failed to parse contact header\n");
+                lock_release(saved_t_data->lock);
+                goto error;
+            }
         }
     }
     //all requests sent at this point - we can unlock the reply lock
@@ -811,46 +880,87 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
      * 2. haven't needed to send ANY AAR's for ANY contacts
      */
     if (aar_sent) {
-    	LM_DBG("Successful async send of AAR\n");
-    	return RX_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
+        LM_DBG("Successful async send of AAR\n");
+        return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
     } else {
-    	create_return_code(RX_RETURN_TRUE);
-    	free_saved_transaction_global_data(saved_t_data);	//no aar sent so we must free the global data
-    	return RX_RETURN_TRUE;
+        create_return_code(CSCF_RETURN_TRUE);
+        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
+        if (saved_t_data) {
+            free_saved_transaction_global_data(saved_t_data); //no aar sent so we must free the global data
+        }
+        //return CSCF_RETURN_ERROR;
+        return CSCF_RETURN_TRUE;
     }
 error:
     LM_ERR("Error trying to send AAR\n");
-    if (!aar_sent)
-    	if (saved_t_data)
-    		free_saved_transaction_global_data(saved_t_data); 	//only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
-    															//otherwise the callback will segfault
-    return RX_RETURN_FALSE;
+    if (!aar_sent) {
+        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
+        if (saved_t_data) {
+            free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
+            //otherwise the callback will segfault
+        }
+    }
+    return CSCF_RETURN_ERROR;
+    //return CSCF_RETURN_FALSE;
 }
 
-static int fixup_aar_register(void** param, int param_no)
-{
-	udomain_t* d;
-	aar_param_t *ap;
-
-	if(param_no!=1)
-		return 0;
-	ap = (aar_param_t*)pkg_malloc(sizeof(aar_param_t));
-	if(ap==NULL)
-	{
-		LM_ERR("no more pkg\n");
-		return -1;
-	}
-	memset(ap, 0, sizeof(aar_param_t));
-	ap->paction = get_action_from_param(param, param_no);
-
-	if (ul.register_udomain((char*) *param, &d) < 0) {
-		LM_ERR("failed to register domain\n");
-		return E_UNSPEC;
-	}
-	ap->domain = d;
-
-	*param = (void*)ap;
-	return 0;
+static int fixup_aar_register(void** param, int param_no) {
+//    udomain_t* d;
+//    aar_param_t *ap;
+//
+//    if (param_no != 1)
+//        return 0;
+//    ap = (aar_param_t*) pkg_malloc(sizeof (aar_param_t));
+//    if (ap == NULL) {
+//        LM_ERR("no more pkg\n");
+//        return -1;
+//    }
+//    memset(ap, 0, sizeof (aar_param_t));
+//    ap->paction = get_action_from_param(param, param_no);
+//
+//    if (ul.register_udomain((char*) *param, &d) < 0) {
+//        LM_ERR("failed to register domain\n");
+//        return E_UNSPEC;
+//    }
+//    ap->domain = d;
+//
+//    *param = (void*) ap;
+//    return 0;
+    if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+    }
+
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0)
+            return -1;
+        return 0;
+    } else if (param_no == 2) {
+        udomain_t* d;
+
+        if (ul.register_udomain((char*) *param, &d) < 0) {
+            LM_ERR("Error doing fixup on assign save");
+            return -1;
+        }
+        *param = (void*) d;
+    }
+
+    return 0;
+}
+
+static int fixup_aar(void** param, int param_no) {
+    if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+    }
+
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0)
+            return -1;
+        return 0;
+    }
+
+    return 0;
 }
 
 /*create a return code to be passed back into config file*/
diff --git a/modules/ims_qos/mod.h b/modules/ims_qos/mod.h
index 11c165d..1fd9f0e 100644
--- a/modules/ims_qos/mod.h
+++ b/modules/ims_qos/mod.h
@@ -49,17 +49,6 @@
 
 #define MOD_NAME "ims_qos"
 
-/** Return and break the execution of routing script */
-#define RX_RETURN_BREAK	0 
-/** Return true in the routing script */
-#define RX_RETURN_TRUE	1
-/** Return positive but indicate AAR not viable and wasnt sent */
-#define RX_RETURN_AAR_NA	2
-/** Return false in the routing script */
-#define RX_RETURN_FALSE -1
-/** Return error in the routing script */
-#define RX_RETURN_ERROR -2
-
 /** callback functions */
 
 struct AAAMessage;
diff --git a/modules/ims_qos/rx_aar.c b/modules/ims_qos/rx_aar.c
index 60179ba..b5e7293 100644
--- a/modules/ims_qos/rx_aar.c
+++ b/modules/ims_qos/rx_aar.c
@@ -65,6 +65,7 @@
 
 #include "mod.h"
 
+#include "../../lib/ims/useful_defs.h"
 #define macro_name(_rc)	#_rc
 
 //extern struct tm_binds tmb;
@@ -74,7 +75,101 @@ str IMS_Serv_AVP_val = {"IMS Services", 12};
 str IMS_Em_Serv_AVP_val = {"Emergency IMS Call", 18};
 str IMS_Reg_AVP_val = {"IMS Registration", 16};
 
-void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
+static void free_dialog_data(void *data) {
+    str *rx_session_id = (str*) data;
+    if (rx_session_id) {
+        if (rx_session_id->s) {
+            shm_free(rx_session_id->s);
+            rx_session_id->s = 0;
+        }
+        shm_free(rx_session_id);
+        rx_session_id = 0;
+    }
+
+}
+
+void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
+    struct cell *t = 0;
+    unsigned int cdp_result;
+    int result = CSCF_RETURN_ERROR;
+
+    LM_DBG("Received AAR callback\n");
+    saved_transaction_t* data = (saved_transaction_t*) param;
+
+    LM_DBG("received AAA answer");
+
+    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
+        LM_ERR("t_continue: transaction not found\n");
+        goto error;
+    } else {
+        LM_DBG("t_continue: transaction found\n");
+    }
+    //we have T, lets restore our state (esp. for AVPs)
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
+
+    if (is_timeout != 0) {
+        LM_ERR("Error timeout when sending AAR message via CDP\n");
+        update_stat(stat_aar_timeouts, 1);
+        goto error;
+    }
+    if (!aaa) {
+        LM_ERR("Error sending message via CDP\n");
+        goto error;
+    }
+
+    update_stat(aar_replies_received, 1);
+    update_stat(aar_replies_response_time, elapsed_msecs);
+
+    /* Process the response to AAR, retrieving result code and associated Rx session ID */
+    if (rx_process_aaa(aaa, &cdp_result) < 0) {
+        LM_ERR("Failed to process AAA from PCRF\n"); //puri.host.len, puri.host.s);
+        goto error;
+    }
+
+    if (cdp_result >= 2000 && cdp_result < 3000) {
+        LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", cdp_result);
+
+        LM_DBG("Auth session ID [%.*s]", aaa->sessionId->data.len, aaa->sessionId->data.s);
+
+        str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
+        passed_rx_session_id->s = 0;
+        passed_rx_session_id->len = 0;
+        STR_SHM_DUP(*passed_rx_session_id, aaa->sessionId->data, "cb_passed_rx_session_id");
+        LM_DBG("passed rx session id [%.*s]", passed_rx_session_id->len, passed_rx_session_id->s);
+
+        dlgb.register_dlgcb_nodlg(&data->callid, &data->ftag, &data->ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED, callback_dialog_terminated, (void*) (passed_rx_session_id), free_dialog_data);
+        result = CSCF_RETURN_TRUE;
+    } else {
+        LM_DBG("Received negative reply from PCRF for AAR Request\n");
+        //we don't free rx_authdata_p here - it is free-ed when the CDP session expires
+        goto error; // if its not a success then that means i want to reject this call!
+    }
+
+    //set success response code AVP
+    create_return_code(result);
+    goto done;
+
+out_of_memory:
+    error :
+            //set failure response code
+            create_return_code(result);
+
+done:
+    if (t) tmb.unref_cell(t);
+    //free memory
+    if (aaa)
+        cdpb.AAAFreeMessage(&aaa);
+
+    tmb.t_continue(data->tindex, data->tlabel, data->act);
+    free_saved_transaction_global_data(data);
+}
+
+void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
     struct cell *t = 0;
     pcontact_t* pcontact;
     unsigned int cdp_result;
@@ -139,12 +234,12 @@ void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
     }
 
     if (cdp_result >= 2000 && cdp_result < 3000) {
-    	if (is_rereg) {
-    		LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
-    		result = CSCF_RETURN_TRUE;
-    		create_return_code(result);
-    		goto done;
-    	}
+        if (is_rereg) {
+            LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
+            result = CSCF_RETURN_TRUE;
+            create_return_code(result);
+            goto done;
+        }
         LM_DBG("Success, received code: [%i] from PCRF for AAR request (contact: [%.*s]), (auth session id: %.*s)\n",
                 cdp_result, local_data->contact.len, local_data->contact.s,
                 local_data->auth_session_id.len, local_data->auth_session_id.s);
@@ -166,7 +261,7 @@ void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
             ul.unlock_udomain(domain_t, &local_data->contact);
             goto error;
         }
-        memset(&ci, 0, sizeof(struct pcontact_info));
+        memset(&ci, 0, sizeof (struct pcontact_info));
         ci.reg_state = PCONTACT_REG_PENDING_AAR;
         ci.num_service_routes = 0;
         ci.num_public_ids = 0;
@@ -231,17 +326,17 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
     sdp_stream_cell_t* req_sdp_stream, *rpl_sdp_stream;
 
     if (!req || !rpl) {
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     if (parse_sdp(req) < 0) {
         LM_ERR("Unable to parse req SDP\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     if (parse_sdp(rpl) < 0) {
         LM_ERR("Unable to parse res SDP\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     sdp_session_num = 0;
@@ -312,13 +407,18 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
  * @returns AAA message or NULL on error
  */
 
-AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res,
-        AAASession* auth, str* callid, str* ftag, str* ttag, char* direction,
-        rx_authsessiondata_t **rx_authdata) {
+int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
+        AAASession* auth, char* direction, saved_transaction_t* saved_t_data) {
+
     AAAMessage* aar = 0;
-    AAAMessage* aaa = 0;
+
+
+    //AAAMessage* aaa = 0;
+
+
     AAA_AVP* avp = 0;
     char x[4];
+    int ret = 0;
 
     str ip;
     uint16_t ip_version;
@@ -444,11 +544,21 @@ AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res,
 
     LM_DBG("sending AAR to PCRF\n");
     if (rx_forced_peer.len)
-        aaa = cdpb.AAASendRecvMessageToPeer(aar, &rx_forced_peer);
+        ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
+            (void*) async_aar_callback, (void*) saved_t_data);
     else
-        aaa = cdpb.AAASendRecvMessage(aar);
+        ret = cdpb.AAASendMessage(aar, (void*) async_aar_callback,
+            (void*) saved_t_data);
 
-    return aaa;
+    return ret;
+
+    //    LM_DBG("sending AAR to PCRF\n");
+    //    if (rx_forced_peer.len)
+    //        aaa = cdpb.AAASendRecvMessageToPeer(aar, &rx_forced_peer);
+    //    else
+    //        aaa = cdpb.AAASendRecvMessage(aar);
+    //
+    //    return aaa;
 
 error:
     LM_ERR("unexpected error\n");
@@ -459,7 +569,7 @@ error:
         cdpb.AAADropAuthSession(auth);
         auth = 0;
     }
-    return NULL;
+    return ret;
 }
 
 /**
@@ -470,8 +580,9 @@ error:
  * @param ip_version - AF_INET or AF_INET6
  * @returns int >0 if sent AAR successfully, otherwise 0
  */
+
 int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip,
-        uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data) {
+        uint16_t *ip_version, saved_transaction_local_t* saved_t_data) {
     AAAMessage* aar = 0;
     int ret = 0;
     AAA_AVP* avp = 0;
@@ -531,9 +642,9 @@ int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip,
     LM_DBG("sending AAR to PCRF\n");
     if (rx_forced_peer.len)
         ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
-            (void*) async_cdp_callback, (void*) saved_t_data);
+            (void*) async_aar_reg_callback, (void*) saved_t_data);
     else
-        ret = cdpb.AAASendMessage(aar, (void*) async_cdp_callback,
+        ret = cdpb.AAASendMessage(aar, (void*) async_aar_reg_callback,
             (void*) saved_t_data);
 
     return ret;
@@ -573,16 +684,27 @@ enum dialog_direction get_dialog_direction(char *direction) {
 void free_saved_transaction_global_data(saved_transaction_t* data) {
     if (!data)
         return;
-
-    lock_dealloc(data->lock);
-    lock_destroy(data->lock);
+    if (data->callid.s && data->callid.len) {
+        shm_free(data->callid.s);
+        data->callid.len = 0;
+    }
+    if (data->ftag.s && data->ftag.len) {
+        shm_free(data->ftag.s);
+        data->ftag.len = 0;
+    }
+    if (data->ttag.s && data->ttag.len) {
+        shm_free(data->ttag.s);
+        data->ttag.len = 0;
+    }
+    if (data->lock) {
+        lock_dealloc(data->lock);
+        lock_destroy(data->lock);
+    }
     shm_free(data);
 }
 
 void free_saved_transaction_data(saved_transaction_local_t* data) {
     if (!data)
         return;
-
-
     shm_free(data);
 }
diff --git a/modules/ims_qos/rx_aar.h b/modules/ims_qos/rx_aar.h
index bc4137e..9f53515 100644
--- a/modules/ims_qos/rx_aar.h
+++ b/modules/ims_qos/rx_aar.h
@@ -57,16 +57,6 @@
 struct cdp_binds cdpb;
 cdp_avp_bind_t *cdp_avp;
 
-/*storage for data coming into AAR_register from config file
- * holds next action (async CDP) and domain
- */
-typedef struct aar_param {
-	int type;
-	udomain_t* domain;
-	cfg_action_t *paction;
-} aar_param_t;
-
-
 /*this is the parcel to pass for CDP async for AAR*/
 typedef struct saved_transaction {
 	gen_lock_t *lock;
@@ -78,6 +68,9 @@ typedef struct saved_transaction {
 	unsigned int ticks;
 	cfg_action_t *act;
 	udomain_t* domain;
+        str callid;
+        str ftag;
+        str ttag;
 } saved_transaction_t;
 
 typedef struct saved_transaction_local {
@@ -101,12 +94,19 @@ struct rx_authdata;
 void free_saved_transaction_data(saved_transaction_local_t* data);
 void free_saved_transaction_global_data(saved_transaction_t* data);
 
-AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, str *callid, str *ftag, str *ttag, char *direction, rx_authsessiondata_t **rx_authdata);
-int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data);
+//AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, str *callid, str *ftag, str *ttag, char *direction, rx_authsessiondata_t **rx_authdata);
+int rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, char *direction, saved_transaction_t* saved_t_data);
+
+//TODOD remove - no longer user AOR parm
+//int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data);
+int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, saved_transaction_local_t* saved_t_data);
+
 int rx_process_aaa(AAAMessage *aaa, unsigned int * rc);
 enum dialog_direction get_dialog_direction(char *direction);
 
-void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs);
+void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs);
+
+void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs);
 
 #endif
 
diff --git a/modules/ims_qos/rx_authdata.c b/modules/ims_qos/rx_authdata.c
index d75d88c..e828634 100644
--- a/modules/ims_qos/rx_authdata.c
+++ b/modules/ims_qos/rx_authdata.c
@@ -79,6 +79,7 @@ int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** sess
 	memset(p_session_data, 0, len);
 
 	p_session_data->subscribed_to_signaling_path_status = 1;
+        p_session_data->must_terminate_dialog = 0; /*irrelevent for reg session data this will always be 0 */
 
 	char* p = (char*)(p_session_data + 1);
 	p_session_data->domain.s = p;
@@ -112,6 +113,7 @@ int create_new_callsessiondata(str* callid, str* ftag, str* ttag, rx_authsession
 	}
 	memset(call_session_data, 0, len);
 	call_session_data->subscribed_to_signaling_path_status = 0; //this is for a media session not regitration
+        call_session_data->must_terminate_dialog = 0; //this is used to determine if the dialog must be torn down when the CDP session terminates
 
 	char *p = (char*)(call_session_data + 1);
 
diff --git a/modules/ims_qos/rx_authdata.h b/modules/ims_qos/rx_authdata.h
index 69373c0..4310c13 100644
--- a/modules/ims_qos/rx_authdata.h
+++ b/modules/ims_qos/rx_authdata.h
@@ -69,6 +69,7 @@ typedef struct rx_authsessiondata {
     int subscribed_to_signaling_path_status; // 0 not subscribed 1 is subscribed
     str domain;				//the domain the registration aor belongs to (for registration)
     str registration_aor; //the aor if this rx session is a subscription to signalling status
+    int must_terminate_dialog; //0 means when this session terminates it must not terminate the relevant dialog, 1 means it must terminate the dialog
 } rx_authsessiondata_t;
 
 int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** session_data);
diff --git a/modules/ims_qos/rx_avp.c b/modules/ims_qos/rx_avp.c
index f92d507..65c8a43 100644
--- a/modules/ims_qos/rx_avp.c
+++ b/modules/ims_qos/rx_avp.c
@@ -56,6 +56,8 @@
 #include "rx_avp.h"
 #include "mod.h"
 
+#include "../../lib/ims/ims_getters.h"
+
 /**< Structure with pointers to cdp funcs, global variable defined in mod.c  */
 extern struct cdp_binds cdpb;
 extern cdp_avp_bind_t *cdp_avp;
@@ -86,7 +88,7 @@ inline int rx_add_avp(AAAMessage *m, char *d, int len, int avp_code,
         cdpb.AAAFreeAVP(&avp);
         return 0;
     }
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 }
 
 /**
@@ -122,7 +124,7 @@ static inline int rx_add_avp_list(AAA_AVP_LIST *list, char *d, int len, int avp_
         avp->prev = 0;
     }
 
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 }
 
 /**
@@ -154,9 +156,12 @@ static inline str rx_get_avp(AAAMessage *msg, int avp_code, int vendor_id,
  * 	see http://beej.us/guide/bgnet/output/html/multipage/inet_ntopman.html
  * 	http://beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html
  */
+
+static unsigned int ip_buflen = 0;
+static char* ip_buf = 0;
+
 int rx_add_framed_ip_avp(AAA_AVP_LIST * list, str ip, uint16_t version) {
     ip_address_prefix ip_adr;
-    char* ip_pkg = 0;
     int ret = 0;
 
     if (ip.len < 0) return 0;
@@ -167,28 +172,36 @@ int rx_add_framed_ip_avp(AAA_AVP_LIST * list, str ip, uint16_t version) {
         if (ip.len > INET6_ADDRSTRLEN)
             goto error;
     }
-    ip_pkg = (char*) pkg_malloc((ip.len + 1) * sizeof (char));
-    if (!ip_pkg) {
-        LM_ERR("PCC_create_framed_ip_avp: could not allocate %i from pkg\n", ip.len + 1);
-        goto error;
+    int len = ip.len + 1;
+    if (!ip_buf || ip_buflen < len) {
+        if (ip_buf)
+                pkg_free(ip_buf);
+        ip_buf = (char*)pkg_malloc(len);
+        if (!ip_buf) {
+	    LM_ERR("rx_add_framed_ip_avp: out of memory \
+					    when allocating %i bytes in pkg\n", len);
+	    goto error;
+        }
+        ip_buflen = len;
     }
-    memcpy(ip_pkg, ip.s, ip.len);
-    ip_pkg[ip.len] = '\0';
-
+    memcpy(ip_buf, ip.s, ip.len);
+    ip_buf[ip.len] = '\0';
+    
     ip_adr.addr.ai_family = version;
 
     if (version == AF_INET) {
 
-        if (inet_pton(AF_INET, ip_pkg, &(ip_adr.addr.ip.v4.s_addr)) != 1) goto error;
+        if (inet_pton(AF_INET, ip_buf, &(ip_adr.addr.ip.v4.s_addr)) != 1) goto error;
         ret = cdp_avp->nasapp.add_Framed_IP_Address(list, ip_adr.addr);
     } else {
 
-        if (inet_pton(AF_INET6, ip_pkg, &(ip_adr.addr.ip.v6.s6_addr)) != 1) goto error;
+        if (inet_pton(AF_INET6, ip_buf, &(ip_adr.addr.ip.v6.s6_addr)) != 1) goto error;
         ret = cdp_avp->nasapp.add_Framed_IPv6_Prefix(list, ip_adr);
     }
 
+    //TODO: should free ip_buf in module shutdown....
+    
 error:
-    if (ip_pkg) pkg_free(ip_pkg);
     return ret;
 }
 
@@ -272,7 +285,7 @@ inline int rx_add_destination_realm_avp(AAAMessage *msg, str data) {
  * Creates and adds an Acct-Application-Id AVP.
  * @param msg - the Diameter message to add to.
  * @param data - the value for the AVP payload
- * @return RX_RETURN_TRUE on success or 0 on error
+ * @return CSCF_RETURN_TRUE on success or 0 on error
  */
 inline int rx_add_auth_application_id_avp(AAAMessage *msg, unsigned int data) {
     char x[4];
@@ -292,7 +305,7 @@ inline int rx_add_auth_application_id_avp(AAAMessage *msg, unsigned int data) {
  * @param msg - the Diameter message to add to.
  * @param r - the sip_message to extract the data from.
  * @param tag - originating (0) terminating (1)
- * @return RX_RETURN_TRUE on success or 0 on error
+ * @return CSCF_RETURN_TRUE on success or 0 on error
  * 
  */
 
@@ -503,8 +516,14 @@ static str permit_out = {"permit out ", 11};
 static str permit_in = {"permit in ", 10};
 static str from_s = {" from ", 6};
 static str to_s = {" to ", 4};
-static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u %s";
-static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u %s";
+//removed final %s - this is options which Rx 29.214 says will not be used for flow-description AVP
+static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u";
+//static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u %s";
+static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u";
+//static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u %s";
+
+static unsigned int flowdata_buflen = 0;
+static str flowdata_buf = {0,0};
 
 AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
         str *ipA, str *portA,
@@ -512,8 +531,8 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
 
     str data;
     int len, len2;
-    str flow_data = {0, 0};
-    str flow_data2 = {0, 0};
+//    str flow_data = {0, 0};
+//    str flow_data2 = {0, 0};
     AAA_AVP *flow_description1 = 0, *flow_description2 = 0, *flow_number = 0;
     AAA_AVP *flow_usage = 0;
 
@@ -531,53 +550,61 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
     len = (permit_out.len + from_s.len + to_s.len + ipB->len + ipA->len + 4 +
             proto_len + portA->len + portB->len) * sizeof (char);
 
-    flow_data.s = (char*) pkg_malloc(len);
-    if (!flow_data.s) {
-        LM_ERR("PCC_create_media_component: out of memory \
-					when allocating %i bytes in pkg\n", len);
-        return NULL;
-    }
-
-    len2 = len - (permit_out.len - permit_in.len) * sizeof (char);
-    flow_data2.s = (char*) pkg_malloc(len2);
-    if (!flow_data2.s) {
-        LM_ERR("PCC_create_media_component: out of memory \
-					when allocating %i bytes in pkg\n", len);
-        pkg_free(flow_data.s);
-        flow_data.s = 0;
-        return NULL;
+    if (!flowdata_buf.s || flowdata_buflen < len) {
+        if (flowdata_buf.s)
+                pkg_free(flowdata_buf.s);
+        flowdata_buf.s = (char*)pkg_malloc(len);
+        if (!flowdata_buf.s) {
+                        LM_ERR("PCC_create_media_component: out of memory \
+                                                        when allocating %i bytes in pkg\n", len);
+                        return NULL ;
+        }
+        flowdata_buflen = len;
     }
 
     set_4bytes(x, number);
-
+    
     flow_number = cdpb.AAACreateAVP(AVP_IMS_Flow_Number,
             AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
             IMS_vendor_id_3GPP, x, 4,
             AVP_DUPLICATE_DATA);
     cdpb.AAAAddAVPToList(&list, flow_number);
-
+    
     /*IMS Flow descriptions*/
     /*first flow is the receive flow*/
-    flow_data.len = snprintf(flow_data.s, len, permit_out_with_ports, proto_int,
+    flowdata_buf.len = snprintf(flowdata_buf.s, len, permit_out_with_ports, proto_int,
             ipB->len, ipB->s, intportB,
             ipA->len, ipA->s, intportA);
 
-    flow_data.len = strlen(flow_data.s);
+    flowdata_buf.len = strlen(flowdata_buf.s);
     flow_description1 = cdpb.AAACreateAVP(AVP_IMS_Flow_Description,
             AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
-            IMS_vendor_id_3GPP, flow_data.s, flow_data.len,
+            IMS_vendor_id_3GPP, flowdata_buf.s, flowdata_buf.len,
             AVP_DUPLICATE_DATA);
     cdpb.AAAAddAVPToList(&list, flow_description1);
 
-    /*second flow*/
-    flow_data2.len = snprintf(flow_data2.s, len2, permit_in_with_ports, proto_int,
+        /*second flow*/
+    len2 = len - (permit_out.len - permit_in.len) * sizeof (char);
+        if (!flowdata_buf.s || flowdata_buflen <= len2) {
+                if (flowdata_buf.s)
+                        pkg_free(flowdata_buf.s);
+                flowdata_buf.s = (char*) pkg_malloc(len2);
+                if (!flowdata_buf.s) {
+                        LM_ERR("PCC_create_media_component: out of memory \
+                                                                when allocating %i bytes in pkg\n", len2);
+                        return NULL ;
+                }
+                flowdata_buflen = len2;
+        }
+
+    flowdata_buf.len = snprintf(flowdata_buf.s, len2, permit_in_with_ports, proto_int,
             ipA->len, ipA->s, intportA,
             ipB->len, ipB->s, intportB);
 
-    flow_data2.len = strlen(flow_data2.s);
+    flowdata_buf.len = strlen(flowdata_buf.s);
     flow_description2 = cdpb.AAACreateAVP(AVP_IMS_Flow_Description,
             AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
-            IMS_vendor_id_3GPP, flow_data2.s, flow_data2.len,
+            IMS_vendor_id_3GPP, flowdata_buf.s, flowdata_buf.len,
             AVP_DUPLICATE_DATA);
     cdpb.AAAAddAVPToList(&list, flow_description2);
 
@@ -591,13 +618,9 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
     /*group all AVPS into one big.. and then free the small ones*/
 
     data = cdpb.AAAGroupAVPS(list);
-
-
     cdpb.AAAFreeAVPList(&list);
-    pkg_free(flow_data.s);
-    flow_data.s = 0;
-    pkg_free(flow_data2.s);
-    flow_data2.s = 0;
+
+    //TODO: should free the buffer for the flows in module shutdown....
 
     return (cdpb.AAACreateAVP(AVP_IMS_Media_Sub_Component,
             AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
@@ -605,7 +628,6 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
             AVP_FREE_DATA));
 }
 
-
 //just for registration to signalling status much cut down MSC AVP
 //see 3GPP TS 29.214 4.4.5
 
diff --git a/modules/ims_qos/rx_str.c b/modules/ims_qos/rx_str.c
index 7521034..fc6763b 100644
--- a/modules/ims_qos/rx_str.c
+++ b/modules/ims_qos/rx_str.c
@@ -58,6 +58,8 @@
 #include "rx_avp.h"
 #include "rx_str.h"
 
+#include "../../lib/ims/ims_getters.h"
+
 extern str IMS_Serv_AVP_val;
 
 int rx_send_str(str *rx_session_id) {
@@ -72,7 +74,7 @@ int rx_send_str(str *rx_session_id) {
 
     if (!rx_session_id || !rx_session_id->s || !rx_session_id->len) {
         LM_ERR("Dialog has no Rx session associated\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }else
     {
         LM_DBG("Rx session id exists\n");
@@ -82,8 +84,8 @@ int rx_send_str(str *rx_session_id) {
     LM_DBG("About to try get Auth session\n");
     auth = cdpb.AAAGetAuthSession(*rx_session_id);
     if (!auth) {
-        LM_ERR("Could not get Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
-        return RX_RETURN_FALSE;
+        LM_DBG("Could not get Auth Session for session id: [%.*s] - this is fine as this might have been started by already sending an STR\n", rx_session_id->len, rx_session_id->s);
+        return CSCF_RETURN_FALSE;
     }else{
         LM_DBG("Retrieved Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
     }
@@ -155,7 +157,7 @@ int rx_send_str(str *rx_session_id) {
 
     LM_DBG("Successfully sent Rx STR for session: [%.*s]\n", rx_session_id->len, rx_session_id->s);
 
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 
 error:
     LM_DBG("Error sending Rx STR for session: [%.*s]\n", rx_session_id->len, rx_session_id->s);
@@ -166,5 +168,5 @@ error:
         auth = 0;
     }
 
-    return RX_RETURN_FALSE;
+    return CSCF_RETURN_FALSE;
 }
diff --git a/modules/ims_registrar_pcscf/save.c b/modules/ims_registrar_pcscf/save.c
index 5ace6e5..676f949 100644
--- a/modules/ims_registrar_pcscf/save.c
+++ b/modules/ims_registrar_pcscf/save.c
@@ -141,32 +141,38 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 				ci.num_service_routes = service_route_cnt;
 				ci.reg_state = PCONTACT_REGISTERED;
 
-				// Received Info: First try AVP, otherwise simply take the source of the request:
-				memset(&val, 0, sizeof(int_str));
-				if (rcv_avp_name.n!=0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) {
-					if (val.s.len>RECEIVED_MAX_SIZE) {
-						LM_ERR("received too long\n");
-						goto error;
-					}
-					if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
-						LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
-						continue;
-					}
-					ci.received_host = parsed_received.host;
-					ci.received_port = parsed_received.port_no;
-					ci.received_proto = parsed_received.proto;
-				} else {
-					ci.received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, sizeof(srcip));
-					ci.received_host.s = srcip;
-					ci.received_port = req->rcv.src_port;
-					ci.received_proto = req->rcv.proto;
-				}
-				// Set to default, if not set:
-				if (ci.received_port == 0) ci.received_port = 5060;
+				ci.received_host.len = 0;
+				ci.received_host.s = 0;
+				ci.received_port = 0;
+				ci.received_proto = 0;
 
 				ul.lock_udomain(_d, &c->uri);
 				if (ul.get_pcontact(_d, &c->uri, &pcontact) != 0) { //need to insert new contact
 					LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now);
+
+					// Received Info: First try AVP, otherwise simply take the source of the request:
+					memset(&val, 0, sizeof(int_str));
+					if (rcv_avp_name.n!=0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) {
+						if (val.s.len>RECEIVED_MAX_SIZE) {
+							LM_ERR("received too long\n");
+							goto error;
+						}
+						if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
+							LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
+							continue;
+						}
+						ci.received_host = parsed_received.host;
+						ci.received_port = parsed_received.port_no;
+						ci.received_proto = parsed_received.proto;
+					} else {
+						ci.received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, sizeof(srcip));
+						ci.received_host.s = srcip;
+						ci.received_port = req->rcv.src_port;
+						ci.received_proto = req->rcv.proto;
+					}
+					// Set to default, if not set:
+					if (ci.received_port == 0) ci.received_port = 5060;
+
 					if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
 						LM_ERR("Failed inserting new pcontact\n");
 					} else {
diff --git a/modules/ims_registrar_pcscf/service_routes.c b/modules/ims_registrar_pcscf/service_routes.c
index 06dc709..ab57cd6 100644
--- a/modules/ims_registrar_pcscf/service_routes.c
+++ b/modules/ims_registrar_pcscf/service_routes.c
@@ -215,7 +215,7 @@ int check_service_routes(struct sip_msg* _m, udomain_t* _d) {
 				LM_DBG("hdr is %p\n", hdr);
 				LM_DBG("r is %p\n", r);
 				if (r)
-					LM_ERR("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s);
+					LM_DBG("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s);
 			}
 			/* Then check the following headers: */
 			for (i=0; i< c->num_service_routes; i++) {
@@ -349,7 +349,7 @@ int force_service_routes(struct sip_msg* _m, udomain_t* _d) {
 		}
 
 		LM_DBG("Setting dst_uri to <%.*s> \n", c->service_routes[0].len,
-			c->service_routes[i].s);
+			c->service_routes[0].s);
 
 		if (set_dst_uri(_m, &c->service_routes[0]) !=0 ) {
 			LM_ERR("Error setting new dst uri\n");
@@ -390,40 +390,14 @@ str * get_asserted_identity(struct sip_msg* _m) {
  * Add proper asserted identies based on registration
  */
 int assert_identity(struct sip_msg* _m, udomain_t* _d, str identity) {
-	// Get the contact:
-	pcontact_t * c = getContactP(_m, _d);
-	// Public identities of this contact
-	ppublic_t * p;
-	
-	// Contact not found => Identity not asserted.
-	if (c == NULL) return -2;
-
-	/* Lock this record while working with the data: */
-	ul.lock_udomain(_d, &c->aor);
-
-	LM_DBG("Checking identity: %.*s\n", identity.len, identity.s);
-
-	LM_DBG("AOR of contact: %.*s\n", c->aor.len, c->aor.s);
-
-	for (p = c->head; p; p = p->next) {
-		LM_DBG("Public identity: %.*s\n", p->public_identity.len, p->public_identity.s);
-		/* Check length: */
-		if (identity.len == p->public_identity.len) {
-			/* Check contents: */
-			if (strncasecmp(identity.s, p->public_identity.s, identity.len) != 0) {
-				LM_DBG("Match!\n");
-				goto success;
-			}
-		} else LM_DBG("Length does not match.\n");
-	}
+	str received_host = {0, 0};
+	char srcip[50];	
 
-	// We should only get here, if we failed:
-	/* Unlock domain */
-	ul.unlock_udomain(_d, &c->aor);
-	return -1;
-success:
-	/* Unlock domain */
-	ul.unlock_udomain(_d, &c->aor);
-	return 1;
+	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
+	received_host.s = srcip;
+	if (ul.assert_identity(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &identity) == 0)
+		return -1;
+	else
+		return 1;
 }
 
diff --git a/modules/ims_registrar_scscf/cxdx_sar.c b/modules/ims_registrar_scscf/cxdx_sar.c
index 3c67ce7..7ff976b 100644
--- a/modules/ims_registrar_scscf/cxdx_sar.c
+++ b/modules/ims_registrar_scscf/cxdx_sar.c
@@ -101,6 +101,7 @@ void async_cdp_callback(int is_timeout, void *param, AAAMessage *saa, long elaps
 
     str xml_data = {0, 0}, ccf1 = {0, 0}, ccf2 = {0, 0}, ecf1 = {0, 0}, ecf2 = {0, 0};
     ims_subscription* s = 0;
+    rerrno = R_FINE;
 
     if (!param) {
         LM_DBG("No transaction data this must have been called from usrloc cb impu deleted - just log result code and then exit");
@@ -249,7 +250,8 @@ success:
     update_stat(accepted_registrations, 1);
 
 done:
-    reg_send_reply_transactional(t->uas.request, data->contact_header, t);
+    if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER)
+        reg_send_reply_transactional(t->uas.request, data->contact_header, t);
     LM_DBG("DBG:SAR Async CDP callback: ... Done resuming transaction\n");
     set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
     set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
@@ -274,7 +276,8 @@ done:
     return;
 
 error:
-    reg_send_reply_transactional(t->uas.request, data->contact_header, t);
+    if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER)
+        reg_send_reply_transactional(t->uas.request, data->contact_header, t);
 
 error_no_send: //if we don't have the transaction then we can't send a transaction response
     update_stat(rejected_registrations, 1);
diff --git a/modules/ims_registrar_scscf/cxdx_sar.h b/modules/ims_registrar_scscf/cxdx_sar.h
index 2f9a8a8..77b0d3d 100644
--- a/modules/ims_registrar_scscf/cxdx_sar.h
+++ b/modules/ims_registrar_scscf/cxdx_sar.h
@@ -47,14 +47,6 @@
 #define CXDX_SAR_H
 
 
-typedef struct sar_param {
-	int type;
-        udomain_t* param;
-	cfg_action_t *paction;
-} sar_param_t;
-
-
-
 extern struct cdp_binds cdpb;
 extern str cxdx_forced_peer; /**< FQDN of the Diameter peer to send requests to */
 extern str cxdx_dest_realm;
diff --git a/modules/ims_registrar_scscf/doc/Makefile b/modules/ims_registrar_scscf/doc/Makefile
new file mode 100644
index 0000000..7aadeb1
--- /dev/null
+++ b/modules/ims_registrar_scscf/doc/Makefile
@@ -0,0 +1,4 @@
+docs = ims_registrar_scscf.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/ims_registrar_scscf/doc/ims_registrar_scscf.xml b/modules/ims_registrar_scscf/doc/ims_registrar_scscf.xml
new file mode 100644
index 0000000..c60e853
--- /dev/null
+++ b/modules/ims_registrar_scscf/doc/ims_registrar_scscf.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+]>
+<book>
+  <bookinfo>
+    <title>IMS Usrloc PCSCF Module</title>
+
+    <productname class="trade">&kamailioname;</productname>
+
+    <authorgroup>
+      <author>
+        <firstname>Jason Penton</firstname>
+
+        <surname/>
+
+        <affiliation>
+          <orgname>Smile Communications</orgname>
+        </affiliation>
+
+        <address>
+			<email>jason.penton at smilecoms.com</email>
+		</address>
+      </author>
+
+      <editor>
+        <firstname>Richard</firstname>
+
+        <surname>Good</surname>
+        
+	<affiliation>
+          <orgname>Smile Communications</orgname>
+        </affiliation>
+
+        <address>
+			<email>richard.good at smilecoms.com</email>
+		</address>
+      </editor>
+    </authorgroup>
+
+    <copyright>
+      <year>2012</year>
+
+      <holder>Smile Communications</holder>
+    </copyright>
+  </bookinfo>
+
+  <toc/>
+
+  <xi:include href="ims_registrar_scscf_admin.xml"
+              xmlns:xi="http://www.w3.org/2001/XInclude"/>
+
+  <xi:include href="ims_registrar_scscf_faq.xml"
+              xmlns:xi="http://www.w3.org/2001/XInclude"/>
+</book>
diff --git a/modules/ims_registrar_scscf/doc/ims_registrar_scscf_admin.xml b/modules/ims_registrar_scscf/doc/ims_registrar_scscf_admin.xml
new file mode 100644
index 0000000..00b9b5c
--- /dev/null
+++ b/modules/ims_registrar_scscf/doc/ims_registrar_scscf_admin.xml
@@ -0,0 +1,727 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+]>
+<!-- Module User's Guide -->
+<chapter>
+  <title>&adminguide;</title>
+
+  <section>
+    <title>Overview</title>
+
+    <para>This module contains REGISTER processing logic for the S-CSCF. The
+    'storage engine' of this module is provided by the ims_usrloc_scscf
+    module:</para>
+  </section>
+
+  <section>
+    <title>Dependencies</title>
+
+    <section>
+      <title>&kamailio; Modules</title>
+
+      <para>The following modules must be loaded before this module:
+      <itemizedlist>
+          <listitem>
+            <para><emphasis>CDP</emphasis></para>
+          </listitem>
+
+          <listitem>
+            <para><emphasis>CDP_AVP</emphasis></para>
+          </listitem>
+
+          <listitem>
+            <para><emphasis>TM</emphasis></para>
+          </listitem>
+
+          <listitem>
+            <para><emphasis>ims_usrloc_scscf</emphasis></para>
+          </listitem>
+        </itemizedlist></para>
+    </section>
+
+    <section>
+      <title>External Libraries or Applications</title>
+
+      <para>The following libraries or applications must be installed before
+      running &kamailio; with this module loaded: <itemizedlist>
+          <listitem>
+            <para><emphasis>LibXML2 - used for parsing the XML Subscription
+            information obtained from the HSS (Home Subscriber
+            Server)</emphasis></para>
+          </listitem>
+        </itemizedlist></para>
+    </section>
+  </section>
+
+  <section>
+    <title>Parameters</title>
+
+    <section>
+      <title>default_expires (int)</title>
+
+      <para>If the processed message contains neither Expires HFs nor expires
+      contact parameters, this value will be used for newly created S-CSCF
+      usrloc records. The parameter contains number of second to expire (for
+      example use 3600 for one hour). If it is set to a lower value than the
+      “min_expires” parameter then it will be ignored. This
+      parameter can be modified via ser config framework. A random value in a
+      specific interval can be selected by using the default_expires_range
+      parameter</para>
+
+      <para><emphasis> Default value is 3600. </emphasis></para>
+
+      <example>
+        <title>Set <varname>default_expires</varname> parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "default_expires", 3600)
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>default_expires_range (int)</title>
+
+      <para>This parameter specifies that the expiry used for newly created
+      S-CSCF usrloc records are not fixed(when “default_expires”
+      applies), but a random value in the interval
+      “[default_expires-default_expires_range%,
+      default_expires+default_expires_range%]”. The value is between 0
+      and 100 and represent the maximim percentage from default_expires that
+      will be substracted or added when computing the value. Default in 0,
+      meaning default_expires is left unmodified. This parameter can be
+      modified via ser config framework.</para>
+
+      <para><emphasis> Default value is 0. </emphasis></para>
+
+      <example>
+        <title>Set <varname>default_expires_range </varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "default_expires_range", 30) # +- 30% from default_expires
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>min_expires (int)</title>
+
+      <para>The minimum expires value of a Contact, values lower than this
+      minimum will be automatically set to the minimum. Value 0 disables the
+      checking. This parameter can be modified via ser config
+      framework.</para>
+
+      <para><emphasis> Default value is 60. </emphasis></para>
+
+      <example>
+        <title>Set <varname>min_expires</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "min_expires", 1800)
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>max_expires (int)</title>
+
+      <para>The maximum expires value of a Contact, values higher than this
+      maximum will be automatically set to the maximum. Value 0 disables the
+      checking. This parameter can be modified via ser config
+      framework.</para>
+
+      <para><emphasis> Default value is 0. </emphasis></para>
+
+      <example>
+        <title>Set <varname>max_expires</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "max_expires", 3600)
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>user_data_dtd (string)</title>
+
+      <para>DTD to check the user data received in SAA (Server Assignment
+      Answer).</para>
+
+      <para><emphasis> Default value is NULL (none). </emphasis></para>
+
+      <example>
+        <title>Set <varname>user_data_dtd</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "user_data_dtd", "/usr/local/etc/kamailio/CxDataType_Rel7.dtd")
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>user_data_xsd (string)</title>
+
+      <para>XSD to check the user data received in SAA (Server Assignment
+      Answer).</para>
+
+      <para><emphasis> Default value is NULL (none). </emphasis></para>
+
+      <example>
+        <title>Set <varname>user_data_xsd</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "user_data_xsd", "/usr/local/etc/kamailio/CxDataType_Rel7.xsd")
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>support_wildcardPSI (int)</title>
+
+      <para>indicate support for wildcard PSI is subscription profile
+      (SAA)</para>
+
+      <para><emphasis> Default value is 0. </emphasis></para>
+
+      <example>
+        <title>Set <varname>support_wildcardPSI</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "support_wildcardPSI", 1)
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>scscf_name (string)</title>
+
+      <para>The name of the S-CSCF</para>
+
+      <para><emphasis> Default value is sip:scscf.ims.smilecoms.com:6060.
+      </emphasis></para>
+
+      <example>
+        <title>Set <varname>scscf_name</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "scscf_name", "sip:scscf2.ims.smilecoms.com:6060")
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>store_profile_dereg (int)</title>
+
+      <para>Should the subscription profile be stored on
+      de-registration</para>
+
+      <para><emphasis> Default value 0.</emphasis></para>
+
+      <example>
+        <title>Set <varname>store_profile_dereg</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "store_profile_dereg", 1)
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>cxdx_dest_realm (string)</title>
+
+      <para>Destination realm to be used in Diameter messages</para>
+
+      <para><emphasis> Default value "ims.smilecoms.com"</emphasis></para>
+
+      <example>
+        <title>Set <varname>cxdx_dest_realm</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "cxdx_dest_realm", "my.domain,org")
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>cxdx_forced_peer (string)</title>
+
+      <para>Forced HSS Peer to use for CxDx Diameter interface</para>
+
+      <para><emphasis> Default value NULL (none)</emphasis></para>
+
+      <example>
+        <title>Set <varname>cxdx_forced_peer</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "cxdx_forced_peer", "hss.ims.smilecoms.com")
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>append_branches (integer)</title>
+
+      <para>The parameter controls how lookup function processes multiple
+      contacts. If there are multiple contacts for the given username in
+      usrloc and this parameter is set to 1, Request-URI will be overwritten
+      with the highest-q rated contact and the rest will be appended to
+      sip_msg structure and can be later used by tm for forking. If the
+      parameter is set to 0, only Request-URI will be overwritten with the
+      highest-q rated contact and the rest will be left unprocessed. This
+      parameter can be modified via Kamailio config framework.</para>
+
+      <para><emphasis> Default value is 0 (disabled)</emphasis></para>
+
+      <example>
+        <title>Set <varname>cxdx_forced_peer</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "append_branches", 1)
+...</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title>method_filtering (integer)</title>
+
+      <para>Tells if the contact filtering based on supported methods should
+      be performed during lookup. It's enabled only if it has a non zero
+      value.</para>
+
+      <para><emphasis> Default value is 0 (disabled)</emphasis></para>
+
+      <example>
+        <title>Set <varname>cxdx_forced_peer</varname>parameter</title>
+
+        <programlisting format="linespecific">...
+        modparam("ims_registrar_scscf", "method_filtering", 1)
+...</programlisting>
+      </example>
+    </section>
+  </section>
+
+  <section>
+    <title>Functions</title>
+
+    <section>
+      <title><function moreinfo="none">save(async_reply_route,
+      domain)</function></title>
+
+      <para>The function processes a REGISTER message. It can add, remove or
+      modify usrloc records depending on Contact and Expires HFs in the
+      REGISTER message. On success and when called from the REQUEST_ROUTE, 200
+      OK will be returned listing all contacts that are currently in usrloc.
+      On an error, error message will be sent with a short description in
+      reason phrase. In case of internal errors the function will return
+      FALSE, otherwise a force to exit the cfg is file is actioned by
+      returning 0 (asynchronous processing)</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>async_reply_route</emphasis>- the route to execute
+          after the save has completed. This is required because the save
+          function is executed asynchronously (Diameter).</para>
+        </listitem>
+
+        <listitem>
+          <para><emphasis>domain</emphasis>- Logical domain within
+          registrar.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE</para>
+
+      <example>
+        <title><function>save</function> usage</title>
+
+        <programlisting format="linespecific">...
+if (!impu_registered("location")) {
+   save("PRE_REG_SAR_REPLY","location");
+}
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function moreinfo="none">lookup(domain)</function></title>
+
+      <para>This function extract the IMPU from the Request-URI and tries to
+      find all registered contacts in usrloc. If there are no such contacts,
+      -1 is returned. If there are, Request-URI will be rewritten with the
+      contact that has the highest q value. The rest of the contacts will be
+      appended to the sip msg structure (if append_branches is set) and can be
+      later used by TM module for forking for example...</para>
+
+      <para>If the method filtering option is enabled, the lookup function
+      will only return contacts that support the method of the request being
+      processed (see allows header)</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <para><itemizedlist>
+          <listitem>
+            <para><emphasis>domain</emphasis> - Logical domain within
+            registrar.</para>
+          </listitem>
+        </itemizedlist></para>
+
+      <para>Return codes:</para>
+
+      <para><itemizedlist>
+          <listitem>
+            <para><emphasis>-1</emphasis> - Not found</para>
+          </listitem>
+
+          <listitem>
+            <para>-2 - Found, but method not allowed (check Allows header for
+            INVITE, MESSAGE, etc).</para>
+          </listitem>
+
+          <listitem>
+            <para>-3 - Error ocurred internally during processing</para>
+          </listitem>
+        </itemizedlist></para>
+
+      <para>This function can be used from REQUEST_ROUTE, FAILURE_ROUTE</para>
+
+      <example>
+        <title><function>lookup</function> usage</title>
+
+        <programlisting format="linespecific">...
+lookup("location");
+switch ($retcode) {
+    case -1:
+    case -3:
+        sl_send_reply("404", "Not Found");
+        exit;
+    case -2:
+        sl_send_reply("405", "Not Found");
+        exit;
+};
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function moreinfo="none">unregister(domain)</function></title>
+
+      <para>This function will remove all bindings for the IMPU found in the
+      Request-URI.</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>Domain</emphasis>- Logical domain within
+          registrar.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used in REQUEST_ROUTE, FAILURE_ROUTE</para>
+
+      <example>
+        <title><function>unregister</function> usage</title>
+
+        <programlisting format="linespecific">...
+unregister("location");
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function moreinfo="none">assign_server_unreg(aysnc_reply_route,
+      domain, direction)</function></title>
+
+      <para>TBD</para>
+
+      <para>used in REQUEST_ROUTE</para>
+    </section>
+
+    <section>
+      <title><function
+      moreinfo="none">impu_registered(domain)</function></title>
+
+      <para>This function checks if the IMPU in the To header is registered in
+      usrloc.</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>domain</emphasis>- Logical domain within
+          registrar.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Return codes:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>1 - True, IMPU exists in registered state in usrloc</para>
+        </listitem>
+
+        <listitem>
+          <para><emphasis>-1 - False, IMPU not registered</emphasis></para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used in REQUEST_ROUTE, FAILURE_ROUTE</para>
+
+      <example>
+        <title><function>impu_registered</function> usage</title>
+
+        <programlisting format="linespecific">...
+impu_registered("location");
+switch ($retcode) {
+    case -1:
+        sl_send_reply("404", "Not Found");
+        exit;
+    case 1:
+        #true, continue with normal processing
+};
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function
+      moreinfo="none">term_impu_registered(domain)</function></title>
+
+      <para>This function checks if the IMPU in the Request-URI is registered
+      in usrloc.</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>domain</emphasis>- Logical domain within
+          registrar.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Return codes:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>1 - True, IMPU exists in registered state in usrloc</para>
+        </listitem>
+
+        <listitem>
+          <para><emphasis>-1 - False, IMPU not registered</emphasis></para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used in REQUEST_ROUTE, FAILURE_ROUTE</para>
+
+      <example>
+        <title><function>term_impu_registered</function> usage</title>
+
+        <programlisting format="linespecific">...
+term_impu_registered("location");
+switch ($retcode) {
+     case -1:
+          sl_send_reply("404", "Not Found");
+          exit;
+     case 1:
+          #true, continue with normal processing
+};
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function moreinfo="none">reg_fetch_contacts(domain, uri,
+      profile)</function></title>
+
+      <para>The function fetches the contacts for 'uri' from table 'domain' to
+      pseudo-variable $imssulc(profile) [imssulc = ims scscf ulc].</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>domain </emphasis>- Name of table that should be
+          used for the lookup of contact addresses.</para>
+        </listitem>
+
+        <listitem>
+          <para><emphasis>uri</emphasis> - The SIP URI address of the user
+          which to fetch the contact addresses for. It can contain
+          pseudo-variables that are evaluated at runtime.</para>
+        </listitem>
+
+        <listitem>
+          <para><emphasis>profile</emphasis> - Name of $imssulc
+          pseudo-variable profile that will store the fetched contacts. It is
+          a static string.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used in REQUEST_ROUTE, FAILURE_ROUTE</para>
+
+      <example>
+        <title><function>reg_fetch_contacts</function> usage</title>
+
+        <programlisting format="linespecific">...
+reg_fetch_contacts("location", "$ru", "callee");
+reg_fetch_contacts("location", "sip:user at kamailio.org", "caller");
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function
+      moreinfo="none">reg_free_contacts(profile)</function></title>
+
+      <para>The function frees the contacts from pseudo-variable
+      $ulc(profile). Should be called to release the content of a profile.
+      Anyhow, fetching a new contact addresses set over a profile will release
+      any existing data in that profile.</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>profile</emphasis> - Name of $imssulc
+          pseudo-variable profile that stores the contacts. It is a static
+          string.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used in REQUEST_ROUTE, FAILURE_ROUTE</para>
+
+      <example>
+        <title><function>reg_free_contacts</function> usage</title>
+
+        <programlisting format="linespecific">...
+reg_free_contacts("callee");
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function
+      moreinfo="none">can_subscribe_to_reg(domain)</function></title>
+
+      <para>This function checks to see that a SUBSCRIBE request is authorised
+      to subscribe to the particular identity. Only 3 entities can
+      subscribe:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>The user agent to it's own state</emphasis></para>
+        </listitem>
+
+        <listitem>
+          <para>The P-CSCF specified in the path header for that user</para>
+        </listitem>
+
+        <listitem>
+          <para>Application Server (AS) not yet implemented</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>domain - Logical domain within
+          registrar.</emphasis></para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used in REQUEST_ROUTE</para>
+
+      <example>
+        <title><function>can_subscribe_to_reg</function> usage</title>
+
+        <programlisting format="linespecific">...
+if (can_subscribe_to_reg("location")){
+     $var(ret)= subscribe_to_reg("location");
+}
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function
+      moreinfo="none">subscribe_to_reg(domain)</function></title>
+
+      <para>Save the subscription to the REG event for the UAC or the
+      appropriate P-CSCF (in the path to the UAC).</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>domain - Logical domain within
+          registrar.</emphasis></para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used in REQUEST_ROUTE</para>
+
+      <example>
+        <title><function>subscribe_to_reg</function> usage</title>
+
+        <programlisting format="linespecific">...
+if (can_subscribe_to_reg("location")){
+     $var(ret)= subscribe_to_reg("location");
+}
+...
+</programlisting>
+      </example>
+    </section>
+  </section>
+
+  <section>
+    <title>RPC Commands</title>
+
+    <para>exported RPC commands.</para>
+
+    <section>
+      <title>ulpcscf.status</title>
+
+      <para>Status of pcscf_usrloc, AORs, max slots, etc.</para>
+    </section>
+  </section>
+
+  <section>
+    <title>Statistics</title>
+
+    <para>Exported statistics are listed in the next sections.</para>
+
+    <section>
+      <title>registered contacts</title>
+
+      <para>Number of AOR contacts in registered state - cannot be
+      reset.</para>
+    </section>
+
+    <section>
+      <title>impus</title>
+
+      <para>Number of IMPUs - cannot be reset.</para>
+    </section>
+
+    <section>
+      <title>expired contacts</title>
+
+      <para>Number of expired contacts - can be reset.</para>
+    </section>
+  </section>
+</chapter>
diff --git a/modules/ims_registrar_scscf/doc/ims_registrar_scscf_faq.xml b/modules/ims_registrar_scscf/doc/ims_registrar_scscf_faq.xml
new file mode 100644
index 0000000..918ef51
--- /dev/null
+++ b/modules/ims_registrar_scscf/doc/ims_registrar_scscf_faq.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Module FAQ -->
+
+<chapter>
+	
+	<title>&faqguide;</title>
+	<qandaset defaultlabel="number">
+	<qandaentry>
+		<question>
+		<para>Where can I find more about &kamailio;?</para>
+		</question>
+		<answer>
+		<para>
+			Take a look at &kamailiohomelink;.
+		</para>
+		</answer>
+	</qandaentry>
+	<qandaentry>
+		<question>
+		<para>Where can I post a question about this module?</para>
+		</question>
+		<answer>
+		<para>
+			First at all check if your question was already answered on one of
+			our mailing lists: 
+		</para>
+		<itemizedlist>
+			<listitem>
+			<para>User Mailing List - &kamailiouserslink;</para>
+			</listitem>
+			<listitem>
+			<para>Developer Mailing List - &kamailiodevlink;</para>
+			</listitem>
+		</itemizedlist>
+		<para>
+			E-mails regarding any stable &kamailio; release should be sent to 
+			&kamailiousersmail; and e-mails regarding development versions
+			should be sent to &kamailiodevmail;.
+		</para>
+		<para>
+			If you want to keep the mail private, send it to 
+			&kamailiohelpmail;.
+		</para>
+		</answer>
+	</qandaentry>
+	<qandaentry>
+		<question>
+		<para>How can I report a bug?</para>
+		</question>
+		<answer>
+		<para>
+			Please follow the guidelines provided at:
+			&kamailiobugslink;.
+		</para>
+		</answer>
+	</qandaentry>
+	</qandaset>
+</chapter>
+
diff --git a/modules/ims_registrar_scscf/reg_mod.c b/modules/ims_registrar_scscf/reg_mod.c
index f948dcb..1347a07 100644
--- a/modules/ims_registrar_scscf/reg_mod.c
+++ b/modules/ims_registrar_scscf/reg_mod.c
@@ -107,15 +107,13 @@ str scscf_serviceroute_uri_str; /* Service Route URI */
 static int mod_init(void);
 static int child_init(int);
 static void mod_destroy(void);
-static int w_save(struct sip_msg* _m, char* _d, char* mode, char* _cflags);
-static int w_assign_server_unreg(struct sip_msg* _m, char* _d, char* _direction);
+static int w_save(struct sip_msg* _m, char * _route, char* _d, char* mode, char* _cflags);
+static int w_assign_server_unreg(struct sip_msg* _m, char* _route, char* _d, char* _direction);
 static int w_lookup(struct sip_msg* _m, char* _d, char* _p2);
 
 /*! \brief Fixup functions */
 static int domain_fixup(void** param, int param_no);
-static int assign_save_fixup3(void** param, int param_no);
-//static int save_fixup2(void** param, int param_no);
-//static int assign_fixup2(void** param, int param_no);
+static int assign_save_fixup3_async(void** param, int param_no);
 static int unreg_fixup(void** param, int param_no);
 static int fetchc_fixup(void** param, int param_no);
 /*! \brief Functions */
@@ -186,11 +184,11 @@ static pv_export_t mod_pvs[] = {
  * Exported functions
  */
 static cmd_export_t cmds[] = {
-    {"save", (cmd_function) w_save, 1, assign_save_fixup3, 0, REQUEST_ROUTE | ONREPLY_ROUTE},
+    {"save", (cmd_function) w_save, 2, assign_save_fixup3_async, 0, REQUEST_ROUTE | ONREPLY_ROUTE},
     {"lookup", (cmd_function) w_lookup, 1, domain_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE},
     {"term_impu_registered", (cmd_function) term_impu_registered, 1, domain_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE},
     {"impu_registered", (cmd_function) impu_registered, 1, domain_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE},
-    {"assign_server_unreg", (cmd_function) w_assign_server_unreg, 2, assign_save_fixup3, 0, REQUEST_ROUTE},
+    {"assign_server_unreg", (cmd_function) w_assign_server_unreg, 3, assign_save_fixup3_async, 0, REQUEST_ROUTE},
     {"add_sock_hdr", (cmd_function) add_sock_hdr, 1, fixup_str_null, 0, REQUEST_ROUTE},
     {"unregister", (cmd_function) unregister, 2, unreg_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE},
     {"reg_fetch_contacts", (cmd_function) pv_fetch_contacts, 3, fetchc_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE},
@@ -510,18 +508,16 @@ static int child_init(int rank) {
 /*! \brief
  * Wrapper to save(location)
  */
-static int w_save(struct sip_msg* _m, char* _d, char* mode, char* _cflags) {
-    //return save(_m, (udomain_t*)_d);
-    return save(_m, _d);
+static int w_save(struct sip_msg* _m, char* _route, char* _d, char* mode, char* _cflags) {
+    return save(_m, _d, _route);
 }
 
-static int w_assign_server_unreg(struct sip_msg* _m, char* _d, char* _direction) {
+static int w_assign_server_unreg(struct sip_msg* _m, char* _route, char* _d, char* _direction) {
     str direction;
 
     direction.s = _direction;
     direction.len = strlen(_direction);
-    //return assign_server_unreg(_m, (udomain_t*)_d, &direction);
-    return assign_server_unreg(_m, _d, &direction);
+    return assign_server_unreg(_m, _d, &direction, _route);
 
 }
 
@@ -565,35 +561,25 @@ static int unreg_fixup(void** param, int param_no) {
 /*
  * Convert the char* parameters
  */
-static int assign_save_fixup3(void** param, int param_no) {
+static int assign_save_fixup3_async(void** param, int param_no) {
 
     if (strlen((char*) *param) <= 0) {
         LM_ERR("empty parameter %d not allowed\n", param_no);
         return -1;
     }
 
-    if (param_no == 1) {
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0)
+            return -1;
+        return 0;
+    } else if (param_no == 2) {
         udomain_t* d;
 
         if (ul.register_udomain((char*) *param, &d) < 0) {
-            LM_ERR("Erroring doing fixup on assign save");
+            LM_ERR("Error doing fixup on assign save");
             return -1;
         }
-
         *param = (void*) d;
-
-        sar_param_t *ap;
-        ap = (sar_param_t*) pkg_malloc(sizeof (sar_param_t));
-        if (ap == NULL) {
-            LM_ERR("no more pkg\n");
-            return -1;
-        }
-        memset(ap, 0, sizeof (sar_param_t));
-        ap->paction = get_action_from_param(param, param_no);
-
-        ap->param = (udomain_t*) * param;
-
-        *param = (void*) ap;
     }
 
     return 0;
diff --git a/modules/ims_registrar_scscf/reg_mod.h b/modules/ims_registrar_scscf/reg_mod.h
index d78e408..328d52f 100644
--- a/modules/ims_registrar_scscf/reg_mod.h
+++ b/modules/ims_registrar_scscf/reg_mod.h
@@ -62,7 +62,6 @@
 #define USERNAME_MAX_SIZE      64
 #define DOMAIN_MAX_SIZE        128
 #define CALLID_MAX_SIZE        255
-#define UA_MAX_SIZE            255
 
 #define PATH_MODE_STRICT	2
 #define PATH_MODE_LAZY		1
diff --git a/modules/ims_registrar_scscf/reply.c b/modules/ims_registrar_scscf/reply.c
index 0dc6a32..64b31c3 100644
--- a/modules/ims_registrar_scscf/reply.c
+++ b/modules/ims_registrar_scscf/reply.c
@@ -38,7 +38,7 @@
 #include "../../ut.h"
 #include "../../parser/msg_parser.h"
 #include "../../parser/contact/contact.h"
-#include "../../lib/kcore/parse_supported.h"
+#include "../../parser/parse_supported.h"
 #include "../../data_lump_rpl.h"
 #include "../ims_usrloc_scscf/usrloc.h"
 #include "rerrno.h"
@@ -563,7 +563,7 @@ int build_p_associated_uri(ims_subscription* s) {
  * Send a reply
  */
 int reg_send_reply_transactional(struct sip_msg* _m, contact_for_header_t* contact_header, struct cell* t_cell) {
-    str unsup = str_init(SUPPORTED_PATH_STR);
+    str unsup = str_init(OPTION_TAG_PATH_STR);
     long code;
     str msg = str_init(MSG_200); /* makes gcc shut up */
     char* buf;
@@ -582,7 +582,7 @@ int reg_send_reply_transactional(struct sip_msg* _m, contact_for_header_t* conta
                     return -1;
                 if (add_path(_m, &_m->path_vec) < 0)
                     return -1;
-            } else if (get_supported(_m) & F_SUPPORTED_PATH) {
+            } else if (get_supported(_m) & F_OPTION_TAG_PATH) {
                 if (add_path(_m, &_m->path_vec) < 0)
                     return -1;
             } else if (path_mode == PATH_MODE_STRICT) {
@@ -656,7 +656,7 @@ int reg_send_reply_transactional(struct sip_msg* _m, contact_for_header_t* conta
  * Send a reply
  */
 int reg_send_reply(struct sip_msg* _m, contact_for_header_t* contact_header) {
-    str unsup = str_init(SUPPORTED_PATH_STR);
+    str unsup = str_init(OPTION_TAG_PATH_STR);
     long code;
     str msg = str_init(MSG_200); /* makes gcc shut up */
     char* buf;
@@ -675,7 +675,7 @@ int reg_send_reply(struct sip_msg* _m, contact_for_header_t* contact_header) {
                     return -1;
                 if (add_path(_m, &_m->path_vec) < 0)
                     return -1;
-            } else if (get_supported(_m) & F_SUPPORTED_PATH) {
+            } else if (get_supported(_m) & F_OPTION_TAG_PATH) {
                 if (add_path(_m, &_m->path_vec) < 0)
                     return -1;
             } else if (path_mode == PATH_MODE_STRICT) {
diff --git a/modules/ims_registrar_scscf/save.c b/modules/ims_registrar_scscf/save.c
index 827f63e..7602bf9 100644
--- a/modules/ims_registrar_scscf/save.c
+++ b/modules/ims_registrar_scscf/save.c
@@ -259,7 +259,7 @@ static inline ucontact_info_t* pack_ci(struct sip_msg* _m, contact_t* _c, unsign
 
         /* additional info from message */
         if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent
-                && _m->user_agent->body.len > 0 && _m->user_agent->body.len < UA_MAX_SIZE) {
+                && _m->user_agent->body.len > 0 && _m->user_agent->body.len < MAX_UA_SIZE) {
             ci.user_agent = &_m->user_agent->body;
         } else {
             ci.user_agent = &no_ua;
@@ -926,20 +926,37 @@ error:
 
 }
 
-int assign_server_unreg(struct sip_msg* _m, char* str1, str* direction) {
+int assign_server_unreg(struct sip_msg* _m, char* str1, str* direction, char* route) {
     str private_identity = {0, 0}, public_identity = {0, 0};
     int assignment_type = AVP_IMS_SAR_NO_ASSIGNMENT;
     int data_available = AVP_IMS_SAR_USER_DATA_NOT_AVAILABLE;
     int require_user_data = 1;
     rerrno = R_FINE;
     tm_cell_t *t = 0;
+    str route_name;
 
     saved_transaction_t* saved_t;
     cfg_action_t* cfg_action;
 
-    sar_param_t* ap = (sar_param_t*) str1;
-    cfg_action = ap->paction->next;
-
+    udomain_t* _d = (udomain_t*) str1;
+    
+    if (fixup_get_svalue(_m, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    
     LM_DBG("Assigning unregistered user for direction [%.*s]\n", direction->len, direction->s);
 
     enum cscf_dialog_direction dir = cscf_get_dialog_direction(direction->s);
@@ -995,7 +1012,7 @@ int assign_server_unreg(struct sip_msg* _m, char* str1, str* direction) {
     saved_t->expires = 1; //not a dereg as this is server_assign_unreg
     saved_t->require_user_data = require_user_data;
     saved_t->sar_assignment_type = assignment_type;
-    saved_t->domain = (udomain_t*) ap->param;
+    saved_t->domain = (udomain_t*) _d;
 
     saved_t->contact_header = 0;
 
@@ -1043,7 +1060,7 @@ error:
  */
 //int save(struct sip_msg* msg, udomain_t* _d) {
 
-int save(struct sip_msg* msg, char* str1) {
+int save(struct sip_msg* msg, char* str1, char *route) {
     int expires;
     int require_user_data = 0;
     int data_available;
@@ -1051,6 +1068,9 @@ int save(struct sip_msg* msg, char* str1) {
     int st;
     str public_identity, private_identity, realm;
     int sar_assignment_type = AVP_IMS_SAR_NO_ASSIGNMENT;
+    str route_name;
+    
+    udomain_t* _d = (udomain_t*) str1;
 
     rerrno = R_FINE;
     get_act_time();
@@ -1062,8 +1082,22 @@ int save(struct sip_msg* msg, char* str1) {
 
     contact_for_header_t* contact_header = 0;
 
-    sar_param_t* ap = (sar_param_t*) str1;
-    cfg_action = ap->paction->next;
+    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
 
     //check which route block we are in - if not request then we fail out.
     if (!is_route_type(REQUEST_ROUTE)) {
@@ -1106,7 +1140,7 @@ int save(struct sip_msg* msg, char* str1) {
 
     expires = cscf_get_max_expires(msg, 0); //check all contacts for max expires
     if (expires != 0) { //if <0 then no expires was found in which case we treat as reg/re-reg with default expires.
-        if (is_impu_registered((udomain_t*) ap->param, &public_identity)) {
+        if (is_impu_registered(_d, &public_identity)) {
             LM_DBG("preparing for SAR assignment for RE-REGISTRATION <%.*s>\n", public_identity.len, public_identity.s);
             sar_assignment_type = AVP_IMS_SAR_RE_REGISTRATION;
         } else {
@@ -1135,7 +1169,7 @@ int save(struct sip_msg* msg, char* str1) {
             //unregister the requested contacts, if none left at the end then send a SAR, otherwise return successfully
             LM_DBG("need to unregister contacts\n");
             //lets update the contacts - we need to know if all were deleted or not for the public identity
-            int res = update_contacts_new(msg, (udomain_t*) ap->param, &public_identity, sar_assignment_type, 0, 0, 0, 0, 0, &contact_header);
+            int res = update_contacts_new(msg, _d, &public_identity, sar_assignment_type, 0, 0, 0, 0, 0, &contact_header);
             if (res <= 0) {
                 LM_ERR("Error processing REGISTER for de-registration\n");
                 free_contact_buf(contact_header);
@@ -1190,7 +1224,8 @@ int save(struct sip_msg* msg, char* str1) {
     saved_t->expires = expires;
     saved_t->require_user_data = require_user_data;
     saved_t->sar_assignment_type = sar_assignment_type;
-    saved_t->domain = (udomain_t*) ap->param;
+    
+    saved_t->domain = _d;
 
     saved_t->public_identity.s = (char*) shm_malloc(public_identity.len + 1);
     if (!saved_t->public_identity.s) {
diff --git a/modules/ims_registrar_scscf/save.h b/modules/ims_registrar_scscf/save.h
index 5ab4488..ac064aa 100644
--- a/modules/ims_registrar_scscf/save.h
+++ b/modules/ims_registrar_scscf/save.h
@@ -56,9 +56,9 @@
 /*! \brief
  * Process REGISTER request and save it's contacts
  */
-int assign_server_unreg(struct sip_msg* _m, char* str1, str* direction);
+int assign_server_unreg(struct sip_msg* _m, char* str1, str* direction, char* route);
 
-int save(struct sip_msg* msg, char* str1);
+int save(struct sip_msg* msg, char* str1, char* route);
 
 int unregister(struct sip_msg* _m, char* _d, char* _uri);
 
diff --git a/modules/ims_usrloc_pcscf/udomain.c b/modules/ims_usrloc_pcscf/udomain.c
index f82c941..3d2d46c 100644
--- a/modules/ims_usrloc_pcscf/udomain.c
+++ b/modules/ims_usrloc_pcscf/udomain.c
@@ -376,7 +376,7 @@ int update_pcontact(struct udomain* _d, struct pcontact_info* _ci, struct pconta
 		}
 	}
 
-	// update received info:
+	// update received info (if info is available):
 	if (_ci->received_host.len > 0) {
 		if (_c->received_host.s)
 			shm_free(_c->received_host.s);
@@ -433,31 +433,80 @@ int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsign
 	int i;
 	struct pcontact* c;
 
-	if (_d->table) {
-		for(i = 0; i < _d->size; i++) {
+	for(i=0; i<_d->size; i++)
+	{
+		c = _d->table[i].first;
+		while(c) {
+			LM_DBG("Port %d (search %d), Proto %d (search %d), reg_state %s (search %s)\n",
+				c->received_port, _port, c->received_proto, _proto, 
+				reg_state_to_string(c->reg_state), reg_state_to_string(PCONTACT_REGISTERED)
+				);
+			// First check, if Proto and Port matches:
+			if ((c->reg_state == PCONTACT_REGISTERED) && (c->received_port == _port) && (c->received_proto == _proto)) {
+				LM_DBG("Received host len %d (search %d)\n", c->received_host.len, _host->len);
+				// Then check the length:
+				if (c->received_host.len == _host->len) {
+					LM_DBG("Received host %.*s (search %.*s)\n",
+						c->received_host.len, c->received_host.s,
+						_host->len, _host->s);
+
+					// Finally really compare the "received_host"
+					if (!memcmp(c->received_host.s, _host->s, _host->len)) {
+						*_c = c;
+						return 0;
+					}
+				}
+			}
+			c = c->next;
 		}
 	}
+	return 1; /* Nothing found */
+}
 
 
+int assert_identity(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity) {
+	int i;
+	struct pcontact* c;
+	// Public identities of this contact
+	struct ppublic * p;
+
 	for(i=0; i<_d->size; i++)
 	{
 		c = _d->table[i].first;
 		while(c) {
+			LM_DBG("Port %d (search %d), Proto %d (search %d), reg_state %s (search %s)\n",
+				c->received_port, _port, c->received_proto, _proto, 
+				reg_state_to_string(c->reg_state), reg_state_to_string(PCONTACT_REGISTERED)
+				);
 			// First check, if Proto and Port matches:
 			if ((c->reg_state == PCONTACT_REGISTERED) && (c->received_port == _port) && (c->received_proto == _proto)) {
+				LM_DBG("Received host len %d (search %d)\n", c->received_host.len, _host->len);
 				// Then check the length:
 				if (c->received_host.len == _host->len) {
+					LM_DBG("Received host %.*s (search %.*s)\n",
+						c->received_host.len, c->received_host.s,
+						_host->len, _host->s);
+
 					// Finally really compare the "received_host"
 					if (!memcmp(c->received_host.s, _host->s, _host->len)) {
-						*_c = c;
-						return 0;
+						for (p = c->head; p; p = p->next) {
+							LM_DBG("Public identity: %.*s\n", p->public_identity.len, p->public_identity.s);
+							/* Check length: */
+							if (_identity->len == p->public_identity.len) {
+								/* Check contents: */
+								if (strncasecmp(_identity->s, p->public_identity.s, _identity->len) == 0) {
+									LM_DBG("Match!\n");
+									return 1;
+								}
+							} else LM_DBG("Length does not match.\n");
+						}
 					}
 				}
 			}
 			c = c->next;
 		}
 	}
-	return 1; /* Nothing found */
+	return 0; /* Nothing found */
 }
 
 int delete_pcontact(udomain_t* _d, str* _aor, struct pcontact* _c)
diff --git a/modules/ims_usrloc_pcscf/udomain.h b/modules/ims_usrloc_pcscf/udomain.h
index f2c74c6..23e4d58 100644
--- a/modules/ims_usrloc_pcscf/udomain.h
+++ b/modules/ims_usrloc_pcscf/udomain.h
@@ -78,6 +78,7 @@ int update_pcontact(struct udomain* _d, struct pcontact_info* _ci, struct pconta
 int insert_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _r);
 int get_pcontact(udomain_t* _d, str* _aor, struct pcontact** _r);
 int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c);
+int assert_identity(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity);
 int delete_pcontact(udomain_t* _d, str* _aor, struct pcontact* _r);
 
 #endif
diff --git a/modules/ims_usrloc_pcscf/usrloc.c b/modules/ims_usrloc_pcscf/usrloc.c
index 3a444b4..5d483b5 100644
--- a/modules/ims_usrloc_pcscf/usrloc.c
+++ b/modules/ims_usrloc_pcscf/usrloc.c
@@ -72,6 +72,7 @@ int bind_usrloc(usrloc_api_t* api) {
 	api->delete_pcontact = delete_pcontact;
 	api->get_pcontact = get_pcontact;
 	api->get_pcontact_by_src = get_pcontact_by_src;
+	api->assert_identity = assert_identity;
 
 	api->update_pcontact = update_pcontact;
 	api->update_rx_regsession = update_rx_regsession;
diff --git a/modules/ims_usrloc_pcscf/usrloc.h b/modules/ims_usrloc_pcscf/usrloc.h
index 38d4a2e..28724af 100644
--- a/modules/ims_usrloc_pcscf/usrloc.h
+++ b/modules/ims_usrloc_pcscf/usrloc.h
@@ -195,6 +195,8 @@ typedef int (*get_pcontact_t)(struct udomain* _d, str* _contact, struct pcontact
 
 typedef int (*get_pcontact_by_src_t)(struct udomain* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c);
 
+typedef int (*assert_identity_t)(struct udomain* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity);
+
 typedef int (*insert_pcontact_t)(struct udomain* _d, str* _aor, struct pcontact_info* ci, struct pcontact** _c);
 typedef int (*delete_pcontact_t)(struct udomain* _d, str* _aor, struct pcontact* _c);
 typedef int (*update_pcontact_t)(struct udomain* _d, struct pcontact_info* ci, struct pcontact* _c);
@@ -220,6 +222,7 @@ typedef struct usrloc_api {
 	delete_pcontact_t delete_pcontact;
 	get_pcontact_t get_pcontact;
 	get_pcontact_by_src_t get_pcontact_by_src;
+	assert_identity_t assert_identity;
 
 	update_pcontact_t update_pcontact;
 	update_rx_regsession_t update_rx_regsession;
diff --git a/modules/ipops/README b/modules/ipops/README
index 99bace3..982db00 100644
--- a/modules/ipops/README
+++ b/modules/ipops/README
@@ -36,6 +36,9 @@ I
               4.8. compare_pure_ips (ip1, ip2)
               4.9. is_ip_rfc1918 (ip)
               4.10. is_in_subnet (ip, subnet)
+              4.11. dns_sys_match_ip(hostname, ipaddr)
+              4.12. dns_int_match_ip(hostname, ipaddr)
+              4.13. dns_query(hostname, pvid)
 
    List of Examples
 
@@ -49,6 +52,9 @@ I
    1.8. compare_pure_ips usage
    1.9. is_ip_rfc1918 usage
    1.10. is_in_subnet usage
+   1.11. dns_sys_match_ip usage
+   1.12. dns_int_match_ip usage
+   1.13. dns_query usage
 
 Chapter 1. Admin Guide
 
@@ -73,11 +79,14 @@ Chapter 1. Admin Guide
         4.8. compare_pure_ips (ip1, ip2)
         4.9. is_ip_rfc1918 (ip)
         4.10. is_in_subnet (ip, subnet)
+        4.11. dns_sys_match_ip(hostname, ipaddr)
+        4.12. dns_int_match_ip(hostname, ipaddr)
+        4.13. dns_query(hostname, pvid)
 
 1. Overview
 
-   This module offers operations for handling IP addresses, both IPv4 and
-   IPv6.
+   The IPops module offers operations for handling IP addresses, both IPv4
+   and IPv6.
 
    IPv6 is defined in RFC 2460. The same IPv6 address can be represented
    by different ASCII strings, so binary comparison is required. For
@@ -124,6 +133,9 @@ Chapter 1. Admin Guide
    4.8. compare_pure_ips (ip1, ip2)
    4.9. is_ip_rfc1918 (ip)
    4.10. is_in_subnet (ip, subnet)
+   4.11. dns_sys_match_ip(hostname, ipaddr)
+   4.12. dns_int_match_ip(hostname, ipaddr)
+   4.13. dns_query(hostname, pvid)
 
 4.1. is_ip (ip)
 
@@ -329,3 +341,78 @@ if (is_in_subnet("10.0.123.123", "10.0.123.1/24")) {
   xlog("L_INFO", "it's in the subnet\n");
 }
 ...
+
+4.11. dns_sys_match_ip(hostname, ipaddr)
+
+   Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
+   otherwise. It does not use the internal DNS resolver, but directly
+   getaddrinfo(...). All addresses returned for the hostname are checked.
+   Note that some hosts may return different lists of IP addresses for
+   each query, if the DNS server is configured in that way (e.g., for
+   providing load balancing through DNS).
+
+   Parameters:
+     * hostname - string or pseudo-variable containing the hostname. The
+       resulting IP addresses from DNS query are compared with ipaddr.
+     * ipaddr - string or pseudo-variable containing the ip address.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.11. dns_sys_match_ip usage
+...
+if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
+    xdbg("ip address not associated with hostname\n");
+}
+...
+
+4.12. dns_int_match_ip(hostname, ipaddr)
+
+   Returns TRUE if ipaddr is associated by DNS to hostname. FALSE
+   otherwise. It uses internal DNS resolver. At this moment, the function
+   might not check all the IP addresses as returned by dns_sys_match_ip(),
+   because the internal resolver targets to discover the first address to
+   be used for relaying SIP traffic. Thus is better to use
+   dns_sys_match_ip() if the host you want to check has many IP addresses,
+   in different address famililies (IPv4/6).
+
+   Parameters:
+     * hostname - string or pseudo-variable containing the hostname. The
+       resulting IP addresses from DNS query are compared with ipaddr.
+     * ipaddr - string or pseudo-variable containing the ip address.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.12. dns_int_match_ip usage
+...
+if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
+    xdbg("ip address not associated with hostname\n");
+}
+...
+
+4.13. dns_query(hostname, pvid)
+
+   Store the IP addresses and their type that correspond to hostname in a
+   config variable $dns(pvid=>key).
+
+   Parameters:
+     * hostname - string or pseudo-variable containing the hostname. The
+       resulting IP addresses from DNS query are compared with ipaddr.
+     * pvid - container id for script variable.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.13. dns_query usage
+...
+if(dns_query("test.com", "xyz"))
+{
+    xlog(" number of addresses: $dns(xyz=>count)\n");
+    xlog(" ipv4 address found: $dns(xyz=>ipv4)\n");
+    xlog(" ipv6 address found: $dns(xyz=>ipv6)\n");
+    $var(i) = 0;
+    while($var(i)<$dns(xyz=>count)) {
+        xlog(" #[$var(i)] type ($dns(xyz=>type[$var(i)]))"
+             " addr [$dns(xyz=>addr[$var(i)])]\n");
+        $var(i) = $var(i) + 1;
+    }
+}
+...
diff --git a/modules/ipops/doc/ipops_admin.xml b/modules/ipops/doc/ipops_admin.xml
index 8cbeac2..bbf68cf 100644
--- a/modules/ipops/doc/ipops_admin.xml
+++ b/modules/ipops/doc/ipops_admin.xml
@@ -19,7 +19,7 @@
     <title>Overview</title>
          
     <para>
-      This module offers operations for handling IP addresses, both IPv4 and IPv6.
+      The IPops module offers operations for handling IP addresses, both IPv4 and IPv6.
     </para>
     <para>
       IPv6 is defined in <ulink url="http://tools.ietf.org/html/rfc2460">RFC 2460</ulink>.
@@ -93,7 +93,7 @@
 
     <title>Functions</title>
              
-    <section>
+    <section id="ipops.f.is_ip">
       <title>
         <function moreinfo="none">is_ip (ip)</function>
       </title>
@@ -131,7 +131,7 @@ if (is_ip($rd)) {
 
     </section>
 
-    <section>
+    <section id="ipops.f.is_pur_ip">
       <title>
         <function moreinfo="none">is_pure_ip (ip)</function>
       </title>
@@ -170,7 +170,7 @@ if (is_pure_ip($var(ip))) {
 
     </section>
 
-    <section>
+    <section id="ipops.f.is_ipv4">
       <title>
         <function moreinfo="none">is_ipv4 (ip)</function>
       </title>
@@ -208,7 +208,7 @@ if (is_ipv4("1.2.3.4")) {
 
     </section>
 
-    <section>
+    <section id="ipops.f.is_ipv6">
       <title>
         <function moreinfo="none">is_ipv6 (ip)</function>
       </title>
@@ -246,7 +246,7 @@ if (is_ipv6("1080:0:0:0:8:800:200C:417A")) {
 
     </section>
 
-    <section>
+    <section id="ipops.f.is_ipv6_reference">
       <title>
         <function moreinfo="none">is_ipv6_reference (ip)</function>
       </title>
@@ -284,7 +284,7 @@ if (is_ipv6_reference("[1080:0:0:0:8:800:200C:417A]")) {
 
     </section>
 
-    <section>
+    <section id="ipops.f.is_ip_type">
       <title>
         <function moreinfo="none">ip_type (ip)</function>
       </title>
@@ -359,7 +359,7 @@ switch($rc) {
 
     </section>
 
-    <section>
+    <section id="ipops.f.compare_ips">
       <title>
         <function moreinfo="none">compare_ips (ip1, ip2)</function>
       </title>
@@ -403,7 +403,7 @@ if (compare_ips("1080:0000:0000:0000:0008:0800:200C:417A", "[1080::8:800:200C:41
 
     </section>
 
-    <section>
+    <section id="ipops.f.compare_pure_ips">
       <title>
         <function moreinfo="none">compare_pure_ips (ip1, ip2)</function>
       </title>
@@ -447,7 +447,7 @@ if (compare_pure_ips($si, "1080::8:800:200C:417A")) {
 
     </section>
 
-    <section>
+    <section id="ipops.f.is_ip_rfc1918">
       <title>
         <function moreinfo="none">is_ip_rfc1918 (ip)</function>
       </title>
@@ -485,7 +485,7 @@ if (is_ip_rfc1918("10.0.123.123")) {
 
     </section>
  
-    <section>
+    <section id="ipops.f.is_in_subnet">
       <title>
         <function moreinfo="none">is_in_subnet (ip, subnet)</function>
       </title>
@@ -529,6 +529,157 @@ if (is_in_subnet("10.0.123.123", "10.0.123.1/24")) {
 
     </section>
 
+    <section id="ipops.f.dns_sys_match_ip">
+      <title>
+        <function moreinfo="none">dns_sys_match_ip(hostname, ipaddr)</function>
+      </title>
+
+      <para>
+		  Returns TRUE if ipaddr is associated by DNS to hostname. FALSE otherwise. It
+		  does not use the internal DNS resolver, but directly getaddrinfo(...). All
+		  addresses returned for the hostname are checked. Note that some hosts may
+		  return different lists of IP addresses for each query, if the DNS server
+		  is configured in that way (e.g., for providing load balancing through DNS).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+			  <emphasis>hostname</emphasis> - string or pseudo-variable containing the hostname.
+			  The resulting IP addresses from DNS query are compared with ipaddr.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>ipaddr</emphasis> - string or pseudo-variable containing the ip address.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from ANY_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>dns_sys_match_ip</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (!dns_sys_match_ip("myhost.com", "1.2.3.4")) {
+    xdbg("ip address not associated with hostname\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section id="ipops.f.dns_int_match_ip">
+      <title>
+        <function moreinfo="none">dns_int_match_ip(hostname, ipaddr)</function>
+      </title>
+
+      <para>
+		  Returns TRUE if ipaddr is associated by DNS to hostname. FALSE otherwise. It
+		  uses internal DNS resolver. At this moment, the function might not check all
+		  the IP addresses as returned by dns_sys_match_ip(), because the internal
+		  resolver targets to discover the first address to be used for relaying
+		  SIP traffic. Thus is better to use dns_sys_match_ip() if the host you want
+		  to check has many IP addresses, in different address famililies (IPv4/6).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+			  <emphasis>hostname</emphasis> - string or pseudo-variable containing the hostname.
+			  The resulting IP addresses from DNS query are compared with ipaddr.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>ipaddr</emphasis> - string or pseudo-variable containing the ip address.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from ANY_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>dns_int_match_ip</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if (!dns_int_match_ip("myhost.com", "1.2.3.4")) {
+    xdbg("ip address not associated with hostname\n");
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section id="ipops.f.dns_query">
+      <title>
+        <function moreinfo="none">dns_query(hostname, pvid)</function>
+      </title>
+
+      <para>
+		  Store the IP addresses and their type that correspond to hostname
+		  in a config variable $dns(pvid=>key).
+      </para>
+
+      <para>Parameters:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+			  <emphasis>hostname</emphasis> - string or pseudo-variable containing the hostname.
+			  The resulting IP addresses from DNS query are compared with ipaddr.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <emphasis>pvid</emphasis> - container id for script variable.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        This function can be used from ANY_ROUTE.
+      </para>
+
+      <example>
+        <title>
+          <function>dns_query</function> usage
+        </title>
+        <programlisting format="linespecific">
+...
+if(dns_query("test.com", "xyz"))
+{
+    xlog(" number of addresses: $dns(xyz=>count)\n");
+    xlog(" ipv4 address found: $dns(xyz=>ipv4)\n");
+    xlog(" ipv6 address found: $dns(xyz=>ipv6)\n");
+    $var(i) = 0;
+    while($var(i)<$dns(xyz=>count)) {
+        xlog(" #[$var(i)] type ($dns(xyz=>type[$var(i)]))"
+             " addr [$dns(xyz=>addr[$var(i)])]\n");
+        $var(i) = $var(i) + 1;
+    }
+}
+...
+        </programlisting>
+      </example>
+
+    </section>
+
   </section>
  
 </chapter>
diff --git a/modules/ipops/ipops_mod.c b/modules/ipops/ipops_mod.c
index 164177b..d90aaa3 100644
--- a/modules/ipops/ipops_mod.c
+++ b/modules/ipops/ipops_mod.c
@@ -40,13 +40,18 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
 #include <arpa/inet.h>
 #include "../../sr_module.h"
 #include "../../dprint.h"
 #include "../../str.h"
 #include "../../mod_fix.h"
 #include "../../pvar.h"
+#include "../../resolve.h"
 #include "api.h"
+#include "ipops_pv.h"
 #include "ip_parser.h"
 #include "rfc1918_parser.h"
 
@@ -83,7 +88,16 @@ static int w_compare_ips(struct sip_msg*, char*, char*);
 static int w_compare_pure_ips(struct sip_msg*, char*, char*);
 static int w_is_ip_rfc1918(struct sip_msg*, char*);
 static int w_ip_is_in_subnet(struct sip_msg*, char*, char*);
+static int w_dns_sys_match_ip(sip_msg_t*, char*, char*);
+static int w_dns_int_match_ip(sip_msg_t*, char*, char*);
 
+static int w_dns_query(struct sip_msg* msg, char* str1, char* str2);
+
+static pv_export_t mod_pvs[] = {
+	{ {"dns", sizeof("dns")-1}, PVT_OTHER, pv_get_dns, 0,
+		pv_parse_dns_name, 0, 0, 0 },
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
 
 /*
  * Exported functions
@@ -110,6 +124,12 @@ static cmd_export_t cmds[] =
   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
   { "is_in_subnet", (cmd_function)w_ip_is_in_subnet, 2, fixup_spve_spve, 0,
   REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
+  { "dns_sys_match_ip", (cmd_function)w_dns_sys_match_ip, 2, fixup_spve_spve, 0,
+  ANY_ROUTE },
+  { "dns_int_match_ip", (cmd_function)w_dns_int_match_ip, 2, fixup_spve_spve, 0,
+  ANY_ROUTE },
+  { "dns_query", (cmd_function)w_dns_query, 2, fixup_spve_spve, 0,
+  ANY_ROUTE },
   { "bind_ipops", (cmd_function)bind_ipops, 0, 0, 0, 0},
   { 0, 0, 0, 0, 0, 0 }
 };
@@ -125,7 +145,7 @@ struct module_exports exports = {
   0,                         /*!< exported parameters */
   0,                         /*!< exported statistics */
   0,                         /*!< exported MI functions */
-  0,                         /*!< exported pseudo-variables */
+  mod_pvs,                   /*!< exported pseudo-variables */
   0,                         /*!< extra processes */
   0,                         /*!< module initialization function */
   (response_function) 0,     /*!< response handling function */
@@ -596,3 +616,158 @@ static int w_is_ip_rfc1918(struct sip_msg* _msg, char* _s)
   else
     return -1;
 }
+
+static inline ip_addr_t *strtoipX(str *ips)
+{
+	/* try to figure out INET class */
+	if(ips->s[0] == '[' || memchr(ips->s, ':', ips->len)!=NULL)
+	{
+		/* IPv6 */
+		return str2ip6(ips);
+	} else {
+		/* IPv4 */
+		return str2ip(ips);
+	}
+}
+
+static int w_dns_sys_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
+{
+	struct addrinfo hints, *res, *p;
+	int status;
+	ip_addr_t *ipa;
+	void *addr;
+	str hns;
+	str ips;
+	struct sockaddr_in *ipv4;
+	struct sockaddr_in6 *ipv6;
+
+	if (fixup_get_svalue(msg, (gparam_p)hnp, &hns))
+	{
+		LM_ERR("cannot evaluate hostname parameter\n");
+		return -2;
+	}
+
+	if (fixup_get_svalue(msg, (gparam_p)ipp, &ips))
+	{
+		LM_ERR("cannot evaluate ip address parameter\n");
+		return -2;
+	}
+
+	ipa = strtoipX(&ips);
+	if(ipa==NULL)
+	{
+		LM_ERR("invalid ip address: %.*s\n", ips.len, ips.s);
+		return -3;
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC; /* allow any of AF_INET or AF_INET6 */
+	// hints.ai_socktype = SOCK_STREAM;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	if ((status = getaddrinfo(hns.s, NULL, &hints, &res)) != 0)
+	{
+        LM_ERR("getaddrinfo: %s\n", gai_strerror(status));
+        return -4;
+    }
+
+	for(p = res;p != NULL; p = p->ai_next)
+	{
+		if(p->ai_family==ipa->af)
+		{
+			if (p->ai_family==AF_INET)
+			{
+				ipv4 = (struct sockaddr_in *)p->ai_addr;
+				addr = &(ipv4->sin_addr);
+			} else {
+				ipv6 = (struct sockaddr_in6 *)p->ai_addr;
+				addr = &(ipv6->sin6_addr);
+			}
+			if(memcmp(ipa->u.addr, addr, ipa->len)==0)
+			{
+				/* matched IP */
+				freeaddrinfo(res);
+				return 1;
+			}
+		}
+    }
+	freeaddrinfo(res);
+
+	return -1;
+}
+
+static int w_dns_int_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
+{
+	ip_addr_t *ipa;
+	str hns;
+	str ips;
+	struct hostent* he;
+	char ** h;
+
+	if (fixup_get_svalue(msg, (gparam_p)hnp, &hns))
+	{
+		LM_ERR("cannot evaluate hostname parameter\n");
+		return -2;
+	}
+
+	if (fixup_get_svalue(msg, (gparam_p)ipp, &ips))
+	{
+		LM_ERR("cannot evaluate ip address parameter\n");
+		return -2;
+	}
+
+	ipa = strtoipX(&ips);
+	if(ipa==NULL)
+	{
+		LM_ERR("invalid ip address: %.*s\n", ips.len, ips.s);
+		return -3;
+	}
+
+	he=resolvehost(hns.s);
+	if (he==0) {
+		DBG("could not resolve %s\n", hns.s);
+		return -4;
+	}
+
+	if (he->h_addrtype==ipa->af)
+	{
+		for(h=he->h_addr_list; (*h); h++)
+		{
+			if(memcmp(ipa->u.addr, *h, ipa->len)==0)
+			{
+				/* match */
+				return 1;
+			}
+		}
+	}
+	/* no match */
+	return -1;
+}
+
+/**
+ *
+ */
+static int w_dns_query(struct sip_msg* msg, char* str1, char* str2)
+{
+	str hostname;
+	str name;
+
+	if(msg==NULL)
+	{
+		LM_ERR("received null msg\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_t*)str1, &hostname)<0)
+	{
+		LM_ERR("cannot get the hostname\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)str2, &name)<0)
+	{
+		LM_ERR("cannot get the pv container name\n");
+		return -1;
+	}
+
+	return dns_update_pv(&hostname, &name);
+}
diff --git a/modules/ipops/ipops_pv.c b/modules/ipops/ipops_pv.c
new file mode 100644
index 0000000..08be1fe
--- /dev/null
+++ b/modules/ipops/ipops_pv.c
@@ -0,0 +1,430 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "../../dprint.h"
+#include "../../hashes.h"
+#include "../../pvar.h"
+
+
+#define PV_DNS_ADDR 64
+#define PV_DNS_RECS 32
+
+typedef struct _sr_dns_record {
+	int type;
+	char addr[PV_DNS_ADDR];
+} sr_dns_record_t;
+
+typedef struct _sr_dns_item {
+	str name;
+	unsigned int hashid;
+	char hostname[256];
+	int count;
+	int ipv4;
+	int ipv6;
+	sr_dns_record_t r[PV_DNS_RECS];
+	struct _sr_dns_item *next;
+} sr_dns_item_t;
+
+#define SR_DNS_PVIDX	1
+
+typedef struct _dns_pv {
+	sr_dns_item_t *item;
+	int type;
+	int flags;
+	pv_spec_t *pidx;
+	int nidx;
+} dns_pv_t;
+
+
+static sr_dns_item_t *_sr_dns_list = NULL;
+
+/**
+ *
+ */
+sr_dns_item_t *sr_dns_get_item(str *name)
+{
+	sr_dns_item_t *it = NULL;
+	unsigned int hashid = 0;
+
+	hashid =  get_hash1_raw(name->s, name->len);
+
+	it = _sr_dns_list;
+	while(it!=NULL)
+	{
+		if(it->hashid==hashid && it->name.len == name->len
+				&& strncmp(it->name.s, name->s, name->len)==0)
+			return it;
+		it = it->next;
+	}
+	return NULL;
+}
+
+/**
+ *
+ */
+sr_dns_item_t *sr_dns_add_item(str *name)
+{
+	sr_dns_item_t *it = NULL;
+	unsigned int hashid = 0;
+
+	hashid =  get_hash1_raw(name->s, name->len);
+
+	it = _sr_dns_list;
+	while(it!=NULL)
+	{
+		if(it->hashid==hashid && it->name.len == name->len
+				&& strncmp(it->name.s, name->s, name->len)==0)
+			return it;
+		it = it->next;
+	}
+	/* add new */
+	it = (sr_dns_item_t*)pkg_malloc(sizeof(sr_dns_item_t));
+	if(it==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return NULL;
+	}
+	memset(it, 0, sizeof(sr_dns_item_t));
+	it->name.s = (char*)pkg_malloc(name->len+1);
+	if(it->name.s==NULL)
+	{
+		LM_ERR("no more pkg.\n");
+		pkg_free(it);
+		return NULL;
+	}
+	memcpy(it->name.s, name->s, name->len);
+	it->name.s[name->len] = '\0';
+	it->name.len = name->len;
+	it->hashid = hashid;
+	it->next = _sr_dns_list;
+	_sr_dns_list = it;
+	return it;
+}
+
+
+/**
+ *
+ */
+int pv_parse_dns_name(pv_spec_t *sp, str *in)
+{
+	dns_pv_t *dpv=NULL;
+	char *p;
+	str pvc;
+	str pvs;
+	str pvi;
+	int sign;
+
+	if(sp==NULL || in==NULL || in->len<=0)
+		return -1;
+
+	dpv = (dns_pv_t*)pkg_malloc(sizeof(dns_pv_t));
+	if(dpv==NULL)
+		return -1;
+
+	memset(dpv, 0, sizeof(dns_pv_t));
+
+	p = in->s;
+
+	while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+		p++;
+	if(p>in->s+in->len || *p=='\0')
+		goto error;
+	pvc.s = p;
+	while(p < in->s + in->len)
+	{
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
+			break;
+		p++;
+	}
+	if(p>in->s+in->len || *p=='\0')
+		goto error;
+	pvc.len = p - pvc.s;
+	if(*p!='=')
+	{
+		while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+			p++;
+		if(p>in->s+in->len || *p=='\0' || *p!='=')
+			goto error;
+	}
+	p++;
+	if(*p!='>')
+		goto error;
+	p++;
+
+	pvs.len = in->len - (int)(p - in->s);
+	pvs.s = p;
+	pvi.s = 0;
+	pvi.len = 0;
+	if(pvs.s[pvs.len-1]==']') {
+		/* index */
+		p = memchr(pvs.s, '[', pvs.len-1);
+		if(p==NULL) {
+			goto error;
+		}
+		pvi.s = p + 1;
+		pvi.len = pvs.s + pvs.len - pvi.s;
+		pvs.len = p - pvs.s;
+	}
+	LM_DBG("dns [%.*s] - key [%.*s] index [%.*s]\n", pvc.len, pvc.s,
+			pvs.len, pvs.s, (pvi.len>0)?pvi.len:0, (pvi.s!=NULL)?pvi.s:0);
+
+	dpv->item = sr_dns_add_item(&pvc);
+	if(dpv->item==NULL)
+		goto error;
+
+	switch(pvs.len)
+	{
+		case 4: 
+			if(strncmp(pvs.s, "addr", 4)==0)
+				dpv->type = 0;
+			else if(strncmp(pvs.s, "type", 4)==0)
+				dpv->type = 1;
+			else if(strncmp(pvs.s, "ipv4", 4)==0)
+				dpv->type = 2;
+			else if(strncmp(pvs.s, "ipv6", 4)==0)
+				dpv->type = 3;
+			else goto error;
+		break;
+		case 5: 
+			if(strncmp(pvs.s, "count", 5)==0)
+				dpv->type = 4;
+			else goto error;
+		break;
+		default:
+			goto error;
+	}
+
+	if(pvi.len>0)
+	{
+		if(pvi.s[0]==PV_MARKER)
+		{
+			dpv->pidx = pv_cache_get(&pvi);
+			if(dpv->pidx==NULL)
+				goto error;
+			dpv->flags |= SR_DNS_PVIDX;
+		} else {
+			sign = 1;
+			p = pvi.s;
+			if(*p=='-')
+			{
+				sign = -1;
+				p++;
+			}
+			dpv->nidx = 0;
+			while(p<pvi.s+pvi.len && *p>='0' && *p<='9')
+			{
+				dpv->nidx = dpv->nidx * 10 + *p - '0';
+				p++;
+			}
+			if(p!=pvi.s+pvi.len)
+			{
+				LM_ERR("invalid index [%.*s]\n", in->len, in->s);
+				return -1;
+			}
+			dpv->nidx *= sign;
+		}
+	}
+	sp->pvp.pvn.u.dname = (void*)dpv;
+	sp->pvp.pvn.type = PV_NAME_OTHER;
+
+	return 0;
+
+error:
+	LM_ERR("error at PV dns name: %.*s\n", in->len, in->s);
+	return -1;
+}
+
+/**
+ *
+ */
+int pv_get_dns(sip_msg_t *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	dns_pv_t *dpv;
+	pv_value_t val;
+
+	if(msg==NULL || param==NULL)
+		return -1;
+
+	dpv = (dns_pv_t*)param->pvn.u.dname;
+	if(dpv==NULL || dpv->item==NULL)
+		return -1;
+
+	if(dpv->pidx!=NULL)
+	{
+		if(pv_get_spec_value(msg, dpv->pidx, &val)<0
+				|| (!(val.flags&PV_VAL_INT)))
+		{
+			LM_ERR("failed to evaluate index variable\n");
+			return pv_get_null(msg, param, res);
+		}
+	} else {
+		val.ri = dpv->nidx;
+	}
+	if(val.ri<0)
+	{
+		if(dpv->item->count+val.ri<0) {
+			return pv_get_null(msg, param, res);
+		}
+		val.ri = dpv->item->count+val.ri;
+	}
+	if(val.ri>=dpv->item->count) {
+		return pv_get_null(msg, param, res);
+	}
+	switch(dpv->type)
+	{
+		case 0: /* address */
+			return pv_get_strzval(msg, param, res,
+					dpv->item->r[val.ri].addr);
+		case 1: /* type */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->r[val.ri].type);
+		case 2: /* ipv4 */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->ipv4);
+		case 3: /* ipv6 */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->ipv6);
+		case 4: /* count */
+			return pv_get_sintval(msg, param, res,
+					dpv->item->count);
+		default: /* else */
+			return pv_get_null(msg, param, res);
+	}
+}
+
+/**
+ *
+ */
+int dns_init_pv(char *path)
+{
+	return 0;
+}
+
+/**
+ *
+ */
+void dns_destroy_list(void)
+{
+	return;
+}
+
+/**
+ *
+ */
+void dns_destroy_pv(void)
+{
+	return;
+}
+
+/**
+ *
+ */
+int dns_update_pv(str *hostname, str *name)
+{
+	sr_dns_item_t *dr = NULL;
+	struct addrinfo hints, *res, *p;
+	struct sockaddr_in *ipv4;
+	struct sockaddr_in6 *ipv6;
+	void *addr;
+	int status;
+	int i;
+	
+	if(hostname->len>255)
+	{
+		LM_DBG("target hostname too long (max 255): %s\n", hostname->s);
+		return -2;
+	}
+	
+	dr = sr_dns_get_item(name);
+	if(dr==NULL)
+	{
+		LM_DBG("container not found: %s\n", name->s);
+		return -3;
+	}
+
+	/* reset the counter */
+	dr->count = 0;
+	dr->ipv4  = 0;
+	dr->ipv6  = 0;
+
+	strncpy(dr->hostname, hostname->s, hostname->len);
+	dr->hostname[hostname->len] = '\0';
+	LM_DBG("attempting to resolve: %s\n", dr->hostname);
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC; /* allow any of AF_INET or AF_INET6 */
+	// hints.ai_socktype = SOCK_STREAM;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	if ((status = getaddrinfo(dr->hostname, NULL, &hints, &res)) != 0)
+	{
+        LM_ERR("unable to resolve %s - getaddrinfo: %s\n",
+				dr->hostname, gai_strerror(status));
+        return -4;
+    }
+
+	i=0;
+	for(p=res; p!=NULL; p=p->ai_next)
+	{
+		if (p->ai_family==AF_INET)
+		{
+			dr->ipv4 = 1;
+			dr->r[i].type = 4;
+			ipv4 = (struct sockaddr_in *)p->ai_addr;
+			addr = &(ipv4->sin_addr);
+		} else {
+			dr->ipv6 = 1;
+			dr->r[i].type = 6;
+			ipv6 = (struct sockaddr_in6 *)p->ai_addr;
+			addr = &(ipv6->sin6_addr);
+		}
+		inet_ntop(p->ai_family, addr, dr->r[i].addr,
+				PV_DNS_ADDR);
+		LM_DBG("#%d - type %d addr: %s (%d)\n", i, dr->r[i].type,
+				dr->r[i].addr, p->ai_socktype);
+		i++;
+		if(i==PV_DNS_RECS) {
+			LM_WARN("more than %d addresses for %s - truncating\n",
+					PV_DNS_RECS, dr->hostname);
+			break;
+		}
+    }
+	freeaddrinfo(res);
+
+	dr->count = i;
+
+	LM_DBG("dns PV updated for: %s (%d)\n", dr->hostname, i);
+
+	return 1;
+}
diff --git a/modules/ipops/ipops_pv.h b/modules/ipops/ipops_pv.h
new file mode 100644
index 0000000..043d891
--- /dev/null
+++ b/modules/ipops/ipops_pv.h
@@ -0,0 +1,39 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _IPOPS_PV_H_
+#define _IPOPS_PV_H_
+
+#include "../../pvar.h"
+
+int pv_parse_dns_name(pv_spec_t *sp, str *in);
+int pv_get_dns(sip_msg_t *msg, pv_param_t *param,
+		pv_value_t *res);
+
+int dns_init_pv(char *path);
+void dns_destroy_pv(void);
+int dns_update_pv(str *tomatch, str *name);
+
+#endif
+
diff --git a/modules/iptrtpproxy/doc/iptrtpproxy_admin.xml b/modules/iptrtpproxy/doc/iptrtpproxy_admin.xml
index b17b0a0..593d6a2 100644
--- a/modules/iptrtpproxy/doc/iptrtpproxy_admin.xml
+++ b/modules/iptrtpproxy/doc/iptrtpproxy_admin.xml
@@ -27,7 +27,7 @@
 
 	<para>
 	This &kamailio; module is written as a light-weight module, there is no 
-	dialog managment as in <emphasis>Nathelper</emphasis>. The reason is that such an API
+	dialog management as in <emphasis>Nathelper</emphasis>. The reason is that such an API
 	should be provided by core or a specialized dialog manager module.
 	Because such module is not in git, session information may be stored 
 	in extra attributes of the <emphasis>avp_db</emphasis> module and
diff --git a/modules/kex/README b/modules/kex/README
index c97c30a..12acac6 100644
--- a/modules/kex/README
+++ b/modules/kex/README
@@ -60,10 +60,10 @@ Daniel-Constantin Mierla
    List of Examples
 
    1.1. setsflag usage
-   1.2. setsflag usage
+   1.2. issflagset usage
    1.3. resetsflag usage
    1.4. setbflag usage
-   1.5. setbflag usage
+   1.5. isbflagset usage
    1.6. resetbflag usage
    1.7. setdsturi usage
    1.8. resetdsturi usage
@@ -183,7 +183,7 @@ setsflag("$var(flag)");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.2. setsflag usage
+   Example 1.2. issflagset usage
 ...
 if(issflagset("1"))
 {
@@ -240,7 +240,7 @@ setbflag("$var(flag)", "1");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.5. setbflag usage
+   Example 1.5. isbflagset usage
 ...
 if(isbflagset("1"))
 {
diff --git a/modules/kex/doc/kex_admin.xml b/modules/kex/doc/kex_admin.xml
index f3f020d..28f8b69 100644
--- a/modules/kex/doc/kex_admin.xml
+++ b/modules/kex/doc/kex_admin.xml
@@ -58,7 +58,7 @@
 
 	<section>
 	<title>Functions</title>
-		<section>
+		<section id="kex.f.setsflag">
 		<title><function moreinfo="none">setsflag(flag)</function></title>
 		<para>
 			Set the script flag.
@@ -87,7 +87,7 @@ setsflag("$var(flag)");
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.issflagset">
 		<title><function moreinfo="none">issflagset(flag)</function></title>
 		<para>
 			Return true of the script flag is set.
@@ -105,7 +105,7 @@ setsflag("$var(flag)");
 		This function can be used from ANY_ROUTE.
 		</para>
 		<example>
-		<title><function>setsflag</function> usage</title>
+		<title><function>issflagset</function> usage</title>
 		<programlisting format="linespecific">
 ...
 if(issflagset("1"))
@@ -116,7 +116,7 @@ if(issflagset("1"))
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.resetsflag">
 		<title><function moreinfo="none">resetsflag(flag)</function></title>
 		<para>
 			Reset the script flag.
@@ -142,7 +142,7 @@ resetsflag("1");
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.setbflag">
 		<title><function moreinfo="none">setbflag(flag [, branch])</function></title>
 		<para>
 			Set the branch flag.
@@ -178,7 +178,7 @@ setbflag("$var(flag)", "1");
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.isbflagset">
 		<title><function moreinfo="none">isbflagset(flag [, branch])</function></title>
 		<para>
 			Return true of the branch flag is set.
@@ -203,7 +203,7 @@ setbflag("$var(flag)", "1");
 		This function can be used from ANY_ROUTE.
 		</para>
 		<example>
-		<title><function>setbflag</function> usage</title>
+		<title><function>isbflagset</function> usage</title>
 		<programlisting format="linespecific">
 ...
 if(isbflagset("1"))
@@ -214,7 +214,7 @@ if(isbflagset("1"))
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.resetbflag">
 		<title><function moreinfo="none">resetbflag(flag [, branch])</function></title>
 		<para>
 			Reset the branch flag.
@@ -247,7 +247,7 @@ resetbflag("1");
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.setdsturi">
 		<title><function moreinfo="none">setdsturi(uri)</function></title>
 		<para>
 			Set the destination address URI (outbound proxy address).
@@ -276,7 +276,7 @@ setdsturi("sip:10.0.0.10");
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.resetdsturi">
 		<title><function moreinfo="none">resetdsturi()</function></title>
 		<para>
 			Reset the destination address URI (outbound proxy address).
@@ -293,7 +293,7 @@ resetdsturi();
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.isdsturiset">
 		<title><function moreinfo="none">isdsturiset()</function></title>
 		<para>
 			Check if the destination address URI (outbound proxy address)
@@ -314,7 +314,7 @@ if(isdsturiset())
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.pv_printf">
 		<title><function moreinfo="none">pv_printf(var, str)</function></title>
 		<para>
 			Evalues the str and sets the resulting value to variable var. For
@@ -348,7 +348,7 @@ pv_printf("$avp(x)", "From: $fU - To: $tU");
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.is_myself">
 		<title><function moreinfo="none">is_myself(uri)</function></title>
 		<para>
 			Check if the parameter matches the 'myself' condition (i.e., is
@@ -378,7 +378,7 @@ if(is_myself("$fu")) {
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.setdebug">
 		<title><function moreinfo="none">setdebug(level)</function></title>
 		<para>
 			Set the debug log level per process.
@@ -407,7 +407,7 @@ setdebug("$var(level)");
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.resetdebug">
 		<title><function moreinfo="none">resetdebug()</function></title>
 		<para>
 		Reset the local debug log level back to the value of core parameter
@@ -425,7 +425,7 @@ resetdebug();
 </programlisting>
 		</example>
 		</section>
-		<section>
+		<section id="kex.f.km_append_branch">
 		<title><function moreinfo="none">km_append_branch([uri])</function></title>
 		<para>
 			This function was replaced by append_branch() from corex module, starting with
@@ -436,7 +436,7 @@ resetdebug();
 
 	<section>
 	<title>MI Commands</title>
-	<section>
+	<section id="kex.m.arg">
 		<title>
 		<function moreinfo="none">arg</function>
 		</title>
@@ -454,8 +454,8 @@ resetdebug();
 		:arg:_reply_fifo_file_
 		_empty_line_
 		</programlisting>
-    </section>
-	<section>
+    	</section>
+	<section id="kex.m.kill">
 		<title>
 		<function moreinfo="none">kill</function>
 		</title>
@@ -473,8 +473,8 @@ resetdebug();
 		:kill:_reply_fifo_file_
 		_empty_line_
 		</programlisting>
-    </section>
-	<section>
+    	</section>
+	<section id="kex.m.pwd">
 		<title>
 		<function moreinfo="none">pwd</function>
 		</title>
@@ -492,8 +492,8 @@ resetdebug();
 		:pwd:_reply_fifo_file_
 		_empty_line_
 		</programlisting>
-    </section>
-	<section>
+    	</section>
+	<section id="kex.m.uptime">
 		<title>
 		<function moreinfo="none">uptime</function>
 		</title>
@@ -512,7 +512,7 @@ resetdebug();
 		_empty_line_
 		</programlisting>
     </section>
-	<section>
+	<section id="kex.m.version">
 		<title>
 		<function moreinfo="none">version</function>
 		</title>
@@ -531,7 +531,7 @@ resetdebug();
 		_empty_line_
 		</programlisting>
     </section>
-	<section>
+	<section id="kex.m.which">
 		<title>
 		<function moreinfo="none">which</function>
 		</title>
@@ -550,7 +550,7 @@ resetdebug();
 		_empty_line_
 		</programlisting>
     </section>
-	<section>
+	<section id="kex.m.get_statistics">
 		<title>
 		<function moreinfo="none">get_statistics</function>
 		</title>
@@ -574,7 +574,7 @@ resetdebug();
 		_empty_line_
 		</programlisting>
     </section>
-	<section>
+	<section id="kex.m.reset_statistics">
 		<title>
 		<function moreinfo="none">reset_statistics</function>
 		</title>
@@ -595,7 +595,7 @@ resetdebug();
 		_empty_line_
 		</programlisting>
     </section>
-	<section>
+	<section id="kex.m.clear_statistics">
 		<title>
 		<function moreinfo="none">clear_statistics</function>
 		</title>
@@ -621,7 +621,7 @@ resetdebug();
 
 	<section>
 	<title>RPC Commands</title>
-	<section>
+	<section id="kex.r.pkg.stats">
 		<title>
 		<function moreinfo="none">pkg.stats</function>
 		</title>
diff --git a/modules/lcr/lcr_mod.c b/modules/lcr/lcr_mod.c
index ae2429f..b770d2e 100644
--- a/modules/lcr/lcr_mod.c
+++ b/modules/lcr/lcr_mod.c
@@ -402,7 +402,7 @@ static void lcr_db_close(void)
  */
 static int mod_init(void)
 {
-    pv_spec_t avp_spec;
+    pv_spec_t *avp_spec;
     str s;
     unsigned short avp_flags;
     unsigned int i;
@@ -475,13 +475,13 @@ static int mod_init(void)
 
     if (gw_uri_avp_param && *gw_uri_avp_param) {
 	s.s = gw_uri_avp_param; s.len = strlen(s.s);
-	if (pv_parse_spec(&s, &avp_spec)==0
-	    || avp_spec.type!=PVT_AVP) {
+    avp_spec = pv_cache_get(&s);
+	if (avp_spec==NULL|| avp_spec->type!=PVT_AVP) {
 	    LM_ERR("malformed or non AVP definition <%s>\n", gw_uri_avp_param);
 	    return -1;
 	}
-	
-	if (pv_get_avp_name(0, &(avp_spec.pvp), &gw_uri_avp, &avp_flags) != 0) {
+
+	if (pv_get_avp_name(0, &(avp_spec->pvp), &gw_uri_avp, &avp_flags) != 0) {
 	    LM_ERR("invalid AVP definition <%s>\n", gw_uri_avp_param);
 	    return -1;
 	}
@@ -493,14 +493,14 @@ static int mod_init(void)
 
     if (ruri_user_avp_param && *ruri_user_avp_param) {
 	s.s = ruri_user_avp_param; s.len = strlen(s.s);
-	if (pv_parse_spec(&s, &avp_spec)==0
-	    || avp_spec.type!=PVT_AVP) {
+    avp_spec = pv_cache_get(&s);
+	if (avp_spec==NULL || avp_spec->type!=PVT_AVP) {
 	    LM_ERR("malformed or non AVP definition <%s>\n",
 		   ruri_user_avp_param);
 	    return -1;
 	}
-	
-	if (pv_get_avp_name(0, &(avp_spec.pvp), &ruri_user_avp, &avp_flags)
+
+	if (pv_get_avp_name(0, &(avp_spec->pvp), &ruri_user_avp, &avp_flags)
 	    != 0) {
 	    LM_ERR("invalid AVP definition <%s>\n", ruri_user_avp_param);
 	    return -1;
@@ -513,11 +513,12 @@ static int mod_init(void)
 
     if (tag_avp_param) {
 	s.s = tag_avp_param; s.len = strlen(s.s);
-	if ((pv_parse_spec(&s, &avp_spec)==0) || (avp_spec.type!=PVT_AVP)) {
+    avp_spec = pv_cache_get(&s);
+	if (avp_spec==NULL || (avp_spec->type!=PVT_AVP)) {
 	    LM_ERR("malformed or non AVP definition <%s>\n", tag_avp_param);
 	    return -1;
 	}
-	if (pv_get_avp_name(0, &(avp_spec.pvp), &tag_avp, &avp_flags) != 0) {
+	if (pv_get_avp_name(0, &(avp_spec->pvp), &tag_avp, &avp_flags) != 0) {
 	    LM_ERR("invalid AVP definition <%s>\n", tag_avp_param);
 	    return -1;
 	}
@@ -526,11 +527,12 @@ static int mod_init(void)
 
     if (flags_avp_param) {
 	s.s = flags_avp_param; s.len = strlen(s.s);
-	if ((pv_parse_spec(&s, &avp_spec)==0) || (avp_spec.type != PVT_AVP)) {
+    avp_spec = pv_cache_get(&s);
+	if (avp_spec==NULL || (avp_spec->type != PVT_AVP)) {
 	    LM_ERR("malformed or non AVP definition <%s>\n", flags_avp_param);
 	    return -1;
 	}
-	if (pv_get_avp_name(0, &(avp_spec.pvp), &flags_avp, &avp_flags) != 0) {
+	if (pv_get_avp_name(0, &(avp_spec->pvp), &flags_avp, &avp_flags) != 0) {
 	    LM_ERR("invalid AVP definition <%s>\n", flags_avp_param);
 	    return -1;
 	}
@@ -540,13 +542,13 @@ static int mod_init(void)
     if (defunct_capability_param > 0) {
 	if (defunct_gw_avp_param && *defunct_gw_avp_param) {
 	    s.s = defunct_gw_avp_param; s.len = strlen(s.s);
-	    if ((pv_parse_spec(&s, &avp_spec) == 0) ||
-		(avp_spec.type != PVT_AVP)) {
+        avp_spec = pv_cache_get(&s);
+	    if (avp_spec==NULL || (avp_spec->type != PVT_AVP)) {
 		LM_ERR("malformed or non AVP definition <%s>\n",
 		       defunct_gw_avp_param);
 		return -1;
 	    }
-	    if (pv_get_avp_name(0, &(avp_spec.pvp), &defunct_gw_avp,
+	    if (pv_get_avp_name(0, &(avp_spec->pvp), &defunct_gw_avp,
 				&avp_flags) != 0) {
 		LM_ERR("invalid AVP definition <%s>\n", defunct_gw_avp_param);
 		return -1;
@@ -558,13 +560,13 @@ static int mod_init(void)
 	}
 	if (lcr_id_avp_param && *lcr_id_avp_param) {
 	    s.s = lcr_id_avp_param; s.len = strlen(s.s);
-	    if ((pv_parse_spec(&s, &avp_spec) == 0) ||
-		(avp_spec.type != PVT_AVP)) {
+        avp_spec = pv_cache_get(&s);
+	    if (avp_spec==NULL || (avp_spec->type != PVT_AVP)) {
 		LM_ERR("malformed or non AVP definition <%s>\n",
 		       lcr_id_avp_param);
 		return -1;
 	    }
-	    if (pv_get_avp_name(0, &(avp_spec.pvp), &lcr_id_avp,
+	    if (pv_get_avp_name(0, &(avp_spec->pvp), &lcr_id_avp,
 				&avp_flags) != 0) {
 		LM_ERR("invalid AVP definition <%s>\n", lcr_id_avp_param);
 		return -1;
@@ -956,12 +958,10 @@ static int insert_gws(db1_res_t *res, struct gw_info *gws,
 		/* 123.123.123.123 */
 		ip_addr = *ip_p;
 	    }
-#ifdef USE_IPV6
 	    else if ((ip_p = str2ip6(&ip_string))) {
 		/* fe80::123:4567:89ab:cdef and [fe80::123:4567:89ab:cdef] */
 		ip_addr = *ip_p;
 	    }
-#endif
 	    else if (inet_aton(ip_string.s, &in_addr) == 0) {
 		/* backwards compatibility for integer or hex notations */
 		ip_addr.u.addr32[0] = in_addr.s_addr;
@@ -1572,13 +1572,11 @@ inline int encode_avp_value(char *value, unsigned int gw_index, uri_type scheme,
 	string = int2str(ip_addr->u.addr32[0], &len);
 	append_str(at, string, len);
     }
-#ifdef USE_IPV6
     else if (ip_addr->af == AF_INET6 && !ip_addr_any(ip_addr)) {
 	append_chr(at, '[');
 	at += ip6tosbuf(ip_addr->u.addr, at, MAX_URI_LEN - (at - value));
 	append_chr(at, ']');
     }
-#endif
     append_chr(at, '|');
     /* hostname */
     append_str(at, hostname, hostname_len);
@@ -1673,10 +1671,8 @@ inline int decode_avp_value(char *value, unsigned int *gw_index, str *scheme,
     if (s.len > 0) {
 	if ((ip = str2ip(&s)) != NULL)
 	    *addr = *ip;
-#ifdef USE_IPV6
 	else if ((ip = str2ip6(&s)) != NULL)
 	    *addr = *ip;
-#endif
 	else {
 	    str2int(&s, &u);
 	    addr->af = AF_INET;
@@ -2393,10 +2389,8 @@ static int from_gw_3(struct sip_msg* _m, char* _lcr_id, char* _addr,
     addr_str.len = strlen(_addr);
     if ((ip = str2ip(&addr_str)) != NULL)
 	src_addr = *ip;
-#ifdef USE_IPV6
     else if ((ip = str2ip6(&addr_str)) != NULL)
 	src_addr = *ip;
-#endif
     else {
 	LM_ERR("addr param value %s is not an IP address\n", _addr);
 	return -1;
@@ -2453,10 +2447,8 @@ static int from_any_gw_2(struct sip_msg* _m, char* _addr, char* _transport)
     addr_str.len = strlen(_addr);
     if ((ip = str2ip(&addr_str)) != NULL)
 	src_addr = *ip;
-#ifdef USE_IPV6
     else if ((ip = str2ip6(&addr_str)) != NULL)
 	src_addr = *ip;
-#endif
     else {
 	LM_ERR("addr param value %s is not an IP address\n", _addr);
 	return -1;
@@ -2549,10 +2541,8 @@ static int to_gw_1(struct sip_msg* _m, char* _lcr_id, char* _s2)
     }
     if ((ip = str2ip(&(_m->parsed_uri.host))) != NULL)
 	dst_addr = *ip;
-#ifdef USE_IPV6
     else if ((ip = str2ip6(&(_m->parsed_uri.host))) != NULL)
 	dst_addr = *ip;
-#endif
     else {
 	LM_DBG("request is not going to gw "
 	       "(Request-URI host is not an IP address)\n");
@@ -2592,10 +2582,8 @@ static int to_gw_3(struct sip_msg* _m, char* _lcr_id, char* _addr,
     addr_str.len = strlen(_addr);
     if ((ip = str2ip(&addr_str)) != NULL)
 	dst_addr = *ip;
-#ifdef USE_IPV6
     else if ((ip = str2ip(&addr_str)) != NULL)
 	dst_addr = *ip;
-#endif
     else {
 	LM_ERR("addr param value %s is not an IP address\n", _addr);
 	return -1;
@@ -2637,10 +2625,8 @@ static int to_any_gw_0(struct sip_msg* _m, char* _s1, char* _s2)
     }
     if ((ip = str2ip(&(_m->parsed_uri.host))) != NULL)
 	dst_addr = *ip;
-#ifdef USE_IPV6
     else if ((ip = str2ip6(&(_m->parsed_uri.host))) != NULL)
 	dst_addr = *ip;
-#endif
     else {
 	LM_DBG("request is not going to gw "
 	       "(Request-URI host is not an IP address)\n");
@@ -2675,10 +2661,8 @@ static int to_any_gw_2(struct sip_msg* _m, char* _addr, char* _transport)
     addr_str.len = strlen(_addr);
     if ((ip = str2ip(&addr_str)) != NULL)
 	dst_addr = *ip;
-#ifdef USE_IPV6
     else if ((ip = str2ip6(&addr_str)) != NULL)
 	dst_addr = *ip;
-#endif
     else {
 	LM_ERR("addr param value %s is not an IP address\n", _addr);
 	return -1;
diff --git a/modules/mangler/contact_ops.c b/modules/mangler/contact_ops.c
index c39f8f6..bdde099 100644
--- a/modules/mangler/contact_ops.c
+++ b/modules/mangler/contact_ops.c
@@ -369,7 +369,7 @@ encode2format (struct sip_msg* msg, str* uri, struct uri_format *format)
 				format->rcv_proto=s_sctp;
 				break;
 			default:
-				BUG("unkown proto %d\n", msg->rcv.proto);
+				BUG("unknown proto %d\n", msg->rcv.proto);
 		}
 	}else{
 		format->rcv_proto.s=0;
diff --git a/modules/matrix/README b/modules/matrix/README
index 69e5089..935ab9f 100644
--- a/modules/matrix/README
+++ b/modules/matrix/README
@@ -139,11 +139,11 @@ Chapter 1. Admin Guide
 
    The URL for the database connection.
 
-   Default value is "mysql://kamailioro:kamailioro@localhost/kamailio".
+   Default value is "mysql://openserro:openserro@localhost/openser".
 
    Example 1.1. Set db_url parameter
 ...
-modparam("matrix", "db_url", "mysql://kamailioro:kamailioro@localhost/kamailio")
+modparam("matrix", "db_url", "mysql://openserro:openserro@localhost/openser")
 ...
 
 3.2. matrix_table (string)
@@ -264,7 +264,7 @@ Chapter 2. Module parameter for database access.
 
    URL to the database containing the data.
 
-   Default value is "mysql://kamailioro:kamailioro@localhost/kamailio".
+   Default value is "mysql://openserro:openserro@localhost/openser".
 
    Example 2.1. Set db_url parameter
 ...
diff --git a/modules/mediaproxy/README b/modules/mediaproxy/README
index cb9e84e..122de08 100644
--- a/modules/mediaproxy/README
+++ b/modules/mediaproxy/README
@@ -10,7 +10,7 @@ Dan Pascu
 
    <dan at ag-projects.com>
 
-   Copyright � 2004 Dan Pascu
+   Copyright © 2004 Dan Pascu
      __________________________________________________________________
 
    Table of Contents
@@ -178,7 +178,7 @@ Chapter 1. Admin Guide
    mediaproxy is disabled, calls to its functions will have no effect,
    allowing you to use the same configuration without changes.
 
-   Default value is "0".
+   Default value is “0”.
 
    Example 1.1. Setting the disable parameter
 ...
@@ -190,7 +190,7 @@ modparam("mediaproxy", "disable", 1)
    It is the path to the filesystem socket where the mediaproxy dispatcher
    listens for commands from the module.
 
-   Default value is "/var/run/mediaproxy/dispatcher.sock".
+   Default value is “/var/run/mediaproxy/dispatcher.sock”.
 
    Example 1.2. Setting the mediaproxy_socket parameter
 ...
@@ -203,7 +203,7 @@ modparam("mediaproxy", "mediaproxy_socket", "/var/run/mediaproxy/dispatcher.sock
    How much time (in milliseconds) to wait for an answer from the
    mediaproxy dispatcher.
 
-   Default value is "500".
+   Default value is “500”.
 
    Example 1.3. Setting the mediaproxy_timeout parameter
 ...
@@ -225,7 +225,7 @@ modparam("mediaproxy", "mediaproxy_timeout", 500)
    to get the correct NAT IP address from where the SIP signaling
    originated.
 
-   Default value is "$avp(signaling_ip)".
+   Default value is “$avp(signaling_ip)”.
 
    Example 1.4. Setting the signaling_ip_avp parameter
 ...
@@ -240,7 +240,7 @@ modparam("mediaproxy", "signaling_ip_avp", "$avp(nat_ip)")
    before calling use_media_proxy(), it will be preferred by the
    dispatcher over the normal selection algorithm.
 
-   Default value is "$avp(media_relay)".
+   Default value is “$avp(media_relay)”.
 
    Example 1.5. Setting the media_relay_avp parameter
 ...
@@ -255,7 +255,7 @@ modparam("mediaproxy", "media_relay_avp", "$avp(media_relay)")
    selected then a low priority candidate will be added and if
    'high-priority' is selected a high priority one.
 
-   Default value is "none".
+   Default value is “none”.
 
    Example 1.6. Setting the ice_candidate parameter
 ...
@@ -269,7 +269,7 @@ modparam("mediaproxy", "ice_candidate", "low-priority")
    value in ice_candidate module parameter. If the AVP is not set, the
    default value will be used.
 
-   Default value is "$avp(ice_candidate)".
+   Default value is “$avp(ice_candidate)”.
 
    Example 1.7. Setting the ice_candidate_avp parameter
 ...
diff --git a/modules/memcached/Makefile b/modules/memcached/Makefile
index 6382d8e..916b6c0 100644
--- a/modules/memcached/Makefile
+++ b/modules/memcached/Makefile
@@ -6,9 +6,19 @@ include ../../Makefile.defs
 auto_gen=
 NAME=memcached.so
 
-DEFS+=-DKAMAILIO_MOD_INTERFACE
+ifeq ($(CROSS_COMPILE),)
+	BUILDER = $(shell which pkg-config)
+endif
+
+ifneq ($(BUILDER),)
+	DEFS += $(shell $(BUILDER) --cflags libmemcached)
+	LIBS += $(shell $(BUILDER) --libs libmemcached)
+else
+	DEFS +=-I$(LOCALBASE)/include -I$(SYSBASE)/include
+	LIBS+=-L$(LOCALBASE)/lib -L$(SYSBASE)/lib -lmemcached
+endif
 
-DEFS +=-I$(LOCALBASE)/include -I$(SYSBASE)/include
-LIBS+=-L$(LOCALBASE)/lib -L$(SYSBASE)/lib -lmemcache
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
 
 include ../../Makefile.modules
diff --git a/modules/memcached/README b/modules/memcached/README
index 0a8c29d..37e1d06 100644
--- a/modules/memcached/README
+++ b/modules/memcached/README
@@ -12,9 +12,8 @@ Henning Westerholt
         1. Overview
         2. Implementation notes
 
-              2.1. Error behaviour
-              2.2. Data safety
-              2.3. Size restrictions
+              2.1. Data safety
+              2.2. Size restrictions
 
         3. Dependencies
 
@@ -27,6 +26,7 @@ Henning Westerholt
               4.2. expire (integer)
               4.3. mode (integer)
               4.4. timeout (integer)
+              4.5. memory (integer)
 
         5.
 
@@ -36,11 +36,13 @@ Henning Westerholt
 
    1.1. Storing and retrieving entries
    1.2. Using atomic operations
-   1.3. Modifying expire time for existing entries
-   1.4. Set servers parameter
-   1.5. Set expire parameter
-   1.6. Set mode parameter
-   1.7. Set timeout parameter
+   1.3. Set custom expire time when adding an entry
+   1.4. Modifying expire time for existing entries
+   1.5. Set servers parameter
+   1.6. Set expire parameter
+   1.7. Set mode parameter
+   1.8. Set timeout parameter
+   1.9. Set memory parameter
 
 Chapter 1. Admin Guide
 
@@ -49,9 +51,8 @@ Chapter 1. Admin Guide
    1. Overview
    2. Implementation notes
 
-        2.1. Error behaviour
-        2.2. Data safety
-        2.3. Size restrictions
+        2.1. Data safety
+        2.2. Size restrictions
 
    3. Dependencies
 
@@ -64,6 +65,7 @@ Chapter 1. Admin Guide
         4.2. expire (integer)
         4.3. mode (integer)
         4.4. timeout (integer)
+        4.5. memory (integer)
 
    5.
 
@@ -98,7 +100,15 @@ $mcdec(cnt) = 1; # decrement by 1
 xlog("counter is now $mct(cnt)");
 ...
 
-   Example 1.3. Modifying expire time for existing entries
+   Example 1.3. Set custom expire time when adding an entry
+...
+$mct(test=>10) = 1;
+xlog("stored value is $mct(test)");
+# sleep 10 seconds
+xlog("stored value is $mct(test)"); # will return <null>
+...
+
+   Example 1.4. Modifying expire time for existing entries
 ...
 $mct(test) = 1;
 xlog("stored value is $mct(test)");
@@ -116,26 +126,13 @@ xlog("stored value is $mct(test)"); # will return <null>
 
 2. Implementation notes
 
-   2.1. Error behaviour
-   2.2. Data safety
-   2.3. Size restrictions
+   2.1. Data safety
+   2.2. Size restrictions
 
    Important notes about made assumptions and adaptions that were
    necessary for the proper integration of this library into Kamailio.
 
-2.1. Error behaviour
-
-   The used memcache library has a rather conservative approach to error
-   handling. In the default configuration each error with severity above
-   “WARN” will lead to a immediately exit (or even an abort) of the
-   execution, causing also a shutdown of Kamailio. This is of course not
-   optimal from a availability point of view. Therefore in the internal
-   error handler this is overriden. This means that we err a bit on the
-   side of data integrity in order to get a sufficient availability. But
-   even with this changes some problems in the memcache server can lead to
-   problems in the library and subsequently also in the server.
-
-2.2. Data safety
+2.1. Data safety
 
    Don't store data in memcached that you don't also have somewhere else.
    This system was designed as fast cache, and not for persistent storage.
@@ -145,12 +142,13 @@ xlog("stored value is $mct(test)"); # will return <null>
    in it where it would be a problem when it disappear from one moment to
    the other.
 
-2.3. Size restrictions
+2.2. Size restrictions
 
    The maximum key length that is supported from memcached is 250
    characters. In order to support longer keys in the Kamailio
    configuration script they are hashed with MD5. This should normally be
-   safe against collisions, as the value space is sufficient large enough.
+   safe against collisions, as the value space is sufficiently large
+   enough.
 
    The maximum value size that is supported is 1MB. The reason for this is
    the internal memory manager used from memcached. But normally this
@@ -171,7 +169,7 @@ xlog("stored value is $mct(test)"); # will return <null>
 
    The following libraries or applications must be installed before
    running Kamailio with this module loaded:
-     * the libmemcache library.
+     * the libmemcached library.
      * the memcached server implementation.
 
 4. Parameters
@@ -180,6 +178,7 @@ xlog("stored value is $mct(test)"); # will return <null>
    4.2. expire (integer)
    4.3. mode (integer)
    4.4. timeout (integer)
+   4.5. memory (integer)
 
 4.1. servers (str)
 
@@ -187,16 +186,15 @@ xlog("stored value is $mct(test)"); # will return <null>
 
    Default value is “localhost:11211”.
 
-   Example 1.4. Set servers parameter
+   Example 1.5. Set servers parameter
 ...
 modparam("memcached", "servers", "localhost:11211")
 ...
 
 4.2. expire (integer)
 
-   The default expire value of all entries in memcached in seconds. The
-   maximal value is 2592000 (about 30 days). You can also specify an
-   arbitrary unix time stamp in the future. A value of zero means that no
+   The default expire value of entries in memcached in seconds. The
+   maximal value is 2592000 (about 30 days). A value of zero means that no
    automatic expiration is done, memcached will then delete the least used
    items when the cache gets full.
 
@@ -206,12 +204,13 @@ modparam("memcached", "servers", "localhost:11211")
    Items can also be deleted before there expire time when the available
    space in memory is exhausted.
 
-   Its possible to override this default value later on by setting a
-   different timeout for this key with the mctex pseudo-variable.
+   It is possible to override this default value when adding a key with
+   the mct psuedo-variable, or later on by setting a different timeout for
+   an existing key with the mctex pseudo-variable.
 
    Default value is “10800”s (3h).
 
-   Example 1.5. Set expire parameter
+   Example 1.6. Set expire parameter
 ...
 modparam("memcached", "expire", 10800)
 ...
@@ -226,7 +225,7 @@ modparam("memcached", "expire", 10800)
 
    Default value is “0” (overwrite).
 
-   Example 1.6. Set mode parameter
+   Example 1.7. Set mode parameter
 ...
 modparam("memcached", "mode", 0)
 ...
@@ -237,19 +236,37 @@ modparam("memcached", "mode", 0)
 
    Default value is “5000” (5s).
 
-   Example 1.7. Set timeout parameter
+   Example 1.8. Set timeout parameter
 ...
 modparam("memcached", "timeout", 10000)
 ...
 
+4.5. memory (integer)
+
+   The memory mode for the memcached client library. The library can use
+   the system memory manager or the internal memory manager from Kamailio.
+   The system memory manager configuration is the default, most
+   implementations (like other projects) probably use this approach as
+   well. The internal memory configuration should be faster and protects
+   better against memory leaks that could bring down your server, as the
+   available memory pool is limited by the Kamailio configuration.
+
+   Default value is “0” (use system memory manager).
+
+   Example 1.9. Set memory parameter
+...
+modparam("memcached", "memory", 1)
+...
+
    5.1. Exported pseudo-variables
 
 5.1. Exported pseudo-variables
 
      * $mct(key)
+     * $mct(key=>expiry)
      * $mcinc(key)
      * $mcdec(key)
      * $mctex(key)
 
    Exported pseudo-variables are documented at
-   http://www.kamailio.org/dokuwiki/.
+   http://www.kamailio.org/wiki/.
diff --git a/modules/memcached/doc/memcached_admin.xml b/modules/memcached/doc/memcached_admin.xml
index 0d09032..d00fd83 100644
--- a/modules/memcached/doc/memcached_admin.xml
+++ b/modules/memcached/doc/memcached_admin.xml
@@ -47,6 +47,17 @@ xlog("counter is now $mct(cnt)");
 ...
 			</programlisting>
 		</example>
+                <example>
+                <title>Set custom expire time when adding an entry</title>
+                        <programlisting format="linespecific">
+...
+$mct(test=>10) = 1;
+xlog("stored value is $mct(test)");
+# sleep 10 seconds
+xlog("stored value is $mct(test)"); # will return <null>
+...
+                        </programlisting>
+                </example>
 		<example>
 		<title>Modifying expire time for existing entries</title>
 			<programlisting format="linespecific">
@@ -75,18 +86,6 @@ xlog("stored value is $mct(test)"); # will return <null>
 			integration of this library into &kamailio;.
 		</para>
 	<section>
-		<title>Error behaviour</title>
-		<para>
-			The used memcache library has a rather conservative approach to error handling. In the
-			default configuration each error with severity above <quote>WARN</quote> will lead to a
-			immediately exit (or even an abort) of the execution, causing also a shutdown of &kamailio;.
-			This is of course not optimal from a availability point of view. Therefore in the internal error
-			handler this is overriden. This means that we err a bit on the side of data integrity in order to
-			get a sufficient availability. But even with this changes some problems in the memcache server
-			can lead to problems in the library and subsequently also in the server.
-		</para>
-	</section>
-	<section>
 		<title>Data safety</title>
 		<para>
 			Don't store data in memcached that you don't also have somewhere else. This system was
@@ -101,7 +100,7 @@ xlog("stored value is $mct(test)"); # will return <null>
 		<para>
 			The maximum key length that is supported from memcached is 250 characters. In order
 			to support longer keys in the &kamailio; configuration script they are hashed with MD5.
-			This should normally be safe against collisions, as the value space is sufficient large enough.
+			This should normally be safe against collisions, as the value space is sufficiently large enough.
 		</para>
 		<para>
 			The maximum value size that is supported is 1MB. The reason for this is the internal memory
@@ -133,7 +132,7 @@ xlog("stored value is $mct(test)"); # will return <null>
 			<itemizedlist>
 			<listitem>
 			<para>
-				<emphasis>the <ulink url="http://freshmeat.net/projects/libmemcache/">libmemcache</ulink> library</emphasis>.
+				<emphasis>the <ulink url="http://libmemcached.org/">libmemcached</ulink> library</emphasis>.
 			</para>
 			</listitem>
 			<listitem>
@@ -147,7 +146,7 @@ xlog("stored value is $mct(test)"); # will return <null>
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="dmq.p.servers">
 		<title><varname>servers</varname> (str)</title>
 		<para>
 		The servers to connect to. At the moment only one server is supported.
@@ -168,12 +167,11 @@ modparam("memcached", "servers", "localhost:11211")
 			</programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="dmq.p.expire">
 		<title><varname>expire</varname> (integer)</title>
 		<para>
-			The default expire value of all entries in memcached in seconds. The maximal
-			value is 2592000 (about 30 days). You can also specify an arbitrary unix time
-			stamp in the future. A value of zero means that no automatic expiration is done,
+			The default expire value of entries in memcached in seconds. The maximal
+			value is 2592000 (about 30 days). A value of zero means that no automatic expiration is done,
 			memcached will then delete the least used items when the cache gets full.
 		</para>
 		<para>
@@ -183,8 +181,9 @@ modparam("memcached", "servers", "localhost:11211")
 			before there expire time when the available space in memory is exhausted.
 		</para>
 		<para>
-			Its possible to override this default value later on by setting a different
-			timeout for this key with the <emphasis>mctex</emphasis> pseudo-variable.
+			It is possible to override this default value when adding a key with the
+			<emphasis>mct</emphasis> psuedo-variable, or later on by setting a different
+			timeout for an existing key with the <emphasis>mctex</emphasis> pseudo-variable.
 		</para>
 		<para>
 		<emphasis>
@@ -200,7 +199,7 @@ modparam("memcached", "expire", 10800)
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="dmq.p.mode">
 		<title><varname>mode</varname> (integer)</title>
 		<para>
 			The used storage mode for the memcached module for write access
@@ -223,7 +222,7 @@ modparam("memcached", "mode", 0)
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="dmq.p.timeout">
 		<title><varname>timeout</varname> (integer)</title>
 		<para>
 			The timeout for the memcache servers access in milliseconds.
@@ -242,6 +241,32 @@ modparam("memcached", "timeout", 10000)
 			</programlisting>
 		</example>
 	</section>
+	<section id="dmq.p.memory">
+		<title><varname>memory</varname> (integer)</title>
+		<para>
+			The memory mode for the memcached client library. The library can
+			use the system memory manager or the internal memory manager from
+			&kamailio;. The system memory manager configuration is the default,
+			most implementations (like other projects) probably use this
+			approach as well. The internal memory configuration should be
+			faster and protects better against memory leaks that could bring
+			down your server, as the available memory pool is limited by the
+			&kamailio; configuration.
+		</para>
+		<para>
+			<emphasis>
+				Default value is <quote>0</quote> (use system memory manager).
+			</emphasis>
+		</para>
+		<example>
+			<title>Set <varname>memory</varname> parameter</title>
+			<programlisting format="linespecific">
+...
+modparam("memcached", "memory", 1)
+...
+			</programlisting>
+		</example>
+	</section>
 	</section>
 	<section>
 		<section>
@@ -250,6 +275,9 @@ modparam("memcached", "timeout", 10000)
 			<listitem><para>
 				<emphasis>$mct(key)</emphasis>
 			</para></listitem>
+                        <listitem><para>
+                                <emphasis>$mct(key=>expiry)</emphasis>
+                        </para></listitem>
 			<listitem><para>
 				<emphasis>$mcinc(key)</emphasis>
 			</para></listitem>
diff --git a/modules/memcached/mcd_var.c b/modules/memcached/mcd_var.c
index 94676e7..a5bdf25 100644
--- a/modules/memcached/mcd_var.c
+++ b/modules/memcached/mcd_var.c
@@ -1,7 +1,6 @@
-/**
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+/*
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -29,20 +28,81 @@
 #include "memcached.h"
 #include "../../ut.h"
 #include "../../mem/mem.h"
+#include "../../pvapi.h"
 #include "../pv/pv_svar.h"
 #include "../../md5utils.h"
 
 
 /*!
- * \brief Checks if the key is avaiable and not too long, hash it with MD5 if necessary
+ * \brief Checks for '=>' delimiter in key name string and if present, extracts expiry value.
+ * \param data string to parse
+ * \param key output string name
+ * \param exp output int expiry (if present)
+ * \return 0 on success, negative on failure
+ */
+static inline int pv_mcd_key_expiry_split_str(str *data, str *key, unsigned int *exp) {
+	char *p;
+	str str_exp;
+	str_exp.s = NULL;
+	str_exp.len = 0;
+	
+	if (data == NULL || data->s == NULL || data->len <= 0) {
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+	
+	p = data->s;
+	key->s = p;
+	key->len = 0;
+
+	while(p < data->s + data->len) {
+		if (*p == '=') {
+			p++;
+			if (*p == '>') {
+				break;
+			} else {
+				key->len++;
+			}
+		} else {
+	                key->len++;
+			p++;
+		}
+	}
+
+	if (key->len < data->len) {
+		/* delimiter is present, try to extract expiry value */
+		p++;
+		if (p < data->s + data->len) {
+			str_exp.s = p;
+			str_exp.len = 0;
+			while(p<data->s+data->len) {
+				str_exp.len++;
+				p++;
+			}
+		}
+		if (str_exp.len > 0) {
+			/* convert to int */
+			*exp = atoi(str_exp.s);
+		}
+		LM_DBG("key is %.*s expiry is %d\n", key->len, key->s, *exp);
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Checks if the key is avaiable and not too long, hashing it with MD5 if necessary.
  * \param msg SIP message
  * \param param pseudo-variable input parameter
- * \param out output string
+ * \param key output string name
+ * \param exp output int expiry (if present)
  * \return 0 on success, negative on failure
  */
-static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str * out) {
+static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str * key, unsigned int * exp ) {
 
+	str pvn;
 	str tmp;
+
 	static char hash[32];
 
 	if (msg == NULL || param == NULL) {
@@ -50,20 +110,24 @@ static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str *
 		return -1;
 	}
 
-	if (pv_printf_s(msg, param->pvn.u.dname, &tmp) != 0)
+	if (pv_printf_s(msg, param->pvn.u.dname, &pvn) != 0)
 	{
-		LM_ERR("cannot get key name\n");
+		LM_ERR("cannot get pv name\n");
+		return -1;
+	}
+
+	if (pv_mcd_key_expiry_split_str(&pvn, &tmp, exp) != 0) {
 		return -1;
 	}
 
 	if (tmp.len < 250) {
-		out->s = tmp.s;
-		out->len = tmp.len;
+		key->s = tmp.s;
+		key->len = tmp.len;
 	} else {
 		LM_DBG("key too long (%d), hash it\n", tmp.len);
 		MD5StringArray (hash, &tmp, 1);
-		out->s = hash;
-		out->len = 32;
+		key->s = hash;
+		key->len = 32;
 	}
 	return 0;
 }
@@ -72,39 +136,42 @@ static inline int pv_mcd_key_check(struct sip_msg *msg, pv_param_t *param, str *
  * \brief Helper to get a cached value from memcached
  * \param msg SIP message
  * \param key value key
- * \param mcd_req request
- * \param mcd_res result
+ * \param return_value returned value
+ * \param flags returned flags
  * \return null on success, negative on failure
  */
 static int pv_get_mcd_value_helper(struct sip_msg *msg, str *key,
-		struct memcache_req **mcd_req, struct memcache_res **mcd_res) {
+		char **return_value, uint32_t *flags) {
 
-	/* we don't use mc_aget here, because we're multi-process */
-	if ( (*mcd_req = mc_req_new()) == NULL) {
-		PKG_MEM_ERROR;
-		return -1;
-	}
-	LM_DBG("allocate new memcache request at %p\n", *mcd_req);
+	memcached_return rc;
+	size_t return_value_length;
 
-	if ( (*mcd_res = mc_req_add(*mcd_req, key->s, key->len)) == NULL) {
-		PKG_MEM_ERROR;
-		return -1;
-	}
-	LM_DBG("allocate new memcache result at %p\n", *mcd_res);
+	*return_value = memcached_get(memcached_h, key->s, key->len, &return_value_length, flags, &rc);
 
-	mc_get(memcached_h, *mcd_req);
-	if (! ( (*mcd_res)->_flags & MCM_RES_FOUND)) {
-		LM_ERR("could not get result for key %.*s\n", key->len, key->s);
-		LM_DBG("free memcache request and result at %p\n", mcd_req);
-		mc_req_free(*mcd_req);
+	if (*return_value == NULL) {
+		if (rc == MEMCACHED_NOTFOUND) {
+			LM_DBG("key %.*s not found\n", key->len, key->s);
+		} else {
+			LM_ERR("could not get result for key %.*s - error was '%s'\n", key->len, key->s, memcached_strerror(memcached_h, rc));
+		}
 		return -1;
 	}
-	LM_DBG("result: %.*s for key %.*s with flag %d\n", (*mcd_res)->bytes, (char*)(*mcd_res)->val,
-		key->len, key->s, (*mcd_res)->flags);
+
+	LM_DBG("result: %s for key %.*s with flag %d\n", *return_value, key->len, key->s, *flags);
 
 	return 0;
 }
 
+static void pv_free_mcd_value(char** buf) {
+	if (*buf!=NULL) {
+		if (mcd_memory) {
+			pkg_free(*buf);
+		} else {
+			free(*buf);
+		}
+	}
+}
+
 /*!
  * \brief Get a cached value from memcached
  * \param msg SIP message
@@ -116,30 +183,41 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
 
 	unsigned int res_int = 0;
 	str key, res_str;
-	struct memcache_req *mcd_req = NULL;
-	struct memcache_res *mcd_res = NULL;
+	unsigned int expiry = mcd_expire;
+
+  	char *return_value;
+	uint32_t return_flags;
 
-	if (pv_mcd_key_check(msg, param, &key) < 0) {
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0) {
 		return pv_get_null(msg, param, res);
 	}
 
 	if (res==NULL)
 		return pv_get_null(msg, param, res);
 
-	if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
-		return pv_get_null(msg, param, res);
+	if (pv_get_mcd_value_helper(msg, &key, &return_value, &return_flags) < 0) {
+		goto errout;
 	}
 
-	res_str.len = mcd_res->bytes;
-	res_str.s = mcd_res->val;
+
+	res_str.len = strlen(return_value);
+	res_str.s = return_value;
+
+
 	/* apparently memcached adds whitespaces to the beginning of the value after atomic operations */
+
 	trim_len(res_str.len, res_str.s, res_str);
 
-	if(mcd_res->flags&VAR_VAL_STR) {
-		 if (pkg_str_dup(&(res->rs), &res_str) < 0) {
-			LM_ERR("could not copy string\n");
+	if(return_flags&VAR_VAL_STR) {
+		res->rs.s = pv_get_buffer();
+		res->rs.len = pv_get_buffer_size();
+		if(res_str.len>=res->rs.len) {
+			LM_ERR("value is too big (%d) - increase pv buffer size\n", res_str.len);
 			goto errout;
 		}
+		memcpy(res->rs.s, res_str.s, res_str.len);
+		res->rs.len = res_str.len;
+		res->rs.s[res->rs.len] = '\0';
 		res->flags = PV_VAL_STR;
 	} else {
 		if (str2int(&res_str, &res_int) < 0) {
@@ -150,18 +228,17 @@ int pv_get_mcd_value(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
 		res->ri = res_int;
 		res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
 	}
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
 
+	pv_free_mcd_value(&return_value);
 	return 0;
 
 errout:
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
+	pv_free_mcd_value(&return_value);
 	return pv_get_null(msg, param, res);
 }
 
 
+
 /*!
  * \brief Set a value in the cache of memcached
  * \todo Replacement of already existing values is not done atomically at the moment.
@@ -176,16 +253,18 @@ errout:
 
 	unsigned int val_flag = 0;
 	str val_str, key;
+	unsigned int expiry = mcd_expire;
 
-	if (pv_mcd_key_check(msg, param, &key) < 0)
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0)
 		return -1;
 
 	if (val == NULL) {
-		if (mc_delete(memcached_h, key.s, key.len, 0) != 0) {
+		if (memcached_delete(memcached_h, key.s, key.len, 0) != MEMCACHED_SUCCESS) {
 			LM_ERR("could not delete key %.*s\n", param->pvn.u.isname.name.s.len,
 				param->pvn.u.isname.name.s.s);
+			return -1;
 		}
-		LM_DBG("delete key %.*s\n", key.len, key.s);
+		LM_WARN("delete key %.*s\n", key.len, key.s);
 		return 0;
 	}
 
@@ -196,13 +275,13 @@ errout:
 		val_flag = VAR_VAL_STR;
 	}
 
-	if (memcached_mode == 0) {
-		if (mc_set(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
+	if (mcd_mode == 0) {
+		if (memcached_set(memcached_h, key.s, key.len, val_str.s, val_str.len, expiry, val_flag) != MEMCACHED_SUCCESS) {
 			LM_ERR("could not set value for key %.*s\n", key.len, key.s);
 			return -1;
 		}
 	} else {
-		if (mc_add(memcached_h, key.s, key.len, val_str.s, val_str.len, memcached_expire, val_flag) != 0) {
+		if (memcached_add(memcached_h, key.s, key.len, val_str.s, val_str.len, expiry, val_flag) != MEMCACHED_SUCCESS) {
 			LM_ERR("could not add value for key %.*s\n", key.len, key.s);
 			return -1;
 		}
@@ -223,46 +302,47 @@ errout:
  * \param param parameter
  * \param op not used
  * \param val value
- * \param atomic_ops function pointer to the atomic operation from the memcache library
+ * \param atomic_ops function pointer to the atomic operation from the memcached library
  * \return 0 on success, -1 on failure
  */
 static int pv_mcd_atomic_helper(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val,
-		unsigned int (* atomic_ops) (struct memcache *mc, char *key, const size_t key_len,
-		const unsigned int val)) {
+		memcached_return (* atomic_ops) (memcached_st *mc, const char *key, size_t key_length, uint32_t offset, uint64_t *value)) {
 
-	unsigned int value = 0;
+	uint64_t value = 0;
 	str key;
-	struct memcache_req *mcd_req = NULL;
-	struct memcache_res *mcd_res = NULL;
+	unsigned int expiry = mcd_expire;
+	char *return_value;
+	uint32_t return_flags;
+	memcached_return rc;
 	
-	if (! val->flags&PV_VAL_INT) {
+	if (!(val->flags&PV_VAL_INT)) {
 		LM_ERR("invalid value %.*s for atomic operation, strings not allowed\n",
 			val->rs.len, val->rs.s);
 		return -1;
 	}
 
-	if (pv_mcd_key_check(msg, param, &key) < 0)
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0)
 		return -1;
 
-	if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
+	if (pv_get_mcd_value_helper(msg, &key, &return_value, &return_flags) < 0) {
+		pv_free_mcd_value(&return_value);
 		return -1;
 	}
 
-	if(mcd_res->flags&VAR_VAL_STR) {
+	pv_free_mcd_value(&return_value);
+
+	if(return_flags&VAR_VAL_STR) {
 		LM_ERR("could not do atomic operations on string for key %.*s\n", key.len, key.s);
-		LM_DBG("free memcache request and result at %p\n", mcd_req);
-		mc_req_free(mcd_req);
 		return -1;
 	}
 
-	LM_DBG("atomic operation on result %.*s for %d with flag %d\n", mcd_res->bytes, (char*)mcd_res->val, val->ri, mcd_res->flags);
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
-
-	value = atomic_ops(memcached_h, key.s, key.len, val->ri);
-	LM_DBG("value from atomic operation %d\n", value);
+	if ((rc = atomic_ops(memcached_h, key.s, key.len, val->ri, &value)) != MEMCACHED_SUCCESS) {
+		LM_ERR("error performing atomic operation on key %.*s - %s\n", key.len, key.s, memcached_strerror(memcached_h, rc));
+		return -1;
+	}
 
 	return 0;
+
 }
 
 
@@ -275,7 +355,7 @@ static int pv_mcd_atomic_helper(struct sip_msg* msg, pv_param_t *param, int op,
  * \return 0 on success, -1 on failure
  */
 int inline pv_inc_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
-	return pv_mcd_atomic_helper(msg, param, op, val, mc_incr);
+	return pv_mcd_atomic_helper(msg, param, op, val, memcached_increment);
 }
 
 
@@ -288,7 +368,7 @@ int inline pv_inc_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_v
  * \return 0 on success, -1 on failure
  */
 int inline pv_dec_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
-	return pv_mcd_atomic_helper(msg, param, op, val, mc_decr);
+	return pv_mcd_atomic_helper(msg, param, op, val, memcached_decrement);
 }
 
 
@@ -305,34 +385,37 @@ int inline pv_dec_mcd_value(struct sip_msg* msg, pv_param_t *param, int op, pv_v
 int pv_set_mcd_expire(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
 {
 	str key;
-	struct memcache_req *mcd_req = NULL;
-	struct memcache_res *mcd_res = NULL;
+	unsigned int expiry = mcd_expire;
+	char *return_value;
+	uint32_t return_flags;
+	memcached_return rc;
 
-	if (! val->flags&PV_VAL_INT) {
+	if (!(val->flags&PV_VAL_INT)) {
 		LM_ERR("invalid value %.*s for expire time, strings not allowed\n",
 			val->rs.len, val->rs.s);
 		return -1;
 	}
 
-	if (pv_mcd_key_check(msg, param, &key) < 0)
+	if (pv_mcd_key_check(msg, param, &key, &expiry) < 0)
 		return -1;
 
-	if (pv_get_mcd_value_helper(msg, &key, &mcd_req, &mcd_res) < 0) {
-		return -1;
+	if (pv_get_mcd_value_helper(msg, &key, &return_value, &return_flags) < 0) {
+		goto errout;
 	}
 
-	LM_DBG("set expire time %d on result %.*s for %d with flag %d\n", val->ri, mcd_res->bytes, (char*)mcd_res->val, val->ri, mcd_res->flags);
+	LM_DBG("set expire time %d for key %.*s with flag %d\n", val->ri, key.len, key.s, return_flags);
 
-	if (mc_set(memcached_h, key.s, key.len, mcd_res->val, mcd_res->bytes, val->ri, mcd_res->flags) != 0) {
-		LM_ERR("could not set expire time %d for key %.*s\n", val->ri, key.len, key.s);
-		LM_DBG("free memcache request and result at %p\n", mcd_req);
-		mc_req_free(mcd_req);
-		return -1;
+	if ((rc= memcached_set(memcached_h, key.s, key.len, return_value, strlen(return_value), val->ri, return_flags)) != MEMCACHED_SUCCESS) {
+		LM_ERR("could not set expire time %d for key %.*s - error was %s\n", val->ri, key.len, key.s, memcached_strerror(memcached_h, rc));
+		goto errout;
 	}
-	LM_DBG("free memcache request and result at %p\n", mcd_req);
-	mc_req_free(mcd_req);
 
+	pv_free_mcd_value(&return_value);
 	return 0;
+
+errout:
+	pv_free_mcd_value(&return_value);
+	return -1;
 }
 
 
diff --git a/modules/memcached/mcd_var.h b/modules/memcached/mcd_var.h
index 610cb00..54ee415 100644
--- a/modules/memcached/mcd_var.h
+++ b/modules/memcached/mcd_var.h
@@ -1,7 +1,6 @@
-/**
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+/*
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  * This file is part of Kamailio, a free SIP server.
  *
diff --git a/modules/memcached/memcached.c b/modules/memcached/memcached.c
index 5de20d0..0815d63 100644
--- a/modules/memcached/memcached.c
+++ b/modules/memcached/memcached.c
@@ -1,7 +1,6 @@
 /*
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -37,23 +36,20 @@
 MODULE_VERSION
 
 
-#define DP_ALERT_TEXT    "ALERT:"
-#define DP_ERR_TEXT      "ERROR:"
-#define DP_WARN_TEXT     "WARNING:"
-#define DP_NOTICE_TEXT   "NOTICE:"
-#define DP_INFO_TEXT     "INFO:"
-
-
 /*! server string */
-char* memcached_srv_str = "localhost:11211";
-/*! cache expire time in seconds */
-unsigned int memcached_expire = 10800;
+char* mcd_srv_str = "localhost:11211";
+/*! cache (default) expire time in seconds */
+unsigned int mcd_expire = 0;
 /*! cache storage mode, set or add */
-unsigned int memcached_mode = 0;
+unsigned int mcd_mode = 0;
 /*! server timeout in ms*/
-int memcached_timeout = 5000;
+unsigned int mcd_timeout = 5000;
+/*! Internal or system memory manager, default is system */
+unsigned int mcd_memory = 0;
 /*! memcached handle */
-struct memcache* memcached_h = NULL;
+struct memcached_st *memcached_h;
+/*! memcached server list */
+struct memcached_server_st *servers;
 
 
 static int mod_init(void);
@@ -81,10 +77,11 @@ static pv_export_t mod_pvs[] = {
  * Exported parameters
  */
 static param_export_t params[] = {
-	{"servers", STR_PARAM, &memcached_srv_str },
-	{"expire",   INT_PARAM, &memcached_expire },
-	{"timeout", INT_PARAM, &memcached_timeout },
-	{"mode",    INT_PARAM, &memcached_mode },
+	{"servers", STR_PARAM, &mcd_srv_str },
+	{"expire",  INT_PARAM, &mcd_expire },
+	{"timeout", INT_PARAM, &mcd_timeout },
+	{"mode",    INT_PARAM, &mcd_mode },
+	{"memory",  INT_PARAM, &mcd_memory },
 	{0, 0, 0}
 };
 
@@ -109,96 +106,122 @@ struct module_exports exports = {
 
 
 /*!
- * \brief Wrapper functions around our internal memory management
+ * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
+ * \param mem freed memory
+ * \note pkg_free does not allow NULL pointer as standard free, therefore we check it here
+ * \see pkg_free
+ */
+static inline void mcd_free(memcached_st *ptr, void *mem, void *context) {
+        if (mem)
+        	pkg_free(mem);
+}
+
+/*!
+ * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
  * \param mem freed memory
+ * \note pkg_free does not allow NULL pointer as standard free, therefore we check it here
  * \see pkg_free
  */
-static inline void memcached_free(void *mem) {
-	pkg_free(mem);
+ static inline void mcd_free_compat(memcached_st *ptr, void *mem) {
+        if (mem)
+                pkg_free(mem);
 }
 
 
 /*!
- * \brief Wrapper functions around our internal memory management
+ * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
  * \param size allocated size
  * \return allocated memory, or NULL on failure
  * \see pkg_malloc
  */
-static inline void* memcached_malloc(const size_t size) {
+static inline void* mcd_malloc(memcached_st *ptr, const size_t size, void *context) {
 	return pkg_malloc(size);
 }
 
+/*!
+ * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
+ * \param size allocated size
+ * \return allocated memory, or NULL on failure
+ * \see pkg_malloc
+ */
+ static inline void* mcd_malloc_compat(memcached_st *ptr, const size_t size) {
+        return pkg_malloc(size);
+}
+
 
 /*!
- * \brief Wrapper functions around our internal memory management
+ * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
  * \param mem pointer to allocated memory
  * \param size new size of memory area
  * \return allocated memory, or NULL on failure
  * \see pkg_realloc
  */
-static inline void* memcached_realloc(void *mem, const size_t size) {
+static inline void* mcd_realloc(memcached_st *ptr, void *mem, const size_t size, void *context) {
  	return pkg_realloc(mem, size);
 }
 
+/*!
+ * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
+ * \param mem pointer to allocated memory
+ * \param size new size of memory area
+ * \return allocated memory, or NULL on failure
+ * \see pkg_realloc
+ */
+static inline void* mcd_realloc_compat(memcached_st *ptr, void *mem, const size_t size) {
+        return pkg_realloc(mem, size);
+}
+
 
 /*!
- * \brief Small wrapper around our internal logging function
+ * \brief Wrapper functions around our internal memory management for libmemcached (version >= 0.38) callback
+ * \param mem pointer to allocated memory
+ * \param size new size of memory area
+ * \return allocated memory, or NULL on failure
+ * \see pkg_malloc
+ * \todo this is not optimal, 	use internal calloc implemention which is not exported yet
  */
-static int memcache_err_func(MCM_ERR_FUNC_ARGS) {
-
-	const struct memcache_ctxt *ctxt;
-	struct memcache_err_ctxt *ectxt;
-	int error_level;
-	const char * error_str;
-
-	MCM_ERR_INIT_CTXT(ctxt, ectxt);
-
-	switch (ectxt->severity) {
-		case MCM_ERR_LVL_INFO:
-			error_level = L_INFO;
-			error_str = DP_INFO_TEXT;
-			break;
-		case MCM_ERR_LVL_NOTICE:
-			error_level = L_NOTICE;
-			error_str = DP_NOTICE_TEXT;
-			break;
-		case MCM_ERR_LVL_WARN:
-			error_level = L_WARN;
-			error_str = DP_WARN_TEXT;
-			break;
-		case MCM_ERR_LVL_ERR:
-			error_level = L_ERR;
-			error_str  = DP_ERR_TEXT;
-			/* try to continue */
- 			ectxt->cont = 'y';
-			break;
-		case MCM_ERR_LVL_FATAL:
-  		default:
-			error_level = L_ALERT;
-			error_str = DP_ALERT_TEXT;
-			ectxt->cont = 'y';
-			break;
+static inline void * mcd_calloc(memcached_st *ptr, size_t nelem, const size_t elsize, void *context) {
+	void* tmp = NULL;
+	tmp = pkg_malloc(nelem * elsize);
+	if (tmp != NULL) {
+		memset(tmp, 0, nelem * elsize);
 	}
+	return tmp;
+}
 
-	/*
-	* ectxt->errmsg - per error message passed along via one of the MCM_*_MSG() macros (optional)
-	* ectxt->errstr - memcache error string (optional, though almost always set)
-	*/
-	if (ectxt->errstr != NULL && ectxt->errmsg != NULL)
-		LM_GEN1(error_level, "%s memcached: %s():%u: %s: %.*s\n", error_str, ectxt->funcname, ectxt->lineno, ectxt->errstr,
-			(int)ectxt->errlen, ectxt->errmsg);
-	else if (ectxt->errstr == NULL && ectxt->errmsg != NULL)
-		LM_GEN1(error_level, "%s memcached: %s():%u: %.*s\n", error_str, ectxt->funcname, ectxt->lineno, (int)ectxt->errlen,
-			ectxt->errmsg);
-	else if (ectxt->errstr != NULL && ectxt->errmsg == NULL)
-		LM_GEN1(error_level, "%s memcached: %s():%u: %s\n", error_str, ectxt->funcname, ectxt->lineno, ectxt->errstr);
-	else
-		LM_GEN1(error_level, "%s memcached: %s():%u\n", error_str, ectxt->funcname, ectxt->lineno);
-
-	return 0;
+/*!
+ * \brief Wrapper functions around our internal memory management for libmemcached (version < 0.38) callback
+ * \param mem pointer to allocated memory
+ * \param size new size of memory area
+ * \return allocated memory, or NULL on failure
+ * \see pkg_malloc
+ * \todo this is not optimal, 	use internal calloc implemention which is not exported yet
+ */
+static inline void * mcd_calloc_compat(memcached_st *ptr, size_t nelem, const size_t elsize) {
+        void* tmp = NULL;
+        tmp = pkg_malloc(nelem * elsize);
+        if (tmp != NULL) {
+                memset(tmp, 0, nelem * elsize);
+        }
+        return tmp;
 }
 
 
+/**
+ * \brief Callback to check if we could connect successfully to a server
+ * \param ptr memcached handler
+ * \param server server instance
+ * \param context context for callback
+ * \return MEMCACHED_SUCCESS on success, MEMCACHED_CONNECTION_FAILURE on failure
+ * \todo FIXME
+static inline memcached_server_fn mcd_check_connection(const memcached_st *ptr, memcached_server_instance_st my_server, void *context) {
+	if (my_server->fd < 0) {
+		return MEMCACHED_CONNECTION_FAILURE;
+	}
+	return MEMCACHED_SUCCESS;
+}
+*/
+
 /*!
  * \brief Module initialization function
  * \return 0 on success, -1 on failure
@@ -206,58 +229,77 @@ static int memcache_err_func(MCM_ERR_FUNC_ARGS) {
 static int mod_init(void) {
 	char *server, *port;
 	unsigned int len = 0;
+	memcached_return rc;
 
-	/* setup the callbacks to our internal memory manager */
-	if (mcMemSetup(memcached_free, memcached_malloc,
-			memcached_malloc, memcached_realloc) != 0) {
-		LM_ERR("could not setup memory management callbacks\n");
-		return -1;
-	}
-
-	if (mcErrSetup(memcache_err_func) != 0) {
-		LM_ERR("could not setup error handler callback\n");
-		return -1;
-	}
-
-	/*! delete eventual log filters */
-	mc_err_filter_del(MCM_ERR_LVL_INFO);
-	mc_err_filter_del(MCM_ERR_LVL_NOTICE);
-
-	memcached_h = mc_new();
-	if (memcached_h == NULL) {
-		PKG_MEM_ERROR;
-		return -1;
-	}
-	
-	if ((port = strchr(memcached_srv_str, ':')) != NULL) {
+	if ((port = strchr(mcd_srv_str, ':')) != NULL) {
 		port = port + 1;
-		len = strlen(memcached_srv_str) - strlen(port) - 1;
+		len = strlen(mcd_srv_str) - strlen(port) - 1;
 	} else {
 		LM_DBG("no port definition, using default port\n");
 		port = "11211";
-		len = strlen(memcached_srv_str) ;
+		len = strlen(mcd_srv_str) ;
 	}
 	
-
 	server = pkg_malloc(len);
 	if (server == NULL) {
 		PKG_MEM_ERROR;
 		return -1;
 	}
 
-	strncpy(server, memcached_srv_str, len);
+	strncpy(server, mcd_srv_str, len);
 	server[len] = '\0';
 
-	mc_timeout(memcached_h, 0, memcached_timeout);
+	memcached_h = memcached_create(NULL);
+	if (memcached_h == NULL) {
+		LM_ERR("could not create memcached structure\n");
+		return -1;
+	}
+	LM_DBG("allocated new server handle at %p", memcached_h);
+
+        if (mcd_memory == 1) {
+                LM_INFO("Use internal kamailio memory manager for memcached client library\n");
+
+#if LIBMEMCACHED_VERSION_HEX >= 0x00038000
+                rc = memcached_set_memory_allocators(memcached_h, (memcached_malloc_fn)mcd_malloc,
+                                             (memcached_free_fn)mcd_free, (memcached_realloc_fn)mcd_realloc,
+                                             (memcached_calloc_fn)mcd_calloc, NULL);
+#else
+                rc = memcached_set_memory_allocators(memcached_h, (memcached_malloc_function)mcd_malloc_compat,
+                                             (memcached_free_function)mcd_free_compat, (memcached_realloc_function)mcd_realloc_compat,
+                                             (memcached_calloc_function)mcd_calloc_compat);
+#endif
+
+		if (rc == MEMCACHED_SUCCESS) {
+			LM_DBG("memory manager callbacks set\n");
+		} else {
+			LM_ERR("memory manager callbacks not set, returned %s.\n", memcached_strerror(memcached_h, rc));
+			return -1;
+		}
+	} else {
+		LM_INFO("Use system memory manager for memcached client library\n");
+	}
 
-	if (mc_server_add(memcached_h, server, port) != 0) {
-		LM_ERR("could not add server %s:%s\n", server, port);
+        servers = memcached_server_list_append(servers, server, atoi(port), &rc);
+	
+	if (memcached_behavior_set(memcached_h, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, mcd_timeout) != MEMCACHED_SUCCESS) {
+		LM_ERR("could not set server connection timeout\n");
 		return -1;
 	}
-	LM_INFO("connected to server %s:%s\n", server, port);
+	rc = memcached_server_push(memcached_h, servers);
+	if (rc == MEMCACHED_SUCCESS) {
+		LM_DBG("added server list to structure\n");
+	} else {
+		LM_ERR("attempt to add server list to structure returned %s.\n", memcached_strerror(memcached_h, rc));
+		return -1;
+	}
+
 	pkg_free(server);
 
-	LM_INFO("memcached client version is %s, released on %d\n", mc_version(), mc_reldate());
+	/** \todo FIXME logic to handle connection errors on startup
+	memcached_server_cursor(memcached_h, (const memcached_server_fn*) &mcd_check_connection, NULL, 1);
+	*/
+	
+	LM_INFO("libmemcached version is %s\n", memcached_lib_version());
 	return 0;
 }
 
@@ -266,9 +308,10 @@ static int mod_init(void) {
  * \brief Module shutdown function
  */
 static void mod_destroy(void) {
-	if (memcached_h != NULL)
-		mc_server_disconnect_all(memcached_h);
-
-	if (memcached_h != NULL)
-		mc_free(memcached_h);
+	if (servers != NULL)
+		memcached_server_list_free(servers);
+	
+	/* Crash on shutdown with internal memory manager, even if we disable the mm callbacks */
+	if (mcd_memory != 1 && memcached_h != NULL)
+		        memcached_free(memcached_h);
 }
diff --git a/modules/memcached/memcached.h b/modules/memcached/memcached.h
index 8fa9ab4..407d39f 100644
--- a/modules/memcached/memcached.h
+++ b/modules/memcached/memcached.h
@@ -1,7 +1,6 @@
 /*
- * $Id$
- *
- * Copyright (C) 2009 Henning Westerholt
+ * Copyright (C) 2009, 2013 Henning Westerholt
+ * Copyright (C) 2013 Charles Chance, sipcentric.com
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -24,21 +23,24 @@
  * \brief memcached module
  */
 
-#include <memcache.h>
+#include <libmemcached/memcached.h>
 
 #ifndef MEMCACHED_H
 #define MEMCACHED_H
 
 /*! server string */
-extern char* db_memcached_srv_str;
+extern char* mcd_srv_str;
 /*! cache expire time in seconds */
-extern unsigned int memcached_expire;
+extern unsigned int mcd_expire;
 /*! cache storage mode, set or add */
-extern unsigned int memcached_mode;
+extern unsigned int mcd_mode;
 /*! server timeout */
-extern int memcached_timeout;
+extern unsigned int mcd_timeout;
+/*! Internal or system memory manager */
+extern unsigned int mcd_memory;
 /*! memcached handle */
-extern struct memcache* memcached_h;
-
+extern struct memcached_st* memcached_h;
+/*! memcached server list */
+extern struct memcached_server_st *servers;
 
 #endif
diff --git a/modules/mi_datagram/datagram_fnc.c b/modules/mi_datagram/datagram_fnc.c
index 9ca206c..3952580 100644
--- a/modules/mi_datagram/datagram_fnc.c
+++ b/modules/mi_datagram/datagram_fnc.c
@@ -148,14 +148,12 @@ int  mi_init_datagram_server(sockaddr_dtgram *addr, unsigned int socket_domain,
 				goto err_rx;
 			}
 			break;
-#ifdef USE_IPV6
 	case AF_INET6: 
 			if(bind(socks->rx_sock, (struct sockaddr*)&addr->udp_addr.sin6, sizeof(addr->udp_addr)) < 0) {
 				LM_ERR("bind: %s\n", strerror(errno));
 				goto err_rx;
 			}
 			break;
-#endif
 	default:
 			LM_ERR("domain not supported\n");
 			goto err_both;
diff --git a/modules/mi_xmlrpc/Makefile b/modules/mi_xmlrpc/Makefile
index 07bb07d..c2c2cb6 100644
--- a/modules/mi_xmlrpc/Makefile
+++ b/modules/mi_xmlrpc/Makefile
@@ -42,8 +42,8 @@ ifeq ($(OLD),yes)
 else
 ifeq ($(NEW),yes)
 	# nothing to do
-else
-$(warning			You are using an unsupported libxmlrpc-c3 \
+#else
+#$(warning			You are using an unsupported libxmlrpc-c3 \
 					 version  ($(XMLRPC_VER)), compile at your own risk!)
 endif
 endif
diff --git a/modules/mi_xmlrpc/abyss_data.h b/modules/mi_xmlrpc/abyss_data.h
index 511c480..9a9ceaa 100644
--- a/modules/mi_xmlrpc/abyss_data.h
+++ b/modules/mi_xmlrpc/abyss_data.h
@@ -18,6 +18,8 @@ typedef struct
 	int size;
 } TString;
 
+abyss_bool StringAlloc(TString *s);
+void StringFree(TString *s);
 #endif
 
 /*********************************************************************
diff --git a/modules/mi_xmlrpc/abyss_response.c b/modules/mi_xmlrpc/abyss_response.c
index 77850e0..aebe8d2 100644
--- a/modules/mi_xmlrpc/abyss_response.c
+++ b/modules/mi_xmlrpc/abyss_response.c
@@ -583,6 +583,7 @@ MIMETypeGuessFromFile(const char * const fileName) {
 
                                   
 
+#ifdef XMLRPC_OLD_VERSION
 /*********************************************************************
 ** Base64
 *********************************************************************/
@@ -623,6 +624,7 @@ void Base64Encode(char *s,char *d)
     /* ...and zero-terminate it. */
     *p = '\0';
 }
+#endif
 
 /******************************************************************************
 **
diff --git a/modules/mi_xmlrpc/abyss_socket_unix.h b/modules/mi_xmlrpc/abyss_socket_unix.h
index 845a4fc..16159e2 100644
--- a/modules/mi_xmlrpc/abyss_socket_unix.h
+++ b/modules/mi_xmlrpc/abyss_socket_unix.h
@@ -7,4 +7,7 @@ SocketUnixInit(abyss_bool * const succeededP);
 void
 SocketUnixTerm(void);
 
+void
+SocketUnixCreate(TSocket ** const socketPP);
+
 #endif
diff --git a/modules/mi_xmlrpc/abyss_xmlrpc_server.c b/modules/mi_xmlrpc/abyss_xmlrpc_server.c
index 55aabf6..ef28031 100644
--- a/modules/mi_xmlrpc/abyss_xmlrpc_server.c
+++ b/modules/mi_xmlrpc/abyss_xmlrpc_server.c
@@ -943,7 +943,6 @@ uriPathParm(const xmlrpc_server_abyss_parms * const parmsP,
 
 #ifdef XMLRPC_OLD_VERSION
 static xmlrpc_server_shutdown_fn shutdownAbyss;
-#endif
 
 static void
 shutdownAbyss(xmlrpc_env * const envP,
@@ -969,7 +968,7 @@ shutdownAbyss(xmlrpc_env * const envP,
     
     ServerTerminate(serverP);
 }
-
+#endif
 
 
 static void
@@ -998,12 +997,12 @@ normalLevelAbyssRun(xmlrpc_env *                      const envP,
 
         ServerUseSigchld(&server);
         
-        if (0)
+        //if (0)
             /* Too much of a security risk.  In 1.07, there is a server
                parameter to enable this.
             */
-            xmlrpc_registry_set_shutdown(parmsP->registryP,
-                                         &shutdownAbyss, &server);
+        //    xmlrpc_registry_set_shutdown(parmsP->registryP,
+        //                                 &shutdownAbyss, &server);
         
         ServerRun(&server);
 
diff --git a/modules/misc_radius/README b/modules/misc_radius/README
index 4398814..ed2a47c 100644
--- a/modules/misc_radius/README
+++ b/modules/misc_radius/README
@@ -10,7 +10,7 @@ Daniel-Constantin Mierla
 
    <miconda at gmail.com>
 
-   Copyright © 2004-2008 Juha Heinanen
+   Copyright � 2004-2008 Juha Heinanen
      __________________________________________________________________
 
    Table of Contents
@@ -35,6 +35,7 @@ Daniel-Constantin Mierla
               3.8. group_extra (string)
               3.9. uri_extra (string)
               3.10. use_sip_uri_host (integer)
+              3.11. common_response (integer)
 
         4. Functions
 
@@ -46,7 +47,7 @@ Daniel-Constantin Mierla
 
    List of Examples
 
-   1.1. “SIP-AVP” RADIUS AVP exmaples
+   1.1. "SIP-AVP" RADIUS AVP exmaples
    1.2. radius_config parameter usage
    1.3. caller_service_type parameter usage
    1.4. callee_service_type parameter usage
@@ -57,11 +58,13 @@ Daniel-Constantin Mierla
    1.9. group_extra parameter usage
    1.10. uri_extra parameter usage
    1.11. use_sip_uri_host parameter usage
-   1.12. radius_load_caller_avps() usage
-   1.13. radius_load_callee_avps() usage
-   1.14. radius_is_user_in() usage
-   1.15. radius_does_uri_exist() usage
-   1.16. radius_does_uri_user_exist() usage
+   1.12. common_response parameter usage
+   1.13. radius response with common_response value 1
+   1.14. radius_load_caller_avps() usage
+   1.15. radius_load_callee_avps() usage
+   1.16. radius_is_user_in() usage
+   1.17. radius_does_uri_exist() usage
+   1.18. radius_does_uri_user_exist() usage
 
 Chapter 1. Admin Guide
 
@@ -85,6 +88,7 @@ Chapter 1. Admin Guide
         3.8. group_extra (string)
         3.9. uri_extra (string)
         3.10. use_sip_uri_host (integer)
+        3.11. common_response (integer)
 
    4. Functions
 
@@ -109,7 +113,7 @@ Chapter 1. Admin Guide
      * SIP_AVP_NAME = STRING_NAME | '#'ID_NUMBER
      * SIP_AVP_VALUE = ':'STRING_VALUE | '#'NUMBER_VALUE
 
-   Example 1.1. “SIP-AVP” RADIUS AVP exmaples
+   Example 1.1. "SIP-AVP" RADIUS AVP exmaples
 ....
 "email:joe at yahoo.com"
     -> STRING NAME AVP (email) with STRING VALUE (joe at yahoo.com)
@@ -122,7 +126,7 @@ Chapter 1. Admin Guide
 ....
 
    Unlike in old avp_radius module, functions radius_load_calle[re]_avps()
-   do not prefix string names of AVPs by string “caller_” or “callee_”
+   do not prefix string names of AVPs by string "caller_" or "callee_"
    depending if caller's or callee's attributes were loaded. If you need
    these prefixes, make your RADIUS server to prepend them into attribute
    names when it constructs reply items.
@@ -161,13 +165,14 @@ Chapter 1. Admin Guide
    3.8. group_extra (string)
    3.9. uri_extra (string)
    3.10. use_sip_uri_host (integer)
+   3.11. common_response (integer)
 
 3.1. radius_config (string)
 
    This is the location of the configuration file of radius client
    libraries.
 
-   Default value is “/usr/local/etc/radiusclient-ng/radiusclient.conf”.
+   Default value is "/usr/local/etc/radiusclient-ng/radiusclient.conf".
 
    Example 1.2. radius_config parameter usage
 ...
@@ -178,7 +183,7 @@ modparam("misc_radius", "radius_config", "/etc/radiusclient.conf")
    This is the value of the Service-Type radius attribute to be used, when
    caller's attributes are loaded.
 
-   Default value is dictionary value of “SIP-Caller-AVPs” Service-Type.
+   Default value is dictionary value of "SIP-Caller-AVPs" Service-Type.
 
    Example 1.3. caller_service_type parameter usage
 ...
@@ -189,7 +194,7 @@ modparam("misc_radius", "caller_service_type", 18)
    This is the value of the Service-Type radius attribute to be used, when
    callee's attributes are loaded.
 
-   Default value is dictionary value of “SIP-Callee-AVPs” Service-Type.
+   Default value is dictionary value of "SIP-Callee-AVPs" Service-Type.
 
    Example 1.4. callee_service_type parameter usage
 ...
@@ -200,7 +205,7 @@ modparam("misc_radius", "callee_service_type", 19)
    This is the value of Service-Type RADIUS attribute to be used, when
    radius_is_user_in() function is called.
 
-   Default value is dictionary value of “Group-Check” Service-Type.
+   Default value is dictionary value of "Group-Check" Service-Type.
 
    Example 1.5. group_service_type parameter usage
 ...
@@ -211,7 +216,7 @@ modparam("misc_radius", "group_service_type", 20)
    This is the value of Service-Type RADIUS attribute to be used, when
    radius_does_uri[_user]_exist() function is called.
 
-   Default value is dictionary value of “Call-Check” Service-Type.
+   Default value is dictionary value of "Call-Check" Service-Type.
 
    Example 1.6. uri_service_type parameter usage
 ...
@@ -286,6 +291,43 @@ modparam("misc_radius", "uri_extra", "Called-Station-Id=$tu")
 ...
 modparam("misc_radius", "use_sip_uri_host", 1)
 
+3.11. common_response (integer)
+
+   Set it to 1 if you need common radius response attributes to be added
+   as AVPs in radius_load_caller_avps and radius_load_callee_avps with
+   name as radius attribute name and value as radius attribute value.
+
+   Default value is "0".
+
+   Example 1.12. common_response parameter usage
+...
+modparam("misc_radius", "common_response", 1)
+...
+radius_load_caller_avps($fU);
+...
+
+   Example 1.13. radius response with common_response value 1
+...
+    Sending Access-Accept of id 60 to 192.168.25.32 port 59736
+    Session-Timeout = 4261674
+    next-hop-ip = "SIP/00111222333444 at cisco-out"
+    SIP-AVP = "email:sr-users at lists.sip-router.org session-timeout#161 next-hop-
+ip:h323/0001111 at myvoip-gate.kamailio.org"
+    session-protocol = "SIP"
+...
+
+$avp(Session-Timeout) has integer value 4261674
+$avp(next-hop-ip) has string value "SIP/005555777888 at cisco-out"
+$avp(session-protocol) has string value "SIP"
+$avp(SIP-AVP) has string value  "email:sr-users at lists.sip-router.org session-tim
+eout#161 next-hop-ip:h323/0001111 at myvoip-gate.kamailio.org"
+
+...
+    When recieving negative response, check appropriate avp's:
+    $avp(Reply-Message) = "Not enough money on deposit '-89.83'. Rejected"
+    $avp(Filter-Id) = "neg_deposit"
+...
+
 4. Functions
 
    4.1. radius_load_caller_avps(caller)
@@ -297,12 +339,12 @@ modparam("misc_radius", "use_sip_uri_host", 1)
 4.1. radius_load_caller_avps(caller)
 
    The functions loads caller's attributes from radius and stores them
-   into AVPs. Parameter “caller” is a string that may contain pseudo
+   into AVPs. Parameter "caller" is a string that may contain pseudo
    variables. It indicates the user, whose attributes are loaded.
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.12. radius_load_caller_avps() usage
+   Example 1.14. radius_load_caller_avps() usage
 ...
 radius_load_caller_avps("$fU@$fd");     # take caller from From URI
 ...
@@ -312,12 +354,12 @@ radius_load_caller_avps("$au@$ar");     # take caller from Authorization
 4.2. radius_load_callee_avps(callee)
 
    The functions loads callee's attributes from radius and stores them
-   into AVPs. Parameter “callee” is a string that may contain pseudo
+   into AVPs. Parameter "callee" is a string that may contain pseudo
    variables. It indicates the user, whose attributes are loaded.
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.13. radius_load_callee_avps() usage
+   Example 1.15. radius_load_callee_avps() usage
 ...
 radius_load_callee_avps("$rU@$rd");     # take callee from Request-URI
 ...
@@ -332,7 +374,7 @@ radius_load_callee_avps("$rU@$rd");     # take callee from Request-URI
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE, and LOCAL_ROUTE.
 
-   Example 1.14. radius_is_user_in() usage
+   Example 1.16. radius_is_user_in() usage
 ...
 radius_is_user_in("$rU@$rd", "1");      # take user from Request-URI
 ...
@@ -347,7 +389,7 @@ radius_is_user_in("$au@$ar", "group_x");# take user from credentials
 
    This function can be used from REQUEST_ROUTE and LOCAL_ROUTE.
 
-   Example 1.15. radius_does_uri_exist() usage
+   Example 1.17. radius_does_uri_exist() usage
 ...
 if (radius_does_uri_exist()) ...        # check Request-URI
 ...
@@ -364,7 +406,7 @@ if (radius_does_uri_exist("$avp(i:99)")) ...    # check URI in $avp(i:99)
 
    This function can be used from REQUEST_ROUTE and LOCAL_ROUTE.
 
-   Example 1.16. radius_does_uri_user_exist() usage
+   Example 1.18. radius_does_uri_user_exist() usage
 ...
 if (radius_does_uri_user_exist()) ...   # check Request-URI userpart
 ...
diff --git a/modules/misc_radius/doc/misc_radius_admin.xml b/modules/misc_radius/doc/misc_radius_admin.xml
index 5e57749..950d8d4 100644
--- a/modules/misc_radius/doc/misc_radius_admin.xml
+++ b/modules/misc_radius/doc/misc_radius_admin.xml
@@ -303,6 +303,51 @@ modparam("misc_radius", "use_sip_uri_host", 1)
 </programlisting>
 		</example>
 	</section>
+	<section>
+		<title><varname>common_response</varname> (integer)</title>
+		<para>
+		Set it to 1 if you need common radius response attributes to
+		be added as AVPs in <function moreinfo="none">radius_load_caller_avps</function>
+        and <function moreinfo="none">radius_load_callee_avps</function>
+        with name as radius attribute name and value as radius attribute value.
+		</para>
+		<para>
+		Default value is <quote>0</quote>.
+		</para>
+		<example>
+		<title><varname>common_response</varname> parameter usage</title>
+		<programlisting format="linespecific">
+...
+modparam("misc_radius", "common_response", 1)
+...
+radius_load_caller_avps($fU);
+...
+</programlisting>
+    </example>
+	<example>
+		<title>radius response with <varname>common_response</varname> value 1</title>
+		<programlisting format="linespecific">
+...
+    Sending Access-Accept of id 60 to 192.168.25.32 port 59736
+    Session-Timeout = 4261674
+    next-hop-ip = "SIP/00111222333444 at cisco-out"
+    SIP-AVP = "email:sr-users at lists.sip-router.org session-timeout#161 next-hop-ip:h323/0001111 at myvoip-gate.kamailio.org"
+    session-protocol = "SIP"
+...
+
+$avp(Session-Timeout) has integer value 4261674
+$avp(next-hop-ip) has string value "SIP/005555777888 at cisco-out"
+$avp(session-protocol) has string value "SIP"
+$avp(SIP-AVP) has string value  "email:sr-users at lists.sip-router.org session-timeout#161 next-hop-ip:h323/0001111 at myvoip-gate.kamailio.org"
+
+...
+    When recieving negative response, check appropriate avp's:
+    $avp(Reply-Message) = "Not enough money on deposit '-89.83'. Rejected"
+    $avp(Filter-Id) = "neg_deposit"
+...
+</programlisting>
+    </example>
+	</section>
 
 	</section>
 
diff --git a/modules/misc_radius/functions.c b/modules/misc_radius/functions.c
index 2a42024..4292999 100644
--- a/modules/misc_radius/functions.c
+++ b/modules/misc_radius/functions.c
@@ -36,7 +36,7 @@ static str val_arr[MAX_EXTRA];
 
 /* Extract one reply item value to AVP flags, name and value */
 static inline int extract_avp(VALUE_PAIR* vp, unsigned short *flags,
-			      int_str *name, int_str *value)
+		int_str *name, int_str *value)
 {
 	static str names, values;
 	unsigned int r;
@@ -107,53 +107,109 @@ error:
 	return -1;
 }
 
+static void generate_avps_rad(VALUE_PAIR* received)
+{
+	int_str name, val;
+	unsigned short flags;
+	VALUE_PAIR *vp;
+
+	vp = received;
+
+	for( ; vp ; vp=vp->next) {
+		flags = AVP_NAME_STR;
+		switch(vp->type)
+		{
+			case PW_TYPE_STRING:
+				flags |= AVP_VAL_STR;
+				name.s.len = strlen(vp->name);
+				val.s.len = strlen(vp->strvalue);
+				name.s.s = vp->name;
+				val.s.s = vp->strvalue;
+				if (add_avp( flags, name, val ) < 0) {
+					LM_ERR("unable to create a new AVP\n");
+				} else {
+					LM_DBG("AVP '%.*s'/%d='%.*s'/%d has been added\n",
+							(flags&AVP_NAME_STR)?name.s.len:4,
+							(flags&AVP_NAME_STR)?name.s.s:"null",
+							(flags&AVP_NAME_STR)?0:name.n,
+							(flags&AVP_VAL_STR)?val.s.len:4,
+							(flags&AVP_VAL_STR)?val.s.s:"null",
+							(flags&AVP_VAL_STR)?0:val.n );
+				}
+				continue;
+			case PW_TYPE_INTEGER:
+				name.s.len = strlen(vp->name);
+				name.s.s = vp->name;
+				val.n = vp->lvalue;
+				if (add_avp( flags, name, val ) < 0) {
+					LM_ERR("unable to create a new AVP\n");
+				} else {
+					LM_DBG("AVP '%.*s'/%d='%.*s'/%d has been added\n",
+							(flags&AVP_NAME_STR)?name.s.len:4,
+							(flags&AVP_NAME_STR)?name.s.s:"null",
+							(flags&AVP_NAME_STR)?0:name.n,
+							(flags&AVP_VAL_STR)?val.s.len:4,
+							(flags&AVP_VAL_STR)?val.s.s:"null",
+							(flags&AVP_VAL_STR)?0:val.n );
+				}
+				continue;
+			default:
+				LM_ERR("skip attribute type %d (non-string)", vp->type);
+				continue;
+		}
+		return;
+	}
+}
+
 
 /* Generate AVPs from Radius reply items */
 static void generate_avps(struct attr *attrs, VALUE_PAIR* received)
 {
-    int_str name, val;
-    unsigned short flags;
-    VALUE_PAIR *vp;
-
-    vp = received;
-
-    for( ; (vp=rc_avpair_get(vp,attrs[SA_SIP_AVP].v,0)) ; vp=vp->next) {
-	flags = 0;
-	if (extract_avp( vp, &flags, &name, &val)!=0 )
-	    continue;
-	if (add_avp( flags, name, val) < 0) {
-	    LM_ERR("unable to create a new AVP\n");
-	} else {
-	    LM_DBG("AVP '%.*s'/%d='%.*s'/%d has been added\n",
-		   (flags&AVP_NAME_STR)?name.s.len:4,
-		   (flags&AVP_NAME_STR)?name.s.s:"null",
-		   (flags&AVP_NAME_STR)?0:name.n,
-		   (flags&AVP_VAL_STR)?val.s.len:4,
-		   (flags&AVP_VAL_STR)?val.s.s:"null",
-		   (flags&AVP_VAL_STR)?0:val.n );
-	}
-    }
-    
-    return;
+	int_str name, val;
+	unsigned short flags;
+	VALUE_PAIR *vp;
+
+	vp = received;
+
+	for( ; (vp=rc_avpair_get(vp,attrs[SA_SIP_AVP].v,0)) ; vp=vp->next) {
+		flags = 0;
+		if (extract_avp( vp, &flags, &name, &val)!=0 )
+			continue;
+		if (add_avp( flags, name, val) < 0) {
+			LM_ERR("unable to create a new AVP\n");
+		} else {
+			LM_DBG("AVP '%.*s'/%d='%.*s'/%d has been added\n",
+					(flags&AVP_NAME_STR)?name.s.len:4,
+					(flags&AVP_NAME_STR)?name.s.s:"null",
+					(flags&AVP_NAME_STR)?0:name.n,
+					(flags&AVP_VAL_STR)?val.s.len:4,
+					(flags&AVP_VAL_STR)?val.s.s:"null",
+					(flags&AVP_VAL_STR)?0:val.n );
+		}
+	}
+
+	return;
 }
 
 /* Macro to add extra attribute */
-#define ADD_EXTRA_AVPAIR(_attrs, _attr, _val, _len)			\
-    do {								\
-	if ((_len) != 0) {						\
-	    if ((_len) == -1) {						\
-		if (_attrs[_attr].t != PW_TYPE_INTEGER) {		\
-		    LM_ERR("attribute %d is not of type integer\n",	\
-			   _attrs[_attr].v);				\
-		    goto error;						\
-		}							\
-	    }								\
-	    if (!rc_avpair_add( rh, &send, _attrs[_attr].v, _val, _len, 0)) { \
-		LM_ERR("failed to add %s, %d\n", _attrs[_attr].n, _attr); \
-		goto error;						\
-	    }								\
-	}								\
-    }while(0)
+#define ADD_EXTRA_AVPAIR(_attrs, _attr, _val, _len)	\
+	do { \
+		if ((_len) != 0) { \
+			if ((_len) == -1) { \
+				if (_attrs[_attr].t != PW_TYPE_INTEGER) { \
+					if (_attrs[_attr].t != PW_TYPE_IPADDR) { \
+						LM_ERR("attribute %d is not of type integer or ipaddr\n", \
+							_attrs[_attr].v); \
+						goto error; \
+					} \
+				} \
+			} \
+			if (!rc_avpair_add( rh, &send, _attrs[_attr].v, _val, _len, 0)) { \
+				LM_ERR("failed to add %s, %d\n", _attrs[_attr].n, _attr); \
+				goto error; \
+			} \
+		} \
+	}while(0)
 
 
 /*
@@ -162,78 +218,83 @@ static void generate_avps(struct attr *attrs, VALUE_PAIR* received)
  */
 int radius_load_caller_avps(struct sip_msg* _m, char* _caller, char* _s2)
 {
-    str user;
-    VALUE_PAIR *send, *received;
-    uint32_t service;
-    static char msg[4096];
-    int extra_cnt, offset, i, res;
-
-    if ((_caller == NULL) ||
-	(fixup_get_svalue(_m, (gparam_p)_caller, &user) != 0)) {
-	LM_ERR("invalid caller parameter");
-	return -1;
-    }
+	str user;
+	VALUE_PAIR *send, *received;
+	uint32_t service;
+	static char msg[4096];
+	int extra_cnt, offset, i, res;
+
+	if ((_caller == NULL) ||
+			(fixup_get_svalue(_m, (gparam_p)_caller, &user) != 0)) {
+		LM_ERR("invalid caller parameter");
+		return -1;
+	}
 
-    send = received = 0;
+	send = received = 0;
 
-    if (!rc_avpair_add(rh, &send, caller_attrs[SA_USER_NAME].v,
-		       user.s, user.len, 0)) {
-	LM_ERR("in adding SA_USER_NAME\n");
-	return -1;
-    }
-
-    service = caller_vals[RV_SIP_CALLER_AVPS].v;
-    if (!rc_avpair_add(rh, &send, caller_attrs[SA_SERVICE_TYPE].v,
-		       &service, -1, 0)) {
-	LM_ERR("error adding SA_SERVICE_TYPE <%u>\n", service);
-	goto error;
-    }
-
-    /* Add extra attributes */
-    extra_cnt = extra2strar(caller_extra, _m, val_arr);
-    if (extra_cnt == -1) {
-	LM_ERR("in getting values of caller extra attributes\n");
-	goto error;
-    }
-    offset = SA_STATIC_MAX;
-    for (i = 0; i < extra_cnt; i++) {
-	if (val_arr[i].len == -1) {
-	    /* Add integer attribute */
-	    ADD_EXTRA_AVPAIR(caller_attrs, offset+i,
-			     &(val_arr[i].s), val_arr[i].len );
-	} else {
-	    /* Add string attribute */
-	    ADD_EXTRA_AVPAIR(caller_attrs, offset+i,
-			     val_arr[i].s, val_arr[i].len );
+	if (!rc_avpair_add(rh, &send, caller_attrs[SA_USER_NAME].v,
+				user.s, user.len, 0)) {
+		LM_ERR("in adding SA_USER_NAME\n");
+		return -1;
 	}
-    }
 
-    if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
-	LM_DBG("success\n");
-	rc_avpair_free(send);
-	generate_avps(caller_attrs, received);
-	rc_avpair_free(received);
-	return 1;
-    } else {
-	rc_avpair_free(send);
-	rc_avpair_free(received);
-#ifdef REJECT_RC
-	if (res == REJECT_RC) {
-	    LM_DBG("rejected\n");
-	    return -1;
-	} else {
-	    LM_ERR("failure\n");
-	    return -2;
+	service = caller_vals[RV_SIP_CALLER_AVPS].v;
+	if (!rc_avpair_add(rh, &send, caller_attrs[SA_SERVICE_TYPE].v,
+				&service, -1, 0)) {
+		LM_ERR("error adding SA_SERVICE_TYPE <%u>\n", service);
+		goto error;
 	}
+
+	/* Add extra attributes */
+	extra_cnt = extra2strar(caller_extra, _m, val_arr);
+	if (extra_cnt == -1) {
+		LM_ERR("in getting values of caller extra attributes\n");
+		goto error;
+	}
+	offset = SA_STATIC_MAX;
+	for (i = 0; i < extra_cnt; i++) {
+		if (val_arr[i].len == -1) {
+			/* Add integer attribute */
+			ADD_EXTRA_AVPAIR(caller_attrs, offset+i,
+					&(val_arr[i].s), val_arr[i].len );
+		} else {
+			/* Add string attribute */
+			ADD_EXTRA_AVPAIR(caller_attrs, offset+i,
+					val_arr[i].s, val_arr[i].len );
+		}
+	}
+
+	if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
+		LM_DBG("success\n");
+		rc_avpair_free(send);
+		if (common_response) {
+			generate_avps_rad(received);
+		} else {
+			generate_avps(caller_attrs, received);
+		}
+		rc_avpair_free(received);
+		return 1;
+	} else {
+		rc_avpair_free(send);
+		if (common_response) generate_avps_rad(received);
+		rc_avpair_free(received);
+#ifdef REJECT_RC
+		if (res == REJECT_RC) {
+			LM_DBG("rejected\n");
+			return -1;
+		} else {
+			LM_ERR("failure\n");
+			return -2;
+		}
 #else
-	LM_DBG("failure\n");
-	return -1;
+		LM_DBG("failure\n");
+		return -1;
 #endif
-    }
+	}
 
- error:
-    rc_avpair_free(send);
-    return -1;
+error:
+	rc_avpair_free(send);
+	return -1;
 }
 
 
@@ -243,78 +304,83 @@ int radius_load_caller_avps(struct sip_msg* _m, char* _caller, char* _s2)
  */
 int radius_load_callee_avps(struct sip_msg* _m, char* _callee, char* _s2)
 {
-    str user;
-    VALUE_PAIR *send, *received;
-    uint32_t service;
-    static char msg[4096];
-    int extra_cnt, offset, i, res;
+	str user;
+	VALUE_PAIR *send, *received;
+	uint32_t service;
+	static char msg[4096];
+	int extra_cnt, offset, i, res;
 
-    send = received = 0;
+	send = received = 0;
 
-    if ((_callee == NULL) ||
-	(fixup_get_svalue(_m, (gparam_p)_callee, &user) != 0)) {
-	LM_ERR("invalid callee parameter");
-	return -1;
-    }
+	if ((_callee == NULL) ||
+			(fixup_get_svalue(_m, (gparam_p)_callee, &user) != 0)) {
+		LM_ERR("invalid callee parameter");
+		return -1;
+	}
 
-    if (!rc_avpair_add(rh, &send, callee_attrs[SA_USER_NAME].v,
-		       user.s, user.len, 0)) {
-	LM_ERR("in adding SA_USER_NAME\n");
-	return -1;
-    }
-
-    service = callee_vals[EV_SIP_CALLEE_AVPS].v;
-    if (!rc_avpair_add(rh, &send, callee_attrs[SA_SERVICE_TYPE].v,
-		       &service, -1, 0)) {
-	LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
-	goto error;
-    }
-
-    /* Add extra attributes */
-    extra_cnt = extra2strar(callee_extra, _m, val_arr);
-    if (extra_cnt == -1) {
-	LM_ERR("in getting values of callee extra attributes\n");
-	goto error;
-    }
-    offset = SA_STATIC_MAX;
-    for (i = 0; i < extra_cnt; i++) {
-	if (val_arr[i].len == -1) {
-	    /* Add integer attribute */
-	    ADD_EXTRA_AVPAIR(callee_attrs, offset+i,
-			     &(val_arr[i].s), val_arr[i].len );
-	} else {
-	    /* Add string attribute */
-	    ADD_EXTRA_AVPAIR(callee_attrs, offset+i,
-			     val_arr[i].s, val_arr[i].len );
+	if (!rc_avpair_add(rh, &send, callee_attrs[SA_USER_NAME].v,
+				user.s, user.len, 0)) {
+		LM_ERR("in adding SA_USER_NAME\n");
+		return -1;
 	}
-    }
 
-    if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
-	LM_DBG("success\n");
-	rc_avpair_free(send);
-	generate_avps(callee_attrs, received);
-	rc_avpair_free(received);
-	return 1;
-    } else {
-	rc_avpair_free(send);
-	rc_avpair_free(received);
-#ifdef REJECT_RC
-	if (res == REJECT_RC) {
-	    LM_DBG("rejected\n");
-	    return -1;
-	} else {
-	    LM_ERR("failure\n");
-	    return -2;
+	service = callee_vals[EV_SIP_CALLEE_AVPS].v;
+	if (!rc_avpair_add(rh, &send, callee_attrs[SA_SERVICE_TYPE].v,
+				&service, -1, 0)) {
+		LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
+		goto error;
 	}
+
+	/* Add extra attributes */
+	extra_cnt = extra2strar(callee_extra, _m, val_arr);
+	if (extra_cnt == -1) {
+		LM_ERR("in getting values of callee extra attributes\n");
+		goto error;
+	}
+	offset = SA_STATIC_MAX;
+	for (i = 0; i < extra_cnt; i++) {
+		if (val_arr[i].len == -1) {
+			/* Add integer attribute */
+			ADD_EXTRA_AVPAIR(callee_attrs, offset+i,
+					&(val_arr[i].s), val_arr[i].len );
+		} else {
+			/* Add string attribute */
+			ADD_EXTRA_AVPAIR(callee_attrs, offset+i,
+					val_arr[i].s, val_arr[i].len );
+		}
+	}
+
+	if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
+		LM_DBG("success\n");
+		rc_avpair_free(send);
+		if (common_response) {
+			generate_avps_rad(received);
+		} else {
+			generate_avps(callee_attrs, received);
+		}
+		rc_avpair_free(received);
+		return 1;
+	} else {
+		rc_avpair_free(send);
+		if (common_response) generate_avps_rad(received);
+		rc_avpair_free(received);
+#ifdef REJECT_RC
+		if (res == REJECT_RC) {
+			LM_DBG("rejected\n");
+			return -1;
+		} else {
+			LM_ERR("failure\n");
+			return -2;
+		}
 #else
-	LM_DBG("failure\n");
-	return -1;
+		LM_DBG("failure\n");
+		return -1;
 #endif
-    }
+	}
 
- error:
-    rc_avpair_free(send);
-    return -1;
+error:
+	rc_avpair_free(send);
+	return -1;
 }
 
 
@@ -326,89 +392,89 @@ int radius_load_callee_avps(struct sip_msg* _m, char* _callee, char* _s2)
  */
 int radius_is_user_in(struct sip_msg* _m, char* _user, char* _group)
 {
-    str user, *group;
-    VALUE_PAIR *send, *received;
-    uint32_t service;
-    static char msg[4096];
-    int extra_cnt, offset, i, res;
+	str user, *group;
+	VALUE_PAIR *send, *received;
+	uint32_t service;
+	static char msg[4096];
+	int extra_cnt, offset, i, res;
 
-    send = received = 0;
+	send = received = 0;
 
-    if ((_user == NULL) ||
-	(fixup_get_svalue(_m, (gparam_p)_user, &user) != 0)) {
-	LM_ERR("invalid user parameter");
-	return -1;
-    }
+	if ((_user == NULL) ||
+			(fixup_get_svalue(_m, (gparam_p)_user, &user) != 0)) {
+		LM_ERR("invalid user parameter");
+		return -1;
+	}
 
-    if (!rc_avpair_add(rh, &send, group_attrs[SA_USER_NAME].v,
-		       user.s, user.len, 0)) {
-	LM_ERR("in adding SA_USER_NAME\n");
-	return -1;
-    }
-
-    group = (str*)_group;
-    if ((group == NULL) || (group->len == 0)) {
-	LM_ERR("invalid group parameter");
-	goto error;
-    }
-    if (!rc_avpair_add(rh, &send, group_attrs[SA_SIP_GROUP].v,
-		       group->s, group->len, 0)) {
-	LM_ERR("in adding SA_SIP_GROUP\n");
-	goto error;
-    }
-
-    service = group_vals[GV_GROUP_CHECK].v;
-    if (!rc_avpair_add(rh, &send, group_attrs[SA_SERVICE_TYPE].v,
-		       &service, -1, 0)) {
-	LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
-	goto error;
-    }
-
-    /* Add extra attributes */
-    extra_cnt = extra2strar(group_extra, _m, val_arr);
-    if (extra_cnt == -1) {
-	LM_ERR("in getting values of group extra attributes\n");
-	goto error;
-    }
-    offset = SA_STATIC_MAX;
-    for (i = 0; i < extra_cnt; i++) {
-	if (val_arr[i].len == -1) {
-	    /* Add integer attribute */
-	    ADD_EXTRA_AVPAIR(group_attrs, offset+i,
-			     &(val_arr[i].s), val_arr[i].len );
-	} else {
-	    /* Add string attribute */
-	    ADD_EXTRA_AVPAIR(group_attrs, offset+i,
-			     val_arr[i].s, val_arr[i].len );
+	if (!rc_avpair_add(rh, &send, group_attrs[SA_USER_NAME].v,
+				user.s, user.len, 0)) {
+		LM_ERR("in adding SA_USER_NAME\n");
+		return -1;
 	}
-    }
 
-    if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
-	LM_DBG("success\n");
-	rc_avpair_free(send);
-	generate_avps(group_attrs, received);
-	rc_avpair_free(received);
-	return 1;
-    } else {
-	rc_avpair_free(send);
-	rc_avpair_free(received);
-#ifdef REJECT_RC
-	if (res == REJECT_RC) {
-	    LM_DBG("rejected\n");
-	    return -1;
-	} else {
-	    LM_ERR("failure\n");
-	    return -2;
+	group = (str*)_group;
+	if ((group == NULL) || (group->len == 0)) {
+		LM_ERR("invalid group parameter");
+		goto error;
+	}
+	if (!rc_avpair_add(rh, &send, group_attrs[SA_SIP_GROUP].v,
+				group->s, group->len, 0)) {
+		LM_ERR("in adding SA_SIP_GROUP\n");
+		goto error;
 	}
+
+	service = group_vals[GV_GROUP_CHECK].v;
+	if (!rc_avpair_add(rh, &send, group_attrs[SA_SERVICE_TYPE].v,
+				&service, -1, 0)) {
+		LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
+		goto error;
+	}
+
+	/* Add extra attributes */
+	extra_cnt = extra2strar(group_extra, _m, val_arr);
+	if (extra_cnt == -1) {
+		LM_ERR("in getting values of group extra attributes\n");
+		goto error;
+	}
+	offset = SA_STATIC_MAX;
+	for (i = 0; i < extra_cnt; i++) {
+		if (val_arr[i].len == -1) {
+			/* Add integer attribute */
+			ADD_EXTRA_AVPAIR(group_attrs, offset+i,
+					&(val_arr[i].s), val_arr[i].len );
+		} else {
+			/* Add string attribute */
+			ADD_EXTRA_AVPAIR(group_attrs, offset+i,
+					val_arr[i].s, val_arr[i].len );
+		}
+	}
+
+	if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
+		LM_DBG("success\n");
+		rc_avpair_free(send);
+		generate_avps(group_attrs, received);
+		rc_avpair_free(received);
+		return 1;
+	} else {
+		rc_avpair_free(send);
+		rc_avpair_free(received);
+#ifdef REJECT_RC
+		if (res == REJECT_RC) {
+			LM_DBG("rejected\n");
+			return -1;
+		} else {
+			LM_ERR("failure\n");
+			return -2;
+		}
 #else
-	LM_DBG("failure\n");
-	return -1;
+		LM_DBG("failure\n");
+		return -1;
 #endif
-    }
+	}
 
- error:
-    rc_avpair_free(send);
-    return -1;
+error:
+	rc_avpair_free(send);
+	return -1;
 }
 
 /*
@@ -421,109 +487,109 @@ int radius_is_user_in(struct sip_msg* _m, char* _user, char* _group)
  */
 int radius_does_uri_user_host_exist(struct sip_msg* _m, str user, str host)
 {
-    char* at, *user_host;
-    VALUE_PAIR *send, *received;
-    uint32_t service;
-    static char msg[4096];
-    int extra_cnt, offset, i, res;
-
-    send = received = 0;
-    user_host = 0;
-
-    if (!use_sip_uri_host) {
-
-	/* Send user at host in SA_USER_NAME attr */
-	user_host = (char*)pkg_malloc(user.len + host.len + 2);
-	if (!user_host) {
-	    LM_ERR("no more pkg memory\n");
-	    return -1;
-	}
-	at = user_host;
-	memcpy(at, user.s, user.len);
-	at += user.len;
-	*at = '@';
-	at++;
-	memcpy(at , host.s, host.len);
-	at += host.len;
-	*at = '\0';
-	if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user_host,
-			   -1, 0)) {
-	    LM_ERR("in adding SA_USER_NAME\n");
-	    pkg_free(user_host);
-	    return -1;
-	}
-
-    } else {
-
-	/* Send user in SA_USER_NAME attribute and host in SA_SIP_URI_HOST
-          attribute */
-	if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v,
-			   user.s, user.len, 0)) {
-	    LM_ERR("adding User-Name failed\n");
-	    return -1;
-	}
-	if (!rc_avpair_add(rh, &send, uri_attrs[SA_SIP_URI_HOST].v,
-			   host.s, host.len, 0)) {
-	    LM_ERR("adding SIP-URI-Host failed\n");
-	    goto error;
-	}
-    }
-
-    service = uri_vals[UV_CALL_CHECK].v;
-    if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v,
-		       &service, -1, 0)) {
-	LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
-	goto error;
-    }
-
-    /* Add extra attributes */
-    extra_cnt = extra2strar(uri_extra, _m, val_arr);
-    if (extra_cnt == -1) {
-	LM_ERR("in getting values of group extra attributes\n");
-	goto error;
-    }
-    offset = SA_STATIC_MAX;
-    for (i = 0; i < extra_cnt; i++) {
-	if (val_arr[i].len == -1) {
-	    /* Add integer attribute */
-	    ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
-			     &(val_arr[i].s), val_arr[i].len );
+	char* at, *user_host;
+	VALUE_PAIR *send, *received;
+	uint32_t service;
+	static char msg[4096];
+	int extra_cnt, offset, i, res;
+
+	send = received = 0;
+	user_host = 0;
+
+	if (!use_sip_uri_host) {
+
+		/* Send user at host in SA_USER_NAME attr */
+		user_host = (char*)pkg_malloc(user.len + host.len + 2);
+		if (!user_host) {
+			LM_ERR("no more pkg memory\n");
+			return -1;
+		}
+		at = user_host;
+		memcpy(at, user.s, user.len);
+		at += user.len;
+		*at = '@';
+		at++;
+		memcpy(at , host.s, host.len);
+		at += host.len;
+		*at = '\0';
+		if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user_host,
+					-1, 0)) {
+			LM_ERR("in adding SA_USER_NAME\n");
+			pkg_free(user_host);
+			return -1;
+		}
+
 	} else {
-	    /* Add string attribute */
-	    ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
-			     val_arr[i].s, val_arr[i].len );
+
+		/* Send user in SA_USER_NAME attribute and host in SA_SIP_URI_HOST
+		   attribute */
+		if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v,
+					user.s, user.len, 0)) {
+			LM_ERR("adding User-Name failed\n");
+			return -1;
+		}
+		if (!rc_avpair_add(rh, &send, uri_attrs[SA_SIP_URI_HOST].v,
+					host.s, host.len, 0)) {
+			LM_ERR("adding SIP-URI-Host failed\n");
+			goto error;
+		}
 	}
-    }
 
-    if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
-	LM_DBG("success\n");
-	if (user_host) pkg_free(user_host);
-	rc_avpair_free(send);
-	generate_avps(uri_attrs, received);
-	rc_avpair_free(received);
-	return 1;
-    } else {
-	if (user_host) pkg_free(user_host);
-	rc_avpair_free(send);
-	rc_avpair_free(received);
-#ifdef REJECT_RC
-	if (res == REJECT_RC) {
-	    LM_DBG("rejected\n");
-	    return -1;
-	} else {
-	    LM_ERR("failure\n");
-	    return -2;
+	service = uri_vals[UV_CALL_CHECK].v;
+	if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v,
+				&service, -1, 0)) {
+		LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
+		goto error;
+	}
+
+	/* Add extra attributes */
+	extra_cnt = extra2strar(uri_extra, _m, val_arr);
+	if (extra_cnt == -1) {
+		LM_ERR("in getting values of group extra attributes\n");
+		goto error;
+	}
+	offset = SA_STATIC_MAX;
+	for (i = 0; i < extra_cnt; i++) {
+		if (val_arr[i].len == -1) {
+			/* Add integer attribute */
+			ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
+					&(val_arr[i].s), val_arr[i].len );
+		} else {
+			/* Add string attribute */
+			ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
+					val_arr[i].s, val_arr[i].len );
+		}
 	}
+
+	if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
+		LM_DBG("success\n");
+		if (user_host) pkg_free(user_host);
+		rc_avpair_free(send);
+		generate_avps(uri_attrs, received);
+		rc_avpair_free(received);
+		return 1;
+	} else {
+		if (user_host) pkg_free(user_host);
+		rc_avpair_free(send);
+		rc_avpair_free(received);
+#ifdef REJECT_RC
+		if (res == REJECT_RC) {
+			LM_DBG("rejected\n");
+			return -1;
+		} else {
+			LM_ERR("failure\n");
+			return -2;
+		}
 #else
-	LM_DBG("failure\n");
-	return -1;
+		LM_DBG("failure\n");
+		return -1;
 #endif
-    }
+	}
 
- error:
-    rc_avpair_free(send);
-    if (user_host) pkg_free(user_host);
-    return -1;
+error:
+	rc_avpair_free(send);
+	if (user_host) pkg_free(user_host);
+	return -1;
 }
 
 
@@ -534,13 +600,13 @@ int radius_does_uri_user_host_exist(struct sip_msg* _m, str user, str host)
 int radius_does_uri_exist_0(struct sip_msg* _m, char* _s1, char* _s2)
 {
 
-    if (parse_sip_msg_uri(_m) < 0) {
-	LM_ERR("parsing Request-URI failed\n");
-	return -1;
-    }
+	if (parse_sip_msg_uri(_m) < 0) {
+		LM_ERR("parsing Request-URI failed\n");
+		return -1;
+	}
 
-    return radius_does_uri_user_host_exist(_m, _m->parsed_uri.user,
-					   _m->parsed_uri.host);
+	return radius_does_uri_user_host_exist(_m, _m->parsed_uri.user,
+			_m->parsed_uri.host);
 }
 
 
@@ -550,34 +616,34 @@ int radius_does_uri_exist_0(struct sip_msg* _m, char* _s1, char* _s2)
  */
 int radius_does_uri_exist_1(struct sip_msg* _m, char* _sp, char* _s2)
 {
-    pv_spec_t *sp;
-    pv_value_t pv_val;
-    struct sip_uri parsed_uri;
-
-    sp = (pv_spec_t *)_sp;
-
-    if (sp && (pv_get_spec_value(_m, sp, &pv_val) == 0)) {
-	if (pv_val.flags & PV_VAL_STR) {
-	    if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
-		LM_ERR("pvar argument is empty\n");
-		return -1;
-	    }
+	pv_spec_t *sp;
+	pv_value_t pv_val;
+	struct sip_uri parsed_uri;
+
+	sp = (pv_spec_t *)_sp;
+
+	if (sp && (pv_get_spec_value(_m, sp, &pv_val) == 0)) {
+		if (pv_val.flags & PV_VAL_STR) {
+			if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
+				LM_ERR("pvar argument is empty\n");
+				return -1;
+			}
+		} else {
+			LM_ERR("pvar value is not string\n");
+			return -1;
+		}
 	} else {
-	    LM_ERR("pvar value is not string\n");
-	    return -1;
+		LM_ERR("cannot get pvar value\n");
+		return -1;
 	}
-    } else {
-	LM_ERR("cannot get pvar value\n");
-	return -1;
-    }
 
-    if (parse_uri(pv_val.rs.s, pv_val.rs.len, &parsed_uri) < 0) {
-	LM_ERR("parsing of URI in pvar failed\n");
-	return -1;
-    }
+	if (parse_uri(pv_val.rs.s, pv_val.rs.len, &parsed_uri) < 0) {
+		LM_ERR("parsing of URI in pvar failed\n");
+		return -1;
+	}
 
-    return radius_does_uri_user_host_exist(_m, parsed_uri.user,
-					   parsed_uri.host);
+	return radius_does_uri_user_host_exist(_m, parsed_uri.user,
+			parsed_uri.host);
 }
 
 
@@ -587,71 +653,71 @@ int radius_does_uri_exist_1(struct sip_msg* _m, char* _sp, char* _s2)
  */
 int radius_does_uri_user_exist(struct sip_msg* _m, str user)
 {
-    static char msg[4096];
-    VALUE_PAIR *send, *received;
-    uint32_t service;
-    int res, extra_cnt, offset, i;
-    
-    send = received = 0;
-    
-    if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v,
-		       user.s, user.len, 0)) {
-	LM_ERR("in adding SA_USER_NAME\n");
-	return -1;
-    }
-    
-    service = uri_vals[UV_CALL_CHECK].v;
-    if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v,
-		       &service, -1, 0)) {
-	LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
-	goto error;
-    }
-
-    /* Add extra attributes */
-    extra_cnt = extra2strar(uri_extra, _m, val_arr);
-    if (extra_cnt == -1) {
-	LM_ERR("in getting values of group extra attributes\n");
-	goto error;
-    }
-    offset = SA_STATIC_MAX;
-    for (i = 0; i < extra_cnt; i++) {
-	if (val_arr[i].len == -1) {
-	    /* Add integer attribute */
-	    ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
-			     &(val_arr[i].s), val_arr[i].len );
-	} else {
-	    /* Add string attribute */
-	    ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
-			     val_arr[i].s, val_arr[i].len );
+	static char msg[4096];
+	VALUE_PAIR *send, *received;
+	uint32_t service;
+	int res, extra_cnt, offset, i;
+
+	send = received = 0;
+
+	if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v,
+				user.s, user.len, 0)) {
+		LM_ERR("in adding SA_USER_NAME\n");
+		return -1;
 	}
-    }
 
-    if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
-	LM_DBG("success\n");
-	rc_avpair_free(send);
-	generate_avps(uri_attrs, received);
-	rc_avpair_free(received);
-	return 1;
-    } else {
-	rc_avpair_free(send);
-	rc_avpair_free(received);
-#ifdef REJECT_RC
-	if (res == REJECT_RC) {
-	    LM_DBG("rejected\n");
-	    return -1;
-	} else {
-	    LM_ERR("failure\n");
-	    return -2;
+	service = uri_vals[UV_CALL_CHECK].v;
+	if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v,
+				&service, -1, 0)) {
+		LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service);
+		goto error;
+	}
+
+	/* Add extra attributes */
+	extra_cnt = extra2strar(uri_extra, _m, val_arr);
+	if (extra_cnt == -1) {
+		LM_ERR("in getting values of group extra attributes\n");
+		goto error;
 	}
+	offset = SA_STATIC_MAX;
+	for (i = 0; i < extra_cnt; i++) {
+		if (val_arr[i].len == -1) {
+			/* Add integer attribute */
+			ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
+					&(val_arr[i].s), val_arr[i].len );
+		} else {
+			/* Add string attribute */
+			ADD_EXTRA_AVPAIR(uri_attrs, offset+i,
+					val_arr[i].s, val_arr[i].len );
+		}
+	}
+
+	if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) {
+		LM_DBG("success\n");
+		rc_avpair_free(send);
+		generate_avps(uri_attrs, received);
+		rc_avpair_free(received);
+		return 1;
+	} else {
+		rc_avpair_free(send);
+		rc_avpair_free(received);
+#ifdef REJECT_RC
+		if (res == REJECT_RC) {
+			LM_DBG("rejected\n");
+			return -1;
+		} else {
+			LM_ERR("failure\n");
+			return -2;
+		}
 #else
-	LM_DBG("failure\n");
-	return -1;
+		LM_DBG("failure\n");
+		return -1;
 #endif
-    }
+	}
 
- error:
-    rc_avpair_free(send);
-    return -1;
+error:
+	rc_avpair_free(send);
+	return -1;
 }
 
 
@@ -662,12 +728,12 @@ int radius_does_uri_user_exist(struct sip_msg* _m, str user)
 int radius_does_uri_user_exist_0(struct sip_msg* _m, char* _s1, char* _s2)
 {
 
-    if (parse_sip_msg_uri(_m) < 0) {
-	LM_ERR("parsing Request-URI failed\n");
-	return -1;
-    }
+	if (parse_sip_msg_uri(_m) < 0) {
+		LM_ERR("parsing Request-URI failed\n");
+		return -1;
+	}
 
-    return radius_does_uri_user_exist(_m, _m->parsed_uri.user);
+	return radius_does_uri_user_exist(_m, _m->parsed_uri.user);
 }
 
 
@@ -678,25 +744,25 @@ int radius_does_uri_user_exist_0(struct sip_msg* _m, char* _s1, char* _s2)
  */
 int radius_does_uri_user_exist_1(struct sip_msg* _m, char* _sp, char* _s2)
 {
-    pv_spec_t *sp;
-    pv_value_t pv_val;
-
-    sp = (pv_spec_t *)_sp;
-
-    if (sp && (pv_get_spec_value(_m, sp, &pv_val) == 0)) {
-	if (pv_val.flags & PV_VAL_STR) {
-	    if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
-		LM_ERR("pvar argument is empty\n");
-		return -1;
-	    }
+	pv_spec_t *sp;
+	pv_value_t pv_val;
+
+	sp = (pv_spec_t *)_sp;
+
+	if (sp && (pv_get_spec_value(_m, sp, &pv_val) == 0)) {
+		if (pv_val.flags & PV_VAL_STR) {
+			if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
+				LM_ERR("pvar argument is empty\n");
+				return -1;
+			}
+		} else {
+			LM_ERR("pvar value is not string\n");
+			return -1;
+		}
 	} else {
-	    LM_ERR("pvar value is not string\n");
-	    return -1;
+		LM_ERR("cannot get pvar value\n");
+		return -1;
 	}
-    } else {
-	LM_ERR("cannot get pvar value\n");
-	return -1;
-    }
 
-    return radius_does_uri_user_exist(_m, pv_val.rs);
+	return radius_does_uri_user_exist(_m, pv_val.rs);
 }
diff --git a/modules/misc_radius/misc_radius.c b/modules/misc_radius/misc_radius.c
index 0330909..15c9caf 100644
--- a/modules/misc_radius/misc_radius.c
+++ b/modules/misc_radius/misc_radius.c
@@ -57,6 +57,7 @@ static int caller_service_type = -1;
 static int callee_service_type = -1;
 static int group_service_type = -1;
 static int uri_service_type = -1;
+int common_response = 0;
 int use_sip_uri_host = 0;
 
 void *rh;
@@ -117,7 +118,8 @@ static param_export_t params[] = {
     {"callee_extra",        STR_PARAM, &callee_extra_str   },
     {"group_extra",         STR_PARAM, &group_extra_str    },
     {"uri_extra",           STR_PARAM, &uri_extra_str      },
-    {"use_sip_uri_host",    INT_PARAM, &use_sip_uri_host},
+    {"use_sip_uri_host",    INT_PARAM, &use_sip_uri_host   },
+    {"common_response",     INT_PARAM, &common_response    },
     {0, 0, 0}
 };	
 
@@ -139,19 +141,19 @@ struct module_exports exports = {
 
 
 /* Macro to set static attribute names */
-#define SET_STATIC(_attrs)		\
-    do {								\
+#define SET_STATIC(_attrs)		                        \
+    do {								                \
 	memset((_attrs), 0, sizeof((_attrs)));				\
-	(_attrs)[SA_SERVICE_TYPE].n	   = "Service-Type";		\
+	(_attrs)[SA_SERVICE_TYPE].n	   = "Service-Type";	\
 	(_attrs)[SA_USER_NAME].n	   = "User-Name";		\
-	(_attrs)[SA_SIP_AVP].n	           = "SIP-AVP";			\
+	(_attrs)[SA_SIP_AVP].n	       = "SIP-AVP";			\
 	(_attrs)[SA_SIP_GROUP].n	   = "SIP-Group";		\
-	if (use_sip_uri_host) {						\
-	    (_attrs)[SA_SIP_URI_HOST].n	   = "SIP-URI-Host";		\
-	} else {							\
-	    (_attrs)[SA_SIP_URI_HOST].n	   = "User-Name";		\
-	}								\
-	n = SA_STATIC_MAX;						\
+	if (use_sip_uri_host) {						        \
+	    (_attrs)[SA_SIP_URI_HOST].n  = "SIP-URI-Host";  \
+	} else {							                \
+	    (_attrs)[SA_SIP_URI_HOST].n  = "User-Name";     \
+	}								                    \
+	n = SA_STATIC_MAX;						            \
     }while(0)
 
 
diff --git a/modules/misc_radius/misc_radius.h b/modules/misc_radius/misc_radius.h
index 02af2d0..0717cfd 100644
--- a/modules/misc_radius/misc_radius.h
+++ b/modules/misc_radius/misc_radius.h
@@ -35,6 +35,7 @@ enum {GV_GROUP_CHECK = 0, GV_STATIC_MAX};
 enum {UV_CALL_CHECK = 0, UV_STATIC_MAX};
 
 extern int use_sip_uri_host;
+extern int common_response;
 
 extern void *rh;
 
diff --git a/modules/mohqueue/Makefile b/modules/mohqueue/Makefile
new file mode 100644
index 0000000..f10bb40
--- /dev/null
+++ b/modules/mohqueue/Makefile
@@ -0,0 +1,18 @@
+# $Id$
+#
+# msgqueue module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=mohqueue.so
+LIBS=
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore $(SERLIBPATH)/srdb1/srdb1
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+include ../../Makefile.modules
diff --git a/modules/mohqueue/NOTES b/modules/mohqueue/NOTES
new file mode 100644
index 0000000..0741d9f
--- /dev/null
+++ b/modules/mohqueue/NOTES
@@ -0,0 +1,6 @@
+Things to look into:
+
+* RFC3261, section 12.1.1 requires UAS to copy Record-Route
+* Check to see if any memory leaks.
+* Should probably respond when caller says BYE after queue says BYE.
+* check RAck number
diff --git a/modules/mohqueue/README b/modules/mohqueue/README
new file mode 100644
index 0000000..ab9cf1e
--- /dev/null
+++ b/modules/mohqueue/README
@@ -0,0 +1,406 @@
+mohqueue Module
+
+Robert Boisvert
+
+   Copyright © 2013 Robert Boisvert, rdbprog at gmail.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. db_url (str)
+              3.2. db_qtable and db_ctable (str)
+              3.3. mohdir (str)
+              3.4. moh_maxcalls (integer)
+
+        4. Functions
+
+              4.1. mohq_process ()
+              4.2. mohq_send (queue_name)
+              4.3. mohq_retrieve (queue_name, URI)
+              4.4. mohq_count (queue_name, pvar)
+
+        5. Database Schema
+
+              5.1. MOHQUEUES Table
+              5.2. MOHQCALLS Table
+
+        6. Audio Files
+
+   List of Examples
+
+   1.1. Set db_url:
+   1.2. Set table names:
+   1.3. Set default directory for audio files:
+   1.4. Set default directory for audio files:
+   1.5. mohq_process usage:
+   1.6. mohq_send usage:
+   1.7. mohq_retrieve usage:
+   1.8. mohq_count usage:
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. db_url (str)
+        3.2. db_qtable and db_ctable (str)
+        3.3. mohdir (str)
+        3.4. moh_maxcalls (integer)
+
+   4. Functions
+
+        4.1. mohq_process ()
+        4.2. mohq_send (queue_name)
+        4.3. mohq_retrieve (queue_name, URI)
+        4.4. mohq_count (queue_name, pvar)
+
+   5. Database Schema
+
+        5.1. MOHQUEUES Table
+        5.2. MOHQCALLS Table
+
+   6. Audio Files
+
+1. Overview
+
+   The mohqueue module diverts INVITE requests into a Music On Hold (MOH)
+   queue where the caller can listen to recorded audio until an operator
+   is available to take the call. When an operator is available, a
+   function can be used to transfer the oldest call in a queue to an
+   operator using an unattended transfer (REFER) to a specified URI. If
+   successful, the call is removed from the queue.
+
+   While in queue, recorded audio is streamed to the caller in an endless
+   loop using the rtpproxy module and application. Each queue can be
+   configured to use different audio files.
+
+   The queues are defined in the database which allows for dynamic
+   configuration of the queues. Each queue is assigned a specific URI to
+   respond to and a location for the audio files.
+
+   As each call arrives the database is updated to show the call status
+   which allows outside processes to inspect the queue. It can also be
+   inspected using a function to see how many calls are currently in
+   queue.
+
+   While in queue, all SIP messages for a call must pass through the
+   mohqueue module so that it can accurately detect the call status.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * a database module
+     * sl module
+     * tm module
+     * rtpproxy module
+
+2.2. External Libraries or Applications
+
+   The rtpproxy applications supported by the rtpproxy module (e.g.
+   http://www.b2bua.org/wiki/RTPproxy).
+
+3. Parameters
+
+   3.1. db_url (str)
+   3.2. db_qtable and db_ctable (str)
+   3.3. mohdir (str)
+   3.4. moh_maxcalls (integer)
+
+3.1. db_url (str)
+
+   The URL to connect to the database for the mohqueue tables.
+
+   Default value for Kamailio.
+
+   Example 1.1. Set db_url:
+...
+modparam ("mohqueue", "db_url", "mysql://kamailio:kamailiorw@localhost/kamailio
+")
+...
+
+3.2. db_qtable and db_ctable (str)
+
+   db_qtable is the name of the table that defines the queues and
+   db_ctable is the table that maintains the call status.
+
+   "MOHQUEUES" for db_qtable and "MOHQCALLS" for db_ctable.
+
+   Example 1.2. Set table names:
+...
+modparam ("mohqueue", "db_qtable", "mqueues")
+modparam ("mohqueue", "db_ctable", "mcalls")
+...
+
+3.3. mohdir (str)
+
+   Path to the directory where the audio files are stored. Audio files are
+   usually relative to this directory although the value can be overridden
+   by a directory specified in the queues table.
+
+   None. If not set by the module it must be defined in the queues table.
+
+   Example 1.3. Set default directory for audio files:
+...
+modparam ("mohqueue", "mohdir", "/var/kamailio/MOH")
+...
+
+3.4. moh_maxcalls (integer)
+
+   Defines the maximum number of calls that can be placed in queue. It is
+   the sum of all calls in all queues. It must be in the range of 1 to
+   5000. NOTE: it may be limited by the processing power of the server or
+   the number of available rtpproxy ports.
+
+   None. If not set by the module it must be defined in the queues table.
+
+   Example 1.4. Set default directory for audio files:
+...
+modparam ("mohqueue", "mohdir", "/var/kamailio/MOH")
+...
+
+4. Functions
+
+   4.1. mohq_process ()
+   4.2. mohq_send (queue_name)
+   4.3. mohq_retrieve (queue_name, URI)
+   4.4. mohq_count (queue_name, pvar)
+
+4.1.  mohq_process ()
+
+   Checks to see if the current SIP message involves a queue. If it does
+   it will process the message and return a TRUE value.
+
+   In order for mohqueue to detect changes in the call it is necessary
+   that all messages involving the call be processed through this
+   function. The easiest way is to accomplish this is to place it at the
+   beginning of the main route of the script.
+
+   mohqueue calls are identified by an RURI that matches a queue URI. Once
+   a call is placed in queue it checks the To header field along with the
+   RURI to find a match, except in the case of a CANCEL which matches only
+   on the RURI.
+
+   This function has no parameters and must be called from a request
+   route.
+
+   Return code:
+     * TRUE=successful and call in queue
+     * FALSE=failed, unrecognized URI or unable to place in queue
+
+   Example 1.5. mohq_process usage:
+...
+request_route {
+  # main route with limited processing
+...
+  # MOH queue?
+  if (mohq_process ()) {
+    xlog ("L_DBG", "Handled by mohqueue");
+    exit;
+  }
+  # An error or not a MOH queue message; continue processing
+...
+}
+...
+
+4.2.  mohq_send (queue_name)
+
+   Normally calls enter the queue with an initial INVITE message that 1)
+   has a RURI that matches a queue URI and 2) is passed through mohq_proc
+   (), which is the preferred method.
+
+   This function is used when you wish to send a call into a queue that
+   does not match the queue URI.
+
+   It has only one parameter, the name of the queue, and must be called
+   from the request route with an initial INVITE message. The queue name
+   can be passed as a literal or pseudo-variable.
+
+   Return code:
+     * TRUE=successful and call in queue
+     * FALSE=failed, unable to place in queue
+
+   Example 1.6. mohq_send usage:
+...
+  # call is initial INVITE and ready for queue?
+  if (some test) {
+    if (mohq_send ("main")) {
+      xlog ("L_DBG", "Sent call to main mohqueue");
+      exit;
+    }
+    # failed to enter queue!
+    ...
+  }
+...
+
+4.3.  mohq_retrieve (queue_name, URI)
+
+   Retrieves the oldest call in a queue and redirects it to a URI.
+   Although the function returns, the transfer of the call may not have
+   completed since the new URI (operator) must answer the call.
+
+   It has two parameters, the queue name and the URI to REFER the call to,
+   both which can be passed as literals or pseudo-variables. It can be
+   called from any route.
+
+   Return code:
+     * TRUE=successful, transfer started
+     * FALSE=failed, parameters are incorrect or there are no calls in
+       queue
+
+   Example 1.7. mohq_retrieve usage:
+...
+#!define MOHQNAME "operators"
+#!define CGROUP   "sip:operators at 10.211.64.5"
+...
+  # redirect oldest call to operator call group
+  if (mohq_retrieve (MOHQNAME, CGROUP)) {
+      xlog ("L_DBG", "Retrieved call from mohqueue");
+      exit;
+    }
+  # queue is empty or something went wrong
+  }
+...
+
+4.4.  mohq_count (queue_name, pvar)
+
+   Finds the number of calls that are in a queue. It will not count calls
+   that are in the process of entering or exiting the queue.
+
+   The function has two parameters, the name of the queue and the
+   pseudo-variable which receives the count. The queue name can be passed
+   as a literal or a pseudo-variable. It can be called from any route.
+
+   Return code:
+     * TRUE=successful, pseudo-variable contains count
+     * FALSE=failed, parameters are incorrect
+
+   Example 1.8. mohq_count usage:
+...
+$var(mohq) = "operators";
+...
+  # more than 10 calls?
+  mohq_count ("$var(mohq)", "$var(mohqcnt)");
+  if ($var(mohqcnt) > 10) {
+    xlog ("L_WARN", "$var(mohq) queue has $var(mohqcnt) calls!");
+  }
+...
+
+5. Database Schema
+
+   5.1. MOHQUEUES Table
+   5.2. MOHQCALLS Table
+
+   mohqueue uses two external database tables to manage the queues and
+   provide status information to outside processes. Internally, it keeps a
+   volatile database in memory of call status. If the module is restarted
+   it loses the internal database and clears the external one.
+
+   On a reqular basis it checks the external table that defines the queues
+   to see if the definition has changed. It makes this check under the
+   following conditions: the queue has not been checked in the last 60
+   seconds AND no call is currently in queue or transitioning in or out.
+   The last condition prevents existing calls from being adversely
+   affected by queue redefinitions.
+
+5.1. MOHQUEUES Table
+
+   This table controls the definition of the queue. The name is set by the
+   db_qtable parameter. There is no internal function to modify the table
+   so it must be configured externally. It contains the following fields:
+     * id (integer): unique identifier that is created automatically. Do
+       not attempt to change this value.
+     * name (25-character string, required): the queue name. Duplicate
+       names are not allowed.
+     * uri (100-character string, required): the URI of the queue. It
+       should not include any parameters or headers (e.g.
+       "sip:user at host;maddr=239.255.255.1" or
+       "sip:user at host?subject=project") although it will match any RURI
+       that contains this URI even if the RURI has parameters or headers.
+       Duplicates are not allowed.
+     * mohdir (100-character string, optional): path to the directory
+       where the audio files for the queue are stored. This path overrides
+       the one provided by the mohdir parameter. If the directory is not
+       accessible by the module the queue is not activated.
+     * mohfile (100-character string, required): the base name of the
+       audio file. See the section about audio files for more information
+       about file names. If no files matching this name are found in the
+       directory the queue is not activated.
+     * debug (integer, required): enables debugging messages for the
+       queue. If non-zero, it will send debugging messages to the log for
+       conditions that involve the queue, whether or not Kamailio has
+       logging enabled for debugging. If zero, it depends on Kamailio's
+       log level.
+
+5.2. MOHQCALLS Table
+
+   This table contains the status of calls that are in queue, or
+   transitioning in or out of a queue. The name is set by the db_ctable
+   parameter. This table is read-only for external processes and its
+   contents should not be modified. It contains the following fields:
+     * id (integer): unique identifier that is created automatically.
+     * mohq_id (integer, required): the id value of the queue.
+     * call_status (integer, required): the status of the call.
+       1=entering; 2=in queue (listening to MOH); 3=leaving
+     * call_from (100-character string, required): the contents of the
+       From header field.
+     * call_id (100-character string, required): the contents of the
+       Call-ID header field.
+     * call_contact (100-character string, optional): the contents of the
+       Contact header field, if it exists.
+     * call_time (datetime, required): time the call entered the queue. If
+       a retrieve fails this time is not changed.
+
+6. Audio Files
+
+   When rtpproxy negotiates to determine which media to use in the audio
+   stream it uses the files in the MOH directory as defined by the
+   MOHQUEUES table. The table defines the location of the files and the
+   base name used to identify each. The actual stream type depends on the
+   RTP payload number that is part of the name. The complete file name for
+   each stream is composed of mohdir/mohfile.type. For example,
+   /var/kamailio/MOH/HeWillCall.8 would be the file for payload type 8
+   (PCMA/8000).
+
+   The supported types and their order of preference are:
+     * 9: G722/8000
+     * 0: PCMU/8000
+     * 8: PCMA/8000
+     * 18: G729/8000
+     * 3: GSM/8000
+     * 4: G723/8000
+     * 15: G728/8000
+     * 5: DVI4/8000
+     * 7: LPC/8000
+     * 12: QCELP/8000
+     * 13: CN/8000
+     * 16: DVI4/11025
+     * 6: DVI4/16000
+     * 17: DVI4/22050
+     * 10: L16/44100
+     * 11: L16/44100
+     * 14: MPA/90000
+
+   See RTP Audio Video Profile for more information about RTP payload
+   types.
diff --git a/modules/mohqueue/doc/Makefile b/modules/mohqueue/doc/Makefile
new file mode 100644
index 0000000..f4f6a5e
--- /dev/null
+++ b/modules/mohqueue/doc/Makefile
@@ -0,0 +1,4 @@
+docs = mohqueue.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/mohqueue/doc/mohqueue.xml b/modules/mohqueue/doc/mohqueue.xml
new file mode 100644
index 0000000..be6818b
--- /dev/null
+++ b/modules/mohqueue/doc/mohqueue.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+  <bookinfo>
+    <title>mohqueue Module</title>
+    <productname class="trade">&kamailioname;</productname>
+    <authorgroup>
+      <author>
+        <firstname>Robert</firstname>
+        <surname>Boisvert</surname>
+        <address>
+          <email>rdbprog at gmail.com</email>
+        </address>
+      </author>
+    </authorgroup>
+    <copyright>
+      <year>2013</year>
+      <holder>Robert Boisvert, rdbprog at gmail.com</holder>
+    </copyright>
+  </bookinfo>
+  <toc></toc>
+  <xi:include href="mohqueue_admin.xml" />
+</book>
\ No newline at end of file
diff --git a/modules/mohqueue/doc/mohqueue_admin.xml b/modules/mohqueue/doc/mohqueue_admin.xml
new file mode 100644
index 0000000..3e53ee7
--- /dev/null
+++ b/modules/mohqueue/doc/mohqueue_admin.xml
@@ -0,0 +1,510 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module Admin Guide -->
+
+<chapter xmlns:xi="http://www.w3.org/2001/XInclude">
+  <title>&adminguide;</title>
+
+  <section id="overview">
+    <title>Overview</title>
+    <para>
+The mohqueue module diverts INVITE requests into a
+<ulink url="http://en.wikipedia.org/wiki/Music_on_hold">Music On
+Hold (MOH)</ulink> queue where the caller can listen to recorded
+audio until an operator is available to take the call. When an
+operator is available, a function can be used to transfer the oldest
+call in a queue to an operator using an unattended transfer (REFER)
+to a specified URI. If successful, the call is removed from the queue.
+    </para>
+    <para>
+While in queue, recorded audio is streamed to the caller in an endless
+loop using the rtpproxy module and application. Each queue can be
+configured to use different audio files.
+    </para>
+    <para>
+The queues are defined in the database which allows for dynamic
+configuration of the queues. Each queue is assigned a specific
+URI to respond to and a location for the audio files.
+    </para>
+    <para>
+As each call arrives the database is updated to show the call
+status which allows outside processes to inspect the queue. It
+can also be inspected using a function to see how many calls are
+currently in queue.
+    </para>
+    <para>
+While in queue, all SIP messages for a call must pass through
+the mohqueue module so that it can accurately detect the call
+status.
+    </para>
+  </section>
+
+  <section id="dependencies">
+    <title>Dependencies</title>
+
+    <section id="mod.depends">
+      <title>Kamailio Modules</title>
+      <para>
+The following modules must be loaded before this module:
+        <itemizedlist>
+          <listitem><emphasis>a database module</emphasis></listitem>
+          <listitem><emphasis>sl module</emphasis></listitem>
+          <listitem><emphasis>tm module</emphasis></listitem>
+          <listitem><emphasis>rtpproxy module</emphasis></listitem>
+        </itemizedlist>
+      </para>
+    </section>
+
+    <section id="app.depends">
+      <title>External Libraries or Applications</title>
+      <para>
+The rtpproxy applications supported by the rtpproxy module (e.g.
+<ulink url="http://www.b2bua.org/wiki/RTPproxy">
+http://www.b2bua.org/wiki/RTPproxy</ulink>).
+      </para>
+    </section>
+
+  </section>
+
+  <section id="parameters">
+    <title>Parameters</title>
+
+    <section id="url.parms">
+      <title><varname>db_url</varname> (str)</title>
+      <para>
+The URL to connect to the database for the mohqueue tables.
+      </para>
+      <para>
+<emphasis>Default value for Kamailio.</emphasis>
+      </para>
+      <example>
+        <title>Set <varname>db_url</varname>:</title>
+        <programlisting format="linespecific">
+...
+modparam ("mohqueue", "db_url", "mysql://kamailio:kamailiorw@localhost/kamailio")
+...
+        </programlisting>
+      </example>
+    </section>
+
+    <section id="table.parms">
+      <title><varname>db_qtable</varname> and <varname>db_ctable</varname> (str)</title>
+      <para>
+<varname>db_qtable</varname> is the name of the table that defines
+the queues and <varname>db_ctable</varname> is the table that
+maintains the call status.
+      </para>
+      <para>
+<emphasis>"MOHQUEUES" for <varname>db_qtable</varname> and
+"MOHQCALLS" for <varname>db_ctable</varname>.</emphasis>
+      </para>
+      <example>
+        <title>Set table names:</title>
+        <programlisting format="linespecific">
+...
+modparam ("mohqueue", "db_qtable", "mqueues")
+modparam ("mohqueue", "db_ctable", "mcalls")
+...
+        </programlisting>
+      </example>
+    </section>
+
+    <section id="dir.parms">
+      <title><varname>mohdir</varname> (str)</title>
+      <para>
+Path to the directory where the audio files are stored. Audio files
+are usually relative to this directory although the value can be
+overridden by a directory specified in the queues table.
+      </para>
+      <para>
+<emphasis>None. If not set by the module it must be defined in the
+queues table.</emphasis>
+      </para>
+      <example>
+        <title>Set default directory for audio files:</title>
+        <programlisting format="linespecific">
+...
+modparam ("mohqueue", "mohdir", "/var/kamailio/MOH")
+...
+        </programlisting>
+      </example>
+    </section>
+
+    <section id="maxcalls.parms">
+      <title><varname>moh_maxcalls</varname> (integer)</title>
+      <para>
+Defines the maximum number of calls that can be placed in queue.
+It is the sum of all calls in all queues. It must be in the range
+of 1 to 5000. <emphasis>NOTE:</emphasis> it may be limited by the
+processing power of the server or the number of available rtpproxy
+ports.
+      </para>
+      <para>
+<emphasis>None. If not set by the module it must be defined in the
+queues table.</emphasis>
+      </para>
+      <example>
+        <title>Set default directory for audio files:</title>
+        <programlisting format="linespecific">
+...
+modparam ("mohqueue", "mohdir", "/var/kamailio/MOH")
+...
+        </programlisting>
+      </example>
+    </section>
+
+  </section>
+
+  <section id="functions">
+    <title>Functions</title>
+
+    <section id="proc.func">
+      <title>
+        <function moreinfo="none">mohq_process ()</function>
+      </title>
+      <para>
+Checks to see if the current SIP message involves a queue. If it
+does it will process the message and return a TRUE value.
+      </para>
+      <para>
+In order for mohqueue to detect changes in the call it is necessary
+that all messages involving the call be processed through this
+function. The easiest way is to accomplish this is to place it at
+the beginning of the main route of the script.
+      </para>
+      <para>
+mohqueue calls are identified by an RURI that matches a queue URI.
+Once a call is placed in queue it checks the <varname>To</varname>
+header field along with the RURI to find a match, except in the case
+of a CANCEL which matches only on the RURI.
+      </para>
+      <para>
+This function has no parameters and must be called from a request route.
+      </para>
+      <para>
+<emphasis>Return code:</emphasis>
+        <itemizedlist>
+          <listitem>
+            <emphasis>TRUE=successful and call in queue</emphasis>
+          </listitem>
+          <listitem>
+            <emphasis>FALSE=failed, unrecognized URI or unable to place in queue</emphasis>
+          </listitem>
+        </itemizedlist>
+      </para>
+      <example>
+        <title><function>mohq_process</function> usage:</title>
+        <programlisting format="linespecific">
+...
+request_route {
+  # main route with limited processing
+...
+  # MOH queue?
+  if (mohq_process ()) {
+    xlog ("L_DBG", "Handled by mohqueue");
+    exit;
+  }
+  # An error or not a MOH queue message; continue processing
+...
+}
+...
+        </programlisting>
+      </example>
+    </section>
+
+    <section id="send.func">
+      <title>
+        <function moreinfo="none">mohq_send (queue_name)</function>
+      </title>
+      <para>
+Normally calls enter the queue with an initial INVITE message that
+1) has a RURI that matches a queue URI and 2) is passed through
+<function>mohq_proc ()</function>, which is the preferred method.
+      </para>
+      <para>
+This function is used when you wish to send a call into a queue that
+does not match the queue URI.
+      </para>
+      <para>
+It has only one parameter, the name of the queue, and must be called
+from the request route with an initial INVITE message. The queue name
+can be passed as a literal or pseudo-variable.
+      </para>
+      <para>
+<emphasis>Return code:</emphasis>
+        <itemizedlist>
+          <listitem>
+            <emphasis>TRUE=successful and call in queue</emphasis>
+          </listitem>
+          <listitem>
+            <emphasis>FALSE=failed, unable to place in queue</emphasis>
+          </listitem>
+        </itemizedlist>
+      </para>
+      <example>
+        <title><function>mohq_send</function> usage:</title>
+        <programlisting format="linespecific">
+...
+  # call is initial INVITE and ready for queue?
+  if (some test) {
+    if (mohq_send ("main")) {
+      xlog ("L_DBG", "Sent call to main mohqueue");
+      exit;
+    }
+    # failed to enter queue!
+    ...
+  }
+...
+        </programlisting>
+      </example>
+    </section>
+
+    <section id="retrieve.func">
+      <title>
+        <function moreinfo="none">mohq_retrieve (queue_name, URI)</function>
+      </title>
+      <para>
+Retrieves the oldest call in a queue and redirects it to a URI.
+Although the function returns, the transfer of the call may not have
+completed since the new URI (operator) must answer the call.
+      </para>
+      <para>
+It has two parameters, the queue name and the URI to REFER the call
+to, both which can be passed as literals or pseudo-variables. It can
+be called from any route.
+      </para>
+      <para>
+<emphasis>Return code:</emphasis>
+        <itemizedlist>
+          <listitem>
+            <emphasis>TRUE=successful, transfer started</emphasis>
+          </listitem>
+          <listitem>
+            <emphasis>FALSE=failed, parameters are incorrect or there are no calls in queue</emphasis>
+          </listitem>
+        </itemizedlist>
+      </para>
+      <example>
+        <title><function>mohq_retrieve</function> usage:</title>
+        <programlisting format="linespecific">
+...
+#!define MOHQNAME "operators"
+#!define CGROUP   "sip:operators at 10.211.64.5"
+...
+  # redirect oldest call to operator call group
+  if (mohq_retrieve (MOHQNAME, CGROUP)) {
+      xlog ("L_DBG", "Retrieved call from mohqueue");
+      exit;
+    }
+  # queue is empty or something went wrong
+  }
+...
+        </programlisting>
+      </example>
+    </section>
+
+    <section id="count.func">
+      <title>
+        <function moreinfo="none">mohq_count (queue_name, pvar)</function>
+      </title>
+      <para>
+Finds the number of calls that are in a queue. It will not count
+calls that are in the process of entering or exiting the queue.
+      </para>
+      <para>
+The function has two parameters, the name of the queue and the
+pseudo-variable which receives the count. The queue name can be
+passed as a literal or a pseudo-variable. It can be called from
+any route.
+      </para>
+      <para>
+<emphasis>Return code:</emphasis>
+        <itemizedlist>
+          <listitem>
+            <emphasis>TRUE=successful, pseudo-variable contains count</emphasis>
+          </listitem>
+          <listitem>
+            <emphasis>FALSE=failed, parameters are incorrect</emphasis>
+          </listitem>
+        </itemizedlist>
+      </para>
+      <example>
+        <title><function>mohq_count</function> usage:</title>
+        <programlisting format="linespecific">
+...
+$var(mohq) = "operators";
+...
+  # more than 10 calls?
+  mohq_count ("$var(mohq)", "$var(mohqcnt)");
+  if ($var(mohqcnt) > 10) {
+    xlog ("L_WARN", "$var(mohq) queue has $var(mohqcnt) calls!");
+  }
+...
+        </programlisting>
+      </example>
+    </section>
+
+  </section>
+
+  <section id="database">
+    <title>Database Schema</title>
+      <para>
+mohqueue uses two external database tables to manage the queues and
+provide status information to outside processes. Internally, it keeps
+a volatile database in memory of call status. If the module is
+restarted it loses the internal database and clears the external
+one.
+      </para>
+      <para>
+On a reqular basis it checks the external table that defines the
+queues to see if the definition has changed. It makes this check
+under the following conditions: the queue has not been checked in the
+last 60 seconds <emphasis>AND</emphasis> no call is currently in
+queue or transitioning in or out. The last condition prevents
+existing calls from being adversely affected by queue redefinitions.
+      </para>
+
+    <section id="mohqueues.dbase">
+      <title>MOHQUEUES Table</title>
+      <para>
+This table controls the definition of the queue. The name is set by
+the <ulink url="#table.parms">db_qtable</ulink> parameter. There is
+no internal function to modify the table so it must be configured
+externally. It contains the following fields:
+        <itemizedlist>
+          <listitem>
+<emphasis>id</emphasis> (integer): unique identifier that is created
+automatically. <emphasis>Do not attempt to change this value.</emphasis>
+          </listitem>
+          <listitem>
+<emphasis>name</emphasis> (25-character string, required): the queue name.
+Duplicate names are not allowed.
+          </listitem>
+          <listitem>
+<emphasis>uri</emphasis> (100-character string, required): the URI of
+the queue. It should not include any parameters or headers (e.g.
+"sip:user at host;maddr=239.255.255.1" or "sip:user at host?subject=project")
+although it will match any RURI that contains this URI even if the
+RURI has parameters or headers. Duplicates are not allowed.
+          </listitem>
+          <listitem>
+<emphasis>mohdir</emphasis> (100-character string, optional): path to
+the directory where the audio files for the queue are stored. This path
+overrides the one provided by the <ulink url="#dir.parms">mohdir</ulink>
+parameter. If the directory is not accessible by the module the queue
+is not activated.
+          </listitem>
+          <listitem>
+<emphasis>mohfile</emphasis> (100-character string, required): the
+base name of the audio file. See the section about
+<ulink url="#audiofiles">audio files</ulink> for more information
+about file names. If no files matching this name are found in the
+directory the queue is not activated.
+          </listitem>
+          <listitem>
+<emphasis>debug</emphasis> (integer, required): enables debugging
+messages for the queue. If non-zero, it will send debugging messages
+to the log for conditions that involve the queue, whether or not
+Kamailio has logging enabled for debugging. If zero, it depends on
+Kamailio's log level.
+          </listitem>
+        </itemizedlist>
+      </para>
+    </section>
+
+    <section id="mohqcalls.dbase">
+      <title>MOHQCALLS Table</title>
+      <para>
+This table contains the status of calls that are in queue, or
+transitioning in or out of a queue. The name is set by the
+<ulink url="#table.parms">db_ctable</ulink> parameter. This table
+is read-only for external processes and its contents should
+<emphasis>not be modified</emphasis>. It contains the following
+fields:
+        <itemizedlist>
+          <listitem>
+<emphasis>id</emphasis> (integer): unique identifier that is created
+automatically.
+          </listitem>
+          <listitem>
+<emphasis>mohq_id</emphasis> (integer, required): the id value of the
+queue.
+          </listitem>
+          <listitem>
+<emphasis>call_status</emphasis> (integer, required): the status of
+the call. 1=entering; 2=in queue (listening to MOH); 3=leaving
+          </listitem>
+          <listitem>
+<emphasis>call_from</emphasis> (100-character string, required): the
+contents of the <varname>From</varname> header field.
+          </listitem>
+          <listitem>
+<emphasis>call_id</emphasis> (100-character string, required): the
+contents of the <varname>Call-ID</varname> header field.
+          </listitem>
+          <listitem>
+<emphasis>call_contact</emphasis> (100-character string, optional):
+the contents of the <varname>Contact</varname> header field, if it
+exists.
+          </listitem>
+          <listitem>
+<emphasis>call_time</emphasis> (datetime, required): time the call
+entered the queue. If a <ulink url="#retrieve.func">retrieve</ulink>
+fails this time is not changed.
+          </listitem>
+        </itemizedlist>
+      </para>
+    </section>
+
+  </section>
+  <section id="audiofiles">
+    <title>Audio Files</title>
+      <para>
+When rtpproxy negotiates to determine which media to use in the audio
+stream it uses the files in the MOH directory as defined by the
+<ulink url="#mohqueues.dbase">MOHQUEUES</ulink> table. The table
+defines the location of the files and the base name used to identify
+each. The actual stream type depends on the RTP payload number that
+is part of the name. The complete file name for each stream is
+composed of <varname>mohdir/mohfile.type</varname>. For example,
+<varname>/var/kamailio/MOH/HeWillCall.8</varname> would be the file
+for payload type 8 (PCMA/8000).
+      </para>
+      <para>
+The supported types and their order of preference are:
+        <itemizedlist>
+          <listitem><emphasis>9</emphasis>: G722/8000</listitem>
+          <listitem><emphasis>0</emphasis>: PCMU/8000</listitem>
+          <listitem><emphasis>8</emphasis>: PCMA/8000</listitem>
+          <listitem><emphasis>18</emphasis>: G729/8000</listitem>
+          <listitem><emphasis>3</emphasis>: GSM/8000</listitem>
+          <listitem><emphasis>4</emphasis>: G723/8000</listitem>
+          <listitem><emphasis>15</emphasis>: G728/8000</listitem>
+          <listitem><emphasis>5</emphasis>: DVI4/8000</listitem>
+          <listitem><emphasis>7</emphasis>: LPC/8000</listitem>
+          <listitem><emphasis>12</emphasis>: QCELP/8000</listitem>
+          <listitem><emphasis>13</emphasis>: CN/8000</listitem>
+          <listitem><emphasis>16</emphasis>: DVI4/11025</listitem>
+          <listitem><emphasis>6</emphasis>: DVI4/16000</listitem>
+          <listitem><emphasis>17</emphasis>: DVI4/22050</listitem>
+          <listitem><emphasis>10</emphasis>: L16/44100</listitem>
+          <listitem><emphasis>11</emphasis>: L16/44100</listitem>
+          <listitem><emphasis>14</emphasis>: MPA/90000</listitem>
+        </itemizedlist>
+      </para>
+      <para>
+See <ulink url="http://en.wikipedia.org/wiki/RTP_audio_video_profile">
+RTP Audio Video Profile</ulink> for more information about RTP
+payload types.
+      </para>
+
+  </section>
+
+</chapter>
diff --git a/modules/mohqueue/mohq.c b/modules/mohqueue/mohq.c
new file mode 100644
index 0000000..0c0d118
--- /dev/null
+++ b/modules/mohqueue/mohq.c
@@ -0,0 +1,442 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "mohq.h"
+#include "mohq_db.h"
+#include "mohq_funcs.h"
+
+MODULE_VERSION
+
+/**********
+* local function declarations
+**********/
+
+int fixup_count (void **, int);
+static int mod_child_init (int);
+static void mod_destroy (void);
+static int mod_init (void);
+
+/**********
+* global varbs
+**********/
+
+mod_data *pmod_data;
+
+/**********
+* module exports
+**********/
+
+/* COMMANDS */
+static cmd_export_t mod_cmds [] = {
+  { "mohq_count", (cmd_function) mohq_count, 2, fixup_count, 0,
+    REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+  { "mohq_process", (cmd_function) mohq_process, 0, NULL, 0, REQUEST_ROUTE },
+  { "mohq_retrieve", (cmd_function) mohq_retrieve, 2, fixup_spve_spve, 0,
+    REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+  { "mohq_send", (cmd_function) mohq_send, 1, fixup_spve_spve, 0, REQUEST_ROUTE },
+  { NULL, NULL, -1, 0, 0 },
+};
+
+/* PARAMETERS */
+char *db_url = DEFAULT_DB_URL;
+char *db_ctable = "mohqcalls";
+char *db_qtable = "mohqueues";
+char *mohdir = "";
+int moh_maxcalls = 50;
+
+static param_export_t mod_parms [] = {
+  { "db_url", STR_PARAM, &db_url },
+  { "db_ctable", STR_PARAM, &db_ctable },
+  { "db_ctable", STR_PARAM, &db_qtable },
+  { "mohdir", STR_PARAM, &mohdir },
+  { "moh_maxcalls", INT_PARAM, &moh_maxcalls },
+  { NULL, 0, NULL },
+};
+
+/* MI COMMANDS */
+static mi_export_t mi_cmds [] = {
+  { "debug", mi_debug, 0, 0, 0 },
+  { "drop_call", mi_drop_call, 0, 0, 0 },
+  { 0, 0, 0, 0, 0 }
+};
+
+/* MODULE EXPORTS */
+struct module_exports exports = {
+  "mohqueue",       /* module name */
+  DEFAULT_DLFLAGS,  /* dlopen flags */
+  mod_cmds,         /* exported functions */
+  mod_parms,        /* exported parameters */
+  0,                /* statistics */
+  mi_cmds,          /* MI functions */
+  0,                /* exported pseudo-variables */
+  0,                /* extra processes */
+  mod_init,         /* module initialization function */
+  0,                /* response handling function */
+  mod_destroy,      /* destructor function */
+  mod_child_init,   /* per-child initialization function */
+};
+
+/**********
+* local functions
+**********/
+
+/**********
+* Fixup Count
+*
+* INPUT:
+*   Arg (1) = parameter array pointer
+*   Arg (1) = parameter number
+* OUTPUT: -1 if failed; 0 if saved as pv_elem_t
+**********/
+
+int fixup_count (void **param, int param_no)
+
+{
+if (param_no == 1)
+  { return fixup_spve_spve (param, 1); }
+if (param_no == 2)
+  { return fixup_pvar_null (param, 1); }
+return 0;
+}
+
+/**********
+* Configuration Initialization
+*
+* INPUT:
+*   pmod_data memory allocated
+*   configuration values set
+* OUTPUT: 0 if failed; else pmod_data has config values
+**********/
+
+static int init_cfg (void)
+
+{
+/**********
+* db_url, db_ctable, db_qtable exist?
+**********/
+
+if (!*db_url)
+  {
+  LM_ERR ("db_url parameter not set!");
+  return 0;
+  }
+pmod_data->pcfg->db_url.s = db_url;
+pmod_data->pcfg->db_url.len = strlen (db_url);
+if (!*db_ctable)
+  {
+  LM_ERR ("db_ctable parameter not set!");
+  return 0;
+  }
+pmod_data->pcfg->db_ctable.s = db_ctable;
+pmod_data->pcfg->db_ctable.len = strlen (db_ctable);
+if (!*db_qtable)
+  {
+  LM_ERR ("db_qtable parameter not set!");
+  return 0;
+  }
+pmod_data->pcfg->db_qtable.s = db_qtable;
+pmod_data->pcfg->db_qtable.len = strlen (db_qtable);
+
+/**********
+* mohdir
+* o exists?
+* o directory?
+**********/
+
+if (!*mohdir)
+  {
+  LM_ERR ("mohdir parameter not set!");
+  return 0;
+  }
+if (strlen (mohdir) > MOHDIRLEN)
+  {
+  LM_ERR ("mohdir too long!");
+  return 0;
+  }
+pmod_data->pcfg->mohdir = mohdir;
+int bfnd = 0;
+struct stat psb [1];
+if (!lstat (mohdir, psb))
+  {
+  if ((psb->st_mode & S_IFMT) == S_IFDIR)
+    { bfnd = 1; }
+  }
+if (!bfnd)
+  {
+  LM_ERR ("mohdir is not a directory!");
+  return 0;
+  }
+
+/**********
+* max calls
+* o valid count?
+* o alloc memory
+**********/
+
+if (moh_maxcalls < 1 || moh_maxcalls > 5000)
+  {
+  LM_ERR ("moh_maxcalls not in range of 1-5000!");
+  return 0;
+  }
+pmod_data->pcall_lst =
+  (call_lst *) shm_malloc (sizeof (call_lst) * moh_maxcalls);
+if (!pmod_data->pcall_lst)
+  {
+  LM_ERR ("Unable to allocate shared memory");
+  return -1;
+  }
+memset (pmod_data->pcall_lst, 0, sizeof (call_lst) * moh_maxcalls);
+pmod_data->call_cnt = moh_maxcalls;
+return -1;
+}
+
+/**********
+* DB Initialization
+*
+* INPUT:
+*   pmod_data memory allocated and cfg values set
+* OUTPUT: 0 if failed; else pmod_data has db_api
+**********/
+
+static int init_db (void)
+
+{
+/**********
+* o bind to DB
+* o check capabilities
+* o init DB
+**********/
+
+str *pdb_url = &pmod_data->pcfg->db_url;
+if (db_bind_mod (pdb_url, pmod_data->pdb))
+  {
+  LM_ERR ("Unable to bind DB API using %s", pdb_url->s);
+  return 0;
+  }
+db_func_t *pdb = pmod_data->pdb;
+if (!DB_CAPABILITY ((*pdb), DB_CAP_ALL))
+  {
+  LM_ERR ("Selected database %s lacks required capabilities", pdb_url->s);
+  return 0;
+  }
+db1_con_t *pconn = mohq_dbconnect ();
+if (!pconn)
+  { return 0; }
+
+/**********
+* o check schema
+* o remove all call recs
+* o load queue list
+**********/
+
+if (db_check_table_version (pdb, pconn,
+  &pmod_data->pcfg->db_ctable, MOHQ_CTABLE_VERSION) < 0)
+  {
+  LM_ERR ("%s table in DB %s not at version %d",
+    pmod_data->pcfg->db_ctable.s, pdb_url->s, MOHQ_CTABLE_VERSION);
+  goto dberr;
+  }
+if (db_check_table_version (pdb, pconn,
+  &pmod_data->pcfg->db_qtable, MOHQ_QTABLE_VERSION) < 0)
+  {
+  LM_ERR ("%s table in DB %s not at version %d",
+    pmod_data->pcfg->db_qtable.s, pdb_url->s, MOHQ_QTABLE_VERSION);
+  goto dberr;
+  }
+clear_calls (pconn);
+update_mohq_lst (pconn);
+pmod_data->mohq_update = time (0);
+mohq_dbdisconnect (pconn);
+return -1;
+
+/**********
+* close DB
+**********/
+
+dberr:
+pdb->close (pconn);
+return 0;
+}
+
+/**********
+* Child Module Initialization
+*
+* INPUT:
+*   Arg (1) = child type
+* OUTPUT: -1 if db_api not ready; else 0
+**********/
+
+int mod_child_init (int rank)
+
+{
+/**********
+* o seed random number generator
+* o make sure DB initialized
+**********/
+
+srand (getpid () + time (0));
+if (rank == PROC_INIT || rank == PROC_TCP_MAIN || rank == PROC_MAIN)
+  { return 0; }
+if (!pmod_data->pdb->init)
+  {
+  LM_CRIT ("DB API not loaded!");
+  return -1;
+  }
+return 0;
+}
+
+/**********
+* Module Teardown
+*
+* INPUT: none
+* OUTPUT: none
+**********/
+
+void mod_destroy (void)
+
+{
+/**********
+* o destroy MOH can call queue locks
+* o deallocate shared mem
+**********/
+
+if (!pmod_data)
+  { return; }
+if (pmod_data->pmohq_lock->plock)
+  { mohq_lock_destroy (pmod_data->pmohq_lock); }
+if (pmod_data->pcall_lock->plock)
+  { mohq_lock_destroy (pmod_data->pcall_lock); }
+if (pmod_data->pmohq_lst)
+  { shm_free (pmod_data->pmohq_lst); }
+if (pmod_data->pcall_lst)
+  { shm_free (pmod_data->pcall_lst); }
+shm_free (pmod_data);
+return;
+}
+
+/**********
+* Module Initialization
+*
+* INPUT: none
+* OUTPUT: -1 if failed; 0 if success
+**********/
+
+int mod_init (void)
+
+{
+/**********
+* o allocate shared mem and init
+* o init configuration data
+* o init DB
+**********/
+
+pmod_data = (mod_data *) shm_malloc (sizeof (mod_data));
+if (!pmod_data)
+  {
+  LM_ERR ("Unable to allocate shared memory");
+  return -1;
+  }
+memset (pmod_data, 0, sizeof (mod_data));
+if (!init_cfg ())
+  { goto initerr; }
+if (!init_db ())
+  { goto initerr; }
+
+/**********
+* o bind to SL/TM/RR modules
+* o bind to RTPPROXY functions
+**********/
+
+if (sl_load_api (pmod_data->psl))
+  {
+  LM_ERR ("Unable to load SL module");
+  goto initerr;
+  }
+if (load_tm_api (pmod_data->ptm))
+  {
+  LM_ERR ("Unable to load TM module");
+  goto initerr;
+  }
+if (load_rr_api (pmod_data->prr))
+  {
+  LM_ERR ("Unable to load RR module");
+  goto initerr;
+  }
+pmod_data->fn_rtp_answer = find_export ("rtpproxy_answer", 0, 0);
+if (!pmod_data->fn_rtp_answer)
+  {
+  LM_ERR ("Unable to load rtpproxy_answer");
+  goto initerr;
+  }
+pmod_data->fn_rtp_offer = find_export ("rtpproxy_offer", 0, 0);
+if (!pmod_data->fn_rtp_offer)
+  {
+  LM_ERR ("Unable to load rtpproxy_offer");
+  goto initerr;
+  }
+pmod_data->fn_rtp_stream_c = find_export ("rtpproxy_stream2uac", 2, 0);
+if (!pmod_data->fn_rtp_stream_c)
+  {
+  LM_ERR ("Unable to load rtpproxy_stream2uac");
+  goto initerr;
+  }
+pmod_data->fn_rtp_stream_s = find_export ("rtpproxy_stream2uas", 2, 0);
+if (!pmod_data->fn_rtp_stream_s)
+  {
+  LM_ERR ("Unable to load rtpproxy_stream2uas");
+  goto initerr;
+  }
+pmod_data->fn_rtp_destroy = find_export ("rtpproxy_destroy", 0, 0);
+if (!pmod_data->fn_rtp_destroy)
+  {
+  LM_ERR ("Unable to load rtpproxy_destroy");
+  goto initerr;
+  }
+
+/**********
+* init MOH and call queue locks
+**********/
+
+if (!mohq_lock_init (pmod_data->pmohq_lock))
+  { goto initerr; }
+if (!mohq_lock_init (pmod_data->pcall_lock))
+  { goto initerr; }
+return 0;
+
+/**********
+* o release shared mem
+* o exit with error
+**********/
+
+initerr:
+if (pmod_data->mohq_cnt)
+  { shm_free (pmod_data->pmohq_lst); }
+if (pmod_data->pcall_lock->plock)
+  { mohq_lock_destroy (pmod_data->pcall_lock); }
+shm_free (pmod_data);
+pmod_data = NULL;
+return -1;
+}
\ No newline at end of file
diff --git a/modules/mohqueue/mohq.h b/modules/mohqueue/mohq.h
new file mode 100644
index 0000000..ef20aff
--- /dev/null
+++ b/modules/mohqueue/mohq.h
@@ -0,0 +1,132 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef MOHQ_H
+#define MOHQ_H
+
+#include "mohq_common.h"
+#include "mohq_locks.h"
+
+/**********
+* definitions
+**********/
+
+#define URI_LEN     100
+#define USLEEP_LEN  10
+#define MOHDIRLEN   100
+#define MOHFILELEN  100
+
+/**********
+* structures
+**********/
+
+typedef struct
+  {
+  int ntype;
+  char *pencode;
+  } rtpmap;
+
+/* mohq_flags values */
+#define MOHQF_ACT 0x01
+#define MOHQF_CHK 0x02
+#define MOHQF_DBG 0x04
+
+typedef struct
+  {
+  char mohq_name [26];
+  char mohq_uri [URI_LEN + 1];
+  char mohq_mohdir [MOHDIRLEN + 1];
+  char mohq_mohfile [MOHFILELEN + 1];
+  int mohq_flags;
+  int mohq_id;
+  } mohq_lst;
+
+/* call_state values */
+#define CLSTA_ENTER     100
+#define CLSTA_PRACKSTRT 101
+#define CLSTA_PRACKRPLY 102
+#define CLSTA_RINGING   103
+#define CLSTA_INVITED   104
+#define CLSTA_CANCEL    105
+#define CLSTA_INQUEUE   200
+#define CLSTA_REFER     301
+#define CLSTA_RFRWAIT   302
+#define CLSTA_BYE       305
+
+typedef struct
+  {
+  int call_active;
+  char call_id [101];
+  char call_from [URI_LEN + 1];
+  char call_referto [URI_LEN + 1];
+  char call_contact [URI_LEN + 1];
+  char call_tag [101];
+  char call_via [1024];
+  char call_addr [IP_ADDR_MAX_STR_SIZE + 4];
+  int call_state;
+  int call_cseq;
+  int call_aport;
+  mohq_lst *pmohq;
+  time_t call_time;
+  unsigned int call_hash;
+  unsigned int call_label;
+  sip_msg_t *call_pmsg;
+  } call_lst;
+
+typedef struct
+  {
+  char *mohdir;
+  str db_url;
+  str db_ctable;
+  str db_qtable;
+  } mod_cfg;
+
+typedef struct
+  {
+  mod_cfg pcfg [1];
+  time_t mohq_update;
+  int mohq_cnt;
+  mohq_lst *pmohq_lst;
+  mohq_lock pmohq_lock [1];
+  int call_cnt;
+  call_lst *pcall_lst;
+  mohq_lock pcall_lock [1];
+  db_func_t pdb [1];
+  tm_api_t ptm [1];
+  sl_api_t psl [1];
+  rr_api_t prr [1];
+  cmd_function fn_rtp_answer;
+  cmd_function fn_rtp_destroy;
+  cmd_function fn_rtp_offer;
+  cmd_function fn_rtp_stream_c;
+  cmd_function fn_rtp_stream_s;
+  } mod_data;
+
+/**********
+* global varb declarations
+**********/
+
+extern mod_data *pmod_data;
+extern rtpmap prtpmap [];
+
+#endif /* MOHQ_H */
\ No newline at end of file
diff --git a/modules/mohqueue/mohq_common.h b/modules/mohqueue/mohq_common.h
new file mode 100644
index 0000000..fb2edc4
--- /dev/null
+++ b/modules/mohqueue/mohq_common.h
@@ -0,0 +1,104 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef MOHQ_COMMON_H
+#define MOHQ_COMMON_H
+
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "../rr/api.h"
+
+#include "../../data_lump.h"
+#include "../../data_lump_rpl.h"
+#include "../../dprint.h"
+#include "../../dset.h"
+#include "../../flags.h"
+#include "../../hashes.h"
+#include "../../locking.h"
+#include "../../lvalue.h"
+#include "../../mod_fix.h"
+#include "../../sr_module.h"
+#include "../../str.h"
+
+#include "../../lib/kcore/cmpapi.h"
+#include "../../lib/kmi/mi.h"
+#include "../../lib/srdb1/db.h"
+#include "../../mem/mem.h"
+#include "../../mem/shm_mem.h"
+#include "../../modules/sl/sl.h"
+#include "../../modules/tm/tm_load.h"
+#include "../../parser/hf.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/contact/parse_contact.h"
+#include "../../parser/parse_expires.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/sdp/sdp.h"
+
+/* convenience macros */
+#define MOHQ_STRUCT_PTR_OFFSET( struct1, cast1, offset1 ) \
+	(cast1)(struct1) + (offset1)
+	
+#define MOHQ_STR_COPY( str1, str2 ) \
+	memcpy((str1)->s, (str2)->s, (str2)->len ); \
+	(str1)->len = (str2)->len;
+
+#define MOHQ_STR_APPEND( str1, str2 ) \
+	memcpy((str1)->s + (str1)->len, (str2)->s, (str2)->len); \
+	(str1)->len += (str2)->len;
+
+#define MOHQ_STR_APPEND_L( str1, str1_lim, s2, s2_len ) \
+	if ((str1)->len + (s2_len) >= (str1_lim)) { \
+	    LM_ERR( "Failed to append to str: too long" ); \
+	} else { \
+	    MOHQ_STR_APPEND((str1), (s2), (s2_len)); \
+	    (str1_lim) -= (s2_len); \
+	}
+
+#define MOHQ_STR_COPY_CSTR( str1, cstr1 ) \
+	memcpy((str1)->s + (str1)->len, (cstr1), strlen((cstr1))); \
+	(str1)->len += strlen((cstr1));
+
+#define MOHQ_STR_APPEND_CSTR( str1, cstr1 ) \
+	MOHQ_STR_COPY_CSTR((str1), (cstr1))
+
+#define MOHQ_STR_APPEND_CSTR_L( str1, str1_lim, cstr1 ) \
+	if ((str1)->len + strlen(cstr1) >= (str1_lim)) { \
+	    LM_ERR( "Failed to append to str: too long" ); \
+	} else { \
+	    MOHQ_STR_APPEND_CSTR((str1), (cstr1)); \
+	}
+
+/* STR_EQ assumes we're not using str pointers, which is obnoxious */
+#define MOHQ_STR_EQ( str1, str2 ) \
+	(((str1)->len == (str2)->len) && \
+		memcmp((str1)->s, (str2)->s, (str1)->len) == 0)
+
+#define MOHQ_STR_EMPTY( str1 ) \
+	(((str1) != NULL && ((str1)->s == NULL || (str1)->len <= 0 )) \
+		|| (str1) == NULL )
+
+#define MOHQ_HEADER_EMPTY( hdr1 ) \
+	((hdr1) == NULL || MOHQ_STR_EMPTY( &(hdr1)->body ))
+
+#endif /* MOHQ_COMMON_H */
\ No newline at end of file
diff --git a/modules/mohqueue/mohq_db.c b/modules/mohqueue/mohq_db.c
new file mode 100644
index 0000000..858faba
--- /dev/null
+++ b/modules/mohqueue/mohq_db.c
@@ -0,0 +1,626 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "mohq.h"
+#include "mohq_db.h"
+#include "mohq_funcs.h"
+
+/**********
+* mohqueue definitions
+**********/
+
+str MOHQCSTR_ID = STR_STATIC_INIT ("id");
+str MOHQCSTR_URI = STR_STATIC_INIT ("uri");
+str MOHQCSTR_MDIR = STR_STATIC_INIT ("mohdir");
+str MOHQCSTR_MFILE = STR_STATIC_INIT ("mohfile");
+str MOHQCSTR_NAME = STR_STATIC_INIT ("name");
+str MOHQCSTR_DEBUG = STR_STATIC_INIT ("debug");
+
+static str *mohq_columns [] =
+  {
+  &MOHQCSTR_ID,
+  &MOHQCSTR_URI,
+  &MOHQCSTR_MDIR,
+  &MOHQCSTR_MFILE,
+  &MOHQCSTR_NAME,
+  &MOHQCSTR_DEBUG,
+  NULL
+  };
+
+/**********
+* mohqcalls definitions
+**********/
+
+str CALLCSTR_CALL = STR_STATIC_INIT ("call_id");
+str CALLCSTR_CNTCT = STR_STATIC_INIT ("call_contact");
+str CALLCSTR_FROM = STR_STATIC_INIT ("call_from");
+str CALLCSTR_MOHQ = STR_STATIC_INIT ("mohq_id");
+str CALLCSTR_STATE = STR_STATIC_INIT ("call_status");
+str CALLCSTR_TIME = STR_STATIC_INIT ("call_time");
+
+static str *call_columns [] =
+  {
+  &CALLCSTR_STATE,
+  &CALLCSTR_CALL,
+  &CALLCSTR_MOHQ,
+  &CALLCSTR_FROM,
+  &CALLCSTR_CNTCT,
+  &CALLCSTR_TIME,
+  NULL
+  };
+
+/**********
+* local function declarations
+**********/
+
+void set_call_key (db_key_t *, int, int);
+void set_call_val (db_val_t *, int, int, void *);
+
+/**********
+* local functions
+**********/
+
+/**********
+* Fill Call Keys
+*
+* INPUT:
+*   Arg (1) = row pointer
+*   Arg (2) = column count
+* OUTPUT: none
+**********/
+
+void fill_call_keys (db_key_t *prkeys, int ncnt)
+
+{
+int nidx;
+for (nidx = 0; nidx < ncnt; nidx++)
+  { set_call_key (prkeys, nidx, nidx); }
+return;
+}
+
+/**********
+* Fill Call Values
+*
+* INPUT:
+*   Arg (1) = row pointer
+*   Arg (2) = call struct pointer
+*   Arg (3) = column count
+* OUTPUT: none
+**********/
+
+void fill_call_vals (db_val_t *prvals, call_lst *pcall, int ncnt)
+
+{
+int nstate = pcall->call_state / 100;
+set_call_val (prvals, CALLCOL_STATE, CALLCOL_STATE, &nstate);
+if (!ncnt)
+  { return; }
+set_call_val (prvals, CALLCOL_MOHQ, CALLCOL_MOHQ, &pcall->pmohq->mohq_id);
+set_call_val (prvals, CALLCOL_CALL, CALLCOL_CALL, pcall->call_id);
+set_call_val (prvals, CALLCOL_FROM, CALLCOL_FROM, pcall->call_from);
+set_call_val (prvals, CALLCOL_CNTCT, CALLCOL_CNTCT, pcall->call_contact);
+set_call_val (prvals, CALLCOL_TIME, CALLCOL_TIME, &pcall->call_time);
+return;
+}
+
+/**********
+* Set Call Column Key
+*
+* INPUT:
+*   Arg (1) = row pointer
+*   Arg (2) = column number
+*   Arg (3) = column id
+* OUTPUT: none
+**********/
+
+void set_call_key (db_key_t *prkeys, int ncol, int ncolid)
+
+{
+prkeys [ncol] = call_columns [ncolid];
+return;
+}
+
+/**********
+* Set Call Column Value
+*
+* INPUT:
+*   Arg (1) = row pointer
+*   Arg (2) = column number
+*   Arg (3) = column id
+*   Arg (4) = value pointer
+* OUTPUT: none
+**********/
+
+void set_call_val (db_val_t *prvals, int ncol, int ncolid, void *pdata)
+
+{
+/**********
+* fill based on column
+**********/
+
+switch (ncolid)
+  {
+  case CALLCOL_MOHQ:
+  case CALLCOL_STATE:
+    prvals [ncol].val.int_val = *((int *)pdata);
+    prvals [ncol].type = DB1_INT;
+    prvals [ncol].nul = 0;
+    break;
+  case CALLCOL_CALL:
+  case CALLCOL_CNTCT:
+  case CALLCOL_FROM:
+    prvals [ncol].val.string_val = (char *)pdata;
+    prvals [ncol].type = DB1_STRING;
+    prvals [ncol].nul = 0;
+    break;
+  case CALLCOL_TIME:
+    prvals [ncol].val.time_val = *((time_t *)pdata);
+    prvals [ncol].type = DB1_DATETIME;
+    prvals [ncol].nul = 0;
+    break;
+  }
+return;
+}
+
+/**********
+* external functions
+**********/
+
+/**********
+* Add Call Record
+*
+* INPUT:
+*   Arg (1) = call index
+* OUTPUT: none
+**********/
+
+void add_call_rec (int ncall_idx)
+
+{
+/**********
+* o fill column names and values
+* o insert new record
+**********/
+
+char *pfncname = "add_call_rec: ";
+db1_con_t *pconn = mohq_dbconnect ();
+if (!pconn)
+  { return; }
+db_func_t *pdb = pmod_data->pdb;
+pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
+db_key_t prkeys [CALL_COLCNT];
+fill_call_keys (prkeys, CALL_COLCNT);
+db_val_t prvals [CALL_COLCNT];
+call_lst *pcall = &pmod_data->pcall_lst [ncall_idx];
+pcall->call_time = time (0);
+fill_call_vals (prvals, pcall, CALL_COLCNT);
+if (pdb->insert (pconn, prkeys, prvals, CALL_COLCNT) < 0)
+  {
+  LM_WARN ("%sUnable to add new row to %s", pfncname,
+    pmod_data->pcfg->db_ctable.s);
+  }
+mohq_dbdisconnect (pconn);
+return;
+}
+
+/**********
+* Clear Call Records
+*
+* INPUT:
+*   Arg (1) = connection pointer
+* OUTPUT: none
+**********/
+
+void clear_calls (db1_con_t *pconn)
+
+{
+/**********
+* delete all records
+**********/
+
+char *pfncname = "clear_calls: ";
+db_func_t *pdb = pmod_data->pdb;
+pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
+if (pdb->delete (pconn, 0, 0, 0, 0) < 0)
+  {
+  LM_WARN ("%sUnable to delete all rows from %s", pfncname,
+    pmod_data->pcfg->db_ctable.s);
+  }
+return;
+}
+
+/**********
+* Delete Call Record
+*
+* INPUT:
+*   Arg (1) = call pointer
+* OUTPUT: none
+**********/
+
+void delete_call_rec (call_lst *pcall)
+
+{
+/**********
+* o setup to delete based on call ID
+* o delete record
+**********/
+
+char *pfncname = "delete_call_rec: ";
+db1_con_t *pconn = mohq_dbconnect ();
+if (!pconn)
+  { return; }
+db_func_t *pdb = pmod_data->pdb;
+pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
+db_key_t prkeys [1];
+set_call_key (prkeys, 0, CALLCOL_CALL);
+db_val_t prvals [1];
+set_call_val (prvals, 0, CALLCOL_CALL, pcall->call_id);
+if (pdb->delete (pconn, prkeys, 0, prvals, 1) < 0)
+  {
+  LM_WARN ("%sUnable to delete row from %s", pfncname,
+    pmod_data->pcfg->db_ctable.s);
+  }
+mohq_dbdisconnect (pconn);
+return;
+}
+
+/**********
+* Connect to DB
+*
+* INPUT: none
+* OUTPUT: DB connection pointer; NULL=failed
+**********/
+
+db1_con_t *mohq_dbconnect (void)
+
+{
+str *pdb_url = &pmod_data->pcfg->db_url;
+db1_con_t *pconn = pmod_data->pdb->init (pdb_url);
+if (!pconn)
+  { LM_ERR ("Unable to connect to DB %s", pdb_url->s); }
+return pconn;
+}
+
+/**********
+* Disconnect from DB
+*
+* INPUT:
+*   Arg (1) = connection pointer
+* OUTPUT: none
+**********/
+
+void mohq_dbdisconnect (db1_con_t *pconn)
+
+{
+pmod_data->pdb->close (pconn);
+return;
+}
+
+/**********
+* Update Call Record
+*
+* INPUT:
+*   Arg (1) = call pointer
+* OUTPUT: none
+**********/
+
+void update_call_rec (call_lst *pcall)
+
+{
+/**********
+* o setup to update based on call ID
+* o update record
+**********/
+
+char *pfncname = "update_call_rec: ";
+db1_con_t *pconn = mohq_dbconnect ();
+if (!pconn)
+  { return; }
+db_func_t *pdb = pmod_data->pdb;
+pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
+db_key_t pqkeys [1];
+set_call_key (pqkeys, 0, CALLCOL_CALL);
+db_val_t pqvals [1];
+set_call_val (pqvals, 0, CALLCOL_CALL, pcall->call_id);
+db_key_t pukeys [1];
+set_call_key (pukeys, 0, CALLCOL_STATE);
+db_val_t puvals [1];
+fill_call_vals (puvals, pcall, CALLCOL_STATE);
+if (pdb->update (pconn, pqkeys, 0, pqvals, pukeys, puvals, 1, 1) < 0)
+  {
+  LM_WARN ("%sUnable to update row in %s", pfncname,
+    pmod_data->pcfg->db_ctable.s);
+  }
+mohq_dbdisconnect (pconn);
+return;
+}
+
+/**********
+* Update Debug Record
+*
+* INPUT:
+*   Arg (1) = MOH queue pointer
+*   Arg (2) = debug flag
+* OUTPUT: none
+**********/
+
+void update_debug (mohq_lst *pqueue, int bdebug)
+
+{
+/**********
+* o setup to update based on queue name
+* o update record
+**********/
+
+char *pfncname = "update_debug: ";
+db1_con_t *pconn = mohq_dbconnect ();
+if (!pconn)
+  { return; }
+db_func_t *pdb = pmod_data->pdb;
+pdb->use_table (pconn, &pmod_data->pcfg->db_qtable);
+db_key_t pqkeys [1] = { mohq_columns [MOHQCOL_NAME] };
+db_val_t pqvals [1];
+pqvals->val.string_val = pqueue->mohq_name;
+pqvals->type = DB1_STRING;
+pqvals->nul = 0;
+db_key_t pukeys [1] = { mohq_columns [MOHQCOL_DEBUG] };
+db_val_t puvals [1];
+puvals->val.int_val = bdebug;
+puvals->type = DB1_INT;
+puvals->nul = 0;
+if (pdb->update (pconn, pqkeys, 0, pqvals, pukeys, puvals, 1, 1) < 0)
+  {
+  LM_WARN ("%sUnable to update row in %s", pfncname,
+    pmod_data->pcfg->db_qtable.s);
+  }
+mohq_dbdisconnect (pconn);
+return;
+}
+
+/**********
+* Update Message Queue List
+*
+* INPUT:
+*   Arg (1) = connection pointer
+* OUTPUT: none
+**********/
+
+void update_mohq_lst (db1_con_t *pconn)
+
+{
+/**********
+* o reset checked flag on all queues
+* o read queues from table
+**********/
+
+char *pfncname = "update_mohq_lst: ";
+if (!pconn)
+  { return; }
+db_func_t *pdb = pmod_data->pdb;
+mohq_lst *pqlst = pmod_data->pmohq_lst;
+int nidx;
+for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
+  { pqlst [nidx].mohq_flags &= ~MOHQF_CHK; }
+pdb->use_table (pconn, &pmod_data->pcfg->db_qtable);
+db_key_t prkeys [MOHQ_COLCNT];
+for (nidx = 0; nidx < MOHQ_COLCNT; nidx++)
+  { prkeys [nidx] = mohq_columns [nidx]; }
+db1_res_t *presult = NULL;
+if (pdb->query (pconn, 0, 0, 0, prkeys, 0, MOHQ_COLCNT, 0, &presult))
+  {
+  LM_ERR ("%stable query (%s) failed!", pfncname,
+    pmod_data->pcfg->db_qtable.s);
+  return;
+  }
+db_row_t *prows = RES_ROWS (presult);
+int nrows = RES_ROW_N (presult);
+db_val_t *prowvals = NULL;
+char *ptext, *puri;
+mohq_lst *pnewlst;
+for (nidx = 0; nidx < nrows; nidx++)
+  {
+  /**********
+  * check URI
+  **********/
+
+  prowvals = ROW_VALUES (prows + nidx);
+  char *pqname = (char *)VAL_STRING (prowvals + MOHQCOL_NAME);
+  puri = (char *)VAL_STRING (prowvals + MOHQCOL_URI);
+  struct sip_uri puri_parsed [1];
+  if (parse_uri (puri, strlen (puri), puri_parsed))
+    {
+    LM_ERR ("Queue,Field (%s,%.*s): %s is not a valid URI!", pqname,
+      STR_FMT (&MOHQCSTR_URI), puri);
+    continue;
+    }
+
+  /**********
+  * check MOHDIR
+  **********/
+
+  char *pmohdir;
+  if (VAL_NULL (prowvals + MOHQCOL_MDIR))
+    { pmohdir = pmod_data->pcfg->mohdir; }
+  else
+    {
+    pmohdir = (char *)VAL_STRING (prowvals + MOHQCOL_MDIR);
+    if (!*pmohdir)
+      { pmohdir = pmod_data->pcfg->mohdir; }
+    else
+      {
+      /**********
+      * mohdir
+      * o exists?
+      * o directory?
+      **********/
+
+      struct stat psb [1];
+      if (lstat (pmohdir, psb))
+        {
+        LM_ERR ("Queue,Field (%s,%.*s): Unable to find %s!", pqname,
+          STR_FMT (&MOHQCSTR_MDIR), pmohdir);
+        continue;
+        }
+      else
+        {
+        if ((psb->st_mode & S_IFMT) != S_IFDIR)
+          {
+          LM_ERR ("Queue,Field (%s,%.*s): %s is not a directory!", pqname,
+            STR_FMT (&MOHQCSTR_MDIR), pmohdir);
+          continue;
+          }
+        }
+      }
+    }
+
+  /**********
+  * check for MOH files
+  **********/
+
+  rtpmap **pmohfiles = find_MOH (pmohdir,
+    (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
+  if (!pmohfiles [0])
+    {
+    LM_ERR ("Queue,Field (%s,%.*s): Unable to find MOH files (%s/%s.*)!",
+      pqname, STR_FMT (&MOHQCSTR_MDIR), pmohdir,
+      (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
+    continue;
+    }
+
+  /**********
+  * find matching queues
+  **********/
+
+  int bfnd = 0;
+  int nidx2;
+  for (nidx2 = 0; nidx2 < pmod_data->mohq_cnt; nidx2++)
+    {
+    if (!strcasecmp (pqlst [nidx2].mohq_uri, puri))
+      {
+      /**********
+      * o data the same?
+      * o mark as found
+      **********/
+
+      if (strcmp (pqlst [nidx2].mohq_mohdir, pmohdir))
+        {
+        strcpy (pqlst [nidx2].mohq_mohdir, pmohdir);
+        LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
+          STR_FMT (&MOHQCSTR_MDIR));
+        }
+      ptext = (char *)VAL_STRING (prowvals + MOHQCOL_MFILE);
+      if (strcmp (pqlst [nidx2].mohq_mohfile, ptext))
+        {
+        strcpy (pqlst [nidx2].mohq_mohfile, ptext);
+        LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
+          STR_FMT (&MOHQCSTR_MFILE));
+        }
+      ptext = (char *)VAL_STRING (prowvals + MOHQCOL_NAME);
+      if (strcmp (pqlst [nidx2].mohq_name, ptext))
+        {
+        strcpy (pqlst [nidx2].mohq_name, ptext);
+        LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
+          STR_FMT (&MOHQCSTR_NAME));
+        }
+      int bdebug = VAL_INT (prowvals + MOHQCOL_DEBUG) ? MOHQF_DBG : 0;
+      if ((pqlst [nidx2].mohq_flags & MOHQF_DBG) != bdebug)
+        {
+        if (bdebug)
+          { pqlst [nidx2].mohq_flags |= MOHQF_DBG; }
+        else
+          { pqlst [nidx2].mohq_flags &= ~MOHQF_DBG; }
+        LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
+          STR_FMT (&MOHQCSTR_DEBUG));
+        }
+      bfnd = -1;
+      pqlst [nidx2].mohq_flags |= MOHQF_CHK;
+      break;
+      }
+    }
+
+  /**********
+  * add new queue
+  **********/
+
+  if (!bfnd)
+    {
+    /**********
+    * o allocate new list
+    * o copy old list
+    * o add new row
+    * o release old list
+    * o adjust pointers to new list
+    **********/
+
+    int nsize = pmod_data->mohq_cnt + 1;
+    pnewlst = (mohq_lst *) shm_malloc (sizeof (mohq_lst) * nsize);
+    if (!pnewlst)
+      {
+      LM_ERR ("%sUnable to allocate shared memory!", pfncname);
+      return;
+      }
+    pmod_data->mohq_cnt = nsize;
+    if (--nsize)
+      { memcpy (pnewlst, pqlst, sizeof (mohq_lst) * nsize); }
+    pnewlst [nsize].mohq_id = prowvals [MOHQCOL_ID].val.int_val;
+    pnewlst [nsize].mohq_flags = MOHQF_CHK;
+    strcpy (pnewlst [nsize].mohq_uri, puri);
+    strcpy (pnewlst [nsize].mohq_mohdir, pmohdir);
+    strcpy (pnewlst [nsize].mohq_mohfile,
+      (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
+    strcpy (pnewlst [nsize].mohq_name,
+      (char *)VAL_STRING (prowvals + MOHQCOL_NAME));
+    if (VAL_INT (prowvals + MOHQCOL_DEBUG))
+      { pnewlst [nsize].mohq_flags |= MOHQF_DBG; }
+    LM_INFO ("Added new queue (%s)", pnewlst [nsize].mohq_name);
+    if (nsize)
+      { shm_free (pmod_data->pmohq_lst); }
+    pmod_data->pmohq_lst = pnewlst;
+    pqlst = pnewlst;
+    }
+  }
+
+/**********
+* find deleted queues
+**********/
+
+for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
+  {
+  /**********
+  * o exists?
+  * o if not last, replace current with last queue
+  **********/
+
+  if (pqlst [nidx].mohq_flags & MOHQF_CHK)
+    { continue; }
+  LM_INFO ("Removed queue (%s)", pqlst [nidx].mohq_name);
+  if (nidx != (pmod_data->mohq_cnt - 1))
+    {
+    memcpy (&pqlst [nidx], &pqlst [pmod_data->mohq_cnt - 1],
+      sizeof (mohq_lst));
+    }
+  --pmod_data->mohq_cnt;
+  --nidx;
+  }
+return;
+}
\ No newline at end of file
diff --git a/modules/mohqueue/mohq_db.h b/modules/mohqueue/mohq_db.h
new file mode 100644
index 0000000..a7dedf3
--- /dev/null
+++ b/modules/mohqueue/mohq_db.h
@@ -0,0 +1,66 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef MOHQ_DB_H
+#define MOHQ_DB_H
+
+/**********
+* DB definitions
+**********/
+
+/* table versions */
+#define MOHQ_CTABLE_VERSION  1
+#define MOHQ_QTABLE_VERSION  1
+
+/* mohqueues columns */
+#define MOHQ_COLCNT   6
+#define MOHQCOL_ID    0
+#define MOHQCOL_URI   1
+#define MOHQCOL_MDIR  2
+#define MOHQCOL_MFILE 3
+#define MOHQCOL_NAME  4
+#define MOHQCOL_DEBUG 5
+
+/* mohqcalls columns */
+#define CALL_COLCNT   6
+#define CALLCOL_STATE 0
+#define CALLCOL_CALL  1
+#define CALLCOL_MOHQ  2
+#define CALLCOL_FROM  3
+#define CALLCOL_CNTCT 4
+#define CALLCOL_TIME  5
+
+/**********
+* DB function declarations
+**********/
+
+void add_call_rec (int);
+void clear_calls (db1_con_t *);
+void delete_call_rec (call_lst *);
+db1_con_t *mohq_dbconnect (void);
+void mohq_dbdisconnect (db1_con_t *);
+void update_call_rec (call_lst *);
+void update_debug (mohq_lst *, int);
+void update_mohq_lst (db1_con_t *pconn);
+
+#endif /* MOHQ_DB_H */
\ No newline at end of file
diff --git a/modules/mohqueue/mohq_funcs.c b/modules/mohqueue/mohq_funcs.c
new file mode 100644
index 0000000..0db62bc
--- /dev/null
+++ b/modules/mohqueue/mohq_funcs.c
@@ -0,0 +1,2665 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdarg.h>
+
+#include "mohq.h"
+#include "mohq_db.h"
+#include "mohq_funcs.h"
+
+/**********
+* definitions
+**********/
+
+#define ALLOWHDR "Allow: INVITE, ACK, BYE, CANCEL, NOTIFY, PRACK"
+#define CLENHDR "Content-Length"
+#define SIPEOL  "\r\n"
+#define USRAGNT "Kamailio MOH Queue v1.0"
+
+/**********
+* local constants
+**********/
+
+str p100rel [1] = {STR_STATIC_INIT ("100rel")};
+str pallq [1] = {STR_STATIC_INIT ("*")};
+str paudio [1] = {STR_STATIC_INIT ("audio")};
+str pbye [1] = {STR_STATIC_INIT ("BYE")};
+str pinvite [1] = {STR_STATIC_INIT ("INVITE")};
+str pmi_nolock [1] = {STR_STATIC_INIT ("Unable to lock queue")};
+str pmi_noqueue [1] = {STR_STATIC_INIT ("No matching queue name found")};
+str prefer [1] = {STR_STATIC_INIT ("REFER")};
+str presp_noaccept [1] = {STR_STATIC_INIT ("Not Acceptable Here")};
+str presp_noallow [1] = {STR_STATIC_INIT ("Method Not Allowed")};
+str presp_nocall [1] = {STR_STATIC_INIT ("Call/Transaction Does Not Exist")};
+str presp_ok [1] = {STR_STATIC_INIT ("OK")};
+str presp_reqpend [1] = {STR_STATIC_INIT ("Request Pending")};
+str presp_reqterm [1] = {STR_STATIC_INIT ("Request Terminated")};
+str presp_ring [1] = {STR_STATIC_INIT ("Ringing")};
+str psipfrag [1] = {STR_STATIC_INIT ("message/sipfrag")};
+str presp_srverr [1] = {STR_STATIC_INIT ("Server Internal Error")};
+str presp_unsupp [1] = {STR_STATIC_INIT ("Unsupported Media Type")};
+
+rtpmap prtpmap [] =
+  {
+  {9, "G722/8000"},
+  {0, "PCMU/8000"},
+  {8, "PCMA/8000"},
+  {18, "G729/8000"},
+  {3, "GSM/8000"},
+  {4, "G723/8000"},
+  {15, "G728/8000"},
+  {5, "DVI4/8000"},
+  {7, "LPC/8000"},
+  {12, "QCELP/8000"},
+  {13, "CN/8000"},
+  {16, "DVI4/11025"},
+  {6, "DVI4/16000"},
+  {17, "DVI4/22050"},
+  {10, "L16/44100"},
+  {11, "L16/44100"},
+  {14, "MPA/90000"},
+  {0, 0}
+  };
+
+rtpmap *pmohfiles [30]; // element count should be equal or greater than prtpmap
+
+str pallowhdr [1] = { STR_STATIC_INIT (ALLOWHDR SIPEOL) };
+
+char pbyemsg [] =
+  {
+  "%s"
+  "Max-Forwards: 70" SIPEOL
+  "Contact: <%s>" SIPEOL
+  "User-Agent: " USRAGNT SIPEOL
+  };
+
+str pextrahdr [1] =
+  {
+  STR_STATIC_INIT (
+  ALLOWHDR SIPEOL
+  "Supported: 100rel" SIPEOL
+  "Accept-Language: en" SIPEOL
+  "Content-Type: application/sdp" SIPEOL
+  "User-Agent: " USRAGNT SIPEOL
+  )
+  };
+
+char pinvitesdp [] =
+  {
+  "v=0" SIPEOL
+  "o=- %d %d IN %s" SIPEOL
+  "s=" USRAGNT SIPEOL
+  "c=IN %s" SIPEOL
+  "t=0 0" SIPEOL
+  "a=send%s" SIPEOL
+  "m=audio %d RTP/AVP "
+  };
+
+char prefermsg [] =
+  {
+  "%s"
+  "Max-Forwards: 70" SIPEOL
+  "Refer-To: <%s>" SIPEOL
+  "Referred-By: <%.*s>" SIPEOL
+  "User-Agent: " USRAGNT SIPEOL
+  };
+
+char preinvitemsg [] =
+  {
+  "%s"
+  "Max-Forwards: 70" SIPEOL
+  "Contact: <%s>" SIPEOL
+  ALLOWHDR SIPEOL
+  "Supported: 100rel" SIPEOL
+  "User-Agent: " USRAGNT SIPEOL
+  "Accept-Language: en" SIPEOL
+  "Content-Type: application/sdp" SIPEOL
+  };
+
+char prtpsdp [] =
+  {
+  "v=0" SIPEOL
+  // IP address and audio port faked since they will be replaced
+  "o=- 1 1 IN IP4 1.1.1.1" SIPEOL
+  "s=" USRAGNT SIPEOL
+  "c=IN IP4 1.1.1.1" SIPEOL
+  "t=0 0" SIPEOL
+  "a=sendrecv" SIPEOL
+  "m=audio 1 RTP/AVP"
+  };
+
+/**********
+* local function declarations
+**********/
+
+void delete_call (call_lst *);
+void drop_call (sip_msg_t *, call_lst *);
+int find_call (sip_msg_t *, call_lst **);
+dlg_t *form_dialog (call_lst *, struct to_body *);
+int form_rtp_SDP (str *, call_lst *, char *);
+static void invite_cb (struct cell *, int, struct tmcb_params *);
+int refer_call (call_lst *, mohq_lock *);
+static void refer_cb (struct cell *, int, struct tmcb_params *);
+int send_prov_rsp (sip_msg_t *, call_lst *);
+int send_rtp_answer (sip_msg_t *, call_lst *);
+int search_hdr_ext (struct hdr_field *, str *);
+int start_stream (sip_msg_t *, call_lst *, int);
+
+/**********
+* local functions
+**********/
+
+/**********
+* Process ACK Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=failed
+**********/
+
+int ack_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* part of INVITE?
+**********/
+
+char *pfncname = "ack_msg: ";
+struct cell *ptrans;
+tm_api_t *ptm = pmod_data->ptm;
+if (pcall->call_state != CLSTA_INVITED)
+  {
+  /**********
+  * ignore if from rejected re-INVITE
+  **********/
+
+  if (pcall->call_state != CLSTA_INQUEUE)
+    { LM_ERR ("%sUnexpected ACK (%s)!", pfncname, pcall->call_from); }
+  else
+    {
+    mohq_debug (pcall->pmohq, "%sACK from refused re-INVITE (%s)!",
+      pfncname, pcall->call_from);
+    }
+  return 1;
+  }
+
+/**********
+* o release INVITE transaction
+* o save SDP address info
+* o put in queue
+**********/
+
+if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
+  {
+  LM_ERR ("%sINVITE transaction missing for call (%s)!",
+    pfncname, pcall->call_from);
+  return 1;
+  }
+else
+  {
+  if (ptm->t_release (pcall->call_pmsg) < 0)
+    {
+    LM_ERR ("%sRelease transaction failed for call (%s)!",
+      pfncname, pcall->call_from);
+    return 1;
+    }
+  }
+pcall->call_hash = pcall->call_label = 0;
+sprintf (pcall->call_addr, "%s %s",
+  pmsg->rcv.dst_ip.af == AF_INET ? "IP4" : "IP6",
+  ip_addr2a (&pmsg->rcv.dst_ip));
+pcall->call_state = CLSTA_INQUEUE;
+update_call_rec (pcall);
+pcall->call_cseq = 1;
+mohq_debug (pcall->pmohq,
+  "%sACK received for call (%s); placed in queue (%s)",
+  pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+return 1;
+}
+
+/**********
+* BYE Callback
+*
+* INPUT:
+*   Arg (1) = cell pointer
+*   Arg (2) = callback type
+*   Arg (3) = callback parms
+* OUTPUT: none
+**********/
+
+static void bye_cb
+  (struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
+
+{
+/**********
+* o error means must have hung after REFER
+* o delete the call
+**********/
+
+char *pfncname = "bye_cb: ";
+call_lst *pcall = (call_lst *)*pcbp->param;
+if (ntype == TMCB_ON_FAILURE)
+  {
+  LM_ERR ("%sCall (%s) did not respond to BYE", pfncname,
+    pcall->call_from);
+  }
+else
+  {
+  int nreply = pcbp->code;
+  if ((nreply / 100) != 2)
+    {
+    LM_ERR ("%sCall (%s) BYE error (%d)", pfncname,
+      pcall->call_from, nreply);
+    }
+  else
+    {
+    mohq_debug (pcall->pmohq, "%sCall (%s) BYE reply=%d", pfncname,
+      pcall->call_from, nreply);
+    }
+  }
+delete_call (pcall);
+return;
+}
+
+/**********
+* Process BYE Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=failed
+**********/
+
+int bye_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* o send OK
+* o teardown call
+**********/
+
+char *pfncname = "bye_msg: ";
+if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
+  {
+  LM_ERR ("%sUnable to create reply to call (%s)", pfncname,
+    pcall->call_from);
+  return 1;
+  }
+if (pcall->call_state >= CLSTA_INQUEUE)
+  { drop_call (pmsg, pcall); }
+else
+  {
+  LM_ERR ("%sEnding call (%s) before placed in queue!",
+    pfncname, pcall->call_from);
+  delete_call (pcall);
+  }
+return 1;
+}
+
+/**********
+* Process CANCEL Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=failed
+**********/
+
+int cancel_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* still in INVITE dialog?
+**********/
+
+char *pfncname = "cancel_msg: ";
+if (pcall->call_state < CLSTA_INQUEUE)
+  {
+  pcall->call_state = CLSTA_CANCEL;
+  mohq_debug (pcall->pmohq, "%sCANCELed call (%s)",
+    pfncname, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 487, presp_reqterm) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  }
+else
+  {
+  LM_ERR ("%sUnable to CANCEL because accepted INVITE for call (%s)!",
+    pfncname, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  }
+return 1;
+}
+
+/**********
+* Close the Call
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: none
+**********/
+
+void close_call (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* o destroy proxy connection
+* o create dialog
+**********/
+
+char *pfncname = "close_call: ";
+int bsent = 0;
+char *phdr = 0;
+if (pmsg != FAKED_REPLY)
+  {
+  mohq_debug (pcall->pmohq, "%sDestroying RTP link for call (%s)",
+    pfncname, pcall->call_from);
+  if (pmod_data->fn_rtp_destroy (pmsg, 0, 0) != 1)
+    {
+    LM_ERR ("%srtpproxy_destroy refused for call (%s)!",
+      pfncname, pcall->call_from);
+    }
+  }
+struct to_body ptob [2];
+dlg_t *pdlg = form_dialog (pcall, ptob);
+if (!pdlg)
+  { goto bye_err; }
+pdlg->state = DLG_CONFIRMED;
+
+/**********
+* form BYE header
+* o calculate size
+* o create buffer
+**********/
+
+tm_api_t *ptm = pmod_data->ptm;
+char *pquri = pcall->pmohq->mohq_uri;
+int npos1 = sizeof (pbyemsg) // BYE template
+  + strlen (pcall->call_via) // Via
+  + strlen (pquri); // Contact
+phdr = pkg_malloc (npos1);
+if (!phdr)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  goto bye_err;
+  }
+sprintf (phdr, pbyemsg,
+  pcall->call_via, // Via
+  pquri); // Contact
+str phdrs [1];
+phdrs->s = phdr;
+phdrs->len = strlen (phdr);
+
+/**********
+* send BYE request
+**********/
+
+uac_req_t puac [1];
+set_uac_req (puac, pbye, phdrs, 0, pdlg,
+  TMCB_LOCAL_COMPLETED | TMCB_ON_FAILURE, bye_cb, pcall);
+pcall->call_state = CLSTA_BYE;
+if (ptm->t_request_within (puac) < 0)
+  {
+  LM_ERR ("%sUnable to create BYE request for call (%s)!",
+    pfncname, pcall->call_from);
+  goto bye_err;
+  }
+mohq_debug (pcall->pmohq, "%sSent BYE request for call (%s)",
+  pfncname, pcall->call_from);
+bsent = 1;
+
+/**********
+* o free memory
+* o delete call
+**********/
+
+bye_err:
+if (pdlg)
+  { pkg_free (pdlg); }
+if (phdr)
+  { pkg_free (phdr); }
+if (!bsent)
+  { delete_call (pcall); }
+return;
+}
+
+/**********
+* Create New Call Record
+*
+* INPUT:
+*   Arg (1) = queue index
+*   Arg (2) = SIP message pointer
+* OUTPUT: call index; -1 if unable to create
+**********/
+
+int create_call (int mohq_idx, sip_msg_t *pmsg)
+
+{
+/**********
+* o lock calls
+* o already in use?
+* o find inactive slot
+**********/
+
+char *pfncname = "create_call: ";
+if (!mohq_lock_set (pmod_data->pcall_lock, 1, 2000))
+  {
+  LM_ERR ("%sUnable to lock calls!", pfncname);
+  return -1;
+  }
+call_lst *pcall;
+int ncall_idx = find_call (pmsg, &pcall);
+if (pcall)
+  {
+  mohq_lock_release (pmod_data->pcall_lock);
+  LM_ERR ("%sCall already in use (%s)!", pfncname, pcall->call_from);
+  return -1;
+  }
+for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
+  {
+  if (!pmod_data->pcall_lst [ncall_idx].call_active)
+    { break; }
+  }
+if (ncall_idx == pmod_data->call_cnt)
+  {
+  mohq_lock_release (pmod_data->pcall_lock);
+  LM_ERR ("%sNo call slots available!", pfncname);
+  return -1;
+  }
+
+/**********
+* add values to new entry
+**********/
+
+pcall = &pmod_data->pcall_lst [ncall_idx];
+pcall->call_active = 1;
+pcall->pmohq = &pmod_data->pmohq_lst [mohq_idx];
+pcall->call_state = 0;
+str *pstr = &pmsg->callid->body;
+strncpy (pcall->call_id, pstr->s, pstr->len);
+pcall->call_id [pstr->len] = '\0';
+pstr = &pmsg->from->body;
+strncpy (pcall->call_from, pstr->s, pstr->len);
+pcall->call_from [pstr->len] = '\0';
+*pcall->call_tag = '\0';
+if (!pmsg->contact)
+  { *pcall->call_contact = '\0'; }
+else
+  {
+  pstr = &pmsg->contact->body;
+  strncpy (pcall->call_contact, pstr->s, pstr->len);
+  pcall->call_contact [pstr->len] = '\0';
+  }
+
+/**********
+* extract Via headers
+**********/
+
+hdr_field_t *phdr = pmsg->h_via1;
+if (phdr)
+  {
+  int npos1 = 0;
+  while ((phdr = next_sibling_hdr (phdr)))
+    {
+    struct via_body *pvia;
+    char *pviabuf;
+    int bovrflow = 0;
+    int npos2;
+    int nvia_max = sizeof (pcall->call_via);
+    for (pvia = (struct via_body *)phdr->parsed; pvia; pvia = pvia->next)
+      {
+      /**********
+      * o skip trailing whitespace
+      * o check if overflow
+      **********/
+
+      npos2 = pvia->bsize;
+      pviabuf = pvia->name.s;
+      while (npos2)
+        {
+        --npos2;
+        if (pviabuf [npos2] == ' ' || pviabuf [npos2] == '\r'
+          || pviabuf [npos2] == '\n' || pviabuf [npos2] == '\t' || pviabuf [npos2] == ',')
+          { continue; }
+        break;
+        }
+      if ((npos2 + npos1 + 7) >= nvia_max)
+        {
+        LM_WARN ("%sVia buffer overflowed!", pfncname);
+        bovrflow = 1;
+        break;
+        }
+
+      /**********
+      * copy via
+      **********/
+
+      strcpy (&pcall->call_via [npos1], "Via: ");
+      npos1 += 5;
+      strncpy (&pcall->call_via [npos1], pviabuf, npos2);
+      npos1 += npos2;
+      strcpy (&pcall->call_via [npos1], SIPEOL);
+      npos1 += 2;
+      }
+    if (bovrflow)
+      { break; }
+    }
+  }
+
+/**********
+* o release call lock
+* o update DB
+* o lock MOH queue
+**********/
+
+pcall->call_state = CLSTA_ENTER;
+mohq_lock_release (pmod_data->pcall_lock);
+add_call_rec (ncall_idx);
+mohq_lock_set (pmod_data->pmohq_lock, 0, 0);
+mohq_debug (pcall->pmohq, "%sAdded call (%s) to queue (%s)",
+  pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+return ncall_idx;
+}
+
+/**********
+* Delete Call
+*
+* INPUT:
+*   Arg (1) = call pointer
+* OUTPUT: none
+**********/
+
+void delete_call (call_lst *pcall)
+
+{
+/**********
+* release transaction
+**********/
+
+char *pfncname = "delete_call: ";
+struct cell *ptrans;
+tm_api_t *ptm = pmod_data->ptm;
+if (pcall->call_hash || pcall->call_label)
+  {
+  if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
+    {
+    LM_ERR ("%sLookup transaction failed for call (%s)!", pfncname,
+      pcall->call_from);
+    }
+  else
+    {
+    if (ptm->t_release (pcall->call_pmsg) < 0)
+      {
+      LM_ERR ("%sRelease transaction failed for call (%s)!",
+        pfncname, pcall->call_from);
+      }
+    }
+  pcall->call_hash = pcall->call_label = 0;
+  }
+
+/**********
+* o update DB
+* o inactivate slot
+* o release MOH queue
+**********/
+
+mohq_debug (pcall->pmohq, "delete_call: Deleting call (%s) from queue (%s)",
+  pcall->call_from, pcall->pmohq->mohq_name);
+delete_call_rec (pcall);
+pcall->call_active = 0;
+mohq_lock_release (pmod_data->pmohq_lock);
+return;
+}
+
+/**********
+* Deny Method
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: none
+**********/
+
+void deny_method (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* RFC 3261 section 8.2.1
+* o get transaction
+* o respond with 405 and Allow header
+**********/
+
+char *pfncname = "deny_method: ";
+tm_api_t *ptm = pmod_data->ptm;
+if (ptm->t_newtran (pmsg) < 0)
+  {
+  LM_ERR ("%sUnable to create new transaction!", pfncname);
+  if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+    {
+    LM_ERR ("%sUnable to create reply to %.*s!", pfncname,
+      STR_FMT (&REQ_LINE (pmsg).method));
+    }
+  return;
+  }
+if (!add_lump_rpl2 (pmsg, pallowhdr->s, pallowhdr->len, LUMP_RPL_HDR))
+  { LM_ERR ("%sUnable to add Allow header!", pfncname); }
+LM_ERR ("%sRefused %.*s for call (%s)!", pfncname,
+  STR_FMT (&REQ_LINE (pmsg).method), pcall->call_from);
+if (ptm->t_reply (pmsg, 405, presp_noallow->s) < 0)
+  {
+  LM_ERR ("%sUnable to create reply to %.*s!", pfncname,
+    STR_FMT (&REQ_LINE (pmsg).method));
+  }
+return;
+}
+
+/**********
+* Drop the Call
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: none
+**********/
+
+void drop_call (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* o destroy proxy connection
+* o delete call
+**********/
+
+char *pfncname = "drop_call: ";
+if (pmsg != FAKED_REPLY)
+  {
+  mohq_debug (pcall->pmohq, "%sDestroying RTP link for call (%s)",
+    pfncname, pcall->call_from);
+  if (pmod_data->fn_rtp_destroy (pmsg, 0, 0) != 1)
+    {
+    LM_ERR ("%srtpproxy_destroy refused for call (%s)!",
+      pfncname, pcall->call_from);
+    }
+  }
+delete_call (pcall);
+return;
+}
+
+/**********
+* Find Call
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = pointer to call pointer
+* OUTPUT: queue index; -1 if unable to find
+**********/
+
+int find_call (sip_msg_t *pmsg, call_lst **ppcall)
+
+{
+/**********
+* o find current RURI
+* o strip off parms or headers
+* o search MOH queue
+**********/
+
+str *pruri =
+  pmsg->new_uri.s ? &pmsg->new_uri : &pmsg->first_line.u.request.uri;
+int nidx;
+str pstr [1];
+pstr->s = pruri->s;
+pstr->len = pruri->len;
+for (nidx = 0; nidx < pruri->len; nidx++)
+  {
+  if (pstr->s [nidx] == ';' || pstr->s [nidx] == '?')
+    {
+    pstr->len = nidx;
+    break;
+    }
+  }
+mohq_lst *pqlst = pmod_data->pmohq_lst;
+int nqidx;
+for (nqidx = 0; nqidx < pmod_data->mohq_cnt; nqidx++)
+  {
+  str pmohstr [1];
+  pmohstr->s = pqlst [nqidx].mohq_uri;
+  pmohstr->len = strlen (pmohstr->s);
+  if (STR_EQ (*pmohstr, *pstr))
+    { break; }
+  }
+*ppcall = 0;
+if (nqidx == pmod_data->mohq_cnt)
+  { return -1;}
+
+/**********
+* o get to tag
+* o get callID
+* o ignore to tag if CANCEL on first INVITE
+* o search call queue
+**********/
+
+str *ptotag = &(get_to (pmsg)->tag_value);
+if (!ptotag->len)
+  { ptotag = 0; }
+if (!pmsg->callid)
+  { return -1; }
+str *pcallid = &pmsg->callid->body;
+if (!pcallid)
+  { return -1; }
+for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+  {
+  /**********
+  * o call active?
+  * o call timed out on ACK?
+  * o callID matches?
+  * o to tag matches?
+  * o return call pointer
+  **********/
+
+  call_lst *pcall = &pmod_data->pcall_lst [nidx];
+  if (!pcall->call_active)
+    { continue; }
+  if (pcall->call_time && (pcall->call_state < CLSTA_INQUEUE))
+    {
+    if ((pcall->call_time + 32) < time (0))
+      {
+      LM_ERR ("find_call: No ACK response for call (%s)", pcall->call_from);
+      delete_call (pcall);
+      continue;
+      }
+    }
+  str tmpstr [1];
+  tmpstr->s = pcall->call_id;
+  tmpstr->len = strlen (tmpstr->s);
+  if (!STR_EQ (*tmpstr, *pcallid))
+    { continue; }
+  if (ptotag)
+    {
+    tmpstr->s = pcall->call_tag;
+    tmpstr->len = strlen (tmpstr->s);
+    if (!STR_EQ (*tmpstr, *ptotag))
+      { continue; }
+    }
+  *ppcall = pcall;
+  return nqidx;
+  }
+
+/**********
+* first INVITE?
+**********/
+
+if (pmsg->REQ_METHOD == METHOD_INVITE)
+  { return 0; }
+return -1;
+}
+
+/**********
+* Find Queue
+*
+* INPUT:
+*   Arg (1) = queue name str pointer
+* OUTPUT: queue index; -1 if unable to find
+**********/
+
+int find_queue (str *pqname)
+
+{
+char *pfncname = "find_queue: ";
+int nidx;
+str tmpstr;
+if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 500))
+  {
+  LM_ERR ("%sUnable to lock queues!", pfncname);
+  return -1;
+  }
+for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
+  {
+  tmpstr.s = pmod_data->pmohq_lst [nidx].mohq_name;
+  tmpstr.len = strlen (tmpstr.s);
+  if (STR_EQ (tmpstr, *pqname))
+    { break; }
+  }
+if (nidx == pmod_data->mohq_cnt)
+  {
+  LM_ERR ("%sUnable to find queue (%.*s)!", pfncname, STR_FMT (pqname));
+  nidx = -1;
+  }
+mohq_lock_release (pmod_data->pmohq_lock);
+return nidx;
+}
+
+/**********
+* Find Referred Call
+*
+* INPUT:
+*   Arg (1) = referred-by value
+* OUTPUT: call index; -1 if unable to find
+**********/
+
+int find_referred_call (str *pvalue)
+
+{
+/**********
+* get URI
+**********/
+
+char *pfncname = "find_referred_call: ";
+struct to_body pref [1];
+parse_to (pvalue->s, &pvalue->s [pvalue->len + 1], pref);
+if (pref->error != PARSE_OK)
+  {
+  // should never happen
+  LM_ERR ("%sInvalid Referred-By URI (%.*s)!", pfncname, STR_FMT (pvalue));
+  return -1;
+  }
+if (pref->param_lst)
+  { free_to_params (pref); }
+
+/**********
+* search calls for matching
+**********/
+
+int nidx;
+str tmpstr;
+struct to_body pfrom [1];
+for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+  {
+  if (!pmod_data->pcall_lst [nidx].call_active)
+    { continue; }
+  tmpstr.s = pmod_data->pcall_lst [nidx].call_from;
+  tmpstr.len = strlen (tmpstr.s);
+  parse_to (tmpstr.s, &tmpstr.s [tmpstr.len + 1], pfrom);
+  if (pfrom->error != PARSE_OK)
+    {
+    // should never happen
+    LM_ERR ("%sInvalid From URI (%.*s)!", pfncname, STR_FMT (&tmpstr));
+    continue;
+    }
+  if (pfrom->param_lst)
+    { free_to_params (pfrom); }
+  if (STR_EQ (pfrom->uri, pref->uri))
+    { return nidx; }
+  }
+return -1;
+}
+
+/**********
+* Process First INVITE Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = queue index
+* OUTPUT: 0=failed
+**********/
+
+int first_invite_msg (sip_msg_t *pmsg, int mohq_idx)
+
+{
+/**********
+* create call record
+**********/
+
+char *pfncname = "first_invite_msg: ";
+int ncall_idx = create_call (mohq_idx, pmsg);
+if (ncall_idx == -1)
+  { return 0; }
+call_lst *pcall = &pmod_data->pcall_lst [ncall_idx];
+
+/**********
+* o SDP exists?
+* o accepts REFER?
+* o send rtpproxy offer
+**********/
+
+if (!(pmsg->msg_flags & FL_SDP_BODY))
+  {
+  if (parse_sdp (pmsg))
+    {
+    LM_ERR ("%sINVITE lacks SDP (%s)!", pfncname, pcall->call_from);
+    delete_call (pcall);
+    return 0;
+    }
+  }
+if (pmsg->allow)
+  {
+  if (!search_hdr_ext (pmsg->allow, prefer))
+    {
+    LM_ERR ("%sMissing REFER support (%s)!", pfncname, pcall->call_from);
+    delete_call (pcall);
+    return 0;
+    }
+  }
+mohq_debug (pcall->pmohq, "%sMaking offer for RTP link for call (%s)",
+  pfncname, pcall->call_from);
+if (pmod_data->fn_rtp_offer (pmsg, 0, 0) != 1)
+  {
+  LM_ERR ("%srtpproxy_offer refused for call (%s)!",
+    pfncname, pcall->call_from);
+  delete_call (pcall);
+  return 0;
+  }
+
+/**********
+* o create new transaction
+* o save To tag
+* o catch failures
+* o save transaction data
+**********/
+
+tm_api_t *ptm = pmod_data->ptm;
+if (ptm->t_newtran (pmsg) < 0)
+  {
+  LM_ERR ("%sUnable to create new transaction for call (%s)!",
+    pfncname, pcall->call_from);
+  delete_call (pcall);
+  return 0;
+  }
+struct cell *ptrans = ptm->t_gett ();
+pcall->call_hash = ptrans->hash_index;
+pcall->call_label = ptrans->label;
+str ptotag [1];
+if (ptm->t_get_reply_totag (pmsg, ptotag) != 1)
+  {
+  LM_ERR ("%sUnable to create totag for call (%s)!",
+    pfncname, pcall->call_from);
+  if (ptm->t_reply (pmsg, 500, presp_srverr->s) < 0)
+    { LM_ERR ("%sUnable to reply to INVITE!", pfncname); }
+  delete_call (pcall);
+  return 1;
+  }
+strncpy (pcall->call_tag, ptotag->s, ptotag->len);
+pcall->call_tag [ptotag->len] = '\0';
+pcall->call_cseq = 1;
+if (ptm->register_tmcb (pmsg, 0, TMCB_DESTROY | TMCB_ON_FAILURE,
+  invite_cb, pcall, 0) < 0)
+  {
+  LM_ERR ("%sUnable to set callback for call (%s)!",
+    pfncname, pcall->call_from);
+  if (ptm->t_reply (pmsg, 500, presp_srverr->s) < 0)
+    { LM_ERR ("%sUnable to reply to INVITE!", pfncname); }
+  delete_call (pcall);
+  return 1;
+  }
+
+/**********
+* o add contact to reply
+* o supports/requires PRACK? (RFC 3262 section 3)
+* o exit if not ringing
+**********/
+
+str pcontact [1];
+char *pcontacthdr = "Contact: <%s>" SIPEOL;
+pcontact->s = pkg_malloc (strlen (pmod_data->pmohq_lst [mohq_idx].mohq_uri)
+  + strlen (pcontacthdr));
+if (!pcontact->s)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  delete_call (pcall);
+  return 1;
+  }
+sprintf (pcontact->s, pcontacthdr, pmod_data->pmohq_lst [mohq_idx].mohq_uri);
+pcontact->len = strlen (pcontact->s);
+if (!add_lump_rpl2 (pmsg, pcontact->s, pcontact->len, LUMP_RPL_HDR))
+  {
+  LM_ERR ("%sUnable to add contact (%s) to call (%s)!",
+    pfncname, pcontact->s, pcall->call_from);
+  }
+pkg_free (pcontact->s);
+pcall->call_pmsg = pmsg;
+if (search_hdr_ext (pmsg->require, p100rel))
+  {
+  if (!send_prov_rsp (pmsg, pcall))
+    {
+    delete_call (pcall);
+    return 1;
+    }
+  }
+else
+  {
+  if (ptm->t_reply (pmsg, 180, presp_ring->s) < 0)
+    {
+    LM_ERR ("%sUnable to reply to INVITE!", pfncname);
+    return 1;
+    }
+  else
+    {
+    pcall->call_state = CLSTA_RINGING;
+    mohq_debug (pcall->pmohq, "%sSent RINGING for call (%s)",
+      pfncname, pcall->call_from);
+    }
+  }
+
+/**********
+* o call cancelled?
+* o accept call with RTP
+**********/
+
+if (pcall->call_state == CLSTA_CANCEL)
+  {
+  delete_call (pcall);
+  return 1;
+  }
+if (!send_rtp_answer (pmsg, pcall))
+  {
+  if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  delete_call (pcall);
+  }
+return 1;
+}
+
+/**********
+* Form Dialog
+*
+* INPUT:
+*   Arg (1) = call pointer
+*   Arg (2) = to_body [2] pointer
+* OUTPUT: dlg_t * if successful; 0=if not
+**********/
+
+dlg_t *form_dialog (call_lst *pcall, struct to_body *pto_body)
+
+{
+/**********
+* get from/to values
+**********/
+
+char *pfncname = "form_dialog: ";
+struct to_body *ptob = &pto_body [0];
+struct to_body *pcontact = &pto_body [1];
+parse_to (pcall->call_from,
+  &pcall->call_from [strlen (pcall->call_from) + 1], ptob);
+if (ptob->error != PARSE_OK)
+  {
+  // should never happen
+  LM_ERR ("%sInvalid from URI (%s)!", pfncname, pcall->call_from);
+  return 0;
+  }
+if (ptob->param_lst)
+  { free_to_params (ptob); }
+str ptarget [1];
+if (!*pcall->call_contact)
+  {
+  ptarget->s = ptob->uri.s;
+  ptarget->len = ptob->uri.len;
+  }
+else
+  {
+  parse_to (pcall->call_contact,
+    &pcall->call_contact [strlen (pcall->call_contact) + 1], pcontact);
+  if (pcontact->error != PARSE_OK)
+    {
+    // should never happen
+    LM_ERR ("%sInvalid contact (%s) for call (%s)!", pfncname,
+      pcall->call_contact, pcall->call_from);
+    return 0;
+    }
+  if (pcontact->param_lst)
+    { free_to_params (pcontact); }
+  ptarget->s = pcontact->uri.s;
+  ptarget->len = pcontact->uri.len;
+  }
+
+/**********
+* create dialog
+**********/
+
+dlg_t *pdlg = (dlg_t *)pkg_malloc (sizeof (dlg_t));
+if (!pdlg)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  return 0;
+  }
+memset (pdlg, 0, sizeof (dlg_t));
+pdlg->loc_seq.value = pcall->call_cseq++;
+pdlg->loc_seq.is_set = 1;
+pdlg->id.call_id.s = pcall->call_id;
+pdlg->id.call_id.len = strlen (pcall->call_id);
+pdlg->id.loc_tag.s = pcall->call_tag;
+pdlg->id.loc_tag.len = strlen (pcall->call_tag);
+pdlg->id.rem_tag.s = ptob->tag_value.s;
+pdlg->id.rem_tag.len = ptob->tag_value.len;
+pdlg->rem_target.s = ptarget->s;
+pdlg->rem_target.len = ptarget->len;
+pdlg->loc_uri.s = pcall->pmohq->mohq_uri;
+pdlg->loc_uri.len = strlen (pdlg->loc_uri.s);
+pdlg->rem_uri.s = ptob->uri.s;
+pdlg->rem_uri.len = ptob->uri.len;
+return pdlg;
+}
+
+/**********
+* Form RTP SDP String
+*
+* INPUT:
+*   Arg (1) = string pointer
+*   Arg (2) = call pointer
+*   Arg (3) = SDP body pointer
+* OUTPUT: 0 if failed
+**********/
+
+int form_rtp_SDP (str *pstr, call_lst *pcall, char *pSDP)
+
+{
+/**********
+* o find available files
+* o calculate size of SDP
+**********/
+
+char *pfncname = "form_rtp_SDP: ";
+rtpmap **pmohfiles = find_MOH (pcall->pmohq->mohq_mohdir,
+  pcall->pmohq->mohq_mohfile);
+if (!pmohfiles [0])
+  {
+  LM_ERR ("%sUnable to find any MOH files for queue (%s)!", pfncname,
+    pcall->pmohq->mohq_name);
+  return 0;
+  }
+int nsize = strlen (pSDP) + 2;
+int nidx;
+for (nidx = 0; pmohfiles [nidx]; nidx++)
+  {
+  nsize += strlen (pmohfiles [nidx]->pencode) // encode length
+    + 19; // space, type number, "a=rtpmap:%d ", EOL
+  }
+
+/**********
+* o allocate memory
+* o form SDP
+**********/
+
+pstr->s = pkg_malloc (nsize + 1);
+if (!pstr->s)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  return 0;
+  }
+strcpy (pstr->s, pSDP);
+nsize = strlen (pstr->s);
+for (nidx = 0; pmohfiles [nidx]; nidx++)
+  {
+  /**********
+  * add payload types to media description
+  **********/
+
+  sprintf (&pstr->s [nsize], " %d", pmohfiles [nidx]->ntype);
+  nsize += strlen (&pstr->s [nsize]);
+  }
+strcpy (&pstr->s [nsize], SIPEOL);
+nsize += 2;
+for (nidx = 0; pmohfiles [nidx]; nidx++)
+  {
+  /**********
+  * add rtpmap attributes
+  **********/
+
+  sprintf (&pstr->s [nsize], "a=rtpmap:%d %s %s",
+    pmohfiles [nidx]->ntype, pmohfiles [nidx]->pencode, SIPEOL);
+  nsize += strlen (&pstr->s [nsize]);
+  }
+pstr->len = nsize;
+return 1;
+}
+
+/**********
+* Invite Callback
+*
+* INPUT:
+*   Arg (1) = cell pointer
+*   Arg (2) = callback type
+*   Arg (3) = callback parms
+* OUTPUT: none
+**********/
+
+static void
+  invite_cb (struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
+
+{
+call_lst *pcall = (call_lst *)*pcbp->param;
+if (ntype == TMCB_DESTROY)
+  { pcall->call_hash = pcall->call_label = 0; }
+LM_ERR ("invite_cb: INVITE failed for call (%s)!", pcall->call_from);
+delete_call (pcall);
+return;
+}
+
+/**********
+* Process NOTIFY Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=failed
+**********/
+
+int notify_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* waiting on REFER?
+**********/
+
+char *pfncname = "notify_msg: ";
+if (pcall->call_state != CLSTA_RFRWAIT)
+  {
+  LM_ERR ("%sNot waiting on a REFER for call (%s)!", pfncname,
+    pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 1;
+  }
+
+/**********
+* o sipfrag?
+* o get status from body
+* o add CRLF so parser can go beyond first line
+**********/
+
+if (!search_hdr_ext (pmsg->content_type, psipfrag))
+  {
+  LM_ERR ("%sNot a %s type for call (%s)!", pfncname,
+    psipfrag->s, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 1;
+  }
+char *pfrag = get_body (pmsg);
+if (!pfrag)
+  {
+  LM_ERR ("%s%s body missing for call (%s)!", pfncname,
+    psipfrag->s, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 1;
+  }
+str pbody [1];
+pbody->len = pmsg->len - (int)(pfrag - pmsg->buf);
+pbody->s = pkg_malloc (pbody->len + 2);
+if (!pbody->s)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  return 1;
+  }
+strncpy (pbody->s, pfrag, pbody->len);
+if (pbody->s [pbody->len - 1] != '\n')
+  {
+  strncpy (&pbody->s [pbody->len], SIPEOL, 2);
+  pbody->len += 2;
+  }
+struct msg_start pstart [1];
+parse_first_line (pbody->s, pbody->len + 1, pstart);
+pkg_free (pbody->s);
+if (pstart->type != SIP_REPLY)
+  {
+  LM_ERR ("%sReply missing for call (%s)!", pfncname, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 1;
+  }
+
+/**********
+* o send OK
+* o REFER done?
+**********/
+
+if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
+  {
+  LM_ERR ("%sUnable to create reply for call (%s)!",
+    pfncname, pcall->call_from);
+  return 1;
+  }
+int nreply = pstart->u.reply.statuscode;
+mohq_debug (pcall->pmohq, "%sNOTIFY received reply (%d) for call (%s)",
+  pfncname, nreply, pcall->call_from);
+switch (nreply / 100)
+  {
+  case 1:
+    break;
+  case 2:
+    close_call (pmsg, pcall);
+    break;
+  default:
+    LM_WARN ("%sUnable to redirect call (%s)!", pfncname, pcall->call_from);
+    if (nreply == 487)
+      {
+      /**********
+      * call was canceled
+      **********/
+
+      drop_call (pmsg, pcall);
+      return 1;
+      }
+
+    /**********
+    * return call to queue
+    **********/
+
+    pcall->call_state = CLSTA_INQUEUE;
+    update_call_rec (pcall);
+    break;
+  }
+return 1;
+}
+
+/**********
+* Process PRACK Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=failed
+**********/
+
+int prack_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* waiting on PRACK?
+**********/
+
+char *pfncname = "prack_msg: ";
+tm_api_t *ptm = pmod_data->ptm;
+if (pcall->call_state != CLSTA_PRACKSTRT)
+  {
+  LM_ERR ("%sUnexpected PRACK (%s)!", pfncname, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 1;
+  }
+
+/**********
+* o check RAck ??? need to check
+* o accept PRACK
+**********/
+
+if (ptm->t_newtran (pmsg) < 0)
+  {
+  LM_ERR ("%sUnable to create new transaction for call (%s)!",
+    pfncname, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 1;
+  }
+if (ptm->t_reply (pmsg, 200, presp_ok->s) < 0)
+  {
+  LM_ERR ("%sUnable to reply to PRACK for call (%s)!",
+    pfncname, pcall->call_from);
+  return 1;
+  }
+pcall->call_state = CLSTA_PRACKRPLY;
+return 1;
+}
+
+/**********
+* Refer Call
+*
+* INPUT:
+*   Arg (1) = call pointer
+*   Arg (2) = lock pointer
+* OUTPUT: 0 if failed
+**********/
+
+int refer_call (call_lst *pcall, mohq_lock *plock)
+
+{
+/**********
+* create dialog
+**********/
+
+char *pfncname = "refer_call: ";
+int nret = 0;
+struct to_body ptob [2];
+dlg_t *pdlg = form_dialog (pcall, ptob);
+if (!pdlg)
+  {
+  mohq_lock_release (plock);
+  return 0;
+  }
+pdlg->state = DLG_CONFIRMED;
+
+/**********
+* form REFER message
+* o calculate basic size
+* o create buffer
+**********/
+
+str puri [1];
+puri->s = pcall->call_referto;
+puri->len = strlen (puri->s);
+int npos1 = sizeof (prefermsg) // REFER template
+  + strlen (pcall->call_via) // Via
+  + puri->len // Refer-To
+  + ptob->uri.len; // Referred-By
+char *pbuf = pkg_malloc (npos1);
+if (!pbuf)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  goto refererr;
+  }
+sprintf (pbuf, prefermsg,
+  pcall->call_via, // Via
+  puri->s, // Refer-To
+  STR_FMT (&ptob->uri)); // Referred-By
+
+/**********
+* send REFER request
+**********/
+
+tm_api_t *ptm = pmod_data->ptm;
+uac_req_t puac [1];
+str phdrs [1];
+phdrs->s = pbuf;
+phdrs->len = strlen (pbuf);
+set_uac_req (puac, prefer, phdrs, 0, pdlg,
+  TMCB_LOCAL_COMPLETED | TMCB_ON_FAILURE, refer_cb, pcall);
+pcall->call_state = CLSTA_REFER;
+update_call_rec (pcall);
+mohq_lock_release (plock);
+if (ptm->t_request_within (puac) < 0)
+  {
+  pcall->call_state = CLSTA_INQUEUE;
+  LM_ERR ("%sUnable to create REFER request for call (%s)!",
+    pfncname, pcall->call_from);
+  update_call_rec (pcall);
+  goto refererr;
+  }
+mohq_debug (pcall->pmohq, "%sSent REFER request for call (%s) to %s",
+  pfncname, pcall->call_from, pcall->call_referto);
+nret = -1;
+
+refererr:
+if (pdlg)
+  { pkg_free (pdlg); }
+pkg_free (pbuf);
+return nret;
+}
+
+/**********
+* REFER Callback
+*
+* INPUT:
+*   Arg (1) = cell pointer
+*   Arg (2) = callback type
+*   Arg (3) = callback parms
+* OUTPUT: none
+**********/
+
+static void refer_cb
+  (struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
+
+{
+char *pfncname = "refer_cb: ";
+call_lst *pcall = (call_lst *)*pcbp->param;
+if ((ntype == TMCB_ON_FAILURE) || (pcbp->req == FAKED_REPLY))
+  {
+  LM_ERR ("%sCall (%s) did not respond to REFER", pfncname,
+    pcall->call_from);
+  drop_call (pcbp->req, pcall);
+  return;
+  }
+int nreply = pcbp->code;
+if ((nreply / 100) == 2)
+  {
+  pcall->call_state = CLSTA_RFRWAIT;
+  mohq_debug (pcall->pmohq, "%sCall (%s) REFER reply=%d",
+    pfncname, pcall->call_from, nreply);
+  }
+else
+  {
+  LM_ERR ("%sCall (%s) REFER error (%d)", pfncname,
+    pcall->call_from, nreply);
+  if (nreply == 481)
+    { delete_call (pcall); }
+  else
+    {
+    pcall->call_state = CLSTA_INQUEUE;
+    update_call_rec (pcall);
+    }
+  }
+return;
+}
+
+/**********
+* Process re-INVITE Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=failed
+**********/
+
+int reinvite_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* RFC 3261 section 14.2
+* o dialog pending?
+* o get SDP
+**********/
+
+char *pfncname = "reinvite_msg: ";
+if ((pcall->call_state / 100) < 2)
+  {
+  mohq_debug (pcall->pmohq, "%sINVITE still pending for call (%s)",
+    pfncname, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 491, presp_reqpend) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 1;
+  }
+if (!(pmsg->msg_flags & FL_SDP_BODY))
+  {
+  if (parse_sdp (pmsg))
+    {
+    LM_ERR ("%sre-INVITE lacks SDP (%s)!", pfncname, pcall->call_from);
+    if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
+      { LM_ERR ("%sUnable to create reply!", pfncname); }
+    return 1;
+    }
+  }
+
+/**********
+* o find available MOH files
+* o look for hold condition and matching payload type
+**********/
+
+rtpmap **pmohfiles = find_MOH (pcall->pmohq->mohq_mohdir,
+  pcall->pmohq->mohq_mohfile);
+int bhold = 0;
+int bmatch = 0;
+int nsession;
+sdp_session_cell_t *psession;
+for (nsession = 0; (psession = get_sdp_session (pmsg, nsession)); nsession++)
+  {
+  int nstream;
+  sdp_stream_cell_t *pstream;
+  for (nstream = 0; (pstream = get_sdp_stream (pmsg, nsession, nstream));
+    nstream++)
+    {
+    /**********
+    * o RTP?
+    * o audio?
+    * o hold?
+    * o at least one payload matches?
+    **********/
+
+    if (!pstream->is_rtp)
+      { continue; }
+    if (!STR_EQ (*paudio, pstream->media))
+      { continue; }
+    if (pstream->is_on_hold)
+      {
+      bhold = 1;
+      break;
+      }
+    if (bmatch)
+      { continue; }
+
+    /**********
+    * check payload types for a match
+    **********/
+
+    sdp_payload_attr_t *ppayload;
+    for (ppayload = pstream->payload_attr; ppayload; ppayload = ppayload->next)
+      {
+      int ntype = atoi (ppayload->rtp_payload.s);
+      int nidx;
+      for (nidx = 0; pmohfiles [nidx]; nidx++)
+        {
+        if (pmohfiles [nidx]->ntype == ntype)
+          {
+          bmatch = 1;
+          break;
+          }
+        }
+      }
+    }
+  }
+
+/**********
+* if no hold, allow re-INVITE if matching file
+**********/
+
+if (!bhold)
+  {
+  if (!bmatch)
+    {
+    LM_ERR ("%sre-INVITE refused because no matching payload for call (%s)!",
+      pfncname, pcall->call_from);
+    if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
+      {
+      LM_ERR ("%sUnable to create reply!", pfncname);
+      return 1;
+      }
+    }
+  else
+    {
+    mohq_debug (pcall->pmohq, "%sAccepted re-INVITE for call (%s)",
+      pfncname, pcall->call_from);
+    if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
+      {
+      LM_ERR ("%sUnable to create reply!", pfncname);
+      return 1;
+      }
+    }
+  return 1;
+  }
+
+/**********
+* hold not allowed, say good-bye
+**********/
+
+LM_ERR ("%sTerminating call (%s) because hold not allowed!",
+  pfncname, pcall->call_from);
+if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
+  {
+  LM_ERR ("%sUnable to create reply!", pfncname);
+  return 1;
+  }
+close_call (pmsg, pcall);
+return 1;
+}
+
+/**********
+* Search Header for Extension
+*
+* INPUT:
+*   Arg (1) = header field pointer
+*   Arg (2) = extension str pointer
+* OUTPUT: 0=not found
+**********/
+
+int search_hdr_ext (struct hdr_field *phdr, str *pext)
+
+{
+if (!phdr)
+  { return 0; }
+str *pstr = &phdr->body;
+int npos1, npos2;
+for (npos1 = 0; npos1 < pstr->len; npos1++)
+  {
+  /**********
+  * o find non-space
+  * o search to end, space or comma
+  * o same size?
+  * o same name?
+  **********/
+
+  if (pstr->s [npos1] == ' ')
+    { continue; }
+  for (npos2 = npos1++; npos1 < pstr->len; npos1++)
+    {
+    if (pstr->s [npos1] == ' ' || pstr->s [npos1] == ',')
+      { break; }
+    }
+  if (npos1 - npos2 != pext->len)
+    { continue; }
+  if (!strncasecmp (&pstr->s [npos2], pext->s, pext->len))
+    { return 1; }
+  }
+return 0;
+}
+
+/**********
+* Send Provisional Response
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=unable to process; 1=processed
+**********/
+
+int send_prov_rsp (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* o send ringing response with require
+* o update record
+**********/
+
+char *pfncname = "send_prov_rsp: ";
+tm_api_t *ptm = pmod_data->ptm;
+pcall->call_cseq = rand ();
+char phdrtmp [200];
+char *phdrtmplt =
+  "Accept-Language: en" SIPEOL
+  "Require: 100rel" SIPEOL
+  "RSeq: %d" SIPEOL
+  "User-Agent: " USRAGNT SIPEOL
+  ;
+sprintf (phdrtmp, phdrtmplt, pcall->call_cseq);
+struct lump_rpl **phdrlump = add_lump_rpl2 (pmsg, phdrtmp,
+  strlen (phdrtmp), LUMP_RPL_HDR);
+if (!phdrlump)
+  {
+  LM_ERR ("%sUnable to create new header for call (%s)!",
+    pfncname, pcall->call_from);
+  if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+    { LM_ERR ("%sUnable to create reply!", pfncname); }
+  return 0;
+  }
+if (ptm->t_reply (pmsg, 180, presp_ring->s) < 0)
+  {
+  LM_ERR ("%sUnable to reply to INVITE for call (%s)",
+    pfncname, pcall->call_from);
+  return 0;
+  }
+pcall->call_state = CLSTA_PRACKSTRT;
+mohq_debug (pcall->pmohq, "%sSent PRACK RINGING for call (%s)",
+  pfncname, pcall->call_from);
+
+/**********
+* o wait until PRACK (64*T1 RFC 3261 section 7.1.1)
+* o remove header lump
+**********/
+
+time_t nstart = time (0) + 32;
+while (1)
+  {
+  usleep (USLEEP_LEN);
+  if (pcall->call_state != CLSTA_PRACKSTRT)
+    { break; }
+  if (nstart < time (0))
+    {
+    LM_ERR ("%sNo PRACK response for call (%s)",
+      pfncname, pcall->call_from);
+    break;
+    }
+  }
+unlink_lump_rpl (pmsg, *phdrlump);
+if (pcall->call_state != CLSTA_PRACKRPLY)
+  { return 0; }
+return 1;
+}
+
+/**********
+* Send RTPProxy Answer
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+* OUTPUT: 0=unable to process; 1=processed
+**********/
+
+int send_rtp_answer (sip_msg_t *pmsg, call_lst *pcall)
+
+{
+/**********
+* build response from request
+**********/
+
+char *pfncname = "send_rtp_answer: ";
+int nret = 0;
+tm_api_t *ptm = pmod_data->ptm;
+struct cell *ptrans = ptm->t_gett ();
+str ptotag [1];
+ptotag->s = pcall->call_tag;
+ptotag->len = strlen (pcall->call_tag);
+str pbuf [1];
+struct bookmark pBM [1];
+pbuf->s = build_res_buf_from_sip_req (200, presp_ok, ptotag, ptrans->uas.request,
+  (unsigned int *)&pbuf->len, pBM);
+if (!pbuf->s || !pbuf->len)
+  {
+  LM_ERR ("%sUnable to create SDP response for call (%s)!",
+    pfncname, pcall->call_from);
+  return 0;
+  }
+
+/**********
+* parse out first line and headers
+**********/
+
+char *pclenhdr = CLENHDR;
+str pparse [20];
+int npos1, npos2;
+int nhdrcnt = 0;
+for (npos1 = 0; npos1 < pbuf->len; npos1++)
+  {
+  /**********
+  * find EOL
+  **********/
+
+  for (npos2 = npos1++; npos1 < pbuf->len; npos1++)
+    {
+    /**********
+    * o not EOL? (CRLF assumed)
+    * o next line a continuation? (RFC 3261 section 7.3.1)
+    **********/
+
+    if (pbuf->s [npos1] != '\n')
+      { continue; }
+    if (npos1 + 1 == pbuf->len)
+      { break; }
+    if (pbuf->s [npos1 + 1] == ' '
+      || pbuf->s [npos1 + 1] == '\t')
+      { continue; }
+    break;
+    }
+
+  /**********
+  * o blank is end of header (RFC 3261 section 7)
+  * o ignore Content-Length (assume followed by colon)
+  * o save header
+  **********/
+
+  if (npos1 - npos2 == 1)
+    { break; }
+  if (npos1 - npos2 > 14)
+    {
+    if (!strncasecmp (&pbuf->s [npos2], pclenhdr, 14))
+      { continue; }
+    }
+  pparse [nhdrcnt].s = &pbuf->s [npos2];
+  pparse [nhdrcnt++].len = npos1 - npos2 + 1;
+  }
+
+/**********
+* recreate buffer with extra headers and SDP
+* o form SDP
+* o count hdrs, extra hdrs, content-length hdr, SDP
+* o alloc new buffer
+* o form new buffer
+* o replace orig buffer
+**********/
+
+str pSDP [1] = {STR_NULL};
+if (!form_rtp_SDP (pSDP, pcall, prtpsdp))
+  { goto answer_done; }
+for (npos1 = npos2 = 0; npos2 < nhdrcnt; npos2++)
+  { npos1 += pparse [npos2].len; }
+char pbodylen [30];
+sprintf (pbodylen, "%s: %d\r\n\r\n", pclenhdr, pSDP->len);
+npos1 += pextrahdr->len + strlen (pbodylen) + pSDP->len + 1;
+char *pnewbuf = pkg_malloc (npos1);
+if (!pnewbuf)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  goto answer_done;
+  }
+for (npos1 = npos2 = 0; npos2 < nhdrcnt; npos2++)
+  {
+  memcpy (&pnewbuf [npos1], pparse [npos2].s, pparse [npos2].len);
+  npos1 += pparse [npos2].len;
+  }
+npos2 = pextrahdr->len;
+memcpy (&pnewbuf [npos1], pextrahdr->s, npos2);
+npos1 += npos2;
+npos2 = strlen (pbodylen);
+memcpy (&pnewbuf [npos1], pbodylen, npos2);
+npos1 += npos2;
+npos2 = pSDP->len;
+memcpy (&pnewbuf [npos1], pSDP->s, npos2);
+npos1 += npos2;
+pkg_free (pbuf->s);
+pbuf->s = pnewbuf;
+pbuf->len = npos1;
+
+/**********
+* build SIP msg
+**********/
+
+struct sip_msg pnmsg [1];
+build_sip_msg_from_buf (pnmsg, pbuf->s, pbuf->len, 0);
+memcpy (&pnmsg->rcv, &pmsg->rcv, sizeof (struct receive_info));
+
+/**********
+* o send rtpproxy answer
+* o form stream file
+* o send stream
+**********/
+
+mohq_debug (pcall->pmohq, "%sAnswering RTP link for call (%s)",
+  pfncname, pcall->call_from);
+if (pmod_data->fn_rtp_answer (pnmsg, 0, 0) != 1)
+  {
+  LM_ERR ("%srtpproxy_answer refused for call (%s)!",
+    pfncname, pcall->call_from);
+  goto answer_done;
+  }
+if (!start_stream (pnmsg, pcall, 0))
+  { goto answer_done; }
+
+/**********
+* o create buffer from response
+* o find SDP
+**********/
+
+pbuf->s = build_res_buf_from_sip_res (pnmsg, (unsigned int *)&pbuf->len);
+pkg_free (pnewbuf);
+free_sip_msg (pnmsg);
+if (!pbuf->s || !pbuf->len)
+  {
+  LM_ERR ("%sUnable to create SDP response for call (%s)!",
+    pfncname, pcall->call_from);
+  goto answer_done;
+  }
+str pnewSDP [1];
+for (npos1 = 0; npos1 < pbuf->len; npos1++)
+  {
+  if (pbuf->s [npos1] != '\n')
+    { continue; }
+  if (pbuf->s [npos1 - 3] == '\r')
+    { break; }
+  }
+pnewSDP->s = &pbuf->s [npos1 + 1];
+pnewSDP->len = pbuf->len - npos1 - 1;
+
+/**********
+* o save media port number
+* o send adjusted reply
+**********/
+
+char *pfnd = strstr (pnewSDP->s, "m=audio ");
+if (!pfnd)
+  {
+  // should not happen
+  LM_ERR ("%sUnable to find audio port for call (%s)!",
+    pfncname, pcall->call_from);
+  goto answer_done;
+  }
+pcall->call_aport = strtol (pfnd + 8, NULL, 10);
+if (!add_lump_rpl2 (pmsg, pextrahdr->s, pextrahdr->len, LUMP_RPL_HDR))
+  {
+  LM_ERR ("%sUnable to add header for call (%s)!",
+    pfncname, pcall->call_from);
+  goto answer_done;
+  }
+if (!add_lump_rpl2 (pmsg, pnewSDP->s, pnewSDP->len, LUMP_RPL_BODY))
+  {
+  LM_ERR ("%sUnable to add SDP body for call (%s)!",
+    pfncname, pcall->call_from);
+  goto answer_done;
+  }
+if (ptm->t_reply (pmsg, 200, presp_ok->s) < 0)
+  {
+  LM_ERR ("%sUnable to reply to INVITE for call (%s)!",
+    pfncname, pcall->call_from);
+  goto answer_done;
+  }
+pcall->call_state = CLSTA_INVITED;
+mohq_debug (pcall->pmohq, "%sResponded to INVITE with RTP for call (%s)",
+  pfncname, pcall->call_from);
+nret = 1;
+
+/**********
+* free buffer and return
+**********/
+
+answer_done:
+if (pSDP->s)
+  { pkg_free (pSDP->s); }
+pkg_free (pbuf->s);
+return nret;
+}
+
+/**********
+* Start Streaming
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = call pointer
+*   Arg (3) = server flag
+* OUTPUT: 0 if failed
+**********/
+
+int start_stream (sip_msg_t *pmsg, call_lst *pcall, int bserver)
+
+{
+char *pfncname = "start_stream: ";
+char pfile [MOHDIRLEN + MOHFILELEN + 2];
+strcpy (pfile, pcall->pmohq->mohq_mohdir);
+int npos = strlen (pfile);
+pfile [npos++] = '/';
+strcpy (&pfile [npos], pcall->pmohq->mohq_mohfile);
+npos += strlen (&pfile [npos]);
+str pMOH [1] = {{pfile, npos}};
+pv_elem_t *pmodel;
+pv_parse_format (pMOH, &pmodel);
+cmd_function fn_stream = bserver ? pmod_data->fn_rtp_stream_s
+  : pmod_data->fn_rtp_stream_c;
+mohq_debug (pcall->pmohq, "%sStarting RTP link for call (%s)",
+  pfncname, pcall->call_from);
+if (fn_stream (pmsg, (char *)pmodel, (char *)-1) != 1)
+  {
+  LM_ERR ("%srtpproxy_stream refused for call (%s)!",
+    pfncname, pcall->call_from);
+  return 0;
+  }
+return 1;
+}
+
+/**********
+* Form Char Array from STR
+*
+* INPUT:
+*   Arg (1) = str pointer
+* OUTPUT: char pointer; NULL if unable to allocate
+**********/
+
+char *form_tmpstr (str *pstr)
+
+{
+char *pcstr = malloc (pstr->len + 1);
+if (!pcstr)
+  {
+  LM_ERR ("No more memory!");
+  return NULL;
+  }
+memcpy (pcstr, pstr->s, pstr->len);
+pcstr [pstr->len] = 0;
+return pcstr;
+}
+
+/**********
+* Release Char Array
+*
+* INPUT:
+*   Arg (1) = char pointer
+* OUTPUT: none
+**********/
+
+void free_tmpstr (char *pcstr)
+
+{
+if (pcstr)
+  { free (pcstr); }
+return;
+}
+
+/**********
+* external functions
+**********/
+
+/**********
+* Find MOH Files
+*
+* INPUT:
+*   Arg (1) = mohdir pointer
+*   Arg (2) = mohfile pointer
+* OUTPUT: array of pointers for matching files; last element=0
+**********/
+
+rtpmap **find_MOH (char *pmohdir, char *pmohfile)
+
+{
+/**********
+* form base file name
+**********/
+
+char pfile [MOHDIRLEN + MOHFILELEN + 6];
+strcpy (pfile, pmohdir);
+int nflen = strlen (pfile);
+pfile [nflen++] = '/';
+strcpy (&pfile [nflen], pmohfile);
+nflen += strlen (&pfile [nflen]);
+pfile [nflen++] = '.';
+
+/**********
+* find available files based on RTP payload type
+**********/
+
+int nidx;
+int nfound = 0;
+for (nidx = 0; prtpmap [nidx].pencode; nidx++)
+  {
+  /**********
+  * o form file name based on payload type
+  * o exists?
+  **********/
+
+  sprintf (&pfile [nflen], "%d", prtpmap [nidx].ntype);
+  struct stat psb [1];
+  if (lstat (pfile, psb))
+    { continue; }
+  pmohfiles [nfound++] = &prtpmap [nidx];
+  }
+pmohfiles [nfound] = 0;
+return pmohfiles;
+}
+
+/**********
+* MI Debug
+*
+* PARAMETERS:
+* queue name = queue to use
+* state = 0=off, <>0=on
+*
+* INPUT:
+*   Arg (1) = command tree pointer
+*   Arg (2) = parms pointer
+* OUTPUT: root pointer
+**********/
+
+struct mi_root *mi_debug (struct mi_root *pcmd_tree, void *parms)
+
+{
+/**********
+* o parm count correct?
+* o find queue
+* o lock queue
+**********/
+
+struct mi_node *pnode = pcmd_tree->node.kids;
+if (!pnode || !pnode->next || pnode->next->next)
+  { return init_mi_tree (400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); }
+int nq_idx = find_queue (&pnode->value);
+if (nq_idx == -1)
+  { return init_mi_tree (400, pmi_noqueue->s, pmi_noqueue->len); }
+char pint [20];
+int nsize = (pnode->next->value.len >= sizeof (pint))
+  ? sizeof (pint) - 1 : pnode->next->value.len;
+strncpy (pint, pnode->next->value.s, nsize);
+pint [nsize] = '\0';
+int bdebug = atoi (pint) ? 1 : 0;
+if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 5000))
+  { return init_mi_tree (400, pmi_nolock->s, pmi_nolock->len); }
+
+/**********
+* o set flag
+* o update queue table
+* o release lock
+**********/
+
+mohq_lst *pqueue = &pmod_data->pmohq_lst [nq_idx];
+if (bdebug)
+  { pqueue->mohq_flags |= MOHQF_DBG; }
+else
+  { pqueue->mohq_flags &= ~MOHQF_DBG; }
+update_debug (pqueue, bdebug);
+mohq_lock_release (pmod_data->pmohq_lock);
+return init_mi_tree (200, MI_OK_S, MI_OK_LEN);
+}
+
+/**********
+* MI Drop Call
+*
+* PARAMETERS:
+* queue name = queue to use
+* callID = *=all, otherwise callID
+*
+* INPUT:
+*   Arg (1) = command tree pointer
+*   Arg (2) = parms pointer
+* OUTPUT: root pointer
+**********/
+
+struct mi_root *mi_drop_call (struct mi_root *pcmd_tree, void *parms)
+
+{
+/**********
+* o parm count correct?
+* o find queue
+* o lock calls
+**********/
+
+struct mi_node *pnode = pcmd_tree->node.kids;
+if (!pnode || !pnode->next || pnode->next->next)
+  { return init_mi_tree (400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); }
+int nq_idx = find_queue (&pnode->value);
+if (nq_idx == -1)
+  { return init_mi_tree (400, pmi_noqueue->s, pmi_noqueue->len); }
+if (!mohq_lock_set (pmod_data->pcall_lock, 0, 5000))
+  { return init_mi_tree (400, pmi_nolock->s, pmi_nolock->len); }
+
+/**********
+* o find matching calls
+* o release lock
+**********/
+
+mohq_lst *pqueue = &pmod_data->pmohq_lst [nq_idx];
+int nidx;
+str *pcallid = &pnode->next->value;
+for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+  {
+  /**********
+  * o call active?
+  * o callID matches?
+  * o close call
+  **********/
+
+  call_lst *pcall = &pmod_data->pcall_lst [nidx];
+  if (!pcall->call_active)
+    { continue; }
+  if (pqueue->mohq_id != pcall->pmohq->mohq_id)
+    { continue; }
+  str tmpstr [1];
+  if (!STR_EQ (*pcallid, *pallq))
+    {
+    tmpstr->s = pcall->call_id;
+    tmpstr->len = strlen (tmpstr->s);
+    if (!STR_EQ (*tmpstr, *pcallid))
+      { continue; }
+    }
+  close_call (FAKED_REPLY, pcall);
+  }
+mohq_lock_release (pmod_data->pcall_lock);
+return init_mi_tree (200, MI_OK_S, MI_OK_LEN);
+}
+
+/**********
+* Count Messages
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = queue name
+*   Arg (3) = pv result name
+* OUTPUT: -1 if no items in queue; else result = count
+**********/
+
+int mohq_count (sip_msg_t *pmsg, char *pqueue, pv_spec_t *presult)
+
+{
+/**********
+* get queue and pv names
+**********/
+
+char *pfncname = "mohq_count: ";
+str pqname [1];
+if (!pqueue || !presult)
+  {
+  LM_ERR ("%sParameters missing!", pfncname);
+  return -1;
+  }
+if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+  {
+  LM_ERR ("%sInvalid queue name!", pfncname);
+  return -1;
+  }
+
+/**********
+* o find queue
+* o lock calls
+* o count items in queue
+**********/
+
+int nq_idx = find_queue (pqname);
+int ncount = 0;
+call_lst *pcalls = pmod_data->pcall_lst;
+int ncall_idx, mohq_id;
+if (!mohq_lock_set (pmod_data->pcall_lock, 0, 200))
+  { LM_ERR ("%sUnable to lock calls!", pfncname); }
+else
+  {
+  if (nq_idx != -1)
+    {
+    mohq_id = pmod_data->pmohq_lst [nq_idx].mohq_id;
+    for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
+      {
+      if (!pcalls [ncall_idx].call_active)
+        { continue; }
+      if (pcalls [ncall_idx].pmohq->mohq_id == mohq_id
+        && pcalls [ncall_idx].call_state == CLSTA_INQUEUE)
+        { ncount++; }
+      }
+    }
+  mohq_lock_release (pmod_data->pcall_lock);
+  }
+
+/**********
+* o set pv result
+* o exit with result
+**********/
+
+pv_value_t pavp_val [1];
+memset (pavp_val, 0, sizeof (pv_value_t));
+pavp_val->ri = ncount;
+pavp_val->flags = PV_TYPE_INT | PV_VAL_INT;
+if (presult->setf (pmsg, &presult->pvp, (int)EQ_T, pavp_val) < 0)
+  {
+  LM_ERR ("%sUnable to set pv value for mohq_count ()!", pfncname);
+  return -1;
+  }
+return 1;
+}
+
+/**********
+* Log Debug Statement
+*
+* INPUT:
+*   Arg (1) = MOH queue pointer
+*   Arg (2) = format pointer
+*   Arg (...) = optional format values
+* OUTPUT: outputs debugging values
+**********/
+
+void mohq_debug (mohq_lst *pmohq, char *pfmt, ...)
+
+{
+/**********
+* o get system and MOHQ log level
+* o exit if no debug printing
+* o force local debug
+* o form message and log
+* o reset log level
+**********/
+
+int nsys_log = get_debug_level (LOG_MNAME, LOG_MNAME_LEN);
+int nmohq_log = (pmohq->mohq_flags & MOHQF_DBG) ? L_DBG : L_INFO;
+if (nmohq_log < L_DBG && nsys_log < L_DBG)
+  { return; }
+if (nsys_log < nmohq_log)
+  { set_local_debug_level (nmohq_log); }
+char ptext [1024];
+va_list ap;
+va_start (ap, pfmt);
+vsnprintf (ptext, sizeof (ptext), pfmt, ap);
+va_end (ap);
+LM_DBG ("%s", ptext);
+if (nsys_log < nmohq_log)
+  { reset_local_debug_level (); }
+return;
+}
+
+/**********
+* Process Message
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+* OUTPUT: -1=not directed to queue; 1=successfully processed
+**********/
+
+int mohq_process (sip_msg_t *pmsg)
+
+{
+/**********
+* o parse headers
+* o lock MOH queue
+* o directed to message queue?
+* o connect to database
+**********/
+
+char *pfncname = "mohq_process: ";
+if (parse_headers (pmsg, HDR_EOH_F, 0) < 0)
+  {
+  LM_ERR ("%sUnable to parse header!", pfncname);
+  return -1;
+  }
+if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 2000))
+  {
+  LM_ERR ("%sUnable to lock calls!", pfncname);
+  return -1;
+  }
+call_lst *pcall;
+int mohq_idx = find_call (pmsg, &pcall);
+db1_con_t *pconn = mohq_dbconnect ();
+if (pconn)
+  {
+  /**********
+  * o last update older than 1 minute?
+  * o exclusively lock MOH queue
+  * o update queue
+  **********/
+
+  if (pmod_data->mohq_update + 60 < time (0))
+    {
+    if (mohq_lock_change (pmod_data->pmohq_lock, 1))
+      {
+      update_mohq_lst (pconn);
+      mohq_lock_change (pmod_data->pmohq_lock, 0);
+      pmod_data->mohq_update = time (0);
+      }
+    }
+  mohq_dbdisconnect (pconn);
+  }
+if (mohq_idx < 0)
+  {
+  mohq_lock_release (pmod_data->pmohq_lock);
+  return -1;
+  }
+
+/**********
+* o process message
+* o release MOH queue
+**********/
+
+mohq_debug (&pmod_data->pmohq_lst [mohq_idx],
+  "%sProcessing %.*s, queue (%s)", pfncname,
+  STR_FMT (&REQ_LINE (pmsg).method),
+  pmod_data->pmohq_lst [mohq_idx].mohq_name);
+int ret;
+switch (pmsg->REQ_METHOD)
+  {
+  case METHOD_INVITE:
+    /**********
+    * initial INVITE?
+    **********/
+
+    if (!pcall)
+      { ret = first_invite_msg (pmsg, mohq_idx); }
+    else
+      { ret = reinvite_msg (pmsg, pcall); }
+    break;
+  case METHOD_NOTIFY:
+    ret = notify_msg (pmsg, pcall);
+    break;
+  case METHOD_PRACK:
+    ret = prack_msg (pmsg, pcall);
+    break;
+  case METHOD_ACK:
+    ret = ack_msg (pmsg, pcall);
+    break;
+  case METHOD_BYE:
+    ret = bye_msg (pmsg, pcall);
+    break;
+  case METHOD_CANCEL:
+    ret = cancel_msg (pmsg, pcall);
+    break;
+  default:
+    deny_method (pmsg, pcall);
+    ret = 1;
+    break;
+  }
+mohq_lock_release (pmod_data->pmohq_lock);
+return ret ? 1 : -1;
+}
+
+/**********
+* Retrieve Oldest Queued Call
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = queue name
+*   Arg (3) = redirect URI
+* OUTPUT: -1 if no items in queue or error; 1 redirects oldest call
+**********/
+
+int mohq_retrieve (sip_msg_t *pmsg, char *pqueue, char *pURI)
+
+{
+/**********
+* o get queue name and URI
+* o check URI
+**********/
+
+char *pfncname = "mohq_retrieve: ";
+str puri [1], pqname [1];
+if (!pqueue || !pURI)
+  {
+  LM_ERR ("%sParameters missing!", pfncname);
+  return -1;
+  }
+if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+  {
+  LM_ERR ("%sInvalid queue name!", pfncname);
+  return -1;
+  }
+if (fixup_get_svalue (pmsg, (gparam_p)pURI, puri))
+  {
+  LM_ERR ("%sInvalid URI!", pfncname);
+  return -1;
+  }
+if (puri->len > URI_LEN)
+  {
+  LM_ERR ("%sURI too long!", pfncname);
+  return -1;
+  }
+struct sip_uri puri_parsed [1];
+if (parse_uri (puri->s, puri->len, puri_parsed))
+  {
+  LM_ERR ("%sInvalid URI (%.*s)!", pfncname, STR_FMT (puri));
+  return -1;
+  }
+
+/**********
+* o find queue
+* o lock calls
+* o find oldest call
+**********/
+
+int nq_idx = find_queue (pqname);
+if (nq_idx == -1)
+  { return -1; }
+if (!mohq_lock_set (pmod_data->pcall_lock, 0, 200))
+  {
+  LM_ERR ("%sUnable to lock calls!", pfncname);
+  return -1;
+  }
+call_lst *pcall = 0;
+int ncall_idx;
+time_t ntime = 0;
+int nfound = -1;
+int mohq_id = pmod_data->pmohq_lst [nq_idx].mohq_id;
+for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
+  {
+  /**********
+  * o active call?
+  * o matching queue?
+  * o in queue?
+  * o check age
+  **********/
+
+  pcall = &pmod_data->pcall_lst [ncall_idx];
+  if (!pcall->call_active)
+    { continue; }
+  if (pcall->pmohq->mohq_id != mohq_id)
+    { continue; }
+  if (pcall->call_state != CLSTA_INQUEUE)
+    { continue; }
+  if (!ntime)
+    {
+    nfound = ncall_idx;
+    ntime = pcall->call_time;
+    }
+  else
+    {
+    if (pcall->call_time < ntime)
+      {
+      nfound = ncall_idx;
+      ntime = pcall->call_time;
+      }
+    }
+  }
+if (nfound == -1)
+  {
+  LM_WARN ("%sNo calls in queue (%.*s)", pfncname, STR_FMT (pqname));
+  mohq_lock_release (pmod_data->pcall_lock);
+  return -1;
+  }
+pcall = &pmod_data->pcall_lst [nfound];
+
+/**********
+* o save refer-to URI
+* o send refer
+**********/
+
+strncpy (pcall->call_referto, puri->s, puri->len);
+pcall->call_referto [puri->len] = '\0';
+if (refer_call (pcall, pmod_data->pcall_lock))
+  { return 1; }
+LM_ERR ("%sUnable to refer call (%s)!", pfncname, pcall->call_from);
+return -1;
+}
+
+/**********
+* Send Message to Queue
+*
+* INPUT:
+*   Arg (1) = SIP message pointer
+*   Arg (2) = queue name
+* OUTPUT: -1 if no items in queue; 1 if successfull
+**********/
+
+int mohq_send (sip_msg_t *pmsg, char *pqueue)
+
+{
+/**********
+* o first INVITE?
+* o get queue name
+**********/
+
+char *pfncname = "mohq_send: ";
+if (pmsg->REQ_METHOD != METHOD_INVITE)
+  {
+  LM_ERR ("%sNot an INVITE message!", pfncname);
+  return -1;
+  }
+to_body_t *pto_body = get_to (pmsg);
+if (pto_body->tag_value.len)
+  {
+  LM_ERR ("%sNot a first INVITE message!", pfncname);
+  return -1;
+  }
+str pqname [1];
+if (!pqueue)
+  {
+  LM_ERR ("%sParameters missing!", pfncname);
+  return -1;
+  }
+if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+  {
+  LM_ERR ("%sInvalid queue name!", pfncname);
+  return -1;
+  }
+
+/**********
+* o find queue
+* o change RURI
+* o relay message
+**********/
+
+int nq_idx = find_queue (pqname);
+if (nq_idx == -1)
+  { return -1; }
+str pruri [1] = {{0, strlen (pmod_data->pmohq_lst [nq_idx].mohq_uri)}};
+pruri->s = pkg_malloc (pruri->len + 1);
+if (!pruri->s)
+  {
+  LM_ERR ("%sNo more memory!", pfncname);
+  return -1;
+  }
+strcpy (pruri->s, pmod_data->pmohq_lst [nq_idx].mohq_uri);
+if (pmsg->new_uri.s)
+  { pkg_free (pmsg->new_uri.s); }
+pmsg->new_uri.s = pruri->s;
+pmsg->new_uri.len = pruri->len;
+pmsg->parsed_uri_ok = 0;
+pmsg->parsed_orig_ruri_ok = 0;
+if (pmod_data->ptm->t_relay (pmsg, 0, 0) < 0)
+  {
+  LM_ERR ("%sUnable to relay INVITE!", pfncname);
+  return -1;
+  }
+return 1;
+}
\ No newline at end of file
diff --git a/modules/mohqueue/mohq_funcs.h b/modules/mohqueue/mohq_funcs.h
new file mode 100644
index 0000000..fb27367
--- /dev/null
+++ b/modules/mohqueue/mohq_funcs.h
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef MOHQ_FUNCS_H
+#define MOHQ_FUNCS_H
+
+/**********
+* module function declarations
+**********/
+
+rtpmap **find_MOH (char *, char *);
+struct mi_root *mi_debug (struct mi_root *, void *);
+struct mi_root *mi_drop_call (struct mi_root *, void *);
+int mohq_count (sip_msg_t *, char *, pv_spec_t *);
+void mohq_debug (mohq_lst *, char *, ...);
+int mohq_process (sip_msg_t *);
+int mohq_retrieve (sip_msg_t *, char *, char *);
+int mohq_send (sip_msg_t *, char *);
+
+#endif /* MOHQ_FUNCS_H */
\ No newline at end of file
diff --git a/modules/mohqueue/mohq_locks.c b/modules/mohqueue/mohq_locks.c
new file mode 100644
index 0000000..d70fd8a
--- /dev/null
+++ b/modules/mohqueue/mohq_locks.c
@@ -0,0 +1,199 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "mohq.h"
+#include "mohq_locks.h"
+
+/**********
+* external functions
+**********/
+
+/**********
+* Change Lock
+*
+* INPUT:
+*   Arg (1) = lock pointer
+*   Arg (2) = exclusive flag
+* OUTPUT: 0 if failed
+**********/
+
+int mohq_lock_change (mohq_lock *plock, int bexcl)
+
+{
+/**********
+* o lock memory
+* o check set type
+* o unlock memory
+**********/
+
+int nret = 0;
+lock_get (plock->plock);
+if (bexcl)
+  {
+  if (plock->lock_cnt == 1)
+    {
+    plock->lock_cnt = -1;
+    nret = 1;
+    }
+  }
+else
+  {
+  if (plock->lock_cnt == -1)
+    {
+    plock->lock_cnt = 1;
+    nret = 1;
+    }
+  }
+lock_release (plock->plock);
+return nret;
+}
+
+/**********
+* Destroy Lock Record
+*
+* INPUT:
+*   Arg (1) = lock pointer
+* OUTPUT: none
+**********/
+
+void mohq_lock_destroy (mohq_lock *plock)
+
+{
+lock_destroy (plock->plock);
+lock_dealloc (plock->plock);
+return;
+}
+
+/**********
+* Init Lock Record
+*
+* INPUT:
+*   Arg (1) = lock pointer
+* OUTPUT: 0 if failed
+**********/
+
+int mohq_lock_init (mohq_lock *plock)
+
+{
+/**********
+* alloc memory and initialize
+**********/
+
+char *pfncname = "mohq_lock_init: ";
+plock->plock = lock_alloc ();
+if (!plock->plock)
+  {
+  LM_ERR ("%sUnable to allocate lock memory!", pfncname);
+  return 0;
+  }
+if (!lock_init (plock->plock))
+  {
+  LM_ERR ("%sUnable to init lock!", pfncname);
+  lock_dealloc (plock->plock);
+  return 0;
+  }
+plock->lock_cnt = 0;
+return -1;
+}
+
+/**********
+* Release Lock
+*
+* INPUT:
+*   Arg (1) = lock pointer
+* OUTPUT: none
+**********/
+
+void mohq_lock_release (mohq_lock *plock)
+
+{
+/**********
+* o lock memory
+* o reduce count
+* o unlock memory
+**********/
+
+lock_get (plock->plock);
+switch (plock->lock_cnt)
+  {
+  case -1:
+    plock->lock_cnt = 0;
+    break;
+  case 0:
+    LM_WARN ("mohq_lock_release: Lock was not set");
+    break;
+  default:
+    plock->lock_cnt--;
+    break;
+  }
+lock_release (plock->plock);
+return;
+}
+
+/**********
+* Set Lock
+*
+* INPUT:
+*   Arg (1) = lock pointer
+*   Arg (2) = exclusive flag
+*   Arg (3) = milliseconds to try; 0 = try once
+* OUTPUT: 0 if failed
+**********/
+
+int mohq_lock_set (mohq_lock *plock, int bexcl, int nms_cnt)
+
+{
+int nret = 0;
+do
+  {
+  /**********
+  * o lock memory
+  * o check set type
+  * o unlock memory
+  * o sleep if failed
+  **********/
+
+  lock_get (plock->plock);
+  if (bexcl)
+    {
+    if (!plock->lock_cnt)
+      {
+      plock->lock_cnt = -1;
+      nret = 1;
+      }
+    }
+  else
+    {
+    if (plock->lock_cnt != -1)
+      {
+      plock->lock_cnt++;
+      nret = 1;
+      }
+    }
+  lock_release (plock->plock);
+  if (!nret)
+    { usleep (1); }
+  }
+while (!nret && --nms_cnt >= 0);
+return nret;
+}
\ No newline at end of file
diff --git a/modules/mohqueue/mohq_locks.h b/modules/mohqueue/mohq_locks.h
new file mode 100644
index 0000000..c3f6ad1
--- /dev/null
+++ b/modules/mohqueue/mohq_locks.h
@@ -0,0 +1,49 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for sip-router, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * The mohqueue module is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef MOHQ_LOCKS_H
+#define MOHQ_LOCKS_H
+
+#include "../../locking.h"
+
+/**********
+* lock record
+**********/
+
+typedef struct
+  {
+  gen_lock_t *plock;
+  int lock_cnt;
+  } mohq_lock;
+
+/**********
+* function declarations
+**********/
+
+int mohq_lock_change (mohq_lock *, int);
+void mohq_lock_destroy (mohq_lock *);
+int mohq_lock_init (mohq_lock *);
+void mohq_lock_release (mohq_lock *);
+int mohq_lock_set (mohq_lock *, int, int);
+
+#endif /* MOHQ_LOCKS_H */
\ No newline at end of file
diff --git a/modules/mqueue/README b/modules/mqueue/README
index ad1c7ba..8d41f8a 100644
--- a/modules/mqueue/README
+++ b/modules/mqueue/README
@@ -128,7 +128,7 @@ modparam("mqueue", "mqueue", "name=qaz")
    4.3. mq_pv_free(queue)
    4.4. mq_size(queue)
 
-4.1. mq_add(queue, key, value)
+4.1.  mq_add(queue, key, value)
 
    Add a new item (key, value) in the queue. If max size of queue is
    exceeded, the oldest one is removed.
@@ -138,7 +138,7 @@ modparam("mqueue", "mqueue", "name=qaz")
 mq_add("myq", "$rU", "call from $fU");
 ...
 
-4.2. mq_fetch(queue)
+4.2.  mq_fetch(queue)
 
    Take oldest item from queue and fill $mqk(queue) and $mqv(queue) pseudo
    variables.
@@ -154,7 +154,7 @@ while(mq_fetch("myq"))
 }
 ...
 
-4.3. mq_pv_free(queue)
+4.3.  mq_pv_free(queue)
 
    Free the item fetched in pseudo-variables. It is optional, a new fetch
    frees the previous values.
@@ -164,7 +164,7 @@ while(mq_fetch("myq"))
 mq_pv_free("myq");
 ...
 
-4.4. mq_size(queue)
+4.4.  mq_size(queue)
 
    Returns the current number of elements in the mqueue.
 
diff --git a/modules/msilo/README b/modules/msilo/README
index 7967573..cec269e 100644
--- a/modules/msilo/README
+++ b/modules/msilo/README
@@ -263,7 +263,7 @@ Chapter 1. Admin Guide
 
    Database URL.
 
-   Default value is "mysql://kamailio:kamailiorw@localhost/kamailio".
+   Default value is "mysql://openser:openserrw@localhost/openser".
 
    Example 1.1. Set the "db_url" parameter
 ...
diff --git a/modules/msrp/README b/modules/msrp/README
index 0d7ca6a..343fd72 100644
--- a/modules/msrp/README
+++ b/modules/msrp/README
@@ -16,7 +16,7 @@ Alex Balashov
 
    <abalashov at evaristesys.com>
 
-   Copyright � 2012 asipto.com
+   Copyright © 2012 asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -158,6 +158,9 @@ Chapter 1. Admin Guide
    The following modules must be loaded before this module:
      * None.
 
+   The following modules are required to make proper use of this module:
+     * tls.
+
 2.2. External Libraries or Applications
 
    The following libraries or applications must be installed before
@@ -256,7 +259,7 @@ modparam("msrp", "use_path_addr", "msrp.kamailio.org:5061")
    4.8. msrp_cmap_save()
    4.9. msrp_cmap_lookup()
 
-4.1. msrp_relay()
+4.1.  msrp_relay()
 
    Relay MSRP frame according to the To-Path. This function has to be
    executed for each MSRP request or reply that has to be forwarded. Note
@@ -272,7 +275,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.2. msrp_reply(code, text [, hdrs])
+4.2.  msrp_reply(code, text [, hdrs])
 
    Send a reply for the current MSRP request, adding optional headers.
 
@@ -287,7 +290,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.3. msrp_is_request()
+4.3.  msrp_is_request()
 
    Return true if the MSRP frame is a request.
 
@@ -304,7 +307,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.4. msrp_is_reply()
+4.4.  msrp_is_reply()
 
    Return true if the MSRP frame is a reply.
 
@@ -321,7 +324,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.5. msrp_set_dst(addr, sock)
+4.5.  msrp_set_dst(addr, sock)
 
    Set destination attributes: addr - target address as MSRP URI; sock -
    local socket to be used (format 'proto:ip:port').
@@ -339,7 +342,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.6. msrp_relay_flags(flags)
+4.6.  msrp_relay_flags(flags)
 
    Set transport layer sending flags for forwarding current MSRP frame;
    flags - a bitmask of flags - 1 (don't create a new connection), 2
@@ -358,7 +361,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.7. msrp_reply_flags(flags)
+4.7.  msrp_reply_flags(flags)
 
    Set transport layer sending flags for replies to the current MSRP
    frame; flags - a bitmask of flags - 1 (don't create a new connection),
@@ -377,7 +380,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.8. msrp_cmap_save()
+4.8.  msrp_cmap_save()
 
    Save details of a MSRP connection upon AUTH request inside the internal
    map table, indexed by session id.
@@ -393,7 +396,7 @@ event_route[msrp:frame-in] {
 }
 ...
 
-4.9. msrp_cmap_lookup()
+4.9.  msrp_cmap_lookup()
 
    Lookup MSRP connection details for current session id.
 
@@ -429,7 +432,7 @@ event_route[msrp:frame-in] {
 
    6.1. msrp.cmaplist
 
-6.1. msrp.cmaplist
+6.1.  msrp.cmaplist
 
    List active MSRP connections.
 
diff --git a/modules/msrp/doc/msrp_admin.xml b/modules/msrp/doc/msrp_admin.xml
index 1d09ac0..0ebd85c 100644
--- a/modules/msrp/doc/msrp_admin.xml
+++ b/modules/msrp/doc/msrp_admin.xml
@@ -65,6 +65,17 @@
 			</listitem>
 			</itemizedlist>
 		</para>
+		<para>
+		The following modules are required to make proper use of this
+		module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>tls</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
 	</section>
 	<section>
 		<title>External Libraries or Applications</title>
diff --git a/modules/msrp/msrp_cmap.c b/modules/msrp/msrp_cmap.c
index f558172..0ae14a6 100644
--- a/modules/msrp/msrp_cmap.c
+++ b/modules/msrp/msrp_cmap.c
@@ -31,6 +31,7 @@
 #include "../../lib/srutils/sruid.h"
 #include "../../rpc.h"
 #include "../../rpc_lookup.h"
+#include "../../sr_module.h"
 
 #include "msrp_netio.h"
 #include "msrp_env.h"
@@ -42,6 +43,7 @@ static sruid_t _msrp_sruid;
 
 extern int msrp_auth_min_expires;
 extern int msrp_auth_max_expires;
+extern int msrp_tls_module_loaded;
 extern str msrp_use_path_addr;
 
 /**
@@ -210,8 +212,8 @@ int msrp_cmap_save(msrp_frame_t *mf)
 	hid = msrp_get_hashid(&_msrp_sruid.uid);	
 	idx = msrp_get_slot(hid, _msrp_cmap_head->mapsize);
 
-	srcaddr.s = sbuf;;
-	if(mf->tcpinfo->rcv->proto==PROTO_TLS)
+	srcaddr.s = sbuf;
+	if (msrp_tls_module_loaded)
 	{
 		memcpy(srcaddr.s, "msrps://", 8);
 		srcaddr.s+=8;
@@ -295,7 +297,7 @@ int msrp_cmap_save(msrp_frame_t *mf)
 	_msrp_cmap_head->cslots[idx].lsize++;
 	lock_release(&_msrp_cmap_head->cslots[idx].lock);
 
-	if(mf->tcpinfo->rcv->proto==PROTO_TLS)
+	if(mf->tcpinfo->rcv->proto==PROTO_TLS || mf->tcpinfo->rcv->proto==PROTO_WSS)
 	{
 		srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE,
 				"Use-Path: msrps://%.*s/%.*s;tcp\r\nExpires: %d\r\n",
diff --git a/modules/msrp/msrp_mod.c b/modules/msrp/msrp_mod.c
index 3204dfc..4b85ffe 100644
--- a/modules/msrp/msrp_mod.c
+++ b/modules/msrp/msrp_mod.c
@@ -69,6 +69,7 @@ int msrp_auth_min_expires = 60;
 int msrp_auth_max_expires = 3600;
 int msrp_timer_interval = 60;
 str msrp_use_path_addr = { 0 };
+int msrp_tls_module_loaded = 0;
 
 static int msrp_frame_received(void *data);
 sip_msg_t *msrp_fake_sipmsg(msrp_frame_t *mf);
@@ -165,7 +166,17 @@ static int mod_init(void)
 			msrp_timer_interval = 60;
 		register_sync_timers(1);
 	}
+
 	sr_event_register_cb(SREV_TCP_MSRP_FRAME, msrp_frame_received);
+
+	if(!module_loaded("tls")) {
+		LM_WARN("\"tls\" module is not loaded. TLS is mandatory for"
+			" MSRP Relays. To comply with RFC 4976 you must use"
+			"  TLS.\n");
+	} else {
+		msrp_tls_module_loaded = 1;
+	}
+
 	return 0;
 }
 
diff --git a/modules/msrp/msrp_vars.c b/modules/msrp/msrp_vars.c
index fdc277a..7e135e5 100644
--- a/modules/msrp/msrp_vars.c
+++ b/modules/msrp/msrp_vars.c
@@ -31,10 +31,13 @@
 #include "../../trim.h"
 #include "../../ut.h"
 #include "../../pvapi.h"
+#include "../../sr_module.h"
 
 #include "msrp_parser.h"
 #include "msrp_vars.h"
 
+extern int msrp_tls_module_loaded;
+
 /**
  *
  */
@@ -273,7 +276,7 @@ int pv_get_msrp(sip_msg_t *msg,  pv_param_t *param, pv_value_t *res)
 				return pv_get_null(msg, param, res);
 			s.s = pv_get_buffer();
 			p = s.s;
-			if(mf->tcpinfo->rcv->proto==PROTO_TLS)
+			if (msrp_tls_module_loaded)
 			{
 				memcpy(p, "msrps://", 8);
 				p+=8;
diff --git a/modules/mtree/README b/modules/mtree/README
index e03b065..c35fb7c 100644
--- a/modules/mtree/README
+++ b/modules/mtree/README
@@ -20,9 +20,9 @@ Juha Heinanen
 
    <jh at tutpro.com>
 
-   Copyright � 2010 Daniel-Constantin Mierla (asipto.com)
+   Copyright (c) 2010 Daniel-Constantin Mierla (asipto.com)
 
-   Copyright � 2011 Juha Heinanen
+   Copyright (c) 2011 Juha Heinanen
      __________________________________________________________________
 
    Table of Contents
@@ -64,6 +64,7 @@ Juha Heinanen
         6. RPC Commands
 
               6.1. mtree.summary
+              6.2. mtree.reload
 
    List of Examples
 
@@ -121,6 +122,7 @@ Chapter 1. Admin Guide
    6. RPC Commands
 
         6.1. mtree.summary
+        6.2. mtree.reload
 
 1. Overview
 
@@ -184,13 +186,17 @@ modparam("mtree", "db_table", "mymtrees")
 
 3.3. mtree (string)
 
-   Definition of memory tree
+   Definition of memory tree with parameters name, dbtable, type, and
+   multi. Name is name of the tree, dbtable is name of dbtable where tree
+   is stored, type is type of tree elements (0 = string, 2 = integer), and
+   multi tells if dbtable can contain more than one tree (0 = one tree, 1
+   = more than one tree identified by tname column).
 
    Default value is "none".
 
    Example 1.3. Set mtree parameter
 ...
-modparam("mtree", "mtree", "name=mytable;dbtable=routes;type=0;")
+modparam("mtree", "mtree", "name=mytree;dbtable=routes;type=0;multi=1")
 ...
 
 3.4. tname_column (string)
@@ -310,7 +316,7 @@ modparam("mtree", "mt_allow_duplicates", 1)
 
    4.1. mt_match(mtree, pv, mode)
 
-4.1. mt_match(mtree, pv, mode)
+4.1.  mt_match(mtree, pv, mode)
 
    Match 'pv' value against 'mtree'. If 'mtree' type is 0 or 2 and value
    of 'mode' is NOT 2, sets a value of the longest matching prefix to
@@ -331,7 +337,7 @@ mt_match("mytree", "$rU", "0");
    5.2. mt_reload
    5.3. mt_summary
 
-5.1. mt_list
+5.1.  mt_list
 
    List content of a tree.
 
@@ -345,7 +351,7 @@ mt_match("mytree", "$rU", "0");
                 _mtname_
                 _empty_line_
 
-5.2. mt_reload
+5.2.  mt_reload
 
    Reload mtree from database.
 
@@ -360,7 +366,7 @@ mt_match("mytree", "$rU", "0");
                 _mtname_
                 _empty_line_
 
-5.3. mt_summary
+5.3.  mt_summary
 
    List usage summary for all trees.
 
@@ -375,9 +381,18 @@ mt_match("mytree", "$rU", "0");
 6. RPC Commands
 
    6.1. mtree.summary
+   6.2. mtree.reload
 
-6.1. mtree.summary
+6.1.  mtree.summary
 
    List usage summary for all trees.
 
    Parameters: none.
+
+6.2.  mtree.reload
+
+   Reload mtree from database to memory.
+
+   Parameters:
+     * _mtree_
+       - name of mtree or empty string meaning all mtrees
diff --git a/modules/mtree/doc/mtree_admin.xml b/modules/mtree/doc/mtree_admin.xml
index 62154f0..0d8fe33 100644
--- a/modules/mtree/doc/mtree_admin.xml
+++ b/modules/mtree/doc/mtree_admin.xml
@@ -97,7 +97,12 @@ modparam("mtree", "db_table", "mymtrees")
 	<section>
 	    <title><varname>mtree</varname> (string)</title>
 	    <para>
-		Definition of memory tree
+		Definition of memory tree with parameters name, dbtable,
+		type, and multi.  Name is name of the tree, dbtable is name
+		of dbtable where tree is stored, type is type of tree elements
+		(0 = string, 2 = integer), and multi tells if dbtable can
+		contain more than one tree (0 = one tree, 1 = more than
+		one tree identified by tname column). 
 	    </para>
 	    <para>
 		<emphasis>
@@ -108,7 +113,7 @@ modparam("mtree", "db_table", "mymtrees")
 		<title>Set <varname>mtree</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("mtree", "mtree", "name=mytable;dbtable=routes;type=0;")
+modparam("mtree", "mtree", "name=mytree;dbtable=routes;type=0;multi=1")
 ...
 </programlisting>
 	    </example>
@@ -428,6 +433,18 @@ mt_match("mytree", "$rU", "0");
 		</para>
 		<para>Parameters: none.</para>
         </section>
+	<section>
+		<title>
+		<function moreinfo="none">mtree.reload</function>
+		</title>
+		<para>
+		Reload mtree from database to memory.
+		</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>_mtree_</para> - name of mtree or empty string meaning all mtrees</listitem>	  
+		</itemizedlist>
+        </section>
     	</section><!-- RPC commands -->
 
 </chapter>
diff --git a/modules/mtree/mtree.c b/modules/mtree/mtree.c
index b823001..2f8550c 100644
--- a/modules/mtree/mtree.c
+++ b/modules/mtree/mtree.c
@@ -98,7 +98,7 @@ int mt_init_list_head(void)
 /**
  *
  */
-m_tree_t* mt_init_tree(str* tname, str *dbtable, int type)
+m_tree_t* mt_init_tree(str* tname, str *dbtable, int type, int multi)
 {
 	m_tree_t *pt = NULL;
 
@@ -111,6 +111,7 @@ m_tree_t* mt_init_tree(str* tname, str *dbtable, int type)
 	memset(pt, 0, sizeof(m_tree_t));
 
 	pt->type = type;
+	pt->multi = multi;
 	pt->tname.s = (char*)shm_malloc((1+tname->len)*sizeof(char));
 	if(pt->tname.s==NULL)
 	{
@@ -156,6 +157,9 @@ int mt_add_to_tree(m_tree_t *pt, str *sp, str *svalue)
 		return -1;
 	}
 
+	LM_DBG("adding to tree <%.*s> of type <%d>\n", pt->tname.len,
+	       pt->tname.s, pt->type);
+
 	if ((pt->type == MT_TREE_IVAL) && (str2sint(svalue, &ivalue) != 0)) {
 		LM_ERR("bad integer string <%.*s>\n", svalue->len, svalue->s);
 		return -1;
@@ -309,7 +313,7 @@ is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch)
 		/* check validity */
 		if(_mt_char_table[(unsigned int)tomatch->s[l]]==255)
 		{
-			LM_DBG("invalid char at %d in [%.*s]\n",
+			LM_DBG("not matching char at %d in [%.*s]\n",
 					l, tomatch->len, tomatch->s);
 			return NULL;
 		}
@@ -720,6 +724,9 @@ int mt_table_spec(char* val)
 		} else if(pit->name.len==4
 				&& strncasecmp(pit->name.s, "type", 4)==0) {
 			str2sint(&pit->body, &tmp.type);
+		} else if(pit->name.len==5
+				&& strncasecmp(pit->name.s, "multi", 5)==0) {
+			str2sint(&pit->body, &tmp.multi);
 		}  else if(pit->name.len==7
 				&& strncasecmp(pit->name.s, "dbtable", 7)==0) {
 			tmp.dbtable = pit->body;
@@ -740,7 +747,11 @@ int mt_table_spec(char* val)
 		LM_ERR("unknown tree type <%d>\n", tmp.type);
 		goto error;
 	}
-
+	if ((tmp.multi != 0) && (tmp.multi != 1)) {
+		LM_ERR("unknown multi value <%d>\n", tmp.multi);
+		goto error;
+	}
+	
 	/* check for same tree */
 	if(_ptree == 0)
 	{
@@ -773,7 +784,8 @@ int mt_table_spec(char* val)
 	{
 		LM_DBG("adding new tname [%s]\n", tmp.tname.s);
 
-		ndl = mt_init_tree(&tmp.tname, &tmp.dbtable, tmp.type);
+		ndl = mt_init_tree(&tmp.tname, &tmp.dbtable, tmp.type,
+				   tmp.multi);
 		if(ndl==NULL)
 		{
 			LM_ERR("no more shm memory\n");
@@ -797,7 +809,8 @@ error:
 	return -1;
 }
 
-m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable, int type)
+m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable, int type,
+		      int multi)
 {
 	m_tree_t *it = NULL;
 	m_tree_t *prev = NULL;
@@ -824,7 +837,7 @@ m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable, int type)
 	{
 		LM_DBG("adding new tname [%s]\n", tname->s);
 
-		ndl = mt_init_tree(tname, dbtable, type);
+		ndl = mt_init_tree(tname, dbtable, type, multi);
 		if(ndl==NULL)
 		{
 			LM_ERR("no more shm memory\n");
diff --git a/modules/mtree/mtree.h b/modules/mtree/mtree.h
index 69d8830..3a33db8 100644
--- a/modules/mtree/mtree.h
+++ b/modules/mtree/mtree.h
@@ -66,6 +66,7 @@ typedef struct _m_tree
 	str tname;
 	str dbtable;
 	int type;
+	int multi;
 	unsigned int nrnodes;
 	unsigned int nritems;
 	unsigned int memsize;
@@ -84,7 +85,7 @@ is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch);
 int mt_match_prefix(struct sip_msg *msg, m_tree_t *pt,
 		    str *tomatch, int mode);
 
-m_tree_t* mt_init_tree(str* tname, str* dbtable, int type);
+m_tree_t* mt_init_tree(str* tname, str* dbtable, int type, int multi);
 void mt_free_tree(m_tree_t *pt);
 int mt_print_tree(m_tree_t *pt);
 void mt_free_node(mt_node_t *pn, int type);
@@ -100,7 +101,7 @@ int mt_defined_trees(void);
 m_tree_t *mt_swap_list_head(m_tree_t *ntree);
 int mt_init_list_head(void);
 m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable,
-		int type);
+		      int type, int multi);
 
 #endif
 
diff --git a/modules/mtree/mtree_mod.c b/modules/mtree/mtree_mod.c
index ee30f79..9099d5b 100644
--- a/modules/mtree/mtree_mod.c
+++ b/modules/mtree/mtree_mod.c
@@ -120,7 +120,7 @@ static struct mi_root* mt_mi_reload(struct mi_root*, void* param);
 static struct mi_root* mt_mi_list(struct mi_root*, void* param);
 static struct mi_root* mt_mi_summary(struct mi_root*, void* param);
 
-static int mt_load_db(str *tname);
+static int mt_load_db(m_tree_t *pt);
 static int mt_load_db_trees();
 
 static cmd_export_t cmds[]={
@@ -291,8 +291,11 @@ static int mod_init(void)
 
 		while(pt!=NULL)
 		{
+		        LM_DBG("loading from tree <%.*s>\n",
+			        pt->tname.len, pt->tname.s);
+
 			/* loading all information from database */
-			if(mt_load_db(&pt->tname)!=0)
+			if(mt_load_db(pt)!=0)
 			{
 				LM_ERR("cannot load info from database\n");
 				goto error1;
@@ -488,9 +491,12 @@ error:
 
 }
 
-static int mt_load_db(str *tname)
+static int mt_load_db(m_tree_t *pt)
 {
 	db_key_t db_cols[3] = {&tprefix_column, &tvalue_column};
+	db_key_t key_cols[1];
+	db_op_t op[1] = {OP_EQ};
+	db_val_t vals[1];
 	str tprefix, tvalue;
 	db1_res_t* db_res = NULL;
 	int i, ret;
@@ -498,16 +504,22 @@ static int mt_load_db(str *tname)
 	m_tree_t *old_tree = NULL; 
 	mt_node_t *bk_head = NULL; 
 
+	key_cols[0] = &tname_column;
+	VAL_TYPE(vals) = DB1_STRING;
+	VAL_NULL(vals) = 0;
+	VAL_STRING(vals) = pt->tname.s;
+
 	if(db_con==NULL)
 	{
 		LM_ERR("no db connection\n");
 		return -1;
 	}
 
-	old_tree = mt_get_tree(tname);
+	old_tree = mt_get_tree(&(pt->tname));
 	if(old_tree==NULL)
 	{
-		LM_ERR("tree definition not found [%.*s]\n", tname->len, tname->s);
+		LM_ERR("tree definition not found [%.*s]\n", pt->tname.len,
+		       pt->tname.s);
 		return -1;
 	}
 	memcpy(&new_tree, old_tree, sizeof(m_tree_t));
@@ -521,7 +533,8 @@ static int mt_load_db(str *tname)
 	}
 
 	if (DB_CAPABILITY(mt_dbf, DB_CAP_FETCH)) {
-		if(mt_dbf.query(db_con, 0, 0, 0, db_cols, 0, 2, 0, 0) < 0)
+		if(mt_dbf.query(db_con, key_cols, op, vals, db_cols, pt->multi,
+				2, 0, 0) < 0)
 		{
 			LM_ERR("Error while querying db\n");
 			return -1;
@@ -539,8 +552,8 @@ static int mt_load_db(str *tname)
 			}
 		}
 	} else {
-		if((ret=mt_dbf.query(db_con, NULL, NULL, NULL, db_cols,
-						0, 2, 0, &db_res))!=0
+		if((ret=mt_dbf.query(db_con, key_cols, op, vals, db_cols,
+						pt->multi, 2, 0, &db_res))!=0
 				|| RES_ROW_N(db_res)<=0 )
 		{
 			mt_dbf.free_result(db_con, db_res);
@@ -697,7 +710,8 @@ static int mt_load_db_trees()
 				LM_ERR("Error - bad values in db\n");
 				continue;
 			}
-			new_tree = mt_add_tree(&new_head, &tname, &db_table, _mt_tree_type);
+			new_tree = mt_add_tree(&new_head, &tname, &db_table,
+					       _mt_tree_type, 0);
 			if(new_tree==NULL)
 			{
 				LM_ERR("New tree cannot be initialized\n");
@@ -797,7 +811,7 @@ static struct mi_root* mt_mi_reload(struct mi_root *cmd_tree, void *param)
 						&& strncmp(pt->tname.s, tname.s, tname.len)==0))
 			{
 				/* re-loading table from database */
-				if(mt_load_db(&pt->tname)!=0)
+				if(mt_load_db(pt)!=0)
 				{
 					LM_ERR("cannot re-load info from database\n");	
 					goto error;
@@ -1046,8 +1060,65 @@ static const char* rpc_mtree_summary_doc[2] = {
 	0
 };
 
+void rpc_mtree_reload(rpc_t* rpc, void* c)
+{
+	str tname = {0, 0};
+	m_tree_t *pt;
+
+	if(db_table.len>0)
+	{
+		/* re-loading all information from database */
+		if(mt_load_db_trees()!=0)
+		{
+			LM_ERR("cannot re-load mtrees from database\n");
+			goto error;
+		}
+	} else {
+		if(!mt_defined_trees())
+		{
+			LM_ERR("empty mtree list\n");
+			goto error;
+		}
+
+		/* read tree name */
+		if (rpc->scan(c, "S", &tname) != 1) {
+			rpc->fault(c, 500, "Failed to get table name parameter");
+			return;
+		}
+
+		pt = mt_get_first_tree();
+
+		while(pt!=NULL)
+		{
+			if(tname.s==NULL
+					|| (tname.s!=NULL && pt->tname.len>=tname.len
+						&& strncmp(pt->tname.s, tname.s, tname.len)==0))
+			{
+				/* re-loading table from database */
+				if(mt_load_db(pt)!=0)
+				{
+					LM_ERR("cannot re-load mtree from database\n");	
+					goto error;
+				}
+			}
+			pt = pt->next;
+		}
+	}
+
+	return;
+
+error:
+	rpc->fault(c, 500, "Mtree Reload Failed");
+}
+
+static const char* rpc_mtree_reload_doc[2] = {
+	"Reload mtrees from database to memory",
+	0
+};
+
 rpc_export_t mtree_rpc[] = {
 	{"mtree.summary", rpc_mtree_summary, rpc_mtree_summary_doc, 0},
+	{"mtree.reload", rpc_mtree_reload, rpc_mtree_reload_doc, 0},
 	{0, 0, 0, 0}
 };
 
diff --git a/modules/nathelper/README b/modules/nathelper/README
index e80b148..e27e29f 100644
--- a/modules/nathelper/README
+++ b/modules/nathelper/README
@@ -55,8 +55,10 @@ Ovidiu Sas
               4.7. sipping_bflag (integer)
               4.8. sipping_from (string)
               4.9. sipping_method (string)
-              4.10. nortpproxy_str (string)
-              4.11. keepalive_timeout (int)
+              4.10. natping_disable_bflag (integer)
+              4.11. nortpproxy_str (string)
+              4.12. keepalive_timeout (int)
+              4.13. udpping_from_path (int)
 
         5. Functions
 
@@ -68,6 +70,7 @@ Ovidiu Sas
               5.6. is_rfc1918(ip_address)
               5.7. add_contact_alias([ip_addr, port, proto])
               5.8. handle_ruri_alias()
+              5.9. set_contact_alias()
 
         6. Exported Pseudo Variables
 
@@ -95,18 +98,21 @@ Ovidiu Sas
    1.7. Set sipping_bflag parameter
    1.8. Set sipping_from parameter
    1.9. Set sipping_method parameter
-   1.10. Set nortpproxy_str parameter
-   1.11. Set keepalive_timeout parameter
-   1.12. fix_nated_contact usage
-   1.13. fix_nated_sdp usage
-   1.14. add_rcv_paramer usage
-   1.15. fix_nated_register usage
-   1.16. add_contact_alias usage
-   1.17. handle_ruri_alias usage
-   1.18. $rr_count usage
-   1.19. $rr_top_count usage
-   1.20. nh_enable_ping usage
-   1.21. @nathelper.rewrite_contact usage
+   1.10. Set natping_disable_bflag parameter
+   1.11. Set nortpproxy_str parameter
+   1.12. Set keepalive_timeout parameter
+   1.13. Set udpping_from_path parameter
+   1.14. fix_nated_contact usage
+   1.15. fix_nated_sdp usage
+   1.16. add_rcv_paramer usage
+   1.17. fix_nated_register usage
+   1.18. add_contact_alias usage
+   1.19. handle_ruri_alias usage
+   1.20. set_contact_alias usage
+   1.21. $rr_count usage
+   1.22. $rr_top_count usage
+   1.23. nh_enable_ping usage
+   1.24. @nathelper.rewrite_contact usage
 
 Chapter 1. Admin Guide
 
@@ -130,8 +136,10 @@ Chapter 1. Admin Guide
         4.7. sipping_bflag (integer)
         4.8. sipping_from (string)
         4.9. sipping_method (string)
-        4.10. nortpproxy_str (string)
-        4.11. keepalive_timeout (int)
+        4.10. natping_disable_bflag (integer)
+        4.11. nortpproxy_str (string)
+        4.12. keepalive_timeout (int)
+        4.13. udpping_from_path (int)
 
    5. Functions
 
@@ -143,6 +151,7 @@ Chapter 1. Admin Guide
         5.6. is_rfc1918(ip_address)
         5.7. add_contact_alias([ip_addr, port, proto])
         5.8. handle_ruri_alias()
+        5.9. set_contact_alias()
 
    6. Exported Pseudo Variables
 
@@ -228,8 +237,10 @@ Chapter 1. Admin Guide
    4.7. sipping_bflag (integer)
    4.8. sipping_from (string)
    4.9. sipping_method (string)
-   4.10. nortpproxy_str (string)
-   4.11. keepalive_timeout (int)
+   4.10. natping_disable_bflag (integer)
+   4.11. nortpproxy_str (string)
+   4.12. keepalive_timeout (int)
+   4.13. udpping_from_path (int)
 
 4.1. force_socket (string)
 
@@ -357,7 +368,21 @@ modparam("nathelper", "sipping_from", "sip:pinger at siphub.net")
 modparam("nathelper", "sipping_method", "INFO")
 ...
 
-4.10. nortpproxy_str (string)
+4.10. natping_disable_bflag (integer)
+
+   What branch flag should be used by the module to disable NAT pings on a
+   per-registration basis. If the given flag is set for a particular
+   registration, then no NAT pings will be sent at all, regardless of any
+   other conditions.
+
+   Default value is -1 (disabled).
+
+   Example 1.10. Set natping_disable_bflag parameter
+...
+modparam("nathelper", "natping_disable_bflag", 8)
+...
+
+4.11. nortpproxy_str (string)
 
    The parameter sets the SDP attribute used by nathelper to mark the
    packet SDP informations have already been mangled.
@@ -370,12 +395,12 @@ Note
 
    Default value is "a=nortpproxy:yes\r\n".
 
-   Example 1.10. Set nortpproxy_str parameter
+   Example 1.11. Set nortpproxy_str parameter
 ...
 modparam("nathelper", "nortpproxy_str", "a=sdpmangled:yes\r\n")
 ...
 
-4.11. keepalive_timeout (int)
+4.12. keepalive_timeout (int)
 
    The parameter sets the interval in secods after which a natted contact
    is removed from location table if it does not reply to SIP keepalives
@@ -389,11 +414,23 @@ modparam("nathelper", "nortpproxy_str", "a=sdpmangled:yes\r\n")
 
    Default value is "0" (feature disabled).
 
-   Example 1.11. Set keepalive_timeout parameter
+   Example 1.12. Set keepalive_timeout parameter
 ...
 modparam("nathelper", "keepalive_timeout", 120)
 ...
 
+4.13. udpping_from_path (int)
+
+   Enable sending UDP pings (keepalives) using raw socket from Path
+   address.
+
+   Default value is "0" (feature disabled).
+
+   Example 1.13. Set udpping_from_path parameter
+...
+modparam("nathelper", "udpping_from_path", 1)
+...
+
 5. Functions
 
    5.1. fix_nated_contact()
@@ -404,6 +441,7 @@ modparam("nathelper", "keepalive_timeout", 120)
    5.6. is_rfc1918(ip_address)
    5.7. add_contact_alias([ip_addr, port, proto])
    5.8. handle_ruri_alias()
+   5.9. set_contact_alias()
 
 5.1. fix_nated_contact()
 
@@ -412,7 +450,7 @@ modparam("nathelper", "keepalive_timeout", 120)
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    BRANCH_ROUTE.
 
-   Example 1.12. fix_nated_contact usage
+   Example 1.14. fix_nated_contact usage
 ...
 if (search("User-Agent: Cisco ATA.*") {fix_nated_contact();};
 ...
@@ -442,7 +480,7 @@ if (search("User-Agent: Cisco ATA.*") {fix_nated_contact();};
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.13. fix_nated_sdp usage
+   Example 1.15. fix_nated_sdp usage
 ...
 if (search("User-Agent: Cisco ATA.*") {fix_nated_sdp("3");};
 ...
@@ -464,7 +502,7 @@ if (search("User-Agent: Cisco ATA.*") {fix_nated_sdp("3");};
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.14. add_rcv_paramer usage
+   Example 1.16. add_rcv_paramer usage
 ...
 add_rcv_param(); # add the parameter to the Contact header
 ....
@@ -484,7 +522,7 @@ add_rcv_param("1"); # add the parameter to the Contact URI
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.15. fix_nated_register usage
+   Example 1.17. fix_nated_register usage
 ...
 fix_nated_register();
 ...
@@ -531,7 +569,7 @@ fix_nated_register();
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    BRANCH_ROUTE, and LOCAL_ROUTE.
 
-   Example 1.16. add_contact_alias usage
+   Example 1.18. add_contact_alias usage
 ...
     if (!is_present_hf("Record-Route")) {
         if (!add_contact_alias("$var(src_ip)", "$Rp", "tcp")) {
@@ -558,7 +596,7 @@ fix_nated_register();
    This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, and
    LOCAL_ROUTE.
 
-   Example 1.17. handle_ruri_alias usage
+   Example 1.19. handle_ruri_alias usage
 ...
     if ($du == "") {
         handle_ruri_alias();
@@ -577,6 +615,27 @@ fix_nated_register();
     };
 ...
 
+5.9. set_contact_alias()
+
+   Adds ;alias=ip~port~transport parameter to contact URI containing
+   received ip, port, and transport protocol. The new contact URI is
+   immediately visible to other modules in the way fix_nated_contact()
+   does it.
+
+   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   BRANCH_ROUTE, and FAILURE_ROUTE.
+
+   Example 1.20. set_contact_alias usage
+...
+    if (!is_present_hf("Record-Route")) {
+        if (!set_contact_alias()) {
+            xlog("L_ERR", "Error in aliasing contact $ct\n");
+            send_reply("400", "Bad request");
+            exit;
+        };
+    };
+...
+
 6. Exported Pseudo Variables
 
    6.1. $rr_count
@@ -586,7 +645,7 @@ fix_nated_register();
 
    Number of Record Routes in received SIP request or reply.
 
-   Example 1.18. $rr_count usage
+   Example 1.21. $rr_count usage
 ...
     $avp(rr_count) = $rr_count;
 ...
@@ -598,7 +657,7 @@ fix_nated_register();
    value of $rr_top_count is 1. If there is no Record Route(s), value of
    $rr_top_count is 0.
 
-   Example 1.19. $rr_top_count usage
+   Example 1.22. $rr_top_count usage
 ...
     if ($rr_count == $avp(rr_count) + $rr_top_count) {
         route(ADD_CONTACT_ALIAS);
@@ -616,7 +675,7 @@ fix_nated_register();
 
    The function takes only one parameter - a number in decimal format.
 
-   Example 1.20. nh_enable_ping usage
+   Example 1.23. nh_enable_ping usage
 ...
 $ kamctl fifo nh_enable_ping 1
 ...
@@ -631,7 +690,7 @@ $ kamctl fifo nh_enable_ping 1
    counted from 1. Only IP:port is rewritten, remaining part are left
    unchanged. Full nameaddr is supported.
 
-   Example 1.21. @nathelper.rewrite_contact usage
+   Example 1.24. @nathelper.rewrite_contact usage
 ...
 $c = @nathelper.rewrite_contact[1];
 ...
diff --git a/modules/nathelper/doc/nathelper_admin.xml b/modules/nathelper/doc/nathelper_admin.xml
index 13f90c3..c80a2d7 100644
--- a/modules/nathelper/doc/nathelper_admin.xml
+++ b/modules/nathelper/doc/nathelper_admin.xml
@@ -328,6 +328,28 @@ modparam("nathelper", "sipping_method", "INFO")
 		</example>
 	</section>
 	<section>
+		<title><varname>natping_disable_bflag</varname> (integer)</title>
+		<para>
+		What branch flag should be used by the module to disable NAT pings
+		on a per-registration basis. If the given flag is set for a
+		particular registration, then no NAT pings will be sent at all,
+		regardless of any other conditions.
+		</para>
+		<para>
+		<emphasis>
+			Default value is -1 (disabled).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>natping_disable_bflag</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("nathelper", "natping_disable_bflag", 8)
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
 		<title><varname>nortpproxy_str</varname> (string)</title>
 		<para>
 		The parameter sets the SDP attribute used by nathelper to mark
@@ -382,6 +404,26 @@ modparam("nathelper", "keepalive_timeout", 120)
 </programlisting>
 		</example>
 	</section>
+	<section id="nathelper.p.udpping_from_path">
+		<title><varname>udpping_from_path</varname> (int)</title>
+		<para>
+		Enable sending UDP pings (keepalives) using raw socket from Path
+		address.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>0</quote> (feature disabled).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>udpping_from_path</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("nathelper", "udpping_from_path", 1)
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 
 
@@ -675,6 +717,36 @@ fix_nated_register();
 		</example>
 	</section>
 
+	<section id="nathelper.set_contact_alias">
+		<title>
+		<function moreinfo="none">set_contact_alias()</function>
+		</title>
+		<para>
+		Adds ;alias=ip~port~transport parameter to contact URI
+		containing received ip, port, and transport protocol. The new
+		contact URI is immediately visible to other modules in the
+		way fix_nated_contact() does it.
+		</para>
+		<para>
+		This function can be used from
+		REQUEST_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE, and FAILURE_ROUTE.
+		</para>
+		<example>
+		<title><function>set_contact_alias</function> usage</title>
+		<programlisting format="linespecific">
+...
+    if (!is_present_hf("Record-Route")) {
+        if (!set_contact_alias()) {
+            xlog("L_ERR", "Error in aliasing contact $ct\n");
+            send_reply("400", "Bad request");
+            exit;
+        };
+    };
+...
+		</programlisting>
+		</example>
+	</section>
+
 	</section>
 
 	<section>
diff --git a/modules/nathelper/nathelper.c b/modules/nathelper/nathelper.c
index 262b758..8e9de7f 100644
--- a/modules/nathelper/nathelper.c
+++ b/modules/nathelper/nathelper.c
@@ -288,6 +288,7 @@ static int nat_uac_test_f(struct sip_msg* msg, char* str1, char* str2);
 static int fix_nated_contact_f(struct sip_msg *, char *, char *);
 static int add_contact_alias_0_f(struct sip_msg *, char *, char *);
 static int add_contact_alias_3_f(struct sip_msg *, char *, char *, char *);
+static int set_contact_alias_f(struct sip_msg* msg, char* str1, char* str2);
 static int handle_ruri_alias_f(struct sip_msg *, char *, char *);
 static int pv_get_rr_count_f(struct sip_msg *, pv_param_t *, pv_value_t *);
 static int pv_get_rr_top_count_f(struct sip_msg *, pv_param_t *, pv_value_t *);
@@ -339,6 +340,7 @@ static const char sbuf[4] = {0, 0, 0, 0};
 static char *force_socket_str = 0;
 static pid_t mypid;
 static int sipping_flag = -1;
+static int natping_disable_flag = -1;
 static int natping_processes = 1;
 
 static str nortpproxy_str = str_init("a=nortpproxy:yes");
@@ -348,6 +350,7 @@ static unsigned short rcv_avp_type = 0;
 static int_str rcv_avp_name;
 
 static char *natping_socket = 0;
+static int udpping_from_path = 0;
 static int raw_sock = -1;
 static unsigned int raw_ip = 0;
 static unsigned short raw_port = 0;
@@ -367,6 +370,9 @@ static cmd_export_t cmds[] = {
 		REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
 	{"add_contact_alias",  (cmd_function)add_contact_alias_3_f,  3,
 		fixup_add_contact_alias, 0,
+		REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
+	{"set_contact_alias",  (cmd_function)set_contact_alias_f,  0,
+		0, 0,
 		REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
 	{"handle_ruri_alias",  (cmd_function)handle_ruri_alias_f,    0,
 		0, 0,
@@ -412,9 +418,11 @@ static param_export_t params[] = {
 	{"sipping_from",          STR_PARAM, &sipping_from.s        },
 	{"sipping_method",        STR_PARAM, &sipping_method.s      },
 	{"sipping_bflag",         INT_PARAM, &sipping_flag          },
+	{"natping_disable_bflag", INT_PARAM, &natping_disable_flag  },
 	{"natping_processes",     INT_PARAM, &natping_processes     },
 	{"natping_socket",        STR_PARAM, &natping_socket        },
 	{"keepalive_timeout",     INT_PARAM, &nh_keepalive_timeout  },
+	{"udpping_from_path",     INT_PARAM, &udpping_from_path     },
 
 	{0, 0, 0}
 };
@@ -627,8 +635,8 @@ mod_init(void)
 	}
 
 	/* create raw socket? */
-	if (natping_socket && natping_socket[0]) {
-		if (get_natping_socket( natping_socket, &raw_ip, &raw_port)!=0)
+	if ((natping_socket && natping_socket[0]) ||  udpping_from_path) {
+		if ((!udpping_from_path) && get_natping_socket( natping_socket, &raw_ip, &raw_port)!=0)
 			return -1;
 		if (init_raw_socket() < 0)
 			return -1;
@@ -670,11 +678,12 @@ mod_init(void)
 			return -1;
 		}
 		if (natping_processes<0) {
-			LM_ERR("bad config - natping_processes must be > 0\n");
+			LM_ERR("bad config - natping_processes must be >= 0\n");
 			return -1;
 		}
 
 		sipping_flag = (sipping_flag==-1)?0:(1<<sipping_flag);
+		natping_disable_flag = (natping_disable_flag==-1)?0:(1<<natping_disable_flag);
 
 		/* set reply function if SIP natping is enabled */
 		if (sipping_flag) {
@@ -843,6 +852,72 @@ fix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2)
 	return 1;
 }
 
+/*
+ * Replaces ip:port pair in the Contact: field with the source address
+ * of the packet.
+ */
+static int
+set_contact_alias_f(struct sip_msg* msg, char* str1, char* str2)
+{
+	char nbuf[MAX_URI_SIZE];
+	str nuri;
+	int br;
+
+	int offset, len;
+	char *buf;
+	contact_t *c;
+	struct lump *anchor;
+	struct sip_uri uri;
+
+	nuri.s = nbuf;
+	nuri.len = MAX_URI_SIZE;
+	if (get_contact_uri(msg, &uri, &c) == -1)
+		return -1;
+	if ((c->uri.s < msg->buf) || (c->uri.s > (msg->buf + msg->len))) {
+		LM_ERR("you can't update contact twice, check your config!\n");
+		return -1;
+	}
+
+	if(uri_add_rcv_alias(msg, &c->uri, &nuri)<0) {
+		LM_DBG("cannot add the alias parameter\n");
+		return -1;
+	}
+
+	br = 1;
+	if(c->uri.s[-1]=='<')
+		br = 0;
+
+
+	len = nuri.len + 2*br;
+	buf = pkg_malloc(len + 1);
+	if (buf == NULL) {
+		LM_ERR("out of pkg memory\n");
+		return -1;
+	}
+	if(br==1) {
+		buf[0] = '<';
+		strncpy(buf+1, nuri.s, nuri.len);
+		buf[len-1] = '>';
+	} else {
+		strncpy(buf, nuri.s, nuri.len);
+	}
+	buf[len] = '\0';
+
+	offset = c->uri.s - msg->buf;
+	anchor = del_lump(msg, offset, c->uri.len, HDR_CONTACT_T);
+	if (anchor == 0)
+		return -1;
+
+	if (insert_new_lump_after(anchor, buf, len, HDR_CONTACT_T) == 0) {
+		pkg_free(buf);
+		return -1;
+	}
+	c->uri.s = buf;
+	c->uri.len = len;
+
+	return 1;
+}
+
 
 #define SALIAS        ";alias="
 #define SALIAS_LEN (sizeof(SALIAS) - 1)
@@ -879,11 +954,8 @@ add_contact_alias_0_f(struct sip_msg* msg, char* str1, char* str2)
     }
 
     /* Compare source ip and port against contact uri */
-    if (((ip = str2ip(&(uri.host))) == NULL)
-#ifdef USE_IPV6
-	&& ((ip = str2ip6(&(uri.host))) == NULL)
-#endif
-	) {
+    if (((ip = str2ip(&(uri.host))) == NULL) &&
+	((ip = str2ip6(&(uri.host))) == NULL)) {
 	LM_DBG("contact uri host is not an ip address\n");
     } else {
 	if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) &&
@@ -1039,9 +1111,7 @@ add_contact_alias_3_f(struct sip_msg* msg, char* _ip, char* _port, char* _proto)
 	return -1;
     }
     if ((str2ip(&ip_str) == NULL)
-#ifdef USE_IPV6
 	&& (str2ip6(&ip_str) == NULL)
-#endif
 	) {
 	LM_ERR("ip param value %s is not valid IP address\n", ip_str.s);
 	return -1;
@@ -1918,6 +1988,53 @@ static int send_raw(const char *buf, int buf_len, union sockaddr_union *to,
 	return sendto(raw_sock, packet, len, 0, (struct sockaddr *) to, sizeof(struct sockaddr_in));
 }
 
+/**
+ * quick function to extract ip:port from path
+ */
+static char *extract_last_path_ip(str path)
+{
+	/* used for raw UDP ping which works only on IPv4 */
+	static char ip[24];
+	char *start = NULL, *end = NULL, *p;
+	int i;
+	int path_depth = 0;
+	int max_path_depth;
+
+	max_path_depth = udpping_from_path - 1;
+
+	if (!path.len || !path.s) return NULL;
+
+	p = path.s;
+	for (i = 0; i < path.len; i++) {
+		if (!strncmp("<sip:", p, 5) && i < path.len - 4) {
+			start = p + 5;
+
+			end = NULL;
+		}
+		if ((*p == ';' || *p == '>') && !end) {
+			end = p;
+			if (max_path_depth) {
+				path_depth++;
+				if (path_depth >= max_path_depth) {
+					break;
+				}
+			}
+		}
+		p++;
+	}
+	if (start && end) {
+		int len = end - start;
+		if (len > sizeof(ip) -1) {
+			return NULL;
+		}
+		memcpy(ip, start, len);
+		ip[len] = '\0';
+		return (char *) ip;
+	} else {
+		return NULL;
+	}
+}
+
 
 static void
 nh_timer(unsigned int ticks, void *timer_idx)
@@ -1936,6 +2053,9 @@ nh_timer(unsigned int ticks, void *timer_idx)
 	unsigned int flags;
 	char proto;
 	struct dest_info dst;
+	char *path_ip_str = NULL;
+	unsigned int path_ip = 0;
+	unsigned short path_port = 0;
 
 	if((*natping_state) == 0)
 		goto done;
@@ -1996,6 +2116,9 @@ nh_timer(unsigned int ticks, void *timer_idx)
 		memcpy( &aorhash, cp, sizeof(aorhash));
 		cp = (char*)cp + sizeof(aorhash);
 
+		if ((flags & natping_disable_flag)) /* always 0 if natping_disable_flag not set */
+			continue;
+
 		/* determin the destination */
 		if ( path.len && (flags&sipping_flag)!=0 ) {
 			/* send to first URI in path */
@@ -2008,6 +2131,20 @@ nh_timer(unsigned int ticks, void *timer_idx)
 				LM_ERR("can't parse contact dst_uri\n");
 				continue;
 			}
+		} else if (path.len && udpping_from_path) {
+			path_ip_str = extract_last_path_ip(path);
+			if (path_ip_str == NULL) {
+				LM_ERR( "ERROR:nathelper:nh_timer: unable to parse path from location\n");
+				continue;
+			}
+			if (get_natping_socket(path_ip_str, &path_ip, &path_port)) {
+				LM_ERR("could not parse path host for udpping_from_path\n");
+				continue;
+			}
+			if (parse_uri(c.s, c.len, &curi) < 0) {
+				LM_ERR("can't parse contact uri\n");
+				continue;
+			}
 		} else {
 			/* send to the contact/received */
 			if (parse_uri(c.s, c.len, &curi) < 0) {
@@ -2051,6 +2188,11 @@ nh_timer(unsigned int ticks, void *timer_idx)
 						 raw_port)<0) {
 				LM_ERR("send_raw failed\n");
 			}
+		} else if (udpping_from_path) {
+			if (send_raw((char*)sbuf, sizeof(sbuf), &dst.to, path_ip, 
+						 path_port)<0) {
+				LM_ERR("send_raw from path failed\n");
+			}
 		} else {
 			if (udp_send(&dst, (char *)sbuf, sizeof(sbuf))<0 ) {
 				LM_ERR("udp_send failed\n");
diff --git a/modules/ndb_redis/doc/ndb_redis_admin.xml b/modules/ndb_redis/doc/ndb_redis_admin.xml
index 51d5706..1f4d6dd 100644
--- a/modules/ndb_redis/doc/ndb_redis_admin.xml
+++ b/modules/ndb_redis/doc/ndb_redis_admin.xml
@@ -59,7 +59,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="ndb_redis.p.server">
 		<title><varname>server</varname> (str)</title>
 		<para>
 			Specify the details to connect to REDIS server. It takes a list of
@@ -98,7 +98,7 @@ modparam("ndb_redis", "server", "name=srvY;unix=/tmp/redis.sock;db=3")
 
 	<section>
 	<title>Functions</title>
-	<section>
+	<section id="ndb_redis.f.redis_cmd">
 	    <title>
 		<function moreinfo="none">redis_cmd(srvname, command, ..., replyid)</function>
 	    </title>
@@ -178,7 +178,7 @@ if(redis_cmd("srvN", "HMGET foo_key field1 field3", "r")) {
 </programlisting>
 	    </example>
 	</section>
-	<section>
+	<section id="ndb_redis.f.redis_free">
 	<title>
 		<function moreinfo="none">redis_free(replyid)</function>
 	</title>
diff --git a/modules/ndb_redis/redis_client.c b/modules/ndb_redis/redis_client.c
index 322cabe..6cf7f6f 100644
--- a/modules/ndb_redis/redis_client.c
+++ b/modules/ndb_redis/redis_client.c
@@ -316,9 +316,10 @@ int redisc_exec(str *srv, str *res, str *cmd, ...)
 	redisc_server_t *rsrv=NULL;
 	redisc_reply_t *rpl;
 	char c;
-	va_list ap;
+	va_list ap, ap2;
 
 	va_start(ap, cmd);
+	va_copy(ap2, ap);
 
 	rsrv = redisc_get_server(srv);
 	if(srv==NULL || cmd==NULL || res==NULL)
@@ -365,7 +366,7 @@ int redisc_exec(str *srv, str *res, str *cmd, ...)
 		}
 		if(redisc_reconnect_server(rsrv)==0)
 		{
-			rpl->rplRedis = redisvCommand(rsrv->ctxRedis, cmd->s, ap);
+			rpl->rplRedis = redisvCommand(rsrv->ctxRedis, cmd->s, ap2);
 		} else {
 			LM_ERR("unable to reconnect to redis server: %.*s\n", srv->len, srv->s);
 			cmd->s[cmd->len] = c;
@@ -374,10 +375,12 @@ int redisc_exec(str *srv, str *res, str *cmd, ...)
 	}
 	cmd->s[cmd->len] = c;
 	va_end(ap);
+	va_end(ap2);
 	return 0;
 
 error_exec:
 	va_end(ap);
+	va_end(ap2);
 	return -1;
 
 }
@@ -483,7 +486,7 @@ redisc_reply_t *redisc_get_reply(str *name)
  */
 int redisc_free_reply(str *name)
 {
-	redisc_reply_t *rpl, *next_rpl;
+	redisc_reply_t *rpl;
 	unsigned int hid;
 
 	if(name==NULL || name->len==0) {
@@ -498,7 +501,6 @@ int redisc_free_reply(str *name)
 
 		if(rpl->hname==hid && rpl->rname.len==name->len
 		   && strncmp(rpl->rname.s, name->s, name->len)==0) {
-			next_rpl = rpl->next;
 			if(rpl->rplRedis) {
 				freeReplyObject(rpl->rplRedis);
 				rpl->rplRedis = NULL;
diff --git a/modules/outbound/README b/modules/outbound/README
index 3a8c558..1f89d4c 100644
--- a/modules/outbound/README
+++ b/modules/outbound/README
@@ -4,7 +4,7 @@ Peter Dunkley
 
    Crocodile RCS Ltd
 
-   Copyright © 2012 Crocodile RCS Ltd
+   Copyright © 2012-2013 Crocodile RCS Ltd
      __________________________________________________________________
 
    Table of Contents
@@ -24,16 +24,17 @@ Peter Dunkley
         3. Parameters
 
               3.1. force_outbound_flag (integer)
+              3.2. force_no_outbound_flag (integer)
 
         4. Functions
         5. MI Commands
 
    List of Examples
 
-   1.1. Compiling Kamailio with STUN support
-   1.2. Edge Proxy Configuration
-   1.3. Registrar Configuration
-   1.4. Set force_outbound_flag parameter
+   1.1. Edge Proxy Configuration
+   1.2. Registrar Configuration
+   1.3. Set force_outbound_flag parameter
+   1.4. Set force_no_outbound_flag parameter
 
 Chapter 1. Admin Guide
 
@@ -52,6 +53,7 @@ Chapter 1. Admin Guide
    3. Parameters
 
         3.1. force_outbound_flag (integer)
+        3.2. force_no_outbound_flag (integer)
 
    4. Functions
    5. MI Commands
@@ -70,12 +72,7 @@ Chapter 1. Admin Guide
 1.1. Edge Proxy Keep-Alives (STUN)
 
    Outbound Edge Proxies MUST support STUN NAT keep-alives on their SIP
-   UDP ports. Kamailio supports this as a compile-time option that is
-   disabled by default.
-
-   Example 1.1. Compiling Kamailio with STUN support
-make FLAVOUR=kamailio cfg STUN=1
-make all
+   UDP ports. Kamailio supports this though the “stun” module.
 
 1.2. Flow Timer
 
@@ -98,7 +95,7 @@ make all
    the Registrar flow timer interval and a little less than the
    “tcp_connection_lifetime”.
 
-   Example 1.2. Edge Proxy Configuration
+   Example 1.1. Edge Proxy Configuration
 #!KAMAILIO
 #
 # Edge proxy configuration
@@ -118,6 +115,7 @@ children=4
 alias="example.com"
 mpath="/usr/lib64/kamailio/modules"
 tcp_connection_lifetime=30 # FLOW_TIMER + 10
+force_rport=yes
 
 
 ####### Modules Section ########
@@ -136,6 +134,7 @@ loadmodule "mi_rpc.so"
 loadmodule "mi_fifo.so"
 loadmodule "textops.so"
 loadmodule "siputils.so"
+loadmodule "stun.so"
 
 # ----------------- setting module-specific parameters ---------------
 
@@ -173,26 +172,31 @@ request_route {
                 if (is_method("INVITE|SUBSCRIBE"))
                         record_route();
 
-                if ($si == "REGISTRAR_IP" && $sp == "REGISTRAR_PORT") {
+                if (@via[2] == "") {
+                        # From client so route to registrar...
+
+                        if ($rU == $null) {
+                                sl_send_reply("484", "Address Incomplete");
+                                exit;
+                        }
+                        remove_hf("Route");
+                        $du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
+                } else {
+                        # From registrar so route using "Route:" headers...
+
                         if (!loose_route()) {
                                 switch($rc) {
                                 case -2:
                                         sl_send_reply("403", "Forbidden");
                                         exit;
                                 default:
+                                        xlog("L_ERR", "in request_route\n");
                                         sl_reply_error();
                                         exit;
                                 }
                         }
 
                         t_on_failure("FAIL_OUTBOUND");
-                } else {
-                        if ($rU == $null) {
-                                sl_send_reply("484", "Address Incomplete");
-                                exit;
-                        }
-                        remove_hf("Route");
-                        $du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
                 }
         }
 
@@ -259,30 +263,160 @@ onreply_route {
         }
 }
 
-failure_route[FAIL_OUTBOUND]{
+failure_route[FAIL_OUTBOUND] {
         if (t_branch_timeout() || !t_branch_replied()) {
                 send_reply("430", "Flow Failed");
         }
 }
 
-   Example 1.3. Registrar Configuration
-...
+   Example 1.2. Registrar Configuration
+MAILIO
+#
+# Registrar configuration
+#
+
+
+####### Global Parameters #########
+
+debug=2
+log_stderror=no
+log_facility=LOG_LOCAL0
+fork=yes
+children=4
+alias="example.com"
+mpath="/usr/lib64/kamailio/modules"
+
+
+####### Modules Section ########
+
 loadmodule "tm.so"
-...
+loadmodule "tmx.so"
+loadmodule "sl.so"
+loadmodule "rr.so"
+loadmodule "pv.so"
+loadmodule "maxfwd.so"
+loadmodule "xlog.so"
+loadmodule "sanity.so"
+loadmodule "ctl.so"
+loadmodule "mi_rpc.so"
+loadmodule "mi_fifo.so"
+loadmodule "textops.so"
+loadmodule "siputils.so"
+loadmodule "usrloc.so"
 loadmodule "registrar.so"
-...
-modparam("tm", "contacts_avp", "tm_contacts")
+
+# ----------------- setting module-specific parameters ---------------
+
+# ----- mi_fifo params -----
+modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
+
+
+# ----- tm params -----
+modparam("tm", "failure_reply_mode", 3)
+modparam("tm", "restart_fr_on_each_reply", 0)
 modparam("tm", "contact_flows_avp", "tm_contact_flows")
-...
+modparam("tm", "contacts_avp", "tm_contacts")
+
+# ----- rr params -----
+modparam("rr", "append_fromtag", 0)
+
+# ----- registrar params -----
 modparam("registrar", "use_path", 1)
-modparam("registrar", "path_mode", 2)
-modparam("registrar", "outbound_mode", 2)
-...
+modparam("registrar", "gruu_enabled", 1)
+modparam("registrar", "outbound_mode", 1)
+
+
+####### Routing Logic ########
+
+request_route {
+        route(REQINIT);
+
+        if (is_method("CANCEL")) {
+                if (t_check_trans()) {
+                        route(RELAY);
+                }
+                exit;
+        }
+
+        route(WITHINDLG);
+
+        t_check_trans();
+
+        remove_hf("Route");
+        if (is_method("INVITE|SUBSCRIBE"))
+                record_route();
+
+        route(REGISTRAR);
+
+        if ($rU==$null) {
+                xlog("L_INFO", "Address Incomplete\n");
+                send_reply("484","Address Incomplete");
+                exit;
+        }
+
+        route(LOCATION);
+}
+
+
+route[RELAY] {
+        if (!t_relay()) {
+                xlog("L_ERR", "t_relay() failed\n");
+                sl_reply_error();
+        }
+        exit;
+}
+
+route[REQINIT] {
+        if (!mf_process_maxfwd_header("10")) {
+                xlog("L_INFO", "Too Many Hops\n");
+                send_reply("483","Too Many Hops");
+                exit;
+        }
+
+        if(!sanity_check("1511", "7"))
+        {
+                xlog("Malformed SIP message from $si:$sp\n");
+                exit;
+        }
+}
+
+route[WITHINDLG] {
+        if (has_totag()) {
+                if (loose_route()) {
+                        if (is_method("NOTIFY")) {
+                                record_route();
+                        }
+                        route(RELAY);
+                } else {
+                        if (is_method("ACK")) {
+                                if (t_check_trans()) {
+                                        route(RELAY);
+                                        exit;
+                                } else {
+                                        exit;
+                                }
+                        }
+                        xlog("L_INFO", "Not Found");
+                        send_reply("404","Not Found");
+                }
+                exit;
+        }
+}
+
+route[REGISTRAR] {
+        if (is_method("REGISTER"))
+        {
+                if (!save("location")) {
+                        xlog("L_ERR", "Unable to save location\n");
+                        sl_reply_error();
+                }
+                exit;
+        }
+}
+
 route[LOCATION] {
-...
         if (!lookup("location")) {
                 $var(rc) = $rc;
-                route(TOVOICEMAIL);
                 t_newtran();
                 switch ($var(rc)) {
                         case -1:
@@ -295,35 +429,49 @@ route[LOCATION] {
                 }
         }
 
-        if (!t_load_contacts()) {
-                send_reply("500", "Server Internal Error");
+        if (!t_load_contacts() || !t_next_contacts()) {
+                xlog("L_ERR", "t_(load|next)_contacts() failed\n");
+                sl_reply_error();
                 exit;
         }
 
-        if (!t_next_contacts()) {
-                send_reply("500", "Server Internal Error");
-                exit;
-        }
+        t_on_failure("FAIL_TRANSACTION");
+        t_on_branch_failure("FAIL-BRANCH");
+        route(RELAY);
+        exit;
+}
 
-        t_on_failure("FAIL_OUTBOUND");
-...
+onreply_route {
+        if (!t_check_trans()) {
+                drop;
+        }
 }
-...
-failure_route[FAIL_OUTBOUND] {
-        if (t_check_status("408|430")) {
-                if (!t_next_contact_flows() && !t_next_contacts()) {
-                        send_reply("500", "Server Internal Error");
+
+failure_route[FAIL_TRANSACTION] {
+        if (!t_check_status("6[0-9][0-9]")) {
+                if (t_next_contacts()) {
+                        t_relay();
                         exit;
                 }
-        } else if (!t_next_contacts()) {
-                send_reply("500", "Server Internal Error");
+        }
+
+        if (t_check_status("430")) {
+                t_reply("480", "Temporarily Unavailable");
                 exit;
         }
+}
 
-        t_on_failure("FAIL_OUTBOUND");
-        route(RELAY);
+event_route[tm:branch-failure:FAIL-BRANCH] {
+        if (t_check_status("403|430")
+                        || (t_branch_timeout() && !t_branch_replied())) {
+                unregister("location", "$tu", "$T_reply_ruid");
+
+                if (t_next_contact_flow()) {
+                        t_on_branch_failure("FAIL-BRANCH");
+                        t_relay();
+                }
+        }
 }
-...
 
 2. Dependencies
 
@@ -335,6 +483,9 @@ failure_route[FAIL_OUTBOUND] {
    The following modules must be loaded before this module:
      * None
 
+   The following modules are required to make proper use of this module:
+     * stun.
+
 2.2. External Libraries or Applications
 
    The following libraries must be installed before running Kamailio with
@@ -344,6 +495,7 @@ failure_route[FAIL_OUTBOUND] {
 3. Parameters
 
    3.1. force_outbound_flag (integer)
+   3.2. force_no_outbound_flag (integer)
 
 3.1. force_outbound_flag (integer)
 
@@ -353,11 +505,24 @@ failure_route[FAIL_OUTBOUND] {
 
    Default value is -1.
 
-   Example 1.4. Set force_outbound_flag parameter
+   Example 1.3. Set force_outbound_flag parameter
 ...
 modparam("outbound", "force_outbound_flag", 1)
 ...
 
+3.2. force_no_outbound_flag (integer)
+
+   A flag which, if set for a request, will force path and rr not to add
+   flow tokens to Path: and Record-Route: headers regardless of the
+   request contents.
+
+   Default value is -1.
+
+   Example 1.4. Set force_no_outbound_flag parameter
+...
+modparam("outbound", "force_no_outbound_flag", 2)
+...
+
 4. Functions
 
    None
diff --git a/modules/outbound/api.h b/modules/outbound/api.h
index 620b745..fc0e8b9 100644
--- a/modules/outbound/api.h
+++ b/modules/outbound/api.h
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -28,7 +28,7 @@
 #include "../../sr_module.h"
 
 typedef int (*encode_flow_token_t)(str *, struct receive_info);
-typedef int (*decode_flow_token_t)(struct receive_info *, str);
+typedef int (*decode_flow_token_t)(struct sip_msg *, struct receive_info **, str);
 typedef int (*use_outbound_t)(struct sip_msg *);
 
 typedef struct ob_binds {
diff --git a/modules/outbound/config.c b/modules/outbound/config.c
new file mode 100644
index 0000000..bcb6fbb
--- /dev/null
+++ b/modules/outbound/config.c
@@ -0,0 +1,43 @@
+/*
+ * $Id$
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file 
+ * \brief Outbound :: Configuration
+ * \ingroup outbound
+ */
+
+#include "../../cfg/cfg.h"
+#include "config.h"
+
+struct cfg_group_outbound default_outbound_cfg = {
+		0,	/* Read only variable to mark if outbound is enabled */
+};
+
+void *outbound_cfg = &default_outbound_cfg;
+
+cfg_def_t outbound_cfg_def[] = {
+	{ "outbound_enabled", CFG_VAR_INT | CFG_ATOMIC | CFG_READONLY,
+	  0, 0, 0, 0,
+	  "If set to one (true) Outbound is enabled." },
+
+	{0, 0, 0, 0, 0, 0}
+};
diff --git a/modules/outbound/config.h b/modules/outbound/config.h
new file mode 100644
index 0000000..0410ff5
--- /dev/null
+++ b/modules/outbound/config.h
@@ -0,0 +1,42 @@
+/*
+ * $Id$
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file 
+ * \brief Outbound :: Configuration Framework support
+ * \ingroup outbound
+ */
+
+
+#ifndef _OUTBOUND_CONFIG_H
+#define _OUTBOUND_CONFIG_H
+
+#include "../../cfg/cfg.h"
+
+struct cfg_group_outbound {
+	int outbound_active;
+};
+
+extern struct cfg_group_outbound default_outbound_cfg;
+extern void *outbound_cfg;
+extern cfg_def_t outbound_cfg_def[];
+
+#endif /* _OUTBOUND_CONFIG_H */
diff --git a/modules/outbound/doc/outbound.xml b/modules/outbound/doc/outbound.xml
index fcf307c..0f770d7 100644
--- a/modules/outbound/doc/outbound.xml
+++ b/modules/outbound/doc/outbound.xml
@@ -23,7 +23,7 @@
 		</author>
 	</authorgroup>
 	<copyright>
-		<year>2012</year>
+		<year>2012-2013</year>
 		<holder>Crocodile RCS Ltd</holder>
 	</copyright>
 	</bookinfo>
diff --git a/modules/outbound/doc/outbound_admin.xml b/modules/outbound/doc/outbound_admin.xml
index 2582caa..de3d659 100644
--- a/modules/outbound/doc/outbound_admin.xml
+++ b/modules/outbound/doc/outbound_admin.xml
@@ -22,15 +22,8 @@
 	<section>
 		<title>Edge Proxy Keep-Alives (STUN)</title>
 		<para>Outbound Edge Proxies MUST support STUN NAT keep-alives
-		on their SIP UDP ports. &kamailio; supports this as a
-		compile-time option that is disabled by default.</para>
-		<example>
-		<title>Compiling &kamailio; with STUN support</title>
-		<programlisting><![CDATA[
-make FLAVOUR=kamailio cfg STUN=1
-make all
-]]></programlisting>
-		</example>
+		on their SIP UDP ports. &kamailio; supports this though the
+		<quote>stun</quote> module.</para>
 	</section>
 	<section>
 		<title>Flow Timer</title>
@@ -76,6 +69,7 @@ children=4
 alias="example.com"
 mpath="/usr/lib64/kamailio/modules"
 tcp_connection_lifetime=30 # FLOW_TIMER + 10
+force_rport=yes
 
 
 ####### Modules Section ########
@@ -94,6 +88,7 @@ loadmodule "mi_rpc.so"
 loadmodule "mi_fifo.so"
 loadmodule "textops.so"
 loadmodule "siputils.so"
+loadmodule "stun.so"
 
 # ----------------- setting module-specific parameters ---------------
 
@@ -131,26 +126,31 @@ request_route {
 		if (is_method("INVITE|SUBSCRIBE"))
 			record_route();
 
-		if ($si == "REGISTRAR_IP" && $sp == "REGISTRAR_PORT") {
+		if (@via[2] == "") {
+			# From client so route to registrar...
+
+			if ($rU == $null) {
+				sl_send_reply("484", "Address Incomplete");
+				exit;
+			}
+			remove_hf("Route");
+			$du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
+		} else {
+			# From registrar so route using "Route:" headers...
+
 			if (!loose_route()) {
 				switch($rc) {
 				case -2:
 					sl_send_reply("403", "Forbidden");
 					exit;
 				default:
+					xlog("L_ERR", "in request_route\n");
 					sl_reply_error();
 					exit;
 				}
 			}
 
 			t_on_failure("FAIL_OUTBOUND");
-		} else {
-			if ($rU == $null) {
-				sl_send_reply("484", "Address Incomplete");
-				exit;
-			}
-			remove_hf("Route");
-			$du = "sip:REGISTRAR_IP:REGISTRAR_PORT";
 		}
 	}
 
@@ -217,7 +217,7 @@ onreply_route {
 	}
 }
 
-failure_route[FAIL_OUTBOUND]{
+failure_route[FAIL_OUTBOUND] {
 	if (t_branch_timeout() || !t_branch_replied()) {
 		send_reply("430", "Flow Failed");
 	}
@@ -227,23 +227,153 @@ failure_route[FAIL_OUTBOUND]{
 	<example>
 	<title>Registrar Configuration</title>
 	<programlisting><![CDATA[
-...
+MAILIO
+#
+# Registrar configuration
+#
+
+
+####### Global Parameters #########
+
+debug=2
+log_stderror=no
+log_facility=LOG_LOCAL0
+fork=yes
+children=4
+alias="example.com"
+mpath="/usr/lib64/kamailio/modules"
+
+
+####### Modules Section ########
+
 loadmodule "tm.so"
-...
+loadmodule "tmx.so"
+loadmodule "sl.so"
+loadmodule "rr.so"
+loadmodule "pv.so"
+loadmodule "maxfwd.so"
+loadmodule "xlog.so"
+loadmodule "sanity.so"
+loadmodule "ctl.so"
+loadmodule "mi_rpc.so"
+loadmodule "mi_fifo.so"
+loadmodule "textops.so"
+loadmodule "siputils.so"
+loadmodule "usrloc.so"
 loadmodule "registrar.so"
-...
-modparam("tm", "contacts_avp", "tm_contacts")
+
+# ----------------- setting module-specific parameters ---------------
+
+# ----- mi_fifo params -----
+modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
+
+
+# ----- tm params -----
+modparam("tm", "failure_reply_mode", 3)
+modparam("tm", "restart_fr_on_each_reply", 0)
 modparam("tm", "contact_flows_avp", "tm_contact_flows")
-...
+modparam("tm", "contacts_avp", "tm_contacts")
+
+# ----- rr params -----
+modparam("rr", "append_fromtag", 0)
+
+# ----- registrar params -----
 modparam("registrar", "use_path", 1)
-modparam("registrar", "path_mode", 2)
-modparam("registrar", "outbound_mode", 2)
-...
+modparam("registrar", "gruu_enabled", 1)
+modparam("registrar", "outbound_mode", 1)
+
+
+####### Routing Logic ########
+
+request_route {
+	route(REQINIT);
+
+	if (is_method("CANCEL")) {
+		if (t_check_trans()) {
+			route(RELAY);
+		}
+		exit;
+	}
+
+	route(WITHINDLG);
+
+	t_check_trans();
+
+	remove_hf("Route");
+	if (is_method("INVITE|SUBSCRIBE"))
+		record_route();
+
+	route(REGISTRAR);
+
+	if ($rU==$null) {
+		xlog("L_INFO", "Address Incomplete\n");
+		send_reply("484","Address Incomplete");
+		exit;
+	}
+
+	route(LOCATION);
+}
+
+
+route[RELAY] {
+	if (!t_relay()) {
+		xlog("L_ERR", "t_relay() failed\n");
+		sl_reply_error();
+	}
+	exit;
+}
+
+route[REQINIT] {
+	if (!mf_process_maxfwd_header("10")) {
+		xlog("L_INFO", "Too Many Hops\n");
+		send_reply("483","Too Many Hops");
+		exit;
+	}
+
+	if(!sanity_check("1511", "7"))
+	{
+		xlog("Malformed SIP message from $si:$sp\n");
+		exit;
+	}
+}
+
+route[WITHINDLG] {
+	if (has_totag()) {
+		if (loose_route()) {
+			if (is_method("NOTIFY")) {
+				record_route();
+			}
+			route(RELAY);
+		} else {
+			if (is_method("ACK")) {
+				if (t_check_trans()) {
+					route(RELAY);
+					exit;
+				} else {
+					exit;
+				}
+			}
+			xlog("L_INFO", "Not Found");
+			send_reply("404","Not Found");
+		}
+		exit;
+	}
+}
+
+route[REGISTRAR] {
+	if (is_method("REGISTER"))
+	{
+		if (!save("location")) {
+			xlog("L_ERR", "Unable to save location\n");
+			sl_reply_error();
+		}
+		exit;
+	}
+}
+
 route[LOCATION] {
-...
 	if (!lookup("location")) {
 		$var(rc) = $rc;
-		route(TOVOICEMAIL);
 		t_newtran();
 		switch ($var(rc)) {
 			case -1:
@@ -256,35 +386,49 @@ route[LOCATION] {
 		}
 	}
 
-	if (!t_load_contacts()) {
-		send_reply("500", "Server Internal Error");
+	if (!t_load_contacts() || !t_next_contacts()) {
+		xlog("L_ERR", "t_(load|next)_contacts() failed\n");
+		sl_reply_error();
 		exit;
 	}
 
-	if (!t_next_contacts()) {
-		send_reply("500", "Server Internal Error");
-		exit;
-	}
+	t_on_failure("FAIL_TRANSACTION");
+	t_on_branch_failure("FAIL-BRANCH");
+	route(RELAY);
+	exit;
+}
 
-	t_on_failure("FAIL_OUTBOUND");
-...
+onreply_route {
+	if (!t_check_trans()) {
+		drop;
+	}
 }
-...
-failure_route[FAIL_OUTBOUND] {
-	if (t_check_status("408|430")) {
-		if (!t_next_contact_flows() && !t_next_contacts()) {
-			send_reply("500", "Server Internal Error");
+
+failure_route[FAIL_TRANSACTION] {
+	if (!t_check_status("6[0-9][0-9]")) {
+		if (t_next_contacts()) {
+			t_relay();
 			exit;
 		}
-	} else if (!t_next_contacts()) {
-		send_reply("500", "Server Internal Error");
+	}
+
+	if (t_check_status("430")) {
+		t_reply("480", "Temporarily Unavailable");
 		exit;
 	}
+}
 
-	t_on_failure("FAIL_OUTBOUND");
-	route(RELAY);
+event_route[tm:branch-failure:FAIL-BRANCH] {
+	if (t_check_status("403|430")
+			|| (t_branch_timeout() && !t_branch_replied())) {
+		unregister("location", "$tu", "$T_reply_ruid");
+
+		if (t_next_contact_flow()) {
+			t_on_branch_failure("FAIL-BRANCH");
+			t_relay();
+		}
+	}
 }
-...
 ]]></programlisting>
 	</example>
 	</section>
@@ -301,6 +445,15 @@ failure_route[FAIL_OUTBOUND] {
 		</listitem>
 		</itemizedlist>
 		</para>
+		<para>
+		The following modules are required to make proper use of this
+		module:
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>stun</emphasis>.</para>
+		</listitem>
+		</itemizedlist>
+		</para>
 	</section>
 
 	<section>
@@ -337,6 +490,25 @@ modparam("outbound", "force_outbound_flag", 1)
 </programlisting>
 		</example>
 	</section>
+
+	<section>
+		<title><varname>force_no_outbound_flag</varname> (integer)</title>
+		<para>A flag which, if set for a request, will force
+		<emphasis>path</emphasis> and <emphasis>rr</emphasis> not
+		to add flow tokens to Path: and Record-Route: headers
+		regardless of the request contents.</para>
+		<para><emphasis>Default value is -1.</emphasis></para>
+		<example>
+		<title>Set <varname>force_no_outbound_flag</varname> parameter
+		</title>
+		<programlisting format="linespecific">
+...
+modparam("outbound", "force_no_outbound_flag", 2)
+...
+</programlisting>
+		</example>
+	</section>
+
 	</section>
 
 	<section>
diff --git a/modules/outbound/ob_mod.c b/modules/outbound/ob_mod.c
index 6318b16..9902e91 100644
--- a/modules/outbound/ob_mod.c
+++ b/modules/outbound/ob_mod.c
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -35,8 +35,10 @@
 #include "../../parser/contact/parse_contact.h"
 #include "../../parser/parse_rr.h"
 #include "../../parser/parse_uri.h"
+#include "../../parser/parse_supported.h"
 
 #include "api.h"
+#include "config.h"
 
 MODULE_VERSION
 
@@ -46,6 +48,7 @@ static int mod_init(void);
 static void destroy(void);
 
 static unsigned int ob_force_flag = (unsigned int) -1;
+static unsigned int ob_force_no_flag = (unsigned int) -1;
 static str ob_key = {0, 0};
 
 static cmd_export_t cmds[]= 
@@ -59,6 +62,7 @@ static cmd_export_t cmds[]=
 static param_export_t params[]=
 {
 	{ "force_outbound_flag",	INT_PARAM, &ob_force_flag },
+	{ "force_no_outbound_flag",     INT_PARAM, &ob_force_no_flag },
 	{ 0, 0, 0 }
 };
 
@@ -86,6 +90,12 @@ static int mod_init(void)
 		return -1;
 	}
 
+	if (ob_force_no_flag != -1 && !flag_in_range(ob_force_no_flag))
+	{
+		LM_ERR("bad no_outbound_flag value (%d)\n", ob_force_no_flag);
+		return -1;
+	}
+
 	if ((ob_key.s = shm_malloc(OB_KEY_LEN)) == NULL)
 	{
 		LM_ERR("Failed to allocate memory for flow-token key\n");
@@ -98,14 +108,19 @@ static int mod_init(void)
 		       "random bytes\n", ob_key.len);
 	}
 
-#ifndef USE_STUN
-	LM_WARN("STUN support not built-in. UDP keep-alive not supported.\n");
-#else
-	if (stun_allow_stun != 1)
+	if (cfg_declare("outbound", outbound_cfg_def, &default_outbound_cfg,
+			cfg_sizeof(outbound), &outbound_cfg))
+	{
+		LM_ERR("declaring config framework variable\n");
+		return -1;
+	}
+	default_outbound_cfg.outbound_active = 1;
+
+	if (!module_loaded("stun"))
 	{
-		LM_WARN("STUN disabled.  UDP keep-alive not supported.\n");
+		LM_WARN("\"stun\" module is not loaded. STUN is required to use"
+			" outbound with UDP.\n");
 	}
-#endif
 
 	return 0;
 }
@@ -195,15 +210,12 @@ int encode_flow_token(str *flow_token, struct receive_info rcv)
 	return 0;
 }
 
-int decode_flow_token(struct receive_info *rcv, str flow_token)
+int decode_flow_token(struct sip_msg *msg, struct receive_info **rcv, str flow_token)
 {
 	int pos = FLOW_TOKEN_START_POS, flow_length, i;
 
-	if (rcv == NULL)
-	{
-		LM_ERR("bad receive_info structure provided\n");
-		return -1;
-	}
+	if (msg->ldv.flow.decoded)
+		goto end;
 
 	if (flow_token.s == NULL)
 	{
@@ -213,7 +225,7 @@ int decode_flow_token(struct receive_info *rcv, str flow_token)
 
 	if (flow_token.len == 0)
 	{
-		LM_ERR("no flow-token found\n");
+		LM_DBG("no flow-token found\n");
 		return -2;
 	}
 
@@ -223,7 +235,7 @@ int decode_flow_token(struct receive_info *rcv, str flow_token)
 	if (flow_length != UNENC_FLOW_TOKEN_MIN_LENGTH
 		&& flow_length != UNENC_FLOW_TOKEN_MAX_LENGTH)
 	{
-		LM_INFO("no flow-token found - bad length (%d)\n", flow_length);
+		LM_DBG("no flow-token found - bad length (%d)\n", flow_length);
 		return -2;
 	}
 
@@ -238,41 +250,44 @@ int decode_flow_token(struct receive_info *rcv, str flow_token)
 		flow_length - FLOW_TOKEN_START_POS,
 		hmac_sha1, NULL) == NULL)
 	{
-		LM_ERR("HMAC-SHA1 failed\n");
+		LM_INFO("HMAC-SHA1 failed\n");
 		return -1;
 	}
 	if (memcmp(unenc_flow_token, &hmac_sha1[SHA1_LENGTH - SHA1_80_LENGTH],
 		SHA1_80_LENGTH) != 0)
 	{
-		LM_ERR("flow-token failed validation\n");
+		LM_INFO("flow-token failed validation\n");
 		return -1;
 	}
 
 	/* Decode protocol information */
 	if (unenc_flow_token[pos] & 0x80)
 	{
-		rcv->dst_ip.af = rcv->src_ip.af = AF_INET6;
-		rcv->dst_ip.len = rcv->src_ip.len = 16;
+		msg->ldv.flow.rcv.dst_ip.af = msg->ldv.flow.rcv.src_ip.af = AF_INET6;
+		msg->ldv.flow.rcv.dst_ip.len = msg->ldv.flow.rcv.src_ip.len = 16;
 	}
 	else
 	{
-		rcv->dst_ip.af = rcv->src_ip.af = AF_INET;
-		rcv->dst_ip.len = rcv->src_ip.len = 4;
+		msg->ldv.flow.rcv.dst_ip.af = msg->ldv.flow.rcv.src_ip.af = AF_INET;
+		msg->ldv.flow.rcv.dst_ip.len = msg->ldv.flow.rcv.src_ip.len = 4;
 	}
-	rcv->proto = unenc_flow_token[pos++] & 0x7f;
+	msg->ldv.flow.rcv.proto = unenc_flow_token[pos++] & 0x7f;
 
 	/* Decode destination address */
-	for (i = 0; i < (rcv->dst_ip.af == AF_INET6 ? 16 : 4); i++)
-		rcv->dst_ip.u.addr[i] = unenc_flow_token[pos++];
-	rcv->dst_port = unenc_flow_token[pos++] << 8;
-	rcv->dst_port |= unenc_flow_token[pos++];
+	for (i = 0; i < (msg->ldv.flow.rcv.dst_ip.af == AF_INET6 ? 16 : 4); i++)
+		msg->ldv.flow.rcv.dst_ip.u.addr[i] = unenc_flow_token[pos++];
+	msg->ldv.flow.rcv.dst_port = unenc_flow_token[pos++] << 8;
+	msg->ldv.flow.rcv.dst_port |= unenc_flow_token[pos++];
 
 	/* Decode source address */
-	for (i = 0; i < (rcv->src_ip.af == AF_INET6 ? 16 : 4); i++)
-		rcv->src_ip.u.addr[i] = unenc_flow_token[pos++];
-	rcv->src_port = unenc_flow_token[pos++] << 8;
-	rcv->src_port |= unenc_flow_token[pos++];
-
+	for (i = 0; i < (msg->ldv.flow.rcv.src_ip.af == AF_INET6 ? 16 : 4); i++)
+		msg->ldv.flow.rcv.src_ip.u.addr[i] = unenc_flow_token[pos++];
+	msg->ldv.flow.rcv.src_port = unenc_flow_token[pos++] << 8;
+	msg->ldv.flow.rcv.src_port |= unenc_flow_token[pos++];
+	msg->ldv.flow.decoded = 1;
+
+end:
+	*rcv = &msg->ldv.flow.rcv;
 	return 0;
 }
 
@@ -325,7 +340,7 @@ static int use_outbound_non_reg(struct sip_msg *msg)
 	param_hooks_t hooks;
 	param_t *params;
 	int ret;
-	struct receive_info rcv;
+	struct receive_info *rcv = NULL;
 
 	/* Check to see if the top Route-URI is me and has a ;ob parameter */
 	if (msg->route
@@ -371,10 +386,10 @@ static int use_outbound_non_reg(struct sip_msg *msg)
 			LM_DBG("found ;ob parameter on Route-URI - outbound"
 				" used\n");
 
-			if (decode_flow_token(&rcv, puri.user) == 0)
+			if (decode_flow_token(msg, &rcv, puri.user) == 0)
 			{
-				if (!ip_addr_cmp(&rcv.src_ip, &msg->rcv.src_ip)
-					|| rcv.src_port != msg->rcv.src_port)
+				if (!ip_addr_cmp(&rcv->src_ip, &msg->rcv.src_ip)
+					|| rcv->src_port != msg->rcv.src_port)
 				{
 					LM_DBG("\"incoming\" request found\n");
 					return 2;
@@ -386,6 +401,14 @@ static int use_outbound_non_reg(struct sip_msg *msg)
 		}
 	}
 
+	/* Check if Supported: outbound is included */
+	if (parse_supported(msg) == 0) {
+                if (!(get_supported(msg) & F_OPTION_TAG_OUTBOUND)) {
+		        LM_DBG("outbound is not supported and thus not used\n");
+		        return 0;
+		}
+	}
+
 	/* Check there is a single Via: */
 	if (!(parse_headers(msg, HDR_VIA2_F, 0) == -1 || msg->via2 == 0
 		|| msg->via2->error != PARSE_OK))
@@ -446,10 +469,18 @@ int use_outbound(struct sip_msg *msg)
 	/* If Outbound is forced return success without any further checks */
 	if (ob_force_flag != -1 && isflagset(msg, ob_force_flag) > 0)
 	{
-		LM_DBG("outbound forced\n");
+		LM_DBG("outbound used by force\n");
 		return 1;
 	}
 
+	/* If Outbound is turned off, return failure without any further
+	   checks */
+	if (ob_force_no_flag != -1 && isflagset(msg, ob_force_no_flag) > 0)
+	{
+		LM_DBG("outbound not used by force\n");
+		return 0;
+	}
+
 	LM_DBG("Analysing %.*s for outbound markers\n",
 		msg->first_line.u.request.method.len,
 		msg->first_line.u.request.method.s);
diff --git a/modules/p_usrloc/README b/modules/p_usrloc/README
index 2220641..6736b43 100644
--- a/modules/p_usrloc/README
+++ b/modules/p_usrloc/README
@@ -275,7 +275,7 @@ Warning
 
    The url to the master database where errors are written to.
 
-   Default value is "mysql://kamailio:kamailiorw@localhost/kamailio"
+   Default value is "mysql://openser:openserrw@localhost/openser"
 
    Example 1.1. Set write_db_url parameter
 ...
@@ -289,7 +289,7 @@ sename")
    from. It is seperated from write access, so for better performance, a
    local replicate can be used for read access.
 
-   Default value is mysql://kamailio:kamailiorw@localhost/kamailio .
+   Default value is mysql://openser:openserrw@localhost/openser .
 
    Example 1.2. Set read_db_url parameter
 ...
@@ -659,9 +659,9 @@ modparam("p_usrloc", "db_mode", 2)
 ...
 
    The URLs are omitted for a better overview, but you can use standard
-   Kamailio database URLs like
-   mysql://kamailio:kamailiorw@localhost/kamailio Databases don't need to
-   be on different hosts, e.g. for testing purposes.
+   Kamailio database URLs like mysql://openser:openserrw@localhost/openser
+   Databases don't need to be on different hosts, e.g. for testing
+   purposes.
 
    This table contains two database groups. The first with id one, and the
    second with the id two.
diff --git a/modules/path/Makefile b/modules/path/Makefile
index a9aa7f1..26d784f 100644
--- a/modules/path/Makefile
+++ b/modules/path/Makefile
@@ -12,4 +12,7 @@ LIBS=
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+
 include ../../Makefile.modules
diff --git a/modules/path/README b/modules/path/README
index 2956bd2..944a5fe 100644
--- a/modules/path/README
+++ b/modules/path/README
@@ -8,7 +8,11 @@ Edited by
 
 Andreas Granig
 
-   Copyright � 2006 Inode GmbH
+Edited by
+
+Richard Fuchs
+
+   Copyright © 2006 Inode GmbH
      __________________________________________________________________
 
    Table of Contents
@@ -33,16 +37,20 @@ Andreas Granig
 
               4.1. add_path()
               4.2. add_path(user)
-              4.3. add_path_received()
-              4.4. add_path_received(user)
+              4.3. add_path(user, parameters)
+              4.4. add_path_received()
+              4.5. add_path_received(user)
+              4.6. add_path_received(user, parameters)
 
    List of Examples
 
    1.1. Set use_received parameter
    1.2. add_path usage
    1.3. add_path(user) usage
-   1.4. add_path_received() usage
-   1.5. add_path_received(user) usage
+   1.4. add_path(user, parameters) usage
+   1.5. add_path_received() usage
+   1.6. add_path_received(user) usage
+   1.7. add_path_received(user, parameters) usage
 
 Chapter 1. Admin Guide
 
@@ -66,8 +74,10 @@ Chapter 1. Admin Guide
 
         4.1. add_path()
         4.2. add_path(user)
-        4.3. add_path_received()
-        4.4. add_path_received(user)
+        4.3. add_path(user, parameters)
+        4.4. add_path_received()
+        4.5. add_path_received(user)
+        4.6. add_path_received(user, parameters)
 
 1. Overview
 
@@ -83,18 +93,18 @@ Chapter 1. Admin Guide
 
 1.1. Path insertion for registrations
 
-   For registrations in a scenario like "[UAC] -> [P1] -> [REG]", the
+   For registrations in a scenario like “[UAC] -> [P1] -> [REG]”, the
    "path" module can be used at the intermediate proxy P1 to insert a Path
    header into the message before forwarding it to the registrar REG. Two
    functions can be used to achieve this:
-     * add_path(...) adds a Path header in the form of "Path:
-       <sip:1.2.3.4;lr>" to the message using the address of the outgoing
+     * add_path(...) adds a Path header in the form of “Path:
+       <sip:1.2.3.4;lr>” to the message using the address of the outgoing
        interface. A port is only added if it's not the default port 5060.
        If a username is passed to the function, it is also included in the
-       Path URI, like "Path: <sip:username at 1.2.3.4;lr>".
+       Path URI, like “Path: <sip:username at 1.2.3.4;lr>”.
      * add_path_received(...) also add a Path header in the same form as
        above, but also adds a parameter indicating the received-URI of the
-       message, like "Path: <sip:1.2.3.4;received=sip:2.3.4.5:1234;lr>".
+       message, like “Path: <sip:1.2.3.4;received=sip:2.3.4.5:1234;lr>”.
        This is especially useful if the proxy does NAT detection and wants
        to pass the NAT'ed address to the registrar.
        If the function is called with a username, it's included in the
@@ -105,12 +115,12 @@ Chapter 1. Admin Guide
    If the NAT'ed address of an UAC is passed to the registrar, the
    registrar routes back subsequent requests using the Path header of the
    registration as Route header of the current request. If the
-   intermediate proxy had inserted a Path header including the "received"
+   intermediate proxy had inserted a Path header including the “received”
    parameter during the registration, this parameter will show up in the
    Route header of the new request as well, allowing the intermediate
    proxy to route to this address instead of the one propagated in the
    Route URI for tunneling through NAT. This behaviour can be activated by
-   setting the module parameter "use_received".
+   setting the module parameter “use_received”.
 
 2. Dependencies
 
@@ -121,7 +131,7 @@ Chapter 1. Admin Guide
 
    The following modules must be loaded before this module:
      * The "rr" module is needed for outbound routing according to the
-       "received" parameter.
+       “received” parameter.
      * The "outbound" module is needed for outbound routing as per RFC
        5626.
 
@@ -137,7 +147,7 @@ Chapter 1. Admin Guide
 
 3.1. use_received (int)
 
-   If set to 1, the "received" parameter of the first Route URI is
+   If set to 1, the “received” parameter of the first Route URI is
    evaluated and used as destination-URI if present.
 
    Default value is 0.
@@ -151,20 +161,22 @@ modparam("path", "use_received", 1)
 
    4.1. add_path()
    4.2. add_path(user)
-   4.3. add_path_received()
-   4.4. add_path_received(user)
+   4.3. add_path(user, parameters)
+   4.4. add_path_received()
+   4.5. add_path_received(user)
+   4.6. add_path_received(user, parameters)
 
-4.1. add_path()
+4.1.  add_path()
 
-   This function is used to insert a Path header in the form "Path:
-   <sip:1.2.3.4;lr>", where "1.2.3.4" is the address of the outgoing
+   This function is used to insert a Path header in the form “Path:
+   <sip:1.2.3.4;lr>”, where “1.2.3.4” is the address of the outgoing
    interface.
 
-   If the "outbound" module was loaded before this module, and outbound is
-   required for this request, the header will be in the form "Path:
-   <sip:flowtoken at 1.2.3.4;lr;ob>", where "flowtoken" is the RFC 5636
+   If the “outbound” module was loaded before this module, and outbound is
+   required for this request, the header will be in the form “Path:
+   <sip:flowtoken at 1.2.3.4;lr;ob>”, where “flowtoken” is the RFC 5636
    flow-token that can be used to identify the source and local address
-   and transport the request was received on, and where "1.2.3.4" is the
+   and transport the request was received on, and where “1.2.3.4” is the
    address of the outgoing interface.
 
    This function can be used from REQUEST_ROUTE.
@@ -177,13 +189,13 @@ if (!add_path()) {
 };
 ...
 
-4.2. add_path(user)
+4.2.  add_path(user)
 
-   This function adds a Path header in the form "Path:
-   <sip:user at 1.2.3.4;lr>".
+   This function adds a Path header in the form “Path:
+   <sip:user at 1.2.3.4;lr>”.
 
    Meaning of the parameters is as follows:
-     * user - The username to be inserted as user part.
+     * user - The username to be inserted as user part. SPVE is supported.
 
    This function can be used from REQUEST_ROUTE.
 
@@ -195,16 +207,38 @@ if (!add_path("loadbalancer")) {
 };
 ...
 
-4.3. add_path_received()
+4.3.  add_path(user, parameters)
+
+   This function adds a Path header in the form “Path:
+   <sip:user at 1.2.3.4;lr>” and appends the given parameters as additional
+   URI parameters.
+
+   Meaning of the parameters is as follows:
+     * user - The username to be inserted as user part. SPVE is supported.
+     * parameters - Additional URI parameters to be appended to the URI.
+       The semicolon separator is added automatically. The script writer
+       is responsible for proper URI escaping. SPVE is supported.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.4. add_path(user, parameters) usage
+...
+if (!add_path("loadbalancer", "ob")) {
+        sl_send_reply("503", "Internal Path Error");
+        ...
+};
+...
+
+4.4.  add_path_received()
 
-   This function adds a Path header in the form "Path:
-   <sip:1.2.3.4;received=sip:2.3.4.5:1234;lr>", setting it's own outgoing
+   This function adds a Path header in the form “Path:
+   <sip:1.2.3.4;received=sip:2.3.4.5:1234;lr>”, setting its own outgoing
    address as domain-part, and the address the request has been received
    from as received-parameter.
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.4. add_path_received() usage
+   Example 1.5. add_path_received() usage
 ...
 if (!add_path_received()) {
         sl_send_reply("503", "Internal Path Error");
@@ -212,19 +246,36 @@ if (!add_path_received()) {
 };
 ...
 
-4.4. add_path_received(user)
+4.5.  add_path_received(user)
 
-   This function adds a Path header in the form "Path:
-   <sip:user at 1.2.3.4;received=sip:2.3.4.5:1234;lr>", setting 'user' as
-   username part of address, it's own outgoing address as domain-part, and
+   This function adds a Path header in the form “Path:
+   <sip:user at 1.2.3.4;received=sip:2.3.4.5:1234;lr>”, setting 'user' as
+   username part of address, its own outgoing address as domain-part, and
    the address the request has been received from as received-parameter.
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.5. add_path_received(user) usage
+   Example 1.6. add_path_received(user) usage
 ...
 if (!add_path_received("inbound")) {
         sl_send_reply("503", "Internal Path Error");
         ...
 };
 ...
+
+4.6.  add_path_received(user, parameters)
+
+   This function adds a Path header in the form “Path:
+   <sip:user at 1.2.3.4;received=sip:2.3.4.5:1234;lr>”, setting 'user' as
+   username part of address, its own outgoing address as domain-part, and
+   the address the request has been received from as received-parameter.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.7. add_path_received(user, parameters) usage
+...
+if (!add_path_received("inbound", "ob")) {
+        sl_send_reply("503", "Internal Path Error");
+        ...
+};
+...
diff --git a/modules/path/doc/path.xml b/modules/path/doc/path.xml
index 46f6b3a..5202a8a 100644
--- a/modules/path/doc/path.xml
+++ b/modules/path/doc/path.xml
@@ -28,6 +28,13 @@
 		    <email>andreas.granig at inode.info</email>
 		</address>
 	    </editor>
+	    <editor>
+		<firstname>Richard</firstname>
+		<surname>Fuchs</surname>
+		<address>
+		    <email>rfuchs at sipwise.com</email>
+		</address>
+	    </editor>
 	</authorgroup>
 	<copyright>
 	    <year>2006</year>
diff --git a/modules/path/doc/path_admin.xml b/modules/path/doc/path_admin.xml
index d68e360..464486a 100644
--- a/modules/path/doc/path_admin.xml
+++ b/modules/path/doc/path_admin.xml
@@ -183,6 +183,7 @@ if (!add_path()) {
 		<listitem>
 			<para>
 			<emphasis>user</emphasis> - The username to be inserted as user part.
+			SPVE is supported.
 			</para>
 		</listitem>
 		</itemizedlist>
@@ -204,11 +205,53 @@ if (!add_path("loadbalancer")) {
 
 	<section>
 		<title>
+		<function moreinfo="none">add_path(user, parameters)</function>
+		</title>
+		<para>
+		This function adds a Path header in the form 
+		<quote>Path: <sip:user at 1.2.3.4;lr></quote> and appends the
+		given <emphasis>parameters</emphasis> as additional URI parameters.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+			<emphasis>user</emphasis> - The username to be inserted as user part.
+			SPVE is supported.
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			<emphasis>parameters</emphasis> - Additional URI parameters to be
+			appended to the URI. The semicolon separator is added automatically.
+			The script writer is responsible for proper URI escaping.
+			SPVE is supported.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title><function>add_path(user, parameters)</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (!add_path("loadbalancer", "ob")) {
+	sl_send_reply("503", "Internal Path Error");
+	...
+};
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title>
 		<function moreinfo="none">add_path_received()</function>
 		</title>
 		<para>
 		This function adds a Path header in the form 
-		<quote>Path: <sip:1.2.3.4;received=sip:2.3.4.5:1234;lr></quote>, setting it's own 
+		<quote>Path: <sip:1.2.3.4;received=sip:2.3.4.5:1234;lr></quote>, setting its own 
 		outgoing address as domain-part, and the address the request has been received from as
 		received-parameter.
 		</para>
@@ -235,7 +278,7 @@ if (!add_path_received()) {
 		<para>
 		This function adds a Path header in the form 
 		<quote>Path: <sip:user at 1.2.3.4;received=sip:2.3.4.5:1234;lr></quote>, setting
-		'user' as username part of address, it's own 
+		'user' as username part of address, its own 
 		outgoing address as domain-part, and the address the request has been received from as
 		received-parameter.
 		</para>
@@ -255,6 +298,33 @@ if (!add_path_received("inbound")) {
 		</example>
 	</section>
 
+	<section>
+		<title>
+		<function moreinfo="none">add_path_received(user, parameters)</function>
+		</title>
+		<para>
+		This function adds a Path header in the form 
+		<quote>Path: <sip:user at 1.2.3.4;received=sip:2.3.4.5:1234;lr></quote>, setting
+		'user' as username part of address, its own 
+		outgoing address as domain-part, and the address the request has been received from as
+		received-parameter.
+		</para>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title><function>add_path_received(user, parameters)</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (!add_path_received("inbound", "ob")) {
+	sl_send_reply("503", "Internal Path Error");
+	...
+};
+...
+</programlisting>
+		</example>
+	</section>
+
 
 	</section>
 
diff --git a/modules/path/path.c b/modules/path/path.c
index b5dc92b..6cf7f8f 100644
--- a/modules/path/path.c
+++ b/modules/path/path.c
@@ -36,6 +36,7 @@
 #include "../../mem/mem.h"
 #include "../../data_lump.h"
 #include "../../parser/parse_param.h"
+#include "../../lib/kcore/strcommon.h"
 #include "../../dset.h"
 
 #include "path.h"
@@ -48,83 +49,72 @@ typedef enum {
 #define PATH_PREFIX		"Path: <sip:"
 #define PATH_PREFIX_LEN		(sizeof(PATH_PREFIX)-1)
 
-#define PATH_LR_PARAM		";lr"
-#define PATH_LR_PARAM_LEN	(sizeof(PATH_LR_PARAM)-1)
+const static char *proto_strings[] = {
+	[PROTO_TCP] = "%3Btransport%3Dtcp",
+	[PROTO_TLS] = "%3Btransport%3Dtls",
+	[PROTO_SCTP] = "%3Btransport%3Dsctp",
+	[PROTO_WS] = "%3Btransport%3Dws",
+	[PROTO_WSS] = "%3Btransport%3Dws",
+};
 
-#define PATH_RC_PARAM		";received="
-#define PATH_RC_PARAM_LEN	(sizeof(PATH_RC_PARAM)-1)
-
-#define PATH_OB_PARAM		";ob"
-#define PATH_OB_PARAM_LEN	(sizeof(PATH_OB_PARAM)-1)
-
-#define	PATH_CRLF		">\r\n"
-#define PATH_CRLF_LEN		(sizeof(PATH_CRLF)-1)
-
-#define ALLOC_AND_COPY_PATH_HDR() \
-	if ((suffix = pkg_malloc(suffix_len)) == NULL) { \
-		LM_ERR("no pkg memory left for suffix\n"); \
-		goto out1; \
-	} \
-	memcpy(suffix, PATH_LR_PARAM, PATH_LR_PARAM_LEN);
-
-static int prepend_path(struct sip_msg* _m, str *user, path_param_t param)
+static int prepend_path(struct sip_msg* _m, str *user, path_param_t param, str *add_params)
 {
 	struct lump *l;
-	char *prefix, *suffix, *crlf;
+	char *prefix, *suffix, *cp;
+	const char *proto_str;
 	int prefix_len, suffix_len;
 	struct hdr_field *hf;
-	str rcv_addr = {0, 0};
-	char *src_ip;
-		
-	prefix = suffix = crlf = 0;
 
-	prefix_len = PATH_PREFIX_LEN + (user->len ? (user->len+1) : 0);
-	prefix = pkg_malloc(prefix_len);
-	if (!prefix) {
-		LM_ERR("no pkg memory left for prefix\n");
+	/* maximum possible length of suffix */
+	suffix_len = strlen(";lr;received=sip::12345%3Btransport%3Dsctp;ob;>\r\n")
+			+ IP_ADDR_MAX_STR_SIZE + (add_params ? add_params->len : 0) + 1;
+
+	cp = suffix = pkg_malloc(suffix_len);
+	if (!suffix) {
+		LM_ERR("no pkg memory left for suffix\n");
 		goto out1;
 	}
-	memcpy(prefix, PATH_PREFIX, PATH_PREFIX_LEN);
-	if (user->len) {
-		memcpy(prefix + PATH_PREFIX_LEN, user->s, user->len);
-		memcpy(prefix + prefix_len - 1, "@", 1);
-	}
+
+	cp += sprintf(cp, ";lr");
 
 	switch(param) {
 	default:
-		suffix_len = PATH_LR_PARAM_LEN;
-		ALLOC_AND_COPY_PATH_HDR();
 		break;
 	case PATH_PARAM_RECEIVED:
-		suffix_len = PATH_LR_PARAM_LEN + PATH_RC_PARAM_LEN;
-		ALLOC_AND_COPY_PATH_HDR();
-		memcpy(suffix + PATH_LR_PARAM_LEN, PATH_RC_PARAM,	
-			PATH_RC_PARAM_LEN);
+		if (_m->rcv.proto < (sizeof(proto_strings) / sizeof(*proto_strings)))
+			proto_str = proto_strings[(unsigned int) _m->rcv.proto];
+		else
+			proto_str = NULL;
+
+		cp += sprintf(cp, ";received=sip:%s:%hu%s", ip_addr2a(&_m->rcv.src_ip),
+				_m->rcv.src_port, proto_str ? : "");
 		break;
 	case PATH_PARAM_OB:
-		suffix_len = PATH_LR_PARAM_LEN + PATH_OB_PARAM_LEN;
-		ALLOC_AND_COPY_PATH_HDR();
-		memcpy(suffix + PATH_LR_PARAM_LEN, PATH_OB_PARAM,
-			PATH_OB_PARAM_LEN);
+		cp += sprintf(cp, ";ob");
 		break;
 	}
 
-	crlf = pkg_malloc(PATH_CRLF_LEN);
-	if (!crlf) {
-		LM_ERR("no pkg memory left for crlf\n");
-		goto out1;
+	if (add_params && add_params->len)
+		cp += sprintf(cp, ";%.*s", add_params->len, add_params->s);
+
+	cp += sprintf(cp, ">\r\n");
+
+	prefix_len = PATH_PREFIX_LEN + (user ? user->len : 0) + 2;
+	prefix = pkg_malloc(prefix_len);
+	if (!prefix) {
+		LM_ERR("no pkg memory left for prefix\n");
+		goto out2;
 	}
-	memcpy(crlf, PATH_CRLF, PATH_CRLF_LEN);
+	if (user && user->len)
+		prefix_len = sprintf(prefix, PATH_PREFIX "%.*s@", user->len, user->s);
+	else
+		prefix_len = sprintf(prefix, PATH_PREFIX);
 
 	if (parse_headers(_m, HDR_PATH_F, 0) < 0) {
 		LM_ERR("failed to parse message for Path header\n");
-		goto out1;
-	}
-	for (hf = _m->headers; hf; hf = hf->next) {
-		if (hf->type == HDR_PATH_T) {
-			break;
-		} 
+		goto out3;
 	}
+	hf = get_hdr(_m, HDR_PATH_T);
 	if (hf)
 		/* path found, add ours in front of that */
 		l = anchor_lump(_m, hf->name.s - _m->buf, 0, 0);
@@ -133,60 +123,24 @@ static int prepend_path(struct sip_msg* _m, str *user, path_param_t param)
 		l = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0);
 	if (!l) {
 		LM_ERR("failed to get anchor\n");
-		goto out1;
+		goto out3;
 	}
 
 	l = insert_new_lump_before(l, prefix, prefix_len, 0);
-	if (!l) goto out1;
+	if (!l) goto out3;
 	l = insert_subst_lump_before(l, SUBST_SND_ALL, 0);
 	if (!l) goto out2;
-	l = insert_new_lump_before(l, suffix, suffix_len, 0);
+	l = insert_new_lump_before(l, suffix, cp - suffix, 0);
 	if (!l) goto out2;
-	if (param == PATH_PARAM_RECEIVED) {
-		/* TODO: agranig: optimize this one! */
-		src_ip = ip_addr2a(&_m->rcv.src_ip);
-		rcv_addr.s = pkg_malloc(6 + IP_ADDR_MAX_STR_SIZE + 22); /* 'sip:<ip>:<port>;transport=sctp'\0 */
-		if(!rcv_addr.s) {
-			LM_ERR("no pkg memory left for receive-address\n");
-			goto out3;
-		}
-		switch (_m->rcv.proto) {
-			case PROTO_UDP:
-				rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 6, "'sip:%s:%u'", src_ip, _m->rcv.src_port);
-				break;
-			case PROTO_TCP:
-				rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 20, "'sip:%s:%u;transport=tcp'", src_ip, _m->rcv.src_port);
-				break;
-			case PROTO_TLS:
-				rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 20, "'sip:%s:%u;transport=tls'", src_ip, _m->rcv.src_port);
-				break;
-			case PROTO_SCTP:
-				rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 21, "'sip:%s:%u;transport=sctp'", src_ip, _m->rcv.src_port);
-				break;
-			case PROTO_WS:
-			case PROTO_WSS:
-				rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 19, "'sip:%s:%u;transport=ws'", src_ip, _m->rcv.src_port);
-				break;
-	    }
-
-		l = insert_new_lump_before(l, rcv_addr.s, rcv_addr.len, 0);
-		if (!l) goto out3;
-	}
-	l = insert_new_lump_before(l, crlf, CRLF_LEN+1, 0);
-	if (!l) goto out4;
-	
+
 	return 1;
-	
-out1:
-	if (prefix) pkg_free(prefix);
-out2:
-	if (suffix) pkg_free(suffix);
-out3:
-	if (rcv_addr.s) pkg_free(rcv_addr.s);
-out4:
-	if (crlf) pkg_free(crlf);
 
-	LM_ERR("failed to insert prefix lump\n");
+out3:
+	pkg_free(prefix);
+out2:
+	pkg_free(suffix);
+out1:
+	LM_ERR("failed to insert Path header\n");
 
 	return -1;
 }
@@ -214,7 +168,7 @@ int add_path(struct sip_msg* _msg, char* _a, char* _b)
 			param = PATH_PARAM_OB;
 	}
 
-	ret = prepend_path(_msg, &user, param);
+	ret = prepend_path(_msg, &user, param, NULL);
 
 	if (user.s != NULL)
 		pkg_free(user.s);
@@ -226,9 +180,17 @@ int add_path(struct sip_msg* _msg, char* _a, char* _b)
  * Prepend own uri to Path header and take care of given
  * user.
  */
-int add_path_usr(struct sip_msg* _msg, char* _usr, char* _b)
+int add_path_usr(struct sip_msg* _msg, char* _usr, char* _parms)
 {
-	return prepend_path(_msg, (str*)_usr, PATH_PARAM_NONE);
+	str user = {0,0};
+	str parms = {0,0};
+
+	if (_usr)
+		get_str_fparam(&user, _msg, (fparam_t *) _usr);
+	if (_parms)
+		get_str_fparam(&parms, _msg, (fparam_t *) _parms);
+
+	return prepend_path(_msg, &user, PATH_PARAM_NONE, &parms);
 }
 
 /*! \brief
@@ -237,17 +199,24 @@ int add_path_usr(struct sip_msg* _msg, char* _usr, char* _b)
  */
 int add_path_received(struct sip_msg* _msg, char* _a, char* _b)
 {
-	str user = {0,0};
-	return prepend_path(_msg, &user, PATH_PARAM_RECEIVED);
+	return prepend_path(_msg, NULL, PATH_PARAM_RECEIVED, NULL);
 }
 
 /*! \brief
  * Prepend own uri to Path header and append received address as
  * "received"-param to that uri and take care of given user.
  */
-int add_path_received_usr(struct sip_msg* _msg, char* _usr, char* _b)
+int add_path_received_usr(struct sip_msg* _msg, char* _usr, char* _parms)
 {
-	return prepend_path(_msg, (str*)_usr, PATH_PARAM_RECEIVED);
+	str user = {0,0};
+	str parms = {0,0};
+
+	if (_usr)
+		get_str_fparam(&user, _msg, (fparam_t *) _usr);
+	if (_parms)
+		get_str_fparam(&parms, _msg, (fparam_t *) _parms);
+
+	return prepend_path(_msg, &user, PATH_PARAM_RECEIVED, &parms);
 }
 
 /*! \brief
@@ -257,6 +226,8 @@ void path_rr_callback(struct sip_msg *_m, str *r_param, void *cb_param)
 {
 	param_hooks_t hooks;
 	param_t *params;
+	static char dst_uri_buf[MAX_URI_SIZE];
+	static str dst_uri;
 			
 	if (parse_params(r_param, CLASS_CONTACT, &hooks, &params) != 0) {
 		LM_ERR("failed to parse route parameters\n");
@@ -264,7 +235,14 @@ void path_rr_callback(struct sip_msg *_m, str *r_param, void *cb_param)
 	}
 
 	if (hooks.contact.received) {
-		if (set_dst_uri(_m, &hooks.contact.received->body) != 0) {
+	        dst_uri.s = dst_uri_buf;
+		dst_uri.len = MAX_URI_SIZE;
+		if (unescape_user(&(hooks.contact.received->body), &dst_uri) < 0) {
+		        LM_ERR("unescaping received failed\n");
+			free_params(params);
+			return;
+		}	    
+		if (set_dst_uri(_m, &dst_uri) != 0) {
 			LM_ERR("failed to set dst-uri\n");
 			free_params(params);
 			return;
diff --git a/modules/path/path_mod.c b/modules/path/path_mod.c
index 15fbc4d..25eda71 100644
--- a/modules/path/path_mod.c
+++ b/modules/path/path_mod.c
@@ -87,11 +87,15 @@ static cmd_export_t cmds[] = {
 	{ "add_path",          (cmd_function)add_path,              0,
 			0,              0,  REQUEST_ROUTE },
 	{ "add_path",          (cmd_function)add_path_usr,          1,
-			fixup_str_null, 0, REQUEST_ROUTE },
+			fixup_spve_null, 0, REQUEST_ROUTE },
+	{ "add_path",          (cmd_function)add_path_usr,          2,
+			fixup_spve_spve, 0, REQUEST_ROUTE },
 	{ "add_path_received", (cmd_function)add_path_received,     0,
 			0,              0, REQUEST_ROUTE },
 	{ "add_path_received", (cmd_function)add_path_received_usr, 1,
-			fixup_str_null, 0, REQUEST_ROUTE },
+			fixup_spve_null, 0, REQUEST_ROUTE },
+	{ "add_path_received", (cmd_function)add_path_received_usr, 2,
+			fixup_spve_spve, 0, REQUEST_ROUTE },
 	{ 0, 0, 0, 0, 0, 0 }
 };
 
@@ -138,7 +142,7 @@ static int mod_init(void)
 	}
 
 	if (ob_load_api(&path_obb) == 0)
-		LM_INFO("Bound path module to outbound module\n");
+		LM_DBG("Bound path module to outbound module\n");
 	else {
 		LM_INFO("outbound module not available\n");
 		memset(&path_obb, 0, sizeof(ob_api_t));
diff --git a/modules/pdb/pdb.c b/modules/pdb/pdb.c
index 6c5db8c..a5f99cd 100644
--- a/modules/pdb/pdb.c
+++ b/modules/pdb/pdb.c
@@ -158,7 +158,7 @@ static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct
 {
 	struct timeval tstart, tnow;
 	struct server_item_t *server;
-	short int carrierid;
+	short int carrierid, *_id;
 	char buf[NETBUFSIZE+1+sizeof(carrierid)];
 	size_t reqlen;
 	int_str avp_val;
@@ -270,7 +270,8 @@ static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct
 				if (recv(server_list->fds[i].fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) { /* do not block - just in case select/poll was wrong */
 					buf[NETBUFSIZE] = '\0';
 					if (strncmp(buf, number.s, number.len) == 0) {
-						carrierid=ntohs(*((short int *)&(buf[reqlen]))); /* convert to host byte order */
+						_id = (short int *)&(buf[reqlen]);
+						carrierid=ntohs(*_id); /* convert to host byte order */
 						goto found;
 					}
 				}
diff --git a/modules/pdt/README b/modules/pdt/README
index 7feb499..9773bfa 100644
--- a/modules/pdt/README
+++ b/modules/pdt/README
@@ -181,7 +181,7 @@ sip:12391001 at mydomain.com  => sip:91001 at alpha.org
 
    URL of the database table to be used.
 
-   Default value is "mysql://kamailio:kamailiorw@localhost/kamailio".
+   Default value is "mysql://openser:openserrw@localhost/openser".
 
    Example 1.2. Set db_url parameter
 ...
diff --git a/modules/permissions/README b/modules/permissions/README
index b05ea08..3ad7325 100644
--- a/modules/permissions/README
+++ b/modules/permissions/README
@@ -14,9 +14,9 @@ Edited by
 
 Juha Heinanen
 
-   Copyright � 2003 Miklos Tirpak
+   Copyright © 2003 Miklos Tirpak
 
-   Copyright � 2006-2008 Juha Heinanen
+   Copyright © 2006-2008 Juha Heinanen
      __________________________________________________________________
 
    Table of Contents
@@ -250,7 +250,7 @@ Chapter 1. Admin Guide
 
    Function for registration checking is called allow_register and the
    algorithm is very similar to the algorithm described in Section 1.1,
-   "Call Routing". The only difference is in the way how pairs are
+   “Call Routing”. The only difference is in the way how pairs are
    created.
 
    Instead of From header field the function uses To header field because
@@ -261,8 +261,8 @@ Chapter 1. Admin Guide
    Thus, pairs used in matching will look like this: (To, Contact 1), (To,
    Contact 2), (To, Contact 3), and so on..
 
-   The algorithm of matching is same as described in Section 1.1, "Call
-   Routing".
+   The algorithm of matching is same as described in Section 1.1, “Call
+   Routing”.
 
 1.3. URI Permissions
 
@@ -291,16 +291,25 @@ Chapter 1. Admin Guide
 
 1.4. Address Permissions
 
-   The module can be used to determine if an address (IP address and port)
-   matches any of the IP subnets stored in cached Kamailio database table.
-   Port 0 in cached database table matches any port. IP address and port
-   to be matched can be either taken from the request
+   The module can be used to determine if an address (IP address and port
+   or DNS domain name) matches any of the addresses stored in cached
+   Kamailio database table. IP addresses in the database table can be
+   subnet addresses. Port 0 in cached database table matches any port. The
+   address and port to be matched can be either taken from the request
    (allow_source_address) or given as pvar arguments (allow_address).
 
-   Addresses stored in cached database table can be grouped together into
-   one or more groups specified by a group identifier (positive integer
-   value, i.e., equal or greater than 1). Group identifier is given as
-   argument to allow_address and allow_source_address functions.
+   Addresses stored in database table can be grouped together into one or
+   more groups specified by a group identifier (positive integer value,
+   i.e., equal or greater than 1). Group identifier is given as argument
+   to allow_address and allow_source_address functions. One group can
+   contain all of the three types of addresses: exact IP address, subnet
+   IP address or DNS domain name.
+
+   When matching is done if the argument is an IP, it is tried to be
+   matched with the records from that group that are of type exact IP or
+   subnet. If the argument is not an IP it is tried to be matched with the
+   records that are DNS domain names. No DNS lookup is performed, only
+   strict matching.
 
    As a side effect of matching the address, non-NULL tag (see tag_col
    module parameter) is added as value to peer_tag AVP if peer_tag_avp
@@ -378,7 +387,7 @@ Chapter 1. Admin Guide
    specify full pathname then the directory in which is the main config
    file is located will be used.
 
-   Default value is "permissions.allow".
+   Default value is “permissions.allow”.
 
    Example 1.1. Set default_allow_file parameter
 ...
@@ -391,7 +400,7 @@ modparam("permissions", "default_allow_file", "/etc/permissions.allow")
    without parameters. If you don't specify full pathname then the
    directory in which the main config file is located will be used.
 
-   Default value is "permissions.deny".
+   Default value is “permissions.deny”.
 
    Example 1.2. Set default_deny_file parameter
 ...
@@ -426,7 +435,7 @@ Note
 
    Including leading dot.
 
-   Default value is ".allow".
+   Default value is “.allow”.
 
    Example 1.4. Set allow_suffix parameter
 ...
@@ -443,7 +452,7 @@ Note
 
    Including leading dot.
 
-   Default value is ".deny".
+   Default value is “.deny”.
 
    Example 1.5. Set deny_suffix parameter
 ...
@@ -455,7 +464,7 @@ modparam("permissions", "deny_suffix", ".deny")
    This is URL of the database to be used to store rules used by
    allow_trusted function.
 
-   Default value is "NULL".
+   Default value is “NULL”.
 
    Example 1.6. Set db_url parameter
 ...
@@ -464,10 +473,10 @@ modparam("permissions", "db_url", "dbdriver://username:password@dbhost/dbname")
 
 3.7. address_table (string)
 
-   Name of database table containing IP subnet information used by
-   allow_address and allow_source_address functions.
+   Name of database table containing IP subnets and DNS domain names used
+   by allow_address and allow_source_address functions.
 
-   Default value is "address".
+   Default value is “address”.
 
    Example 1.7. Set address_table parameter
 ...
@@ -479,7 +488,7 @@ modparam("permissions", "address_table", "addr")
    Name of address table column containing group identifier of the
    address.
 
-   Default value is "grp".
+   Default value is “grp”.
 
    Example 1.8. Set grp_col parameter
 ...
@@ -490,7 +499,7 @@ modparam("permissions", "grp_col", "group_id")
 
    Name of address table column containing IP address part of the address.
 
-   Default value is "ip_addr".
+   Default value is “ip_addr”.
 
    Example 1.9. Set ip_addr_col parameter
 ...
@@ -502,7 +511,7 @@ modparam("permissions", "ip_addr_col", "ip_address")
    Name of address table column containing network mask of the address.
    Possible values are 0-32.
 
-   Default value is "mask".
+   Default value is “mask”.
 
    Example 1.10. Set mask_col parameter
 ...
@@ -513,7 +522,7 @@ modparam("permissions", "mask_col", "subnet_length")
 
    Name of address table column containing port part of the address.
 
-   Default value is "port".
+   Default value is “port”.
 
    Example 1.11. Set port_col parameter
 ...
@@ -537,7 +546,7 @@ modparam("permissions", "db_mode", 1)
    Name of database table containing matching rules used by allow_trusted
    function.
 
-   Default value is "trusted".
+   Default value is “trusted”.
 
    Example 1.13. Set trusted_table parameter
 ...
@@ -549,7 +558,7 @@ modparam("permissions", "trusted_table", "pbx")
    Name of trusted table column containing source IP address that is
    matched against source IP address of received request.
 
-   Default value is "src_ip".
+   Default value is “src_ip”.
 
    Example 1.14. Set source_col parameter
 ...
@@ -560,10 +569,10 @@ modparam("permissions", "source_col", "source_ip_address")
 
    Name of trusted table column containing transport protocol that is
    matched against transport protocol of received request. Possible values
-   that can be stored in proto_col are "any", "udp", "tcp", "tls", "sctp",
-   and "none". Value "any" matches always and value "none" never.
+   that can be stored in proto_col are “any”, “udp”, “tcp”, “tls”, “sctp”,
+   and “none”. Value “any” matches always and value “none” never.
 
-   Default value is "proto".
+   Default value is “proto”.
 
    Example 1.15. Set proto_col parameter
 ...
@@ -575,7 +584,7 @@ modparam("permissions", "proto_col", "transport")
    Name of trusted table column containing regular expression that is
    matched against From URI.
 
-   Default value is "from_pattern".
+   Default value is “from_pattern”.
 
    Example 1.16. Set from_col parameter
 ...
@@ -588,7 +597,7 @@ modparam("permissions", "from_col", "regexp")
    added as value to peer_tag AVP if peer_tag AVP has been defined and if
    the address or peer matches.
 
-   Default value is "tag".
+   Default value is “tag”.
 
    Example 1.17. Set tag_col parameter
 ...
@@ -600,7 +609,7 @@ modparam("permissions", "tag_col", "peer_tag")
    If defined, the AVP will be set as side effect of allow_trusted() call
    to not NULL tag column value of the matching peer.
 
-   Default value is "undefined".
+   Default value is “undefined”.
 
    Example 1.18. Set peer_tag_avp parameter
 ...
@@ -613,7 +622,7 @@ modparam("permissions", "peer_tag_avp", "$avp(i:707)")
    adds the tags of all matches to the avp. In addition the return value
    of allow_trusted() is the number of matches.
 
-   Default value is "0".
+   Default value is “0”.
 
    Example 1.19. Set peer_tag_mode parameter
 ...
@@ -634,10 +643,10 @@ modparam("permissions", "peer_tag_mode", "1")
    4.10. allow_address_group(addr, port)
    4.11. allow_trusted([src_ip_pvar, proto_pvar])
 
-4.1. allow_routing()
+4.1.  allow_routing()
 
    Returns true if all pairs constructed as described in Section 1.1,
-   "Call Routing" have appropriate permissions according to the
+   “Call Routing” have appropriate permissions according to the
    configuration files. This function uses default configuration files
    specified in default_allow_file and default_deny_file.
 
@@ -650,10 +659,10 @@ if (allow_routing()) {
 };
 ...
 
-4.2. allow_routing(basename)
+4.2.  allow_routing(basename)
 
    Returns true if all pairs constructed as described in Section 1.1,
-   "Call Routing" have appropriate permissions according to the
+   “Call Routing” have appropriate permissions according to the
    configuration files given as parameters.
 
    Meaning of the parameters is as follows:
@@ -673,10 +682,10 @@ if (allow_routing("basename")) {
 };
 ...
 
-4.3. allow_routing(allow_file,deny_file)
+4.3.  allow_routing(allow_file,deny_file)
 
    Returns true if all pairs constructed as described in Section 1.1,
-   "Call Routing" have appropriate permissions according to the
+   “Call Routing” have appropriate permissions according to the
    configuration files given as parameters.
 
    Meaning of the parameters is as follows:
@@ -698,10 +707,10 @@ if (allow_routing("rules.allow", "rules.deny")) {
 };
 ...
 
-4.4. allow_register(basename)
+4.4.  allow_register(basename)
 
    The function returns true if all pairs constructed as described in
-   Section 1.2, "Registration Permissions" have appropriate permissions
+   Section 1.2, “Registration Permissions” have appropriate permissions
    according to the configuration files given as parameters.
 
    Meaning of the parameters is as follows:
@@ -726,10 +735,10 @@ if (method=="REGISTER") {
 };
 ...
 
-4.5. allow_register(allow_file, deny_file)
+4.5.  allow_register(allow_file, deny_file)
 
    The function returns true if all pairs constructed as described in
-   Section 1.2, "Registration Permissions" have appropriate permissions
+   Section 1.2, “Registration Permissions” have appropriate permissions
    according to the configuration files given as parameters.
 
    Meaning of the parameters is as follows:
@@ -756,10 +765,10 @@ if (method=="REGISTER") {
 };
 ...
 
-4.6. allow_uri(basename, pvar)
+4.6.  allow_uri(basename, pvar)
 
-   Returns true if the pair constructed as described in Section 1.3, "URI
-   Permissions" have appropriate permissions according to the
+   Returns true if the pair constructed as described in Section 1.3, “URI
+   Permissions” have appropriate permissions according to the
    configuration files specified by the parameter.
 
    Meaning of the parameter is as follows:
@@ -783,13 +792,17 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 };
 ...
 
-4.7. allow_address(group_id, ip_addr_pvar, port_pvar)
+4.7.  allow_address(group_id, ip_addr_pvar, port_pvar)
 
-   Returns true if IP address and port given as values of pvar arguments
-   belonging to a group given as group_id argument matches an IP subnet
-   found in cached address table. Cached address table entry containing
-   port value 0 matches any port. group_id argument can be an integer
-   string or a pseudo variable.
+   Returns true if address and port given as values of pvar arguments
+   belonging to a group given as group_id argument matches an IP subnet or
+   a DNS domain name found in cached address table. When matching is done
+   if the argument is an IP, it is tried to be matched with the records
+   from that group that are of type exact IP or subnet. If the argument is
+   not an IP it is tried to be matched with the records that are DNS
+   domain names. No DNS lookup is performed, only strict matching. Cached
+   address table entry containing port value 0 matches any port. group_id
+   argument can be an integer string or a pseudo variable.
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
@@ -800,13 +813,15 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 if (!allow_address("1", "$si", "$sp")) {
         sl_send_reply("403", "Forbidden");
 };
-// Check IP address/port stored in AVPs i:704/i:705 is in group 2
-if (!allow_address("2", "$avp(i:704)", "$avp(i:705)") {
+// Check address/port stored in AVPs src_adr/src_port is in group 2
+$avp(dst_adr) = "sipdomain.com";
+$avp(dst_port) = "0";
+if (!allow_address("2", "$avp(dst_adr)", "$avp(dst_port)") {
         sl_send_reply("403", "Forbidden");
 };
 ...
 
-4.8. allow_source_address([group_id])
+4.8.  allow_source_address([group_id])
 
    Equal to allow_address(group_id, "$si", "$sp"). If 'group_id' is
    missing, the function is equal to allow_address("1", "$si", "$sp").
@@ -822,7 +837,7 @@ if (!allow_source_address("1")) {
 };
 ...
 
-4.9. allow_source_address_group()
+4.9.  allow_source_address_group()
 
    Checks if source address/port is found in cached address or subnet
    table in any group. If yes, returns that group. If not returns -1. Port
@@ -839,7 +854,7 @@ if ($var(group) != -1) {
 };
 ...
 
-4.10. allow_address_group(addr, port)
+4.10.  allow_address_group(addr, port)
 
    Checks if address/port is found in cached address or subnet table in
    any group. If yes, returns that group. If not returns -1. Port value 0
@@ -857,13 +872,13 @@ if ($var(group) != -1) {
 };
 ...
 
-4.11. allow_trusted([src_ip_pvar, proto_pvar])
+4.11.  allow_trusted([src_ip_pvar, proto_pvar])
 
    Checks based either on request's source address and transport protocol
    or source address and transport protocol given in pvar arguments, and
    From URI of request if request can be trusted without authentication.
-   Returns 1 if a match is found as described in Section 1.5, "Trusted
-   Requests" and -1 otherwise. If a match is found and peer_tag_avp has
+   Returns 1 if a match is found as described in Section 1.5, “Trusted
+   Requests” and -1 otherwise. If a match is found and peer_tag_avp has
    been defined, adds a non-NULL tag column value of the matching peer to
    AVP peer_tag_avp.
 
@@ -893,7 +908,7 @@ if (allow_trusted("$si", "$proto")) {
    5.5. trusted_dump
    5.6. allow_uri
 
-5.1. address_reload
+5.1.  address_reload
 
    Causes permissions module to re-read the contents of address database
    table into cache memory. In cache memory the entries are for
@@ -902,35 +917,35 @@ if (allow_trusted("$si", "$proto")) {
 
    Parameters: none
 
-5.2. address_dump
+5.2.  address_dump
 
    Causes permissions module to dump contents of cache memory address
    table.
 
    Parameters: none
 
-5.3. subnet_dump
+5.3.  subnet_dump
 
    Causes permissions module to dump contents of cache memory subnet
    table.
 
    Parameters: none
 
-5.4. trusted_reload
+5.4.  trusted_reload
 
    Causes permissions module to re-read the contents of trusted table into
    cache memory.
 
    Parameters: none
 
-5.5. trusted_dump
+5.5.  trusted_dump
 
    Causes permissions module to dump contents of trusted table from cache
    memory.
 
    Parameters: none
 
-5.6. allow_uri
+5.6.  allow_uri
 
    Tests if (URI, Contact) pair is allowed according to allow/deny files.
    The files must already have been loaded by Kamailio.
@@ -951,7 +966,7 @@ if (allow_trusted("$si", "$proto")) {
    6.5. trustedReload
    6.6. trustedDump
 
-6.1. addressReload
+6.1.  addressReload
 
    Causes permissions module to re-read the contents of address database
    table into cache memory. In cache memory the entries are for
@@ -960,21 +975,21 @@ if (allow_trusted("$si", "$proto")) {
 
    Parameters: none
 
-6.2. addressDump
+6.2.  addressDump
 
    Causes permissions module to dump contents of cache memory address
    table. (Not the subnet table).
 
    Parameters: none
 
-6.3. subnetDump
+6.3.  subnetDump
 
    Causes permissions module to dump contents of cache memory subnet
    table.
 
    Parameters: none
 
-6.4. testUri basename uri contact
+6.4.  testUri basename uri contact
 
    Tests if (URI, Contact) pair is allowed according to allow/deny files.
    The files must already have been loaded by Kamailio.
@@ -986,14 +1001,14 @@ if (allow_trusted("$si", "$proto")) {
      * URI - URI to be tested
      * Contact - Contact to be tested
 
-6.5. trustedReload
+6.5.  trustedReload
 
    Causes permissions module to re-read the contents of trusted table into
    cache memory.
 
    Parameters: none
 
-6.6. trustedDump
+6.6.  trustedDump
 
    Causes permissions module to dump contents of trusted table from cache
    memory.
diff --git a/modules/permissions/address.c b/modules/permissions/address.c
index 501d59e..6dc3275 100644
--- a/modules/permissions/address.c
+++ b/modules/permissions/address.c
@@ -54,6 +54,11 @@ struct subnet **subnet_table;        /* Ptr to current subnet table */
 struct subnet *subnet_table_1;       /* Ptr to subnet table 1 */
 struct subnet *subnet_table_2;       /* Ptr to subnet table 2 */
 
+struct domain_name_list ***domain_list_table;        /* Ptr to current domain name table */
+static struct domain_name_list **domain_list_table_1;       /* Ptr to domain name table 1 */
+static struct domain_name_list **domain_list_table_2;       /* Ptr to domain name table 2 */
+
+
 static db1_con_t* db_handle = 0;
 static db_func_t perm_dbf;
 
@@ -62,12 +67,8 @@ static inline ip_addr_t *strtoipX(str *ips)
 	/* try to figure out INET class */
 	if(ips->s[0] == '[' || memchr(ips->s, ':', ips->len)!=NULL)
 	{
-#ifdef USE_IPV6
 		/* IPv6 */
 		return str2ip6(ips);
-#else
-		return 0;
-#endif
 	} else {
 		/* IPv4 */
 		return str2ip(ips);
@@ -87,6 +88,7 @@ int reload_address_table(void)
 
 	struct addr_list **new_hash_table;
 	struct subnet *new_subnet_table;
+	struct domain_name_list **new_domain_name_table;
 	int i;
 	unsigned int gid;
 	unsigned int port;
@@ -129,6 +131,16 @@ int reload_address_table(void)
 		new_subnet_table = subnet_table_1;
 	}
 
+	/* Choose new domain name table */
+	if (*domain_list_table == domain_list_table_1) {
+		empty_domain_name_table(domain_list_table_2);
+		new_domain_name_table = domain_list_table_2;
+	} else {
+		empty_domain_name_table(domain_list_table_1);
+		new_domain_name_table = domain_list_table_1;
+	}
+
+
 	row = RES_ROWS(res);
 
 	LM_DBG("Number of rows in address table: %d\n", RES_ROW_N(res));
@@ -173,42 +185,55 @@ int reload_address_table(void)
 		port = VAL_UINT(val + 3);
 		tagv = VAL_NULL(val + 4)?NULL:(char *)VAL_STRING(val + 4);
 		ipa = strtoipX(&ips);
-		if(ipa==NULL)
+		if ( ipa==NULL )
 		{
-			LM_DBG("failure during IP address conversion\n");
-			goto dberror;
-		}
-		if(ipa->af == AF_INET6) {
-			if(mask<0 || mask>128) {
-				LM_DBG("failure during IP mask check for v6\n");
-				goto dberror;
-			}
+			LM_DBG("Domain name: %.*s\n", ips.len, ips.s);
+		//	goto dberror;
 		} else {
-			if(mask<0 || mask>32) {
-				LM_DBG("failure during IP mask check for v4\n");
-				goto dberror;
+			if(ipa->af == AF_INET6) {
+				if(mask<0 || mask>128) {
+					LM_DBG("failure during IP mask check for v6\n");
+					goto dberror;
+				}
+			} else {
+				if(mask<0 || mask>32) {
+					LM_DBG("failure during IP mask check for v4\n");
+					goto dberror;
+				}
 			}
 		}
-		if((ipa->af==AF_INET6 && mask==128) || (ipa->af==AF_INET && mask==32))
-		{
-			if (addr_hash_table_insert(new_hash_table, gid, ipa, port, tagv)
-					== -1) {
-				LM_ERR("hash table problem\n");
-				perm_dbf.free_result(db_handle, res);
-				return -1;
+
+		if ( ipa ) {
+			if ( (ipa->af==AF_INET6 && mask==128) || (ipa->af==AF_INET && mask==32) ) {
+				if (addr_hash_table_insert(new_hash_table, gid, ipa, port, tagv)
+						== -1) {
+					LM_ERR("hash table problem\n");
+					perm_dbf.free_result(db_handle, res);
+					return -1;
+				}
+				LM_DBG("Tuple <%u, %s, %u> inserted into address hash table\n",
+						gid, ips.s, port);
+			} else {
+				if (subnet_table_insert(new_subnet_table, gid, ipa, mask,
+								port, tagv)
+							== -1) {
+					LM_ERR("subnet table problem\n");
+					perm_dbf.free_result(db_handle, res);
+					return -1;
+				}
+				LM_DBG("Tuple <%u, %s, %u, %u> inserted into subnet table\n",
+						gid, ips.s, port, mask);
 			}
-			LM_DBG("Tuple <%u, %s, %u> inserted into address hash table\n",
-					gid, ips.s, port);
 		} else {
-			if (subnet_table_insert(new_subnet_table, gid, ipa, mask,
+				if (domain_name_table_insert(new_domain_name_table, gid, &ips,
 							port, tagv)
 						== -1) {
-				LM_ERR("subnet table problem\n");
+				LM_ERR("domain name table problem\n");
 				perm_dbf.free_result(db_handle, res);
 				return -1;
 			}
-			LM_DBG("Tuple <%u, %s, %u, %u> inserted into subnet table\n",
-					gid, ips.s, port, mask);
+			LM_DBG("Tuple <%u, %s, %u> inserted into domain name table\n",
+					gid, ips.s, port);
 		}
 	}
 
@@ -216,6 +241,7 @@ int reload_address_table(void)
 
 	*addr_hash_table = new_hash_table;
 	*subnet_table = new_subnet_table;
+	*domain_list_table = new_domain_name_table;
 
 	LM_DBG("address table reloaded successfully.\n");
 
@@ -227,6 +253,31 @@ dberror:
 	return -1;
 }
 
+/*
+ * Wrapper to reload addr table from mi or rpc
+ * we need to open the db_handle
+ */
+int reload_address_table_cmd(void)
+{
+	if (!db_handle) {
+		db_handle = perm_dbf.init(&db_url);
+		if (!db_handle) {
+			LM_ERR("unable to connect database\n");
+			return -1;
+		}
+	}
+
+	if (reload_address_table () != 1) {
+		perm_dbf.close(db_handle);
+		db_handle = 0;
+		return -1;
+	}
+
+	perm_dbf.close(db_handle);
+	db_handle = 0;
+
+	return 1;
+}
 
 /*
  * Initialize data structures
@@ -293,6 +344,21 @@ int init_addresses(void)
 
 	*subnet_table = subnet_table_1;
 
+	domain_list_table_1 = new_domain_name_table();
+	if (!domain_list_table_1) goto error;
+
+	domain_list_table_2 = new_domain_name_table();
+	if (!domain_list_table_2) goto error;
+
+	domain_list_table = (struct domain_name_list ***)shm_malloc(sizeof(struct domain_name_list **));
+	if (!domain_list_table) {
+		LM_ERR("no more shm memory for domain name table\n");
+		goto error;
+	}
+
+	*domain_list_table = domain_list_table_1;
+
+
 	if (reload_address_table() == -1) {
 		LM_CRIT("reload of address table failed\n");
 		goto error;
@@ -328,6 +394,20 @@ error:
 		shm_free(subnet_table);
 		subnet_table = 0;
 	}
+
+	if (domain_list_table_1) {
+		free_domain_name_table(domain_list_table_1);
+		domain_list_table_1 = 0;
+	}
+	if (domain_list_table_2) {
+		free_domain_name_table(domain_list_table_2);
+		domain_list_table_2 = 0;
+	}
+	if (domain_list_table) {
+		shm_free(domain_list_table);
+		domain_list_table = 0;
+	}
+
 	perm_dbf.close(db_handle);
 	db_handle = 0;
 	return -1;
@@ -361,6 +441,9 @@ void clean_addresses(void)
 	if (subnet_table_1) free_subnet_table(subnet_table_1);
 	if (subnet_table_2) free_subnet_table(subnet_table_2);
 	if (subnet_table) shm_free(subnet_table);
+	if (domain_list_table_1) free_domain_name_table(domain_list_table_1);
+	if (domain_list_table_2) free_domain_name_table(domain_list_table_2);
+	if (domain_list_table) shm_free(domain_list_table);
 }
 
 
@@ -387,10 +470,8 @@ int allow_address(struct sip_msg* _msg, char* _addr_group, char* _addr_sp,
 		LM_ERR("cannot get value of address pvar\n");
 		return -1;
 	}
-	if ( (ipa=strtoipX(&ips)) == NULL ) {
-		LM_ERR("failed to convert IP address string to in_addr\n");
-		return -1;
-	}
+
+	ipa=strtoipX(&ips);
 
 	if (_port_sp==NULL
 			|| (fixup_get_ivalue(_msg, (gparam_p)_port_sp, (int*)&port) < 0)) {
@@ -398,10 +479,14 @@ int allow_address(struct sip_msg* _msg, char* _addr_group, char* _addr_sp,
 		return -1;
 	}
 
-	if (match_addr_hash_table(*addr_hash_table, addr_group, ipa, port) == 1)
-		return 1;
-	else
-		return match_subnet_table(*subnet_table, addr_group, ipa, port);
+	if ( ipa ) {
+		if (match_addr_hash_table(*addr_hash_table, addr_group, ipa, port) == 1)
+			return 1;
+		else
+			return match_subnet_table(*subnet_table, addr_group, ipa, port);
+	} else {
+		return match_domain_name_table(*domain_list_table, addr_group, &ips, port);
+	}
 }
 
 
@@ -479,30 +564,35 @@ int allow_address_group(struct sip_msg* _msg, char* _addr, char* _port)
 		LM_ERR("cannot get value of address pvar\n");
 		return -1;
 	}
-	if ( (ipa=strtoipX(&ips)) == NULL ) {
-		LM_ERR("failed to convert IP address string to in_addr\n");
-		return -1;
-	}
-
 	if (_port==NULL
 			|| (fixup_get_ivalue(_msg, (gparam_p)_port, (int*)&port) < 0)) {
 		LM_ERR("cannot get value of port pvar\n");
 		return -1;
 	}
 
-	LM_DBG("looking for <%.*s, %u> in address table\n",
-			ips.len, ips.s, port);
-	group = find_group_in_addr_hash_table(*addr_hash_table,
-			ipa, port);
-	LM_DBG("Found address in group <%d>\n", group);
+	ipa=strtoipX(&ips);
 
-	if (group != -1) return group;
+	if ( ipa ) {
+		LM_DBG("looking for <%.*s, %u> in address table\n",
+				ips.len, ips.s, port);
+		group = find_group_in_addr_hash_table(*addr_hash_table,
+				ipa, port);
+		LM_DBG("Found address in group <%d>\n", group);
+
+		if (group != -1) return group;
+
+		LM_DBG("looking for <%.*s, %u> in subnet table\n",
+				ips.len, ips.s, port);
+		group = find_group_in_subnet_table(*subnet_table,
+				ipa, port);
+		LM_DBG("Found a match of subnet in group <%d>\n", group);
+	} else {
+		LM_DBG("looking for <%.*s, %u> in domain_name table\n",
+				ips.len, ips.s, port);
+		group = find_group_in_domain_name_table(*domain_list_table,
+				&ips, port);
+		LM_DBG("Found a match of domain_name in group <%d>\n", group);
+	}
 
-	LM_DBG("looking for <%.*s, %u> in subnet table\n",
-			ips.len, ips.s, port);
-	group = find_group_in_subnet_table(*subnet_table,
-			&_msg->rcv.src_ip,
-			_msg->rcv.src_port);
-	LM_DBG("Found a match of subnet in group <%d>\n", group);
 	return group;
 }
diff --git a/modules/permissions/address.h b/modules/permissions/address.h
index e501204..ef72253 100644
--- a/modules/permissions/address.h
+++ b/modules/permissions/address.h
@@ -34,6 +34,9 @@ extern struct addr_list ***addr_hash_table;
 extern struct subnet **subnet_table; 
 
 
+/* Pointer to current domain name table */
+extern struct domain_name_list ***domain_list_table;
+
 /*
  * Initialize data structures
  */
@@ -52,6 +55,11 @@ int mi_init_addresses(void);
  */
 int reload_address_table(void);
 
+/*
+ * Wrapper to reload addr table from mi or rpc
+ * we need to open the db_handle
+ */
+int reload_address_table_cmd(void);
 
 /*
  * Close connections and release memory
diff --git a/modules/permissions/doc/permissions_admin.xml b/modules/permissions/doc/permissions_admin.xml
index 216203a..8e2ba00 100644
--- a/modules/permissions/doc/permissions_admin.xml
+++ b/modules/permissions/doc/permissions_admin.xml
@@ -169,19 +169,29 @@
 		<title>Address Permissions</title>
 		<para>
 		The module can be used to determine if an address (IP
-		address and port) matches any of the IP subnets
-		stored in cached &kamailio; database table.
-		Port 0 in cached database table matches any port.  IP
+		address and port or DNS domain name) matches any of the
+		addresses stored in cached &kamailio; database table.
+		IP addresses in the database table can be subnet addresses.
+		Port 0 in cached database table matches any port. The
 		address and port to be matched can be either taken from
 		the request (allow_source_address) or given as pvar
 		arguments (allow_address).
 		</para>
 		<para>
-		Addresses stored in cached database table can be grouped
+		Addresses stored in database table can be grouped
 		together into one or more groups specified by a group
 		identifier (positive integer value, i.e., equal or greater than 1).
 		Group identifier is given as argument to allow_address and
 		allow_source_address functions.
+		One group can contain all of the three types of addresses: exact 
+		IP address, subnet IP address or DNS domain name.
+		</para>
+		<para>
+		When matching is done if the argument is an IP, it is tried to
+		be matched with the records from that group that are of type exact
+		IP or subnet. If the argument is not an IP it is tried to be matched
+		with the records that are DNS domain names. No DNS lookup is performed,
+		only strict matching.
 		</para>
 		<para>
 		As a side effect of matching the address, non-NULL tag 
@@ -424,7 +434,7 @@ modparam("permissions", "db_url", "&exampledb;")
 	<section>
 		<title><varname>address_table</varname> (string)</title>
 		<para>
-		Name of database table containing IP subnet information used by
+		Name of database table containing IP subnets and DNS domain names used by
 		<function moreinfo="none">allow_address</function> and
                 <function moreinfo="none">allow_source_address</function>
                 functions.
@@ -947,9 +957,15 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 		<function moreinfo="none">allow_address(group_id, ip_addr_pvar, port_pvar)</function>
 		</title>
 		<para>
-		Returns true if IP address and port given as values of pvar
+		Returns true if address and port given as values of pvar
 		arguments belonging to a group given as group_id argument
-		matches an IP subnet found in cached address table.
+		matches an IP subnet or a DNS domain name found in cached
+		address table.
+		When matching is done if the argument is an IP, it is tried to
+		be matched with the records from that group that are of type exact
+		IP or subnet. If the argument is not an IP it is tried to be matched
+		with the records that are DNS domain names. No DNS lookup is performed,
+		only strict matching.
 		Cached address table entry containing port value 0
 		matches any port.  group_id argument can be an integer
 		string or a pseudo variable. 
@@ -966,8 +982,10 @@ if (allow_uri("basename", "$avp(i:705)") {  // Check URI stored in $avp(i:705)
 if (!allow_address("1", "$si", "$sp")) {
 	sl_send_reply("403", "Forbidden");
 };
-// Check IP address/port stored in AVPs i:704/i:705 is in group 2
-if (!allow_address("2", "$avp(i:704)", "$avp(i:705)") {
+// Check address/port stored in AVPs src_adr/src_port is in group 2
+$avp(dst_adr) = "sipdomain.com";
+$avp(dst_port) = "0";
+if (!allow_address("2", "$avp(dst_adr)", "$avp(dst_port)") {
 	sl_send_reply("403", "Forbidden");
 };
 ...
@@ -1070,7 +1088,7 @@ if ($var(group) != -1) {
 		Source address and transport protocol given in pvar
 		arguments must be in string format.  Valid transport
 		protocol values are (ignoring case) "any", "udp, "tcp", "tls",
-		and "sctp".
+		"ws", "wss" and "sctp".
 		</para>
 		<para>
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
diff --git a/modules/permissions/hash.c b/modules/permissions/hash.c
index c32853a..3a16581 100644
--- a/modules/permissions/hash.c
+++ b/modules/permissions/hash.c
@@ -830,3 +830,220 @@ void free_subnet_table(struct subnet* table)
 
 	shm_free(table);
 }
+
+/*
+ * Create and initialize a domain_name table
+ */
+struct domain_name_list** new_domain_name_table(void)
+{
+	struct domain_name_list** ptr;
+
+	/* Initializing hash tables and hash table variable */
+	ptr = (struct domain_name_list **)shm_malloc
+		(sizeof(struct domain_name_list*) * PERM_HASH_SIZE);
+	if (!ptr) {
+		LM_ERR("no shm memory for hash table\n");
+		return 0;
+	}
+
+	memset(ptr, 0, sizeof(struct domain_name*) * PERM_HASH_SIZE);
+	return ptr;
+}
+
+
+/* 
+ * Free contents of hash table, it doesn't destroy the
+ * hash table itself
+ */
+void empty_domain_name_table(struct domain_name_list **table)
+{
+	int i;
+	struct domain_name_list *np, *next;
+
+	for (i = 0; i < PERM_HASH_SIZE; i++) {
+		np = table[i];
+		while (np) {
+			next = np->next;
+			shm_free(np);
+			np = next;
+		}
+		table[i] = 0;
+	}
+}
+
+/*
+ * Release all memory allocated for a hash table
+ */
+void free_domain_name_table(struct domain_name_list** table)
+{
+	if (!table)
+		return;
+
+	empty_domain_name_table(table);
+	shm_free(table);
+}
+
+
+/* 
+ * Check if an entry exists in hash table that has given group, domain_name, and
+ * port.  Port 0 in hash table matches any port.
+ */
+int match_domain_name_table(struct domain_name_list** table, unsigned int group,
+		str *domain_name, unsigned int port)
+{
+	struct domain_name_list *np;
+	avp_value_t val;
+
+	for (np = table[perm_hash(*domain_name)]; np != NULL; np = np->next) {
+		if ( (np->grp == group)
+				&& ((np->port == 0) || (np->port == port))
+				&& np->domain.len == domain_name->len
+				&& strncmp(np->domain.s, domain_name->s, domain_name->len)==0 ) {
+
+			if (tag_avp.n && np->tag.s) {
+				val.s = np->tag;
+				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
+					LM_ERR("setting of tag_avp failed\n");
+					return -1;
+				}
+			}
+
+			return 1;
+		}
+	}
+
+	return -1;
+}
+
+
+/* 
+ * Check if an domain_name/port entry exists in hash table in any group.
+ * Returns first group in which ip_addr/port is found.
+ * Port 0 in hash table matches any port. 
+ */
+int find_group_in_domain_name_table(struct domain_name_list** table,
+		str *domain_name, unsigned int port)
+{
+	struct domain_name_list *np;
+
+	for (np = table[perm_hash(*domain_name)]; np != NULL; np = np->next) {
+		if ( ((np->port == 0) || (np->port == port))
+				&& np->domain.len == domain_name->len
+				&& strncmp(np->domain.s, domain_name->s, domain_name->len)==0 ) {
+			return np->grp;
+		}
+	}
+
+	return -1;
+}
+
+
+/* 
+ * Add <grp, domain_name, port> into hash table
+ */
+int domain_name_table_insert(struct domain_name_list** table, unsigned int grp,
+		str *domain_name, unsigned int port, char *tagv)
+{
+	struct domain_name_list *np;
+	unsigned int hash_val;
+	int len;
+
+	len = sizeof(struct domain_name_list) + domain_name->len;
+	if(tagv!=NULL)
+		len += strlen(tagv) + 1;
+
+	np = (struct domain_name_list *) shm_malloc(len);
+	if (np == NULL) {
+		LM_ERR("no shm memory for table entry\n");
+		return -1;
+	}
+
+	memset(np, 0, len);
+
+	np->grp = grp;
+	np->domain.s = (char*)np + sizeof(struct domain_name_list);
+	memcpy(np->domain.s, domain_name->s, domain_name->len);
+	np->domain.len = domain_name->len;
+	np->port = port;
+	if(tagv!=NULL) {
+		np->tag.s = (char*)np + sizeof(struct domain_name_list) + domain_name->len;
+		np->tag.len = strlen(tagv);
+		strcpy(np->tag.s, tagv);
+	}
+
+	LM_DBG("** Added domain name: %.*s\n", np->domain.len, np->domain.s);
+
+	hash_val = perm_hash(*domain_name);
+	np->next = table[hash_val];
+	table[hash_val] = np;
+
+	return 1;
+}
+
+
+/*! \brief
+ * RPC: Print addresses stored in hash table 
+ */
+int domain_name_table_rpc_print(struct domain_name_list** table, rpc_t* rpc, void* c)
+{
+	int i;
+	void* th;
+	void* ih;
+	struct domain_name_list *np;
+
+
+	if (rpc->add(c, "{", &th) < 0)
+	{
+		rpc->fault(c, 500, "Internal error creating rpc");
+		return -1;
+	}
+
+	for (i = 0; i < PERM_HASH_SIZE; i++) {
+		np = table[i];
+		while (np) {
+			if(rpc->struct_add(th, "dd{", 
+					"table", i,
+					"group", np->grp,
+					"item", &ih) < 0) {
+				rpc->fault(c, 500, "Internal error creating rpc ih");
+				return -1;
+			}
+
+			if(rpc->struct_add(ih, "S", "domain_name", &np->domain) < 0) {
+				rpc->fault(c, 500, "Internal error creating rpc data (ip)");
+				return -1;
+			}
+			if(rpc->struct_add(ih, "ds", "port",  np->port,
+						"tag",  np->tag.len ? np->tag.s : "NULL") < 0) {
+				rpc->fault(c, 500, "Internal error creating rpc data");
+				return -1;
+			}
+			np = np->next;
+		}
+	}
+	return 0;
+}
+
+/*! \brief
+ * MI: Print domain name stored in hash table 
+ */
+int domain_name_table_mi_print(struct domain_name_list** table, struct mi_node* rpl)
+{
+	int i;
+	struct domain_name_list *np;
+
+	for (i = 0; i < PERM_HASH_SIZE; i++) {
+		np = table[i];
+		while (np) {
+			if (addf_mi_node_child(rpl, 0, 0, 0,
+						"%4d <%u, %.*s, %u> [%s]",
+						i, np->grp, np->domain.len, np->domain.s,
+						np->port, (np->tag.s==NULL)?"":np->tag.s) == 0)
+				return -1;
+			np = np->next;
+		}
+	}
+	return 0;
+}
+
+
diff --git a/modules/permissions/hash.h b/modules/permissions/hash.h
index dc3031d..9b534cb 100644
--- a/modules/permissions/hash.h
+++ b/modules/permissions/hash.h
@@ -240,4 +240,58 @@ int subnet_table_mi_print(struct subnet* table, struct mi_node* rpl);
 int subnet_table_rpc_print(struct subnet* table, rpc_t* rpc, void* c);
 
 
+/*
+ * Structure used to store domain names
+ */
+struct domain_name_list {
+	unsigned int grp;        /* address group */
+	str  domain;        /* domain_name */
+	unsigned int port;       /* port or 0 */
+	str tag;
+	struct domain_name_list* next;
+};
+
+/*
+ * Create a domain_name table
+ */
+struct domain_name_list** new_domain_name_table(void);
+
+/*
+ * Release memory allocated for a subnet table
+ */
+void free_domain_name_table(struct domain_name_list** table);
+
+/* 
+ * Empty contents of domain_name hash table
+ */
+void empty_domain_name_table(struct domain_name_list** table);
+
+/* 
+ * Check if an entry exists in domain_name table that matches given group, domain_name,
+ * and port.  Port 0 in  matches any port.
+ */
+int match_domain_name_table(struct domain_name_list** table, unsigned int group,
+		str *domain_name, unsigned int port);
+
+/* 
+ * Add <grp, domain_name, port> into hash table
+ */
+int domain_name_table_insert(struct domain_name_list** table, unsigned int grp,
+		str *domain_name, unsigned int port, char *tagv);
+
+/* 
+ * Check if an domain_name/port entry exists in hash table in any group.
+ * Returns first group in which ip_addr/port is found.
+ * Port 0 in hash table matches any port. 
+ */
+int find_group_in_domain_name_table(struct domain_name_list** table,
+		str *domain_name, unsigned int port);
+
+/*! \brief
+ * RPC: Print addresses stored in hash table 
+ */
+void domain_name_table_print(struct subnet* table, FILE* reply_file);
+int domain_name_table_rpc_print(struct domain_name_list** table, rpc_t* rpc, void* c);
+int domain_name_table_mi_print(struct domain_name_list** table, struct mi_node* rpl);
+
 #endif /* _PERM_HASH_H_ */
diff --git a/modules/permissions/mi.c b/modules/permissions/mi.c
index e38bc05..9467f1d 100644
--- a/modules/permissions/mi.c
+++ b/modules/permissions/mi.c
@@ -114,7 +114,7 @@ void rpc_trusted_dump(rpc_t* rpc, void* c) {
  */
 struct mi_root* mi_address_reload(struct mi_root *cmd_tree, void *param)
 {
-    if (reload_address_table () == 1) {
+    if (reload_address_table_cmd () == 1) {
 	return init_mi_tree( 200, MI_SSTR(MI_OK));
     } else {
 	return init_mi_tree( 400, MI_SSTR("Address table reload failed"));
@@ -125,7 +125,7 @@ struct mi_root* mi_address_reload(struct mi_root *cmd_tree, void *param)
  * RPC function to reload address table
  */
 void rpc_address_reload(rpc_t* rpc, void* c) {
-	if (reload_address_table () != 1) {
+	if (reload_address_table_cmd () != 1) {
 		rpc->fault(c, 500, "Reload failed.");
 		return;
 	}
@@ -196,6 +196,38 @@ void rpc_subnet_dump(rpc_t* rpc, void* c) {
 	return;
 }
 
+/*
+ * MI function to print domain name table
+ */
+struct mi_root* mi_domain_name_dump(struct mi_root *cmd_tree, void *param)
+{
+	struct mi_root* rpl_tree;
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==NULL) return 0;
+
+	if(domain_list_table && domain_name_table_mi_print(*domain_list_table, &rpl_tree->node) <  0) {
+		LM_ERR("failed to add a node\n");
+		free_mi_tree(rpl_tree);
+		return 0;
+	}
+
+	return rpl_tree;
+}
+
+
+/*! \brief
+ * RPC function to dump domain name table
+ */
+void rpc_domain_name_dump(rpc_t* rpc, void* c) {
+
+	if ( domain_name_table_rpc_print(*domain_list_table, rpc, c) < 0 ) {
+		LM_DBG("failed to print a subnet_table dump\n");
+	}
+	return;
+}
+
+
 #define MAX_FILE_LEN 128
 
 /*! \brief
diff --git a/modules/permissions/mi.h b/modules/permissions/mi.h
index 09f3897..4747ac7 100644
--- a/modules/permissions/mi.h
+++ b/modules/permissions/mi.h
@@ -36,6 +36,7 @@
 #define MI_ADDRESS_RELOAD "address_reload"
 #define MI_ADDRESS_DUMP "address_dump"
 #define MI_SUBNET_DUMP "subnet_dump"
+#define MI_DOMAIN_DUMP "perm_domain_dump"
 
 #define MI_ALLOW_URI "allow_uri"
 
@@ -54,6 +55,9 @@ void rpc_address_dump(rpc_t* rpc, void* c);
 struct mi_root* mi_subnet_dump(struct mi_root *cmd_tree, void *param);
 void rpc_subnet_dump(rpc_t* rpc, void* c);
 
+struct mi_root* mi_domain_name_dump(struct mi_root *cmd_tree, void *param);
+void rpc_domain_name_dump(rpc_t* rpc, void* c);
+
 struct mi_root* mi_allow_uri(struct mi_root *cmd, void *param);
 void rpc_test_uri(rpc_t* rpc, void* c);
 
diff --git a/modules/permissions/permissions.c b/modules/permissions/permissions.c
index 2b7a279..d48f9e2 100644
--- a/modules/permissions/permissions.c
+++ b/modules/permissions/permissions.c
@@ -188,6 +188,7 @@ static mi_export_t mi_cmds[] = {
 		mi_addr_child_init },
 	{ MI_ADDRESS_DUMP,    mi_address_dump,    MI_NO_INPUT_FLAG,  0,  0 },
 	{ MI_SUBNET_DUMP,     mi_subnet_dump,     MI_NO_INPUT_FLAG,  0,  0 },
+	{ MI_DOMAIN_DUMP,     mi_domain_name_dump,MI_NO_INPUT_FLAG,  0,  0 },
 	{ MI_ALLOW_URI,       mi_allow_uri,       0,  0,  0 },
 	{ 0, 0, 0, 0, 0 }
 };
@@ -405,7 +406,7 @@ static int check_routing(struct sip_msg* msg, int idx)
 	}
 
 check_branches:
-	for( br_idx=0 ; (branch.s=get_branch(br_idx,&branch.len,&q,0,0,0,0))!=0 ;
+	for( br_idx=0 ; (branch.s=get_branch(br_idx,&branch.len,&q,0,0,0,0,0,0,0))!=0 ;
 			br_idx++ ) {
 		uri_str = get_plain_uri(&branch);
 		if (!uri_str) {
@@ -1009,6 +1010,12 @@ static const char* rpc_subnet_dump_doc[2] = {
 	0
 };
 
+static const char* rpc_domain_name_dump_doc[2] = {
+	"Dump permissions domain name table",
+	0
+};
+
+
 static const char* rpc_test_uri_doc[2] = {
 	"Tests if (URI, Contact) pair is allowed according to allow/deny files",
 	0
@@ -1020,6 +1027,7 @@ rpc_export_t permissions_rpc[] = {
 	{"permissions.trustedDump", rpc_trusted_dump, rpc_trusted_dump_doc, 0},
 	{"permissions.addressDump", rpc_address_dump, rpc_address_dump_doc, 0},
 	{"permissions.subnetDump", rpc_subnet_dump, rpc_subnet_dump_doc, 0},
+	{"permissions.domainDump", rpc_domain_name_dump, rpc_domain_name_dump_doc, 0},
 	{"permissions.testUri", rpc_test_uri, rpc_test_uri_doc, 0},
 	{0, 0, 0, 0}
 };
diff --git a/modules/permissions/trusted.c b/modules/permissions/trusted.c
index ef79dc7..dd76a64 100644
--- a/modules/permissions/trusted.c
+++ b/modules/permissions/trusted.c
@@ -512,7 +512,7 @@ int allow_trusted_2(struct sip_msg* _msg, char* _src_ip_sp, char* _proto_sp)
 	return -1;
     }
 
-    if(proto.len!=3 && proto.len!=4)
+    if(proto.len<2 || proto.len>4)
 	goto error;
 
     switch(proto.s[0]) {
diff --git a/modules/pike/doc/pike_admin.xml b/modules/pike/doc/pike_admin.xml
index a245a69..9ccc91c 100644
--- a/modules/pike/doc/pike_admin.xml
+++ b/modules/pike/doc/pike_admin.xml
@@ -58,7 +58,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="pike.p.sampling_time_unit">
 		<title><varname>sampling_time_unit</varname> (integer)</title>
 		<para>
 		Time period in seconds used for sampling (or the sampling accuracy).
@@ -85,7 +85,7 @@ modparam("pike", "sampling_time_unit", 10)
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="pike.p.reqs_density_per_unit">
 		<title><varname>reqs_density_per_unit</varname> (integer)</title>
 		<para>
 		How many requests should be allowed per sampling_time_unit before 
@@ -107,7 +107,7 @@ modparam("pike", "reqs_density_per_unit", 30)
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="pike.p.remove_latency">
 		<title><varname>remove_latency</varname> (integer)</title>
 		<para>
 		For how long the IP address will be kept in memory after the last 
@@ -132,7 +132,7 @@ modparam("pike", "remove_latency", 130)
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="pike.p.pike_log_level">
 		<title><varname>pike_log_level</varname> (integer)</title>
 		<para>
 		Log level to be used by module to auto report the blocking (only first
@@ -157,7 +157,7 @@ modparam("pike", "pike_log_level", -1)
 
 	<section>
 	<title>Functions</title>
-	<section>
+	<section id="pike.f.pike_check_req">
 		<title>
 		<function moreinfo="none">pike_check_req()</function>
 		</title>
@@ -208,7 +208,7 @@ if (!pike_check_req()) { exit; };
 
 	<section>
 	<title>MI Commands</title>
-	<section>
+	<section id="pike.m.pike_list">
 		<title>
 		<function moreinfo="none">pike_list</function>
 		</title>
diff --git a/modules/pike/pike.c b/modules/pike/pike.c
index 3b23a94..5d34659 100644
--- a/modules/pike/pike.c
+++ b/modules/pike/pike.c
@@ -154,6 +154,9 @@ static int pike_init(void)
 	register_timer( clean_routine , 0, 1 );
 	register_timer( swap_routine , 0, time_unit );
 
+	/* Register counter */
+	pike_counter_init();
+
 	return 0;
 error3:
 	destroy_ip_tree();
diff --git a/modules/pike/pike_funcs.c b/modules/pike/pike_funcs.c
index ba69756..009bb68 100644
--- a/modules/pike/pike_funcs.c
+++ b/modules/pike/pike_funcs.c
@@ -43,6 +43,7 @@
 #include "../../timer.h"
 #include "../../ip_addr.h"
 #include "../../resolve.h"
+#include "../../counters.h"
 #include "ip_tree.h"
 #include "pike_funcs.h"
 #include "timer.h"
@@ -55,6 +56,13 @@ extern struct list_link* timer;
 extern int               timeout;
 extern int               pike_log_level;
 
+counter_handle_t blocked;
+
+void pike_counter_init()
+{
+	counter_register(&blocked, "pike", "blocked_ips", 0, 0, 0, "Counter of blocked IP addresses", 0);
+}
+
 
 
 int pike_check_req(struct sip_msg *msg, char *foo, char *bar)
@@ -154,6 +162,7 @@ int pike_check_req(struct sip_msg *msg, char *foo, char *bar)
 		if (flags&NEWRED_NODE) {
 			LM_GEN1( pike_log_level,
 				"PIKE - BLOCKing ip %s, node=%p\n",ip_addr2a(ip),node);
+			counter_inc(blocked);
 			return -2;
 		}
 		return -1;
diff --git a/modules/pike/pike_funcs.h b/modules/pike/pike_funcs.h
index e0f6e5a..1c8beb3 100644
--- a/modules/pike/pike_funcs.h
+++ b/modules/pike/pike_funcs.h
@@ -28,6 +28,7 @@
 #include "../../locking.h"
 
 
+void pike_counter_init(void);
 int  pike_check_req(struct sip_msg *msg, char *foo, char *bar);
 void clean_routine(unsigned int, void*);
 void swap_routine(unsigned int, void*);
diff --git a/modules/pipelimit/README b/modules/pipelimit/README
index 4106f3d..2e8295f 100644
--- a/modules/pipelimit/README
+++ b/modules/pipelimit/README
@@ -362,7 +362,7 @@ with unexpected retcode=$var(check_result)\n");
 
 5.1. pl_stats
 
-   Lists the parameters and variabiles in the pipelimit module.
+   Lists the parameters and variables in the pipelimit module.
 
    Name: pl_stats
 
diff --git a/modules/pipelimit/doc/pipelimit_admin.xml b/modules/pipelimit/doc/pipelimit_admin.xml
index dd6e12f..ec879f1 100644
--- a/modules/pipelimit/doc/pipelimit_admin.xml
+++ b/modules/pipelimit/doc/pipelimit_admin.xml
@@ -65,7 +65,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="pipelimit.p.db_url">
 	    <title><varname>db_url</varname> (string)</title>
 	    <para>
 		URL of the database server to be used.
@@ -85,7 +85,7 @@ modparam("pipelimit", "db_url", "&exampledb;")
 	    </example>
 	</section>
 
-	<section>
+	<section id="pipelimit.p.plp_table_name">
 	    <title><varname>plp_table_name</varname> (string)</title>
 	    <para>
 			Name of DB table where data definition for pipes is stores.
@@ -105,7 +105,7 @@ modparam("pipelimit", "plp_table_name", "mypipes")
 	    </example>
 	</section>
 
-	<section>
+	<section id="pipelimit.p.plp_pipeid_column">
 	    <title><varname>plp_pipeid_column</varname> (string)</title>
 	    <para>
 		Name of 'pipeid' column.
@@ -125,7 +125,7 @@ modparam("pipelimit", "plp_pipeid_column", "name")
 	    </example>
 	</section>
 
-	<section>
+	<section id="pipelimit.p.plp_limit_column">
 	    <title><varname>plp_limit_column</varname> (string)</title>
 	    <para>
 		Name of 'limit' column.
@@ -145,7 +145,7 @@ modparam("pipelimit", "plp_limit_column", "name")
 	    </example>
 	</section>
 
-	<section>
+	<section id="pipelimit.p.plp_algorithm_column">
 	    <title><varname>plp_algorithm_column</varname> (string)</title>
 	    <para>
 		Name of 'algorithm' column.
@@ -165,7 +165,7 @@ modparam("pipelimit", "plp_algorithm_column", "name")
 	    </example>
 	</section>
 
-	<section>
+	<section id="pipelimit.p.timer_interval">
 		<title><varname>timer_interval</varname> (integer)</title>
 		<para>
 		The initial length of a timer interval in seconds. All amounts of
@@ -190,7 +190,7 @@ modparam("pipelimit", "timer_interval", 5)
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="pipelimit.p.reply_code">
 		<title><varname>reply_code</varname> (integer)</title>
 		<para>
 		The code of the reply sent by &kamailio; while limiting.
@@ -221,7 +221,7 @@ modparam("pipelimit", "reply_code", 505)
 		</programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="pipelimit.p.reply_reason">
 		<title><varname>reply_reason</varname> (string)</title>
 		<para>
 		The reason of the reply sent by &kamailio; while limiting.
@@ -254,7 +254,7 @@ modparam("pipelimit", "reply_reason", "Limiting")
 	</section>
 	<section>
 	<title>Functions</title>
-	<section>
+	<section id="pipelimit.f.pl_check">
 		<title>
 		<function moreinfo="none">pl_check(name)</function>
 		</title>
@@ -319,7 +319,7 @@ with unexpected retcode=$var(check_result)\n");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="pipelimit.f.pl_drop">
 		<title>
 		<function moreinfo="none">pl_drop([ [min ], max ])</function>
 		</title>
@@ -366,12 +366,12 @@ with unexpected retcode=$var(check_result)\n");
 
 	<section>
 	<title>MI Commands</title>
-	<section>
+	<section id="pipelimit.m.pl_stats">
 		<title>
 		<function moreinfo="none">pl_stats</function>
 		</title>
 		<para>
-		Lists the parameters and variabiles in the pipelimit module.
+		Lists the parameters and variables in the pipelimit module.
 		</para>
 		<para>
 		Name: <emphasis>pl_stats</emphasis>
@@ -385,7 +385,7 @@ with unexpected retcode=$var(check_result)\n");
 		_empty_line_
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.m.pl_set_pipe">
 		<title>
 		<function moreinfo="none">pl_set_pipe</function>
 		</title>
@@ -420,7 +420,7 @@ with unexpected retcode=$var(check_result)\n");
 		_empty_line_
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.m.pl_get_pipes">
 		<title>
 		<function moreinfo="none">pl_get_pipes</function>
 		</title>
@@ -439,7 +439,7 @@ with unexpected retcode=$var(check_result)\n");
 		_empty_line_
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.m.pl_set_pid">
 		<title>
 		<function moreinfo="none">pl_set_pid</function>
 		</title>
@@ -472,7 +472,7 @@ with unexpected retcode=$var(check_result)\n");
 		_empty_line_
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.m.pl_get_pid">
 		<title>
 		<function moreinfo="none">pl_get_pid</function>
 		</title>
@@ -491,12 +491,12 @@ with unexpected retcode=$var(check_result)\n");
 		_empty_line_
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.m.pl_push_load">
 		<title>
 		<function moreinfo="none">pl_push_load</function>
 		</title>
 		<para>
-		Force the value of the load parameter.  This command is useful
+		Force the value of the load parameter. This command is useful
 		for testing the Feedback algorithm.
 		</para>
 		<para>
@@ -522,7 +522,7 @@ with unexpected retcode=$var(check_result)\n");
 	
 	<section>
 	<title>RPC Commands</title>
-	<section>
+	<section id="pipelimit.r.pl.stats">
 		<title>
 		<function moreinfo="none">pl.stats</function>
 		</title>
@@ -541,7 +541,7 @@ with unexpected retcode=$var(check_result)\n");
 	kamcmd pl.stats
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.r.pl.set_pipe">
 		<title>
 		<function moreinfo="none">pl.set_pipe</function>
 		</title>
@@ -572,7 +572,7 @@ with unexpected retcode=$var(check_result)\n");
 	kamcmd pl.set_pipe 2 RED 10
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.r.pl.get_pipes">
 		<title>
 		<function moreinfo="none">pl.get_pipes</function>
 		</title>
@@ -590,7 +590,7 @@ with unexpected retcode=$var(check_result)\n");
 	kamcmd pl.get_pipes
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.r.pl.set_pid">
 		<title>
 		<function moreinfo="none">pl.set_pid</function>
 		</title>
@@ -619,7 +619,7 @@ with unexpected retcode=$var(check_result)\n");
 	kamcmd pl.set_pid 0.5 0.5 0.5
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.r.pl.get_pid">
 		<title>
 		<function moreinfo="none">pl.get_pid</function>
 		</title>
@@ -637,12 +637,12 @@ with unexpected retcode=$var(check_result)\n");
 	kamcmd pl.get_pid
 		</programlisting>
 	</section>
-	<section>
+	<section id="pipelimit.r.pl.push_load">
 		<title>
 		<function moreinfo="none">pl.push_load</function>
 		</title>
 		<para>
-		Force the value of the load parameter.  This command is useful
+		Force the value of the load parameter. This command is useful
 		for testing the Feedback algorithm.
 		</para>
 		<para>
diff --git a/modules/presence/README b/modules/presence/README
index 1c202a8..f8681e4 100644
--- a/modules/presence/README
+++ b/modules/presence/README
@@ -16,9 +16,9 @@ Edited by
 
 Juha Heinanen
 
-   Copyright © 2006 Voice Sistem SRL
+   Copyright � 2006 Voice Sistem SRL
 
-   Copyright © 2009 Juha Heinanen
+   Copyright � 2009 Juha Heinanen
      __________________________________________________________________
 
    Table of Contents
@@ -70,7 +70,11 @@ Juha Heinanen
               5.1. refreshWatchers
               5.2. cleanup
 
-        6. Installation
+        6. RPC Commands
+
+              6.1. presence.cleanup
+
+        7. Installation
 
    2. Developer Guide
 
@@ -170,7 +174,11 @@ Chapter 1. Admin Guide
         5.1. refreshWatchers
         5.2. cleanup
 
-   6. Installation
+   6. RPC Commands
+
+        6.1. presence.cleanup
+
+   7. Installation
 
 1. Overview
 
@@ -245,19 +253,19 @@ Chapter 1. Admin Guide
    If set, the module is a fully operational presence server. Otherwise,
    it is used as a 'library', for its exported functions.
 
-   Default value is “NULL”.
+   Default value is "NULL".
 
    Example 1.1. Set db_url parameter
 ...
 modparam("presence", "db_url",
-        "mysql://openser:openserrw@localhost/openser")
+        "mysql://kamailio:kamailiorw@localhost/kamailio")
 ...
 
 3.2. presentity_table(str)
 
    The name of the db table where PUBLISH presence information is stored.
 
-   Default value is “presentity”.
+   Default value is "presentity".
 
    Example 1.2. Set presentity_table parameter
 ...
@@ -269,7 +277,7 @@ modparam("presence", "presentity_table", "presentity")
    The name of the db table where active subscription information is
    stored.
 
-   Default value is “active_watchers”.
+   Default value is "active_watchers".
 
    Example 1.3. Set active_watchers_table parameter
 ...
@@ -280,7 +288,7 @@ modparam("presence", "active_watchers_table", "active_watchers")
 
    The name of the db table where subscription states are stored.
 
-   Default value is “watchers”.
+   Default value is "watchers".
 
    Example 1.4. Set watchers_table parameter
 ...
@@ -292,7 +300,7 @@ modparam("presence", "watchers_table", "watchers")
    The period in seconds between checks if there are expired messages
    stored in database.
 
-   Default value is “100”. A zero or negative value disables this
+   Default value is "100". A zero or negative value disables this
    activity.
 
    Example 1.5. Set clean_period parameter
@@ -305,7 +313,7 @@ modparam("presence", "clean_period", 100)
    The period at which to synchronize cached subscriber info with the
    database.
 
-   Default value is “100”. A zero or negative value disables
+   Default value is "100". A zero or negative value disables
    synchronization.
 
    Example 1.6. Set db_update_period parameter
@@ -323,7 +331,7 @@ modparam("presence", "db_update_period", 100)
    than 0. When notifier_processes is less than or equal to 0 NOTIFY
    requests are sent immediately.
 
-   Default value is “5”.
+   Default value is "5".
 
    Example 1.7. Set waitn_time parameter
 ...
@@ -340,7 +348,7 @@ modparam("presence", "waitn_time", 10)
    Separate notifier processes are only run when subs_db_mode is 3 (DB
    only mode).
 
-   Default value is “10”.
+   Default value is "10".
 
    Example 1.8. Set notifier_poll_rate parameter
 ...
@@ -360,7 +368,7 @@ modparam("presence", "notifier_poll_rate", 20)
    NOTIFY requests can be sent on a dialog at the same time, there are
    race conditions which result in CSeq re-use.
 
-   Default value is “1”.
+   Default value is "1".
 
    Example 1.9. Set notifier_processes parameter
 ...
@@ -372,7 +380,7 @@ modparam("presence", "notifier_processes", 2)
    The prefix used when generating to_tag when sending replies for
    SUBSCRIBE requests.
 
-   Default value is “10”.
+   Default value is "10".
 
    Example 1.10. Set to_tag_pref parameter
 ...
@@ -385,7 +393,7 @@ modparam("presence", "to_tag_pref", 'pres')
    when sending a 200OK for a publish. It is used for forcing the client
    to send an update before the old publish expires.
 
-   Default value is “0”.
+   Default value is "0".
 
    Example 1.11. Set expires_offset parameter
 ...
@@ -397,7 +405,7 @@ modparam("presence", "expires_offset", 10)
    The the maximum admissible expires value for PUBLISH/SUBSCRIBE message
    (in seconds).
 
-   Default value is “3600”.
+   Default value is "3600".
 
    Example 1.12. Set max_expires parameter
 ...
@@ -468,7 +476,7 @@ modparam("presence", "subs_db_mode", 1)
    database or there are other external entities inserting data into the
    presentity table.
 
-   Default value is “1”.
+   Default value is "1".
 
    Example 1.15. Set publ_cache parameter
 ...
@@ -481,7 +489,7 @@ modparam("presence", "publ_cache", 0)
    This parameter will be used as the power of 2 when computing table
    size.
 
-   Default value is “9 (512)”.
+   Default value is "9 (512)".
 
    Example 1.16. Set subs_htable_size parameter
 ...
@@ -493,7 +501,7 @@ modparam("presence", "subs_htable_size", 11)
    The size of the in-memory hash table to store publish records. This
    parameter will be used as the power of 2 when computing table size.
 
-   Default value is “9 (512)”.
+   Default value is "9 (512)".
 
    Example 1.17. Set pres_htable_size parameter
 ...
@@ -508,7 +516,7 @@ modparam("presence", "pres_htable_size", 11)
    empty NOTIFY to an message-summary event. This parameter is enabled by
    default, thus addering to the standard.
 
-   Default value is “1 ”.
+   Default value is "1 ".
 
    Example 1.18. Set send_fast_notify parameter
 ...
@@ -523,7 +531,7 @@ modparam("presence", "send_fast_notify", 0)
    this check requires extra processing that should be avoided if this
    feature is not supported by the clients.
 
-   Default value is “0 ”.
+   Default value is "0 ".
 
    Example 1.19. Set enable_sphere_check parameter
 ...
@@ -538,7 +546,7 @@ modparam("presence", "enable_sphere_check", 1)
    on. Disabling this will keep subscriptions active on unreliable
    networks.
 
-   Default value is “1”.
+   Default value is "1".
 
    Example 1.20. Set timeout_rm_subs parameter
 ...
@@ -740,7 +748,21 @@ pres_update_watchers("sip:test at kamailio.org", "presence");
                 :cleanup:fifo_reply
                 _empty_line_
 
-6. Installation
+6. RPC Commands
+
+   6.1. presence.cleanup
+
+6.1.  presence.cleanup
+
+   Manually triggers the cleanup functions for the active_watchers,
+   presentity, and watchers tables. Useful if you have set clean_period
+   and/or db_update_period to zero or less.
+
+   Name: presence.cleanup
+
+   Parameters: none
+
+7. Installation
 
    The module requires 3 tables in the Kamailio database: "presentity",
    "active_watchers" and "watchers". The SQL syntax to create them can be
diff --git a/modules/presence/doc/presence_admin.xml b/modules/presence/doc/presence_admin.xml
index b2fcf6e..02b3562 100644
--- a/modules/presence/doc/presence_admin.xml
+++ b/modules/presence/doc/presence_admin.xml
@@ -902,6 +902,25 @@ pres_update_watchers("sip:test at kamailio.org", "presence");
 </section>
 
 <section>
+	<title>RPC Commands</title>
+	<section>
+	  <title>
+		<function moreinfo="none">presence.cleanup</function>
+	  </title>
+	  <para>
+		Manually triggers the cleanup functions for the active_watchers, presentity,
+		and watchers tables. Useful if you have set <varname>clean_period</varname>
+		and/or <varname>db_update_period</varname> to zero or less.
+	  </para>
+	  <para>
+		Name: <emphasis>presence.cleanup</emphasis>
+	  </para>
+	  <para>Parameters: <emphasis>none</emphasis></para>
+
+	</section>
+</section>
+
+<section>
 	<title>Installation</title>
 	<para>
 	The module requires 3 tables in the &kamailio; database: "presentity",
diff --git a/modules/presence/event_list.c b/modules/presence/event_list.c
index ee272c1..ece09a0 100644
--- a/modules/presence/event_list.c
+++ b/modules/presence/event_list.c
@@ -255,7 +255,7 @@ int add_event(pres_ev_t* event)
 	}
 	EvList->ev_count++;
 	
-	LM_DBG("succesfully added event: %.*s - len= %d\n",ev->name.len,
+	LM_DBG("successfully added event: %.*s - len= %d\n",ev->name.len,
 			ev->name.s, ev->name.len);
 done:
 	free_event_params(parsed_event.params.list, PKG_MEM_TYPE);
diff --git a/modules/presence/hash.c b/modules/presence/hash.c
index c7d366a..de7f08f 100644
--- a/modules/presence/hash.c
+++ b/modules/presence/hash.c
@@ -634,7 +634,7 @@ int update_phtable(presentity_t* presentity, str pres_uri, str body)
 	if(presentity->event->get_rules_doc(&presentity->user, &presentity->domain,
 				&xcap_doc)< 0)
 	{
-		LM_ERR("failed to retreive xcap document\n");
+		LM_ERR("failed to retrieve xcap document\n");
 		ret= -1;
 		goto done;
 	}
diff --git a/modules/presence/presence.c b/modules/presence/presence.c
index ed7f4d1..067a1e1 100644
--- a/modules/presence/presence.c
+++ b/modules/presence/presence.c
@@ -73,6 +73,8 @@
 #include "notify.h"
 #include "../../mod_fix.h"
 #include "../../timer_proc.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
 
 MODULE_VERSION
 
@@ -127,6 +129,7 @@ static int w_pres_update_watchers(struct sip_msg *msg, char *puri,
 		char *pevent);
 static int fixup_refresh_watchers(void** param, int param_no);
 static int fixup_update_watchers(void** param, int param_no);
+static int presence_init_rpc(void);
 
 int counter =0;
 int pid = 0;
@@ -231,6 +234,11 @@ static int mod_init(void)
 		LM_ERR("failed to register MI commands\n");
 		return -1;
 	}
+	if(presence_init_rpc()!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
 
 	db_url.len = db_url.s ? strlen(db_url.s) : 0;
 	LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len,db_url.s);
@@ -1780,4 +1788,37 @@ static int fixup_update_watchers(void** param, int param_no)
 		return fixup_spve_null(param, 1);
 	}
 	return 0;
+
+}
+
+void rpc_presence_cleanup(rpc_t* rpc, void* c)
+{
+	LM_DBG("rpc_presence_cleanup:start\n");
+
+	(void) msg_watchers_clean(0,0);
+	(void) msg_presentity_clean(0,0);
+	(void) timer_db_update(0,0);
+		
+	rpc->printf(c, "Reload OK");
+	return;
+}
+
+static const char* rpc_presence_cleanup_doc[2] = {
+	"Manually triggers the cleanup functions for the active_watchers, presentity, and watchers tables.",
+	0
+};
+
+rpc_export_t presence_rpc[] = {
+	{"presence.cleanup", rpc_presence_cleanup, rpc_presence_cleanup_doc, 0},
+	{0, 0, 0, 0}
+};
+
+static int presence_init_rpc(void)
+{
+	if (rpc_register_array(presence_rpc)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+	return 0;
 }
diff --git a/modules/presence_conference/presence_conference.c b/modules/presence_conference/presence_conference.c
index fecad7b..51c0340 100644
--- a/modules/presence_conference/presence_conference.c
+++ b/modules/presence_conference/presence_conference.c
@@ -109,7 +109,7 @@ static int mod_init(void)
 	}
 
 	pres_add_event = pres.add_event;
-	if (add_event == NULL) {
+	if (pres_add_event == NULL) {
 		LM_ERR("could not import add_event function\n");
 		return -1;
 	}
diff --git a/modules/presence_dialoginfo/notify_body.c b/modules/presence_dialoginfo/notify_body.c
index cc65efb..23ea1b2 100644
--- a/modules/presence_dialoginfo/notify_body.c
+++ b/modules/presence_dialoginfo/notify_body.c
@@ -47,6 +47,8 @@
 #include "pidf.h"
 
 str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n);
+int check_relevant_state (xmlChar * dialog_id, xmlDocPtr * xml_array, int total_nodes);
+
 extern int force_single_dialog;
 
 void free_xml_body(char* body)
@@ -73,7 +75,7 @@ str* dlginfo_agg_nbody(str* pres_user, str* pres_domain, str** body_array, int n
 	LM_DBG("[n_body]=%p\n", n_body);
 	if(n_body) {
 		LM_DBG("[*n_body]=%.*s\n",
-			n_body->len, n_body->s);
+				n_body->len, n_body->s);
 	}
 	if(n_body== NULL && n!= 0)
 	{
@@ -81,7 +83,7 @@ str* dlginfo_agg_nbody(str* pres_user, str* pres_domain, str** body_array, int n
 	}
 
 	xmlCleanupParser();
-    xmlMemoryDump();
+	xmlMemoryDump();
 
 	return n_body;
 }	
@@ -93,15 +95,23 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 	xmlDocPtr  doc = NULL;
 	xmlNodePtr root_node = NULL;
 	xmlNsPtr   namespace = NULL;
+	int winner_priority = -1, priority;
 
 	xmlNodePtr p_root= NULL;
 	xmlDocPtr* xml_array ;
 	xmlNodePtr node = NULL;
-	char *state;
-	int winner_priority = -1, priority ;
+	xmlNodePtr terminated_node = NULL;
+	xmlNodePtr early_node = NULL;
+	xmlNodePtr confirmed_node = NULL;
+
+	char *state = NULL;
+	xmlChar *dialog_id = NULL;
+	int node_id = -1;
+
 	xmlNodePtr winner_dialog_node = NULL ;
 	str *body= NULL;
-    char buf[MAX_URI_SIZE+1];
+
+	char buf[MAX_URI_SIZE+1];
 
 	LM_DBG("[pres_user]=%.*s [pres_domain]= %.*s, [n]=%d\n",
 			pres_user->len, pres_user->s, pres_domain->len, pres_domain->s, n);
@@ -122,7 +132,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 
 		xml_array[j] = NULL;
 		xml_array[j] = xmlParseMemory( body_array[i]->s, body_array[i]->len );
-		
+
 		/* LM_DBG("parsing XML body: [n]=%d, [i]=%d, [j]=%d xml_array[j]=%p\n", n, i, j, xml_array[j] ); */
 
 		if( xml_array[j]== NULL)
@@ -147,54 +157,54 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 	/* LM_DBG("number of bodies in total [n]=%d, number of useful bodies [j]=%d\n", n, j ); */
 
 	/* create the new NOTIFY body  */
-    if ( (pres_user->len + pres_domain->len + 1 + 4 + 1) >= MAX_URI_SIZE) {
-        LM_ERR("entity URI too long, maximum=%d\n", MAX_URI_SIZE);
-        return NULL;
-    }
+	if ( (pres_user->len + pres_domain->len + 1 + 4 + 1) >= MAX_URI_SIZE) {
+		LM_ERR("entity URI too long, maximum=%d\n", MAX_URI_SIZE);
+		return NULL;
+	}
 	memcpy(buf, "sip:", 4);
 	memcpy(buf+4, pres_user->s, pres_user->len);
 	buf[pres_user->len+4] = '@';
 	memcpy(buf + pres_user->len + 5, pres_domain->s, pres_domain->len);
 	buf[pres_user->len + 5 + pres_domain->len]= '\0';
 
-    doc = xmlNewDoc(BAD_CAST "1.0");
-    if(doc==0)
-        return NULL;
+	doc = xmlNewDoc(BAD_CAST "1.0");
+	if(doc==0)
+		return NULL;
 
-    root_node = xmlNewNode(NULL, BAD_CAST "dialog-info");
-    if(root_node==0)
-        goto error;
+	root_node = xmlNewNode(NULL, BAD_CAST "dialog-info");
+	if(root_node==0)
+		goto error;
 
-    xmlDocSetRootElement(doc, root_node);
+	xmlDocSetRootElement(doc, root_node);
 	namespace = xmlNewNs(root_node, BAD_CAST "urn:ietf:params:xml:ns:dialog-info", NULL);
 	if (!namespace) {
 		LM_ERR("creating namespace failed\n");
 	}
 	xmlSetNs(root_node, namespace);
 	/* The version must be increased for each new document and is a 32bit int.
-       As the version is different for each watcher, we can not set here the
-       correct value. Thus, we just put here a placeholder which will be 
+	   As the version is different for each watcher, we can not set here the
+	   correct value. Thus, we just put here a placeholder which will be
 	   replaced by the correct value in the aux_body_processing callback.
 	   Thus we have CPU intensive XML aggregation only once and can use
 	   quick search&replace in the per-watcher aux_body_processing callback.
 	   We use 11 chracters as an signed int (although RFC says unsigned int we
 	   use signed int as presence module stores "version" in DB as
 	   signed int) has max. 10 characters + 1 character for the sign
-	*/
-    xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "00000000000");
-    xmlNewProp(root_node, BAD_CAST  "state",  BAD_CAST "full" );
-    xmlNewProp(root_node, BAD_CAST "entity",  BAD_CAST buf);
+	   */
+	xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "00000000000");
+	xmlNewProp(root_node, BAD_CAST  "state",  BAD_CAST "full" );
+	xmlNewProp(root_node, BAD_CAST "entity",  BAD_CAST buf);
 
 	/* loop over all bodies and create the aggregated body */
 	for(i=0; i<j; i++)
 	{
 		/* LM_DBG("[n]=%d, [i]=%d, [j]=%d xml_array[i]=%p\n", n, i, j, xml_array[j] ); */
 		p_root= xmlDocGetRootElement(xml_array[i]);
-			if(p_root ==NULL) {
-				LM_ERR("while geting the xml_tree root element\n");
-				goto error;
-			}
-			if (p_root->children) {
+		if(p_root ==NULL) {
+			LM_ERR("the xml_tree root element is null\n");
+			goto error;
+		}
+		if (p_root->children) {
 			for (node = p_root->children; node; node = node->next) {
 				if (node->type == XML_ELEMENT_NODE) {
 					LM_DBG("node type: Element, name: %s\n", node->name);
@@ -213,15 +223,59 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 					} else {
 						/* try to put only the most important into the XML document
 						 * order of importance: terminated->trying->proceeding->confirmed->early
+						 * - check first the relevant states and jump priority for them
 						 */
+						if(strcasecmp((char*)node->name,"dialog") == 0)
+						{
+							node_id = i;
+							dialog_id = xmlGetProp(node,(const xmlChar *)"id");
+							LM_DBG("Dialog id for this node : %s\n", dialog_id);
+						}
 						state = xmlNodeGetNodeContentByName(node, "state", NULL);
-						if (state) {
+						if(state) {
 							LM_DBG("state element content = %s\n", state);
-							priority = get_dialog_state_priority(state);
-							if (priority > winner_priority) {
-								winner_priority = priority;
-								LM_DBG("new winner priority = %s (%d)\n", state, winner_priority);
-								winner_dialog_node = node;
+							if (strcasecmp(state,"terminated") == 0)
+							{
+								terminated_node = node;
+							} else if (strcasecmp(state,"confirmed") == 0 && node_id == i) {
+								/*  here we check if confirmed is terminated or not
+								 *  if it is not we are in the middle of the conversation
+								 */
+								if(check_relevant_state(dialog_id, xml_array, j) > 1)
+								{
+									LM_DBG("confirmed state for dialog %s, but it was terminated\n", dialog_id );
+								}else{
+									LM_DBG("confirmed state for dialog %s, and it is not terminated\n", dialog_id );
+									confirmed_node = node;
+								}
+
+
+							} else if (strcasecmp(state,"early") == 0 && node_id == i) {
+								if(check_relevant_state(dialog_id, xml_array, j)  > 0)
+								{
+									LM_DBG("early state for dialog %s, but it was confirmed or terminated\n", dialog_id );
+								}else{
+									LM_DBG("early state for dialog %s and it is still relevant\n", dialog_id );
+									early_node = node;
+								}
+							}
+							if(early_node != NULL) {
+								winner_dialog_node = early_node;
+							} else {
+								if(confirmed_node != NULL)
+								{
+									winner_dialog_node = confirmed_node;
+								}else {
+									winner_dialog_node = terminated_node;
+								}
+							}
+							if(winner_dialog_node == NULL) {
+								priority = get_dialog_state_priority(state);
+								if (priority > winner_priority) {
+									winner_priority = priority;
+									LM_DBG("new winner priority = %s (%d)\n", state, winner_priority);
+									winner_dialog_node = node;
+								}
 							}
 							xmlFree(state);
 						}
@@ -232,6 +286,10 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 	}
 
 	if (force_single_dialog && (j!=1)) {
+		if(winner_dialog_node == NULL) {
+			LM_ERR("no winning node found\n");
+			goto error;
+		}
 		xmlUnlinkNode(winner_dialog_node);
 		if(xmlAddChild(root_node, winner_dialog_node)== NULL) {
 			LM_ERR("while adding winner-child\n");
@@ -247,7 +305,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 	xmlDocDumpFormatMemory(doc,(xmlChar**)(void*)&body->s, 
 			&body->len, 1);	
 
-  	for(i=0; i<j; i++)
+	for(i=0; i<j; i++)
 	{
 		if(xml_array[i]!=NULL)
 			xmlFreeDoc( xml_array[i]);
@@ -256,9 +314,9 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n)
 		xmlFreeDoc(doc);
 	if(xml_array!=NULL)
 		pkg_free(xml_array);
-    
+
 	xmlCleanupParser();
-    xmlMemoryDump();
+	xmlMemoryDump();
 
 	return body;
 
@@ -294,6 +352,66 @@ int get_dialog_state_priority(char *state) {
 	return 0;
 }
 
+/* returns 2 -> terminated, 1 -> confirmed, 3 -> both */
+int check_relevant_state (xmlChar * dialog_id, xmlDocPtr * xml_array, int total_nodes)
+{
+	int result = 0;
+	int i = 0;
+	int node_id = -1;
+	char *state;
+	xmlChar *dialog_id_tmp = NULL;
+	xmlNodePtr p_root;
+	xmlNodePtr node = NULL;
+	for (i = 0; i < total_nodes; i++)
+	{
+		p_root = xmlDocGetRootElement (xml_array[i]);
+		if (p_root == NULL)
+		{
+			LM_DBG ("the xml_tree root element is null\n");
+		} else {
+			if (p_root->children)
+				for (node = p_root->children; node; node = node->next)
+				{
+					if (node->type == XML_ELEMENT_NODE)
+					{
+						if (strcasecmp ((char*)node->name, "dialog") == 0)
+						{
+							/* Getting the node id so we would be sure
+							 * that terminate state from same one the same */
+							dialog_id_tmp = xmlGetProp (node, (const xmlChar *) "id");
+							node_id = i;
+						}
+						state = xmlNodeGetNodeContentByName (node, "state", NULL);
+						if (state)
+						{
+							/* check if state is terminated for this dialog. */
+							if ((strcasecmp (state, "terminated") == 0)
+									&& (node_id == i) && (node_id >= 0)
+									&& (strcasecmp ((char*)dialog_id_tmp, (char*)dialog_id) == 0))
+							{
+								LM_DBG ("Found terminated in dialog %s\n",
+										dialog_id);
+								result += 2;
+							}
+							/* check if state is confirmed for this dialog. */
+							if ((strcasecmp (state, "confirmed") == 0)
+									&& (node_id == i) && (node_id >= 0)
+									&& (strcasecmp ((char*)dialog_id_tmp, (char*)dialog_id) == 0))
+							{
+								LM_DBG ("Found confirmed in dialog %s\n", dialog_id);
+								result += 1;
+							}
+
+							xmlFree (state);
+						}
+					}
+				}
+		}
+	}
+	LM_DBG ("result cheching dialog %s is %d\n", dialog_id, result);
+	return result;
+}
+
 
 str *dlginfo_body_setversion(subs_t *subs, str *body) {
 	char *version_start=0;
@@ -312,7 +430,7 @@ str *dlginfo_body_setversion(subs_t *subs, str *body) {
 	}
 	version_start = strstr(body->s + 34, "version=");
 	if (!version_start) {
-	    LM_ERR("version string not found!\n");
+		LM_ERR("version string not found!\n");
 		return NULL;
 	}
 	version_start += 9;
diff --git a/modules/presence_xml/add_events.c b/modules/presence_xml/add_events.c
index f2c8547..dc3ab61 100644
--- a/modules/presence_xml/add_events.c
+++ b/modules/presence_xml/add_events.c
@@ -44,6 +44,7 @@
 extern int disable_presence;
 extern int disable_winfo;
 extern int disable_bla;
+extern int disable_xcapdiff;
 
 static str pu_415_rpl  = str_init("Unsupported media type");
 
@@ -119,6 +120,25 @@ int xml_add_events(void)
 		LM_DBG("added 'dialog;sla' event to presence module\n");
 	}
 	
+	if (!disable_xcapdiff) {
+		/* constructing xcap-diff event */
+		memset(&event, 0, sizeof(pres_ev_t));
+		event.name.s= "xcap-diff";
+		event.name.len= 9;
+
+		event.content_type.s= "application/xcap-diff+xml";
+		event.content_type.len= 25;
+
+		event.type= PUBL_TYPE;
+		event.default_expires= 3600;
+		if(pres_add_event(&event)< 0)
+		{
+			LM_ERR("while adding event xcap-diff\n");
+			return -1;
+		}
+		LM_DBG("added 'xcap-diff' event to presence module\n");
+	}
+
 	return 0;
 }
 /*
diff --git a/modules/presence_xml/presence_xml.c b/modules/presence_xml/presence_xml.c
index 45fcbd5..3ffff5c 100644
--- a/modules/presence_xml/presence_xml.c
+++ b/modules/presence_xml/presence_xml.c
@@ -94,6 +94,7 @@ int disable_presence = 0;
 int disable_winfo    = 0;
 int disable_bla      = 1;
 int passive_mode     = 0;
+int disable_xcapdiff = 0;
 str xcapauth_userdel_reason = str_init("probation");
 
 /** SL API structure */
@@ -126,6 +127,7 @@ static param_export_t params[]={
 	{ "disable_presence",	INT_PARAM, &disable_presence },
 	{ "disable_winfo",		INT_PARAM, &disable_winfo },
 	{ "disable_bla",		INT_PARAM, &disable_bla },
+	{ "disable_xcapdiff",	INT_PARAM, &disable_xcapdiff },
 	{ "passive_mode",		INT_PARAM, &passive_mode },
 	{ "xcapauth_userdel_reason", STR_PARAM, &xcapauth_userdel_reason.s},
 	{ 0, 0, 0}
diff --git a/modules/pua/add_events.c b/modules/pua/add_events.c
index 76a12db..b802232 100644
--- a/modules/pua/add_events.c
+++ b/modules/pua/add_events.c
@@ -98,6 +98,14 @@ int pua_add_events(void)
 		}
 	}
 	
+	/* add xcap-diff */
+	if(add_pua_event(XCAPDIFF_EVENT, "xcap-diff",
+				"application/xcap-diff+xml", 0)< 0)
+	{
+		LM_ERR("while adding event xcap-diff\n");
+		return -1;
+	}
+
 	return 0;
 
 }	
diff --git a/modules/pua/hash.h b/modules/pua/hash.h
index 9912eba..65020be 100644
--- a/modules/pua/hash.h
+++ b/modules/pua/hash.h
@@ -42,6 +42,7 @@
 #define CONFERENCE_EVENT    1<<4
 #define DIALOG_EVENT        1<<5
 #define REGINFO_EVENT       1<<6
+#define XCAPDIFF_EVENT      1<<7
 
 #define UL_PUBLISH          1<<0
 #define BLA_PUBLISH         1<<1
@@ -57,6 +58,8 @@
 #define PURPLE_PUBLISH      1<<11
 #define REGINFO_PUBLISH     1<<12
 #define REGINFO_SUBSCRIBE   1<<13
+#define XCAPDIFF_PUBLISH    1<<14
+#define XCAPDIFF_SUBSCRIBE  1<<15
 
 #define NO_UPDATEDB_FLAG    1<<0
 #define UPDATEDB_FLAG       1<<1
diff --git a/modules/pua_dialoginfo/dialog_publish.c b/modules/pua_dialoginfo/dialog_publish.c
index 95b6cb3..a9018e1 100644
--- a/modules/pua_dialoginfo/dialog_publish.c
+++ b/modules/pua_dialoginfo/dialog_publish.c
@@ -73,24 +73,24 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 		LM_ERR("entity URI '%.*s' too long, maximum=%d\n",entity->len, entity->s, MAX_URI_SIZE);
 		return NULL;
 	}
-    memcpy(buf, entity->s, entity->len);
+	memcpy(buf, entity->s, entity->len);
 	buf[entity->len]= '\0';
 
-	/* create the Publish body  */
+	/* create the Publish body */
 	doc = xmlNewDoc(BAD_CAST "1.0");
 	if(doc==0)
 		return NULL;
 
-    root_node = xmlNewNode(NULL, BAD_CAST "dialog-info");
+	root_node = xmlNewNode(NULL, BAD_CAST "dialog-info");
 	if(root_node==0)
 		goto error;
-    
+
 	xmlDocSetRootElement(doc, root_node);
 
-    xmlNewProp(root_node, BAD_CAST "xmlns",
+	xmlNewProp(root_node, BAD_CAST "xmlns",
 			BAD_CAST "urn:ietf:params:xml:ns:dialog-info");
 	/* we set the version to 0 but it should be set to the correct value
-       in the pua module */
+	in the pua module */
 	xmlNewProp(root_node, BAD_CAST "version",
 			BAD_CAST "0");
 	xmlNewProp(root_node, BAD_CAST  "state",
@@ -100,12 +100,12 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 
 	/* RFC 3245 differs between id and call-id. For example if a call
 	   is forked and 2 early dialogs are established, we should send 2
-	    PUBLISH requests, both have the same call-id but different id.
-	    Thus, id could be for example derived from the totag.
+	   PUBLISH requests, both have the same call-id but different id.
+	   Thus, id could be for example derived from the totag.
 
-	    Currently the dialog module does not support multiple dialogs.
-	    Thus, it does no make sense to differ here between multiple dialog.
-	    Thus, id and call-id will be populated identically */
+	   Currently the dialog module does not support multiple dialogs.
+	   Thus, it does no make sense to differ here between multiple dialog.
+	   Thus, id and call-id will be populated identically */
 
 	/* dialog tag */
 	dialog_node =xmlNewChild(root_node, NULL, BAD_CAST "dialog", NULL) ;
@@ -119,7 +119,7 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 		LM_ERR("call-id '%.*s' too long, maximum=%d\n", callid->len, callid->s, MAX_URI_SIZE);
 		return NULL;
 	}
-    memcpy(buf, callid->s, callid->len);
+	memcpy(buf, callid->s, callid->len);
 	buf[callid->len]= '\0';
 
 	xmlNewProp(dialog_node, BAD_CAST "id", BAD_CAST buf);
@@ -132,7 +132,7 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 				LM_ERR("localtag '%.*s' too long, maximum=%d\n", localtag->len, localtag->s, MAX_URI_SIZE);
 				return NULL;
 			}
-		    memcpy(buf, localtag->s, localtag->len);
+			memcpy(buf, localtag->s, localtag->len);
 			buf[localtag->len]= '\0';
 			xmlNewProp(dialog_node, BAD_CAST "local-tag", BAD_CAST buf);
 		}
@@ -141,7 +141,7 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 				LM_ERR("remotetag '%.*s' too long, maximum=%d\n", remotetag->len, remotetag->s, MAX_URI_SIZE);
 				return NULL;
 			}
-		    memcpy(buf, remotetag->s, remotetag->len);
+			memcpy(buf, remotetag->s, remotetag->len);
 			buf[remotetag->len]= '\0';
 			xmlNewProp(dialog_node, BAD_CAST "remote-tag", BAD_CAST buf);
 		}
@@ -174,7 +174,7 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 			LM_ERR("peer '%.*s' too long, maximum=%d\n", peer->len, peer->s, MAX_URI_SIZE);
 			return NULL;
 		}
-    	memcpy(buf, peer->s, peer->len);
+		memcpy(buf, peer->s, peer->len);
 		buf[peer->len]= '\0';
 
 		tag_node = xmlNewChild(remote_node, NULL, BAD_CAST "identity", BAD_CAST buf) ;
@@ -207,7 +207,7 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 			LM_ERR("entity '%.*s' too long, maximum=%d\n", entity->len, entity->s, MAX_URI_SIZE);
 			return NULL;
 		}
-    	memcpy(buf, entity->s, entity->len);
+		memcpy(buf, entity->s, entity->len);
 		buf[entity->len]= '\0';
 
 		tag_node = xmlNewChild(local_node, NULL, BAD_CAST "identity", BAD_CAST buf) ;
@@ -242,9 +242,9 @@ str* build_dialoginfo(char *state, str *entity, str *peer, str *callid,
 
 	LM_DBG("new_body:\n%.*s\n",body->len, body->s);
 
-    /*free the document */
+	/*free the document */
 	xmlFreeDoc(doc);
-    xmlCleanupParser();
+	xmlCleanupParser();
 
 	return body;
 
@@ -269,15 +269,15 @@ void dialog_publish(char *state, str* ruri, str *entity, str *peer, str *callid,
 	publ_info_t* publ= NULL;
 	int size= 0;
 	str content_type;
-    struct sip_uri ruri_uri;
+	struct sip_uri ruri_uri;
 
 
-    if (parse_uri(ruri->s, ruri->len, &ruri_uri) < 0) {
+	if (parse_uri(ruri->s, ruri->len, &ruri_uri) < 0) {
 		LM_ERR("failed to parse the PUBLISH R-URI\n");
 		return;
 	}
 
-    if(do_pubruri_localcheck) {
+	if(do_pubruri_localcheck) {
 
 		/* send PUBLISH only if the receiver PUBLISH R-URI is local*/
 		if (!check_self(&(ruri_uri.host), 0, 0)) {
@@ -285,7 +285,7 @@ void dialog_publish(char *state, str* ruri, str *entity, str *peer, str *callid,
 			return;
 		}
 
-    }
+	}
 
 	content_type.s= "application/dialog-info+xml";
 	content_type.len= 27;
@@ -299,8 +299,8 @@ void dialog_publish(char *state, str* ruri, str *entity, str *peer, str *callid,
 	size= sizeof(publ_info_t) 
 			+ sizeof(str) 			/* *pres_uri */
 			+ ( ruri->len 		/* pres_uri->s */
-			  + callid->len + 16	/* id.s */
-			  + content_type.len	/* content_type.s */
+			+ callid->len + 16	/* id.s */
+			+ content_type.len	/* content_type.s */
 			)*sizeof(char); 
 	
 	if(body)
diff --git a/modules/pua_dialoginfo/pua_dialoginfo.c b/modules/pua_dialoginfo/pua_dialoginfo.c
index 9c842b0..1e88a04 100644
--- a/modules/pua_dialoginfo/pua_dialoginfo.c
+++ b/modules/pua_dialoginfo/pua_dialoginfo.c
@@ -82,14 +82,14 @@ unsigned short pubruri_callee_avp_type;
 int_str pubruri_callee_avp_name;
 
 /* Module parameter variables */
-int include_callid      = DEF_INCLUDE_CALLID;
-int include_localremote = DEF_INCLUDE_LOCALREMOTE;
-int include_tags        = DEF_INCLUDE_TAGS;
-int override_lifetime   = DEF_OVERRIDE_LIFETIME;
-int caller_confirmed    = DEF_CALLER_ALWAYS_CONFIRMED;
-int include_req_uri     = DEF_INCLUDE_REQ_URI;
-int send_publish_flag = DEF_SEND_PUBLISH_FLAG;
-int use_pubruri_avps    = DEF_USE_PUBRURI_AVPS;
+int include_callid         = DEF_INCLUDE_CALLID;
+int include_localremote    = DEF_INCLUDE_LOCALREMOTE;
+int include_tags           = DEF_INCLUDE_TAGS;
+int override_lifetime      = DEF_OVERRIDE_LIFETIME;
+int caller_confirmed       = DEF_CALLER_ALWAYS_CONFIRMED;
+int include_req_uri        = DEF_INCLUDE_REQ_URI;
+int send_publish_flag      = DEF_SEND_PUBLISH_FLAG;
+int use_pubruri_avps       = DEF_USE_PUBRURI_AVPS;
 char * pubruri_caller_avp  = DEF_PUBRURI_CALLER_AVP;
 char * pubruri_callee_avp  = DEF_PUBRURI_CALLEE_AVP;
 
@@ -112,7 +112,7 @@ static param_export_t params[]={
 	{"override_lifetime",   INT_PARAM, &override_lifetime },
 	{"caller_confirmed",    INT_PARAM, &caller_confirmed },
 	{"include_req_uri",     INT_PARAM, &include_req_uri },
-	{"send_publish_flag"	,	 INT_PARAM, &send_publish_flag },
+	{"send_publish_flag",   INT_PARAM, &send_publish_flag },
 	{"use_pubruri_avps",    INT_PARAM, &use_pubruri_avps },
 	{"pubruri_caller_avp",  STR_PARAM, &pubruri_caller_avp },
 	{"pubruri_callee_avp",  STR_PARAM, &pubruri_callee_avp },
@@ -120,20 +120,20 @@ static param_export_t params[]={
 };
 
 struct module_exports exports= {
-	"pua_dialoginfo",		/* module name */
-	DEFAULT_DLFLAGS,		/* dlopen flags */
-	cmds,					/* exported functions */
-	params,					/* exported parameters */
-	0,						/* exported statistics */
-	0,						/* exported MI functions */
-	0,						/* exported pseudo-variables */
-	0,						/* extra processes */
-	mod_init,				/* module initialization function */
-	0,						/* response handling function */
-	0,						/* destroy function */
-	NULL					/* per-child init function */
+	"pua_dialoginfo",    /* module name */
+	DEFAULT_DLFLAGS,     /* dlopen flags */
+	cmds,                /* exported functions */
+	params,              /* exported parameters */
+	0,                   /* exported statistics */
+	0,                   /* exported MI functions */
+	0,                   /* exported pseudo-variables */
+	0,                   /* extra processes */
+	mod_init,            /* module initialization function */
+	0,                   /* response handling function */
+	0,                   /* destroy function */
+	NULL                 /* per-child init function */
 };
-	
+
 
 #ifdef PUA_DIALOGINFO_DEBUG
 static void
@@ -149,41 +149,41 @@ __dialog_cbtest(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
 		LM_ERR("dialog callback: tag[1] = %.*s", dlg->tag[1].len, dlg->tag[1].s);
 	}
 
-if (type != DLGCB_DESTROY) {
-	msg = dlg_get_valid_msg(_params);
-	if (!msg) {
-		LM_ERR("no SIP message available in callback parameters\n");
-		return;
-	}
+	if (type != DLGCB_DESTROY) {
+		msg = dlg_get_valid_msg(_params);
+		if (!msg) {
+			LM_ERR("no SIP message available in callback parameters\n");
+			return;
+		}
 
-	/* get to tag*/
-	if ( !msg->to) {
-		// to header not defined, parse to header
-		LM_ERR("to header not defined, parse to header\n");
-		if (parse_headers(msg, HDR_TO_F,0)<0) {
-			//parser error
-			LM_ERR("parsing of to-header failed\n");
-			tag.s = 0;
-			tag.len = 0;
-		} else if (!msg->to) {
-			// to header still not defined
-			LM_ERR("no to although to-header is parsed: bad reply or missing TO hdr :-/\n");
-			tag.s = 0;
-			tag.len = 0;
-		} else 
+		/* get to tag*/
+		if ( !msg->to) {
+			// to header not defined, parse to header
+			LM_ERR("to header not defined, parse to header\n");
+			if (parse_headers(msg, HDR_TO_F,0)<0) {
+				//parser error
+				LM_ERR("parsing of to-header failed\n");
+				tag.s = 0;
+				tag.len = 0;
+			} else if (!msg->to) {
+				// to header still not defined
+				LM_ERR("no to although to-header is parsed: bad reply or missing TO hdr :-/\n");
+				tag.s = 0;
+				tag.len = 0;
+			} else 
+				tag = get_to(msg)->tag_value;
+		} else {
 			tag = get_to(msg)->tag_value;
-	} else {
-		tag = get_to(msg)->tag_value;
-		if (tag.s==0 || tag.len==0) {
-			LM_ERR("missing TAG param in TO hdr :-/\n");
-			tag.s = 0;
-			tag.len = 0;
+			if (tag.s==0 || tag.len==0) {
+				LM_ERR("missing TAG param in TO hdr :-/\n");
+				tag.s = 0;
+				tag.len = 0;
+			}
+		}
+		if (tag.s) {
+			LM_ERR("dialog callback: msg->to->parsed->tag_value = %.*s", tag.len, tag.s);
 		}
 	}
-	if (tag.s) {
-		LM_ERR("dialog callback: msg->to->parsed->tag_value = %.*s", tag.len, tag.s);
-	}
-}
 
 	switch (type) {
 	case DLGCB_FAILED:
@@ -315,7 +315,7 @@ __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_para
  *  Be careful: returns NULL pointer if no avp present!
  *
  */
-struct str_list*  get_str_list(unsigned short avp_flags, int_str avp_name) {
+struct str_list* get_str_list(unsigned short avp_flags, int_str avp_name) {
 
 	int_str avp_value;
 	unsigned int len;
@@ -383,11 +383,11 @@ __dialog_created(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
 			dlg->req_uri.len +
 			dlg->contact[0].len;
 
-    dlginfo = (struct dlginfo_cell*)shm_malloc( len );
-    if (dlginfo==0) {
-        LM_ERR("no more shm mem (%d)\n",len);
-        return;
-    }
+	dlginfo = (struct dlginfo_cell*)shm_malloc( len );
+	if (dlginfo==0) {
+		LM_ERR("no more shm mem (%d)\n",len);
+		return;
+	}
 	memset( dlginfo, 0, len);
 
 	/* copy from dlg structure to dlginfo structure */
diff --git a/modules/pua_mi/mi_func.c b/modules/pua_mi/mi_func.c
index 6343f61..d0061de 100644
--- a/modules/pua_mi/mi_func.c
+++ b/modules/pua_mi/mi_func.c
@@ -220,7 +220,7 @@ struct mi_root* mi_pua_publish(struct mi_root* cmd, void* param)
 	publ.event= get_event_flag(&event);
 	if(publ.event< 0)
 	{
-		LM_ERR("unkown event\n");
+		LM_ERR("unknown event\n");
 		return init_mi_tree(400, "Unknown event", 13);
 	}
 	if(content_type.len!= 1)
@@ -461,7 +461,7 @@ struct mi_root* mi_pua_subscribe(struct mi_root* cmd, void* param)
 	subs.event= get_event_flag(&event);
 	if(subs.event< 0)
 	{
-		LM_ERR("unkown event\n");
+		LM_ERR("unknown event\n");
 		return init_mi_tree(400, "Unknown event", 13);
 	}
 
diff --git a/modules/pua_reginfo/Makefile b/modules/pua_reginfo/Makefile
index b6d8e40..532f159 100644
--- a/modules/pua_reginfo/Makefile
+++ b/modules/pua_reginfo/Makefile
@@ -24,4 +24,7 @@ endif
 
 DEFS+=-DKAMAILIO_MOD_INTERFACE
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
+
 include ../../Makefile.modules
diff --git a/modules/pua_reginfo/README b/modules/pua_reginfo/README
index 5799d0c..0b5709f 100644
--- a/modules/pua_reginfo/README
+++ b/modules/pua_reginfo/README
@@ -10,7 +10,7 @@ Carsten Bock
 
    <carsten at ng-voice.com>
 
-   Copyright © 2011 Carsten Bock, carsten at ng-voice.com,
+   Copyright � 2011 Carsten Bock, carsten at ng-voice.com,
    http://www.ng-voice.com
      __________________________________________________________________
 
@@ -27,25 +27,23 @@ Carsten Bock
         3. Parameters
 
               3.1. default_domain(str)
-              3.2. default_domain(str)
-              3.3. publish_reginfo(int)
-              3.4. outbound_proxy(str)
-              3.5. server_address(str)
+              3.2. publish_reginfo(int)
+              3.3. outbound_proxy(str)
+              3.4. server_address(str)
 
         4. Functions
 
-              4.1. reginfo_handle_notify
+              4.1. reginfo_handle_notify(uldomain)
               4.2. reginfo_subscribe(uri[, expires])
 
    List of Examples
 
    1.1. Set default_domain parameter
-   1.2. Set default_domain parameter
-   1.3. Set publish_reginfo parameter
-   1.4. Set outbound_proxy parameter
-   1.5. Set server_address parameter
-   1.6. reginfo_handle_notify usage
-   1.7. reginfo_subscribe usage
+   1.2. Set publish_reginfo parameter
+   1.3. Set outbound_proxy parameter
+   1.4. Set server_address parameter
+   1.5. reginfo_handle_notify usage
+   1.6. reginfo_subscribe usage
 
 Chapter 1. Admin Guide
 
@@ -60,14 +58,13 @@ Chapter 1. Admin Guide
    3. Parameters
 
         3.1. default_domain(str)
-        3.2. default_domain(str)
-        3.3. publish_reginfo(int)
-        3.4. outbound_proxy(str)
-        3.5. server_address(str)
+        3.2. publish_reginfo(int)
+        3.3. outbound_proxy(str)
+        3.4. server_address(str)
 
    4. Functions
 
-        4.1. reginfo_handle_notify
+        4.1. reginfo_handle_notify(uldomain)
         4.2. reginfo_subscribe(uri[, expires])
 
 1. Overview
@@ -115,69 +112,59 @@ Chapter 1. Admin Guide
 3. Parameters
 
    3.1. default_domain(str)
-   3.2. default_domain(str)
-   3.3. publish_reginfo(int)
-   3.4. outbound_proxy(str)
-   3.5. server_address(str)
+   3.2. publish_reginfo(int)
+   3.3. outbound_proxy(str)
+   3.4. server_address(str)
 
 3.1. default_domain(str)
 
    The default domain for the registered users to be used when
    constructing the uri for the registrar callback.
 
-   Default value is “NULL”.
+   Default value is "NULL".
 
    Example 1.1. Set default_domain parameter
 ...
-modparam("pua_bla", "default_domain", "kamailio.org")
-...
-
-3.2. default_domain(str)
-
-   The domain to be used to publish information about a user.
-
-   Example 1.2. Set default_domain parameter
-...
 modparam("pua_reginfo", "default_domain", "kamailio.org")
 ...
 
-3.3. publish_reginfo(int)
+3.2. publish_reginfo(int)
 
    Whether or not to generate PUBLISH requests.
 
-   Default value is “1” (enabled).
+   Default value is "1" (enabled).
 
-   Example 1.3. Set publish_reginfo parameter
+   Example 1.2. Set publish_reginfo parameter
 ...
 modparam("pua_reginfo", "publish_reginfo", 0)
 ...
 
-3.4. outbound_proxy(str)
+3.3. outbound_proxy(str)
 
    The outbound_proxy uri to be used when sending Subscribe requests.
 
-   Default value is “NULL”.
+   Default value is "NULL".
 
-   Example 1.4. Set outbound_proxy parameter
+   Example 1.3. Set outbound_proxy parameter
 ...
 modparam("pua_reginfo", "outbound_proxy", "sip:proxy at kamailio.org")
 ...
 
-3.5. server_address(str)
+3.4. server_address(str)
 
    The IP address of the server.
 
-   Example 1.5. Set server_address parameter
+   Example 1.4. Set server_address parameter
 ...
 modparam("pua_reginfo", "server_address", "sip:reginfo at 160.34.23.12")
 ...
 
 4. Functions
 
-   4.1. reginfo_handle_notify
+   4.1. reginfo_handle_notify(uldomain)
    4.2. reginfo_subscribe(uri[, expires])
 
-4.1.  reginfo_handle_notify
+4.1. reginfo_handle_notify(uldomain)
 
    This function processes received "NOTIFY"-requests and updates the
    local registry accordingly.
@@ -185,20 +172,23 @@ modparam("pua_reginfo", "server_address", "sip:reginfo at 160.34.23.12")
    This method does not create any SIP-Reponse, this has to be done the
    script-writer.
 
+   The parameter has to correspond to user location table (domain) where
+   to store the record.
+
    Return codes:
      * 2 - contacts successfully updated, but no more contacts online now.
        1 - contacts successfully updated and at at least one contact still
        registered.
        -1 - Invalid NOTIFY or other error (see log-file)
 
-   Example 1.6. reginfo_handle_notify usage
+   Example 1.5. reginfo_handle_notify usage
 ...
 if(is_method("NOTIFY"))
-        if (reginfo_handle_notify())
+        if (reginfo_handle_notify("location"))
                 send_reply("202", "Accepted");
 ...
 
-4.2.  reginfo_subscribe(uri[, expires])
+4.2. reginfo_subscribe(uri[, expires])
 
    This function will subscribe for reginfo-information at the given
    server URI.
@@ -209,7 +199,7 @@ if(is_method("NOTIFY"))
        expires - Expiration date for this subscription, in seconds
        (default 3600)
 
-   Example 1.7. reginfo_subscribe usage
+   Example 1.6. reginfo_subscribe usage
 ...
 route {
         t_on_reply("1");
diff --git a/modules/pua_reginfo/doc/pua_reginfo_admin.xml b/modules/pua_reginfo/doc/pua_reginfo_admin.xml
index b651f44..210ff95 100644
--- a/modules/pua_reginfo/doc/pua_reginfo_admin.xml
+++ b/modules/pua_reginfo/doc/pua_reginfo_admin.xml
@@ -99,7 +99,7 @@
 		<title>Set <varname>default_domain</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("pua_bla", "default_domain", "kamailio.org")
+modparam("pua_reginfo", "default_domain", "kamailio.org")
 ...
 </programlisting>
 		</example>
@@ -157,9 +157,9 @@ modparam("pua_reginfo", "server_address", "sip:reginfo at 160.34.23.12")
 	</section>	
 	<section>
 		<title>Functions</title>
-		<section>
+		<section id="pua_reginfo.f.reginfo_handle_notify">
 			<title>
-				<function moreinfo="none">reginfo_handle_notify</function>
+				<function moreinfo="none">reginfo_handle_notify(uldomain)</function>
 			</title>
 			<para>
 				This function processes received "NOTIFY"-requests and updates
@@ -169,6 +169,10 @@ modparam("pua_reginfo", "server_address", "sip:reginfo at 160.34.23.12")
 				This method does not create any SIP-Reponse, this has to be done
 				the script-writer.
 			</para>
+			<para>
+				The parameter has to correspond to user location table (domain)
+				where to store the record.
+			</para>
 			<para>Return codes:</para>
 			<itemizedlist>
 			<listitem>
@@ -191,7 +195,7 @@ modparam("pua_reginfo", "server_address", "sip:reginfo at 160.34.23.12")
 				<programlisting format="linespecific">
 ...
 if(is_method("NOTIFY")) 
-	if (reginfo_handle_notify())
+	if (reginfo_handle_notify("location"))
 		send_reply("202", "Accepted");
 ...
 				</programlisting>
diff --git a/modules/pua_reginfo/notify.c b/modules/pua_reginfo/notify.c
index a6f7428..c1ea699 100644
--- a/modules/pua_reginfo/notify.c
+++ b/modules/pua_reginfo/notify.c
@@ -26,6 +26,7 @@
 #include "../../parser/parse_content.h"
 #include "../../parser/parse_uri.h"
 #include "../../modules/usrloc/usrloc.h"
+#include "../../lib/srutils/sruid.h"
 #include <libxml/parser.h>
 #include "pua_reginfo.h"
 
@@ -62,7 +63,10 @@
 #define RESULT_CONTACTS_FOUND 1
 #define RESULT_NO_CONTACTS 2
 
-int process_contact(udomain_t * domain, urecord_t ** ul_record, str aor, str callid, int cseq, int expires, int event, str contact_uri) {
+extern sruid_t _reginfo_sruid;
+
+int process_contact(udomain_t * domain, urecord_t ** ul_record, str aor, str callid,
+		int cseq, int expires, int event, str contact_uri) {
 	str no_str = {0, 0};
 	static str no_ua = str_init("n/a");
 	static ucontact_info_t ci;
@@ -102,6 +106,13 @@ int process_contact(udomain_t * domain, urecord_t ** ul_record, str aor, str cal
 	/* set expire time */
 	ci.expires = time(0) + expires;
 
+	/* set ruid */
+	if(sruid_next(&_reginfo_sruid) < 0) {
+		LM_ERR("failed to generate ruid");
+	} else {
+		ci.ruid = _reginfo_sruid.uid;
+	}
+
 	/* Now we start looking for the contact: */
 	if (((*ul_record)->contacts == 0)
 		|| (ul.get_ucontact(*ul_record, &contact_uri, &callid, &no_str, cseq+1, &ul_contact) != 0)) {
@@ -197,6 +208,8 @@ int reginfo_parse_event(char * s) {
 int process_body(str notify_body, udomain_t * domain) {
 	xmlDocPtr doc= NULL;
 	xmlNodePtr doc_root = NULL, registrations = NULL, contacts = NULL, uris = NULL;
+	char uri[MAX_URI_SIZE];
+	str aor_key = {0, 0};
 	str aor = {0, 0};
 	str callid = {0, 0};
 	str contact_uri = {0, 0};
@@ -249,14 +262,20 @@ int process_body(str notify_body, udomain_t * domain) {
 			goto next_registration;
 		}
 
+		if (reginfo_use_domain) {
+			aor_key.s = uri;
+		} else {
+			aor_key.s = parsed_aor.user.s;
+		}
+		aor_key.len = strlen(aor_key.s);
 		/* Now let's lock that domain for this AOR: */		
-		ul.lock_udomain(domain, &aor);
+		ul.lock_udomain(domain, &aor_key);
 		/* and retrieve the user-record for this user: */
-		result = ul.get_urecord(domain, &aor, &ul_record);
+		result = ul.get_urecord(domain, &aor_key, &ul_record);
 		if (result < 0) {
-			ul.unlock_udomain(domain, &aor);
+			ul.unlock_udomain(domain, &aor_key);
 			LM_ERR("failed to query usrloc (AOR %.*s)\n",
-				aor.len, aor.s);
+				aor_key.len, aor_key.s);
 			goto next_registration;
 		}
 		/* If no contacts found, then set the ul_record to NULL */
@@ -274,7 +293,7 @@ int process_body(str notify_body, udomain_t * domain) {
 					}
 					ul_contact = ul_contact->next;
 				}
-				if (ul.delete_urecord(domain, &aor, ul_record) < 0) {
+				if (ul.delete_urecord(domain, &aor_key, ul_record) < 0) {
 					LM_ERR("failed to remove record from usrloc\n");
 				}
 				/* If already a registration with contacts was found, then keep that result.
@@ -360,7 +379,7 @@ int process_body(str notify_body, udomain_t * domain) {
 						contact_uri.len, contact_uri.s);
 
 					/* Add to Usrloc: */
-					result = process_contact(domain, &ul_record, parsed_aor.user, callid, cseq, expires, event, contact_uri);
+					result = process_contact(domain, &ul_record, aor_key, callid, cseq, expires, event, contact_uri);
 				
 					/* Process the result */
 					if (final_result != RESULT_CONTACTS_FOUND) final_result = result;
@@ -374,7 +393,8 @@ next_contact:
 next_registration:
 		// if (ul_record) ul.release_urecord(ul_record);		
 		/* Unlock the domain for this AOR: */
-		ul.unlock_udomain(domain, &aor);
+		if (aor_key.len > 0)
+			ul.unlock_udomain(domain, &aor_key);
 
 		registrations = registrations->next;
 	}
diff --git a/modules/pua_reginfo/pua_reginfo.c b/modules/pua_reginfo/pua_reginfo.c
index a9ffe76..b3ddb26 100644
--- a/modules/pua_reginfo/pua_reginfo.c
+++ b/modules/pua_reginfo/pua_reginfo.c
@@ -25,6 +25,7 @@
 #include "../pua/pua_bind.h"
 /* Bindings to usrloc */
 #include "../usrloc/usrloc.h"
+#include "../../lib/srutils/sruid.h"
 
 #include "pua_reginfo.h"
 #include "subscribe.h"
@@ -43,6 +44,9 @@ str server_address = {NULL, 0};
 
 int publish_reginfo = 1;
 
+sruid_t _reginfo_sruid;
+
+int reginfo_use_domain = 0;
 
 /** Fixup functions */
 static int domain_fixup(void** param, int param_no);
@@ -161,6 +165,15 @@ static int mod_init(void)
 			return -1;
 		}
 	}
+
+	if(sruid_init(&_reginfo_sruid, (char)'-', "regi", SRUID_INC)<0)
+		return -1;
+
+	/*
+	 * Import use_domain parameter from usrloc
+	 */
+	reginfo_use_domain = ul.use_domain;
+
 	return 0;
 }
 
diff --git a/modules/pua_reginfo/pua_reginfo.h b/modules/pua_reginfo/pua_reginfo.h
index 2ff8e54..972ae0b 100644
--- a/modules/pua_reginfo/pua_reginfo.h
+++ b/modules/pua_reginfo/pua_reginfo.h
@@ -34,4 +34,6 @@ str server_address;
 extern usrloc_api_t ul; /*!< Structure containing pointers to usrloc functions*/
 extern pua_api_t pua; /*!< Structure containing pointers to PUA functions*/
 
+extern int reginfo_use_domain;
+
 #endif
diff --git a/modules/pua_usrloc/ul_publish.c b/modules/pua_usrloc/ul_publish.c
index 4eaf7a9..24dd3c9 100644
--- a/modules/pua_usrloc/ul_publish.c
+++ b/modules/pua_usrloc/ul_publish.c
@@ -323,8 +323,8 @@ void ul_publish(ucontact_t* c, int type, void* param)
 	print_publ(publ);
 	if((error=pua_send_publish(publ))< 0)
 	{
-		LM_ERR("while sending publish\n");
-		if(type & UL_CONTACT_UPDATE && error == ERR_PUBLISH_NO_BODY) {
+		LM_ERR("while sending publish for ul event %d\n", type);
+		if((type & UL_CONTACT_UPDATE) && error == ERR_PUBLISH_NO_BODY) {
 			/* This error can occur if Kamailio was restarted/stopped and for any reason couldn't store a pua
 			 * entry in 'pua' DB table. It can also occur if 'pua' table is cleaned externally while Kamailio
 			 * is stopped so cannot retrieve these entries from DB when restarting.
diff --git a/modules/pv/README b/modules/pv/README
index bf44993..edfd000 100644
--- a/modules/pv/README
+++ b/modules/pv/README
@@ -14,6 +14,8 @@ Daniel-Constantin Mierla
    Copyright � 2008-2011 Daniel-Constantin Mierla (asipto.com)
 
    Copyright � 2011 Juha Heinanen
+
+   Copyright � 2013 Olle E. Johansson, Edvina AB
      __________________________________________________________________
 
    Table of Contents
@@ -45,6 +47,11 @@ Daniel-Constantin Mierla
               5.1. shv_set
               5.2. shv_get
 
+        6. RPC Commands
+
+              6.1. pv.shvSet
+              6.2. pv.shvGet
+
    List of Examples
 
    1.1. shvset parameter usage
@@ -87,6 +94,11 @@ Chapter 1. Admin Guide
         5.1. shv_set
         5.2. shv_get
 
+   6. RPC Commands
+
+        6.1. pv.shvSet
+        6.2. pv.shvGet
+
 1. Overview
 
    This module collects the core pseudo-variables that can be used in
@@ -296,3 +308,28 @@ $ kamctl fifo shv_set debug int 0
 $ kamctl fifo shv_get debug
 $ kamctl fifo shv_get
 ...
+
+6. RPC Commands
+
+   6.1. pv.shvSet
+   6.2. pv.shvGet
+
+6.1. pv.shvSet
+
+   Set the value of a shared variable ($shv(name)).
+
+   Parameters:
+     * _name_: shared variable name
+     * _type_: type of the value
+          + "int": integer value
+          + "str": string value
+     * _value_: value to be set
+
+6.2. pv.shvGet
+
+   Get the value of a shared variable ($shv(name)).
+
+   Parameters:
+     * _name_: shared variable name
+
+   If no name is given, all shared variables are listed
diff --git a/modules/pv/doc/pv.xml b/modules/pv/doc/pv.xml
index 1ca758a..acae2e8 100644
--- a/modules/pv/doc/pv.xml
+++ b/modules/pv/doc/pv.xml
@@ -38,6 +38,10 @@
 	    <year>2011</year>
 	    <holder>Juha Heinanen</holder>
 	</copyright>
+	<copyright>
+	    <year>2013</year>
+	    <holder>Olle E. Johansson, Edvina AB</holder>
+	</copyright>
     </bookinfo>
     <toc></toc>
     
diff --git a/modules/pv/doc/pv_admin.xml b/modules/pv/doc/pv_admin.xml
index 38fce2a..c3f97cc 100644
--- a/modules/pv/doc/pv_admin.xml
+++ b/modules/pv/doc/pv_admin.xml
@@ -336,5 +336,39 @@ $ &ctltool; fifo shv_get
 			</example>
 		</section>
 	</section>
+	<section>
+        <title>RPC Commands</title>
+		<section>
+			<title><function moreinfo="none">pv.shvSet</function></title>
+			<para>
+				Set the value of a shared variable ($shv(name)).
+			</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>_name_: shared variable name</para></listitem>
+			
+			<listitem><para>_type_: type of the value</para>
+			      <itemizedlist>
+	    <listitem><para> <quote>int</quote>: integer value </para></listitem> 
+		<listitem><para> <quote>str</quote>: string value </para></listitem>	
+				  </itemizedlist>
+			</listitem>	  
+
+			<listitem><para>_value_: value to be set</para></listitem>
+		</itemizedlist>
+		</section>
+		<section>
+			<title><function moreinfo="none">pv.shvGet</function></title>
+			<para>
+				Get the value of a shared variable ($shv(name)).
+			</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>_name_: shared variable name</para></listitem>
+		</itemizedlist>
+		<para>If no name is given, all shared variables are listed</para>
+		</section>
+	</section>
+	
 </chapter>
 
diff --git a/modules/pv/pv.c b/modules/pv/pv.c
index 0b22faf..2b13ec8 100644
--- a/modules/pv/pv.c
+++ b/modules/pv/pv.c
@@ -28,6 +28,9 @@
 #include "../../pvar.h"
 #include "../../mod_fix.h"
 #include "../../lib/kmi/mi.h"
+#include "../../rpc.h"
+#include "../../rpc_lookup.h"
+
 
 #include "pv_branch.h"
 #include "pv_core.h"
@@ -60,6 +63,8 @@ static tr_export_t mod_trans[] = {
 };
 
 static pv_export_t mod_pvs[] = {
+	{ {"_s", (sizeof("_s")-1)}, PVT_OTHER, pv_get__s, 0,
+		pv_parse__s_name, 0, 0, 0 },
 	{ {"af", (sizeof("af")-1)}, PVT_OTHER, pv_get_af, 0,
 		pv_parse_af_name, 0, 0, 0 },
 	{ {"branch", sizeof("branch")-1}, /* branch attributes */
@@ -82,7 +87,7 @@ static pv_export_t mod_pvs[] = {
 		pv_parse_snd_name, 0, 0, 0 },
 #ifdef WITH_XAVP
 	{ {"xavp", sizeof("xavp")-1}, /* xavp */
-		PVT_OTHER, pv_get_xavp, pv_set_xavp,
+		PVT_XAVP, pv_get_xavp, pv_set_xavp,
 		pv_parse_xavp_name, 0, 0, 0 },
 #endif
 
@@ -94,7 +99,7 @@ static pv_export_t mod_pvs[] = {
 		pv_set_scriptvar, pv_parse_scriptvar_name, 0, 0, 0},
 	{{"ai", (sizeof("ai")-1)}, /* */
 		PVT_OTHER, pv_get_pai, 0,
-		0, 0, 0, 0},
+		0, pv_parse_index, 0, 0},
 	{{"adu", (sizeof("adu")-1)}, /* auth digest uri */
 		PVT_OTHER, pv_get_authattr, 0,
 		0, 0, pv_init_iname, 3},
@@ -140,6 +145,9 @@ static pv_export_t mod_pvs[] = {
 	{{"cnt", sizeof("cnt")-1},
 		PVT_OTHER, pv_get_cnt, 0,
 		pv_parse_cnt_name, 0, 0, 0 },
+	{{"conid", (sizeof("conid")-1)}, /* */
+		PVT_OTHER, pv_get_tcpconn_id, 0,
+		0, 0, 0, 0},
 	{{"cs", (sizeof("cs")-1)}, /* */
 		PVT_OTHER, pv_get_cseq, 0,
 		0, 0, 0, 0},
@@ -259,10 +267,10 @@ static pv_export_t mod_pvs[] = {
 		0, 0, pv_init_iname, 1},
 	{{"pd", (sizeof("pd")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 3},
+		0, pv_parse_index, pv_init_iname, 3},
 	{{"pn", (sizeof("pn")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 4},
+		0, pv_parse_index, pv_init_iname, 4},
 	{{"pp", (sizeof("pp")-1)}, /* */
 		PVT_OTHER, pv_get_pid, 0,
 		0, 0, 0, 0},
@@ -274,10 +282,10 @@ static pv_export_t mod_pvs[] = {
 		0, 0, 0, 0},
 	{{"pu", (sizeof("pu")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 1},
+		0, pv_parse_index, pv_init_iname, 1},
 	{{"pU", (sizeof("pU")-1)}, /* */
 		PVT_OTHER, pv_get_ppi_attr, 0,
-		0, 0, pv_init_iname, 2},
+		0, pv_parse_index, pv_init_iname, 2},
 	{{"rb", (sizeof("rb")-1)}, /* */
 		PVT_MSG_BODY, pv_get_msg_body, 0,
 		0, 0, 0, 0},
@@ -407,6 +415,12 @@ static pv_export_t mod_pvs[] = {
 	{{"ua", (sizeof("ua")-1)}, /* */
 		PVT_OTHER, pv_get_useragent, 0,
 		0, 0, 0, 0},
+	{{"ruid", (sizeof("ruid")-1)}, /* */
+		PVT_OTHER, pv_get_ruid, 0,
+		0, 0, 0, 0},
+	{{"location_ua", (sizeof("location_ua")-1)}, /* */
+		PVT_OTHER, pv_get_location_ua, 0,
+		0, 0, 0, 0},
 
 	{ {"shv", (sizeof("shv")-1)}, PVT_OTHER, pv_get_shvar,
 		pv_set_shvar, pv_parse_shvar_name, 0, 0, 0},
@@ -448,6 +462,7 @@ static int pv_unset(struct sip_msg* msg, char* pvid, char *foo);
 static int is_int(struct sip_msg* msg, char* pvar, char* s2);
 static int pv_typeof(sip_msg_t *msg, char *pv, char *t);
 static int pv_not_empty(sip_msg_t *msg, char *pv, char *s2);
+static int pv_init_rpc(void);
 
 static cmd_export_t cmds[]={
 	{"pv_isset",  (cmd_function)pv_isset,  1, fixup_pvar_null, 0, 
@@ -495,6 +510,11 @@ static int mod_init(void)
 		LM_ERR("failed to register MI commands\n");
 		return -1;
 	}
+	if(pv_init_rpc()!=0)
+        {
+                LM_ERR("failed to register RPC commands\n");
+                return -1;
+        }
 
 	return 0;
 }
@@ -629,3 +649,29 @@ static int is_int(struct sip_msg* msg, char* pvar, char* s2)
 
 	return -1;
 }
+
+static const char* rpc_shv_set_doc[2] = {
+	"Set a shared variable (args: name type value)",
+	0
+};
+
+static const char* rpc_shv_get_doc[2] = {
+	"Get the value of a shared variable. If no argument, dumps all",
+	0
+};
+
+rpc_export_t pv_rpc[] = {
+	{"pv.shvSet", rpc_shv_set, rpc_shv_set_doc, 0},
+	{"pv.shvGet", rpc_shv_get, rpc_shv_get_doc, 0},
+	{0, 0, 0, 0}
+};
+
+static int pv_init_rpc(void)
+{
+	if (rpc_register_array(pv_rpc)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/modules/pv/pv_branch.c b/modules/pv/pv_branch.c
index 2abd639..0b5138a 100644
--- a/modules/pv/pv_branch.c
+++ b/modules/pv/pv_branch.c
@@ -40,6 +40,8 @@ int pv_get_branchx(struct sip_msg *msg, pv_param_t *param,
 	str path;
 	unsigned int fl = 0;
 	struct socket_info* fsocket = NULL;
+	str ruid;
+	str location_ua;
 
 	/* get the index */
 	if(pv_get_spec_index(msg, param, &idx, &idxf)!=0)
@@ -48,7 +50,7 @@ int pv_get_branchx(struct sip_msg *msg, pv_param_t *param,
 		return pv_get_null(msg, param, res);
 	}
 
-	uri.s = get_branch(idx, &uri.len, &lq, &duri, &path, &fl, &fsocket);
+	uri.s = get_branch(idx, &uri.len, &lq, &duri, &path, &fl, &fsocket, &ruid, 0, &location_ua);
 
 	/* branch(count) doesn't need a valid branch, everything else does */
 	if(uri.s == 0 && ( param->pvn.u.isname.name.n != 5/* count*/ ))
@@ -79,6 +81,14 @@ int pv_get_branchx(struct sip_msg *msg, pv_param_t *param,
 			return pv_get_uintval(msg, param, res, nr_branches);
 		case 6: /* flags */
 			return pv_get_uintval(msg, param, res, fl);
+		case 7: /* ruid */
+			if(ruid.len==0)
+				return pv_get_null(msg, param, res);
+			return pv_get_strval(msg, param, res, &ruid);
+		case 8: /* location_ua */
+			if(location_ua.len==0)
+				return pv_get_null(msg, param, res);
+			return pv_get_strval(msg, param, res, &location_ua);
 		default:
 			/* 0 - uri */
 			return pv_get_strval(msg, param, res, &uri);
@@ -245,6 +255,12 @@ int pv_set_branchx(struct sip_msg* msg, pv_param_t *param,
 			}
 			br->flags = val->ri;
 		break;
+		case 7: /* ruid */
+			/* do nothing - cannot set the ruid */
+		break;
+		case 8: /* location_ua */
+			/* do nothing - cannot set the location_ua */
+		break;
 		default:
 			/* 0 - uri */
 			if(val==NULL || (val->flags&PV_VAL_NULL))
@@ -296,6 +312,8 @@ int pv_parse_branchx_name(pv_spec_p sp, str *in)
 		case 4: 
 			if(strncmp(in->s, "path", 4)==0)
 				sp->pvp.pvn.u.isname.name.n = 2;
+			else if (strncmp(in->s, "ruid", 4)==0)
+				sp->pvp.pvn.u.isname.name.n = 7;
 			else goto error;
 		break;
 		case 1: 
@@ -306,6 +324,8 @@ int pv_parse_branchx_name(pv_spec_p sp, str *in)
 		case 11: 
 			if(strncmp(in->s, "send_socket", 11)==0)
 				sp->pvp.pvn.u.isname.name.n = 4;
+			else if(strncmp(in->s, "location_ua", 11)==0)
+				sp->pvp.pvn.u.isname.name.n = 8;
 			else goto error;
 		break;
 		case 5: 
diff --git a/modules/pv/pv_core.c b/modules/pv/pv_core.c
index ac0b638..85e6f8a 100644
--- a/modules/pv/pv_core.c
+++ b/modules/pv/pv_core.c
@@ -32,6 +32,8 @@
 #include "../../socket_info.h"
 #include "../../data_lump.h"
 #include "../../lib/kcore/cmpapi.h"
+#include "../../tcp_conn.h"
+#include "../../pvapi.h"
 
 #include "../../parser/parse_from.h"
 #include "../../parser/parse_uri.h"
@@ -40,8 +42,7 @@
 #include "../../parser/parse_refer_to.h"
 #include "../../parser/parse_rpid.h"
 #include "../../parser/parse_diversion.h"
-#include "../../lib/kcore/parse_ppi.h"
-#include "../../lib/kcore/parse_pai.h"
+#include "../../parser/parse_ppi_pai.h"
 #include "../../parser/digest/digest.h"
 
 #include "pv_core.h"
@@ -71,10 +72,6 @@ int _pv_pid = 0;
 
 #define PV_FIELD_DELIM ", "
 #define PV_FIELD_DELIM_LEN (sizeof(PV_FIELD_DELIM) - 1)
-#define PV_LOCAL_BUF_SIZE	511
-
-static char pv_local_buf[PV_LOCAL_BUF_SIZE+1];
-
 
 int pv_get_msgid(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
@@ -865,38 +862,84 @@ int pv_get_rpid(struct sip_msg *msg, pv_param_t *param,
 int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 {
+    int idxf;
+    int idx;
     struct sip_uri *uri;
-    
-    if(msg==NULL)
-	return -1;
+    p_id_body_t *ppi_body = NULL;
+	to_body_t *ppi_uri = NULL;
+	int i, cur_id;
 
-    if(parse_ppi_header(msg) < 0) {
-	LM_DBG("no P-Preferred-Identity header\n");
-	return pv_get_null(msg, param, res);
-    }
-	
-    if(msg->ppi == NULL || get_ppi(msg) == NULL) {
-	       LM_DBG("no P-Preferred-Identity header\n");
+    if(msg==NULL)
+		return -1;
+    
+	if(parse_ppi_header(msg) < 0)
+    {
+		LM_DBG("no P-Preferred-Identity header\n");
 		return pv_get_null(msg, param, res);
     }
-    
+
+    if (pv_get_spec_index(msg, param, &idx, &idxf) != 0)
+    {
+    	LM_ERR("Invalid index\n");
+		return -1;
+    }
+
+    if (idxf == PV_IDX_ALL)
+	{
+		LM_ERR("Unable to return 'all' PPI values\n");
+		return -1;
+	}
+
+	ppi_body = get_ppi(msg);
+	ppi_uri = &ppi_body->id[0];
+	cur_id = 0;
+	i = 0;
+	while (i < idx)
+	{
+		cur_id++;
+		if (cur_id < ppi_body->num_ids)
+		{
+			ppi_uri = &ppi_body->id[cur_id];
+			i++;
+		}
+		else if (ppi_body->next != NULL)
+		{
+			ppi_body = ppi_body->next;
+			ppi_uri = &ppi_body->id[0];
+			cur_id = 0;
+			i++;
+		}
+		else
+		{
+			/* No more PPIs */
+			return pv_get_null(msg, param, res);
+		}
+
+	}
+	/* Found the ID at index 'idx' */
+
     if(param->pvn.u.isname.name.n == 1) { /* uri */
-		return pv_get_strval(msg, param, res, &(get_ppi(msg)->uri));
+		return pv_get_strval(msg, param, res, &(ppi_uri->uri));
     }
 	
     if(param->pvn.u.isname.name.n==4) { /* display name */
-		if(get_ppi(msg)->display.s == NULL ||
-				get_ppi(msg)->display.len <= 0) {
+		if(ppi_uri->display.s == NULL ||
+				ppi_uri->display.len <= 0) {
 		    LM_DBG("no P-Preferred-Identity display name\n");
 			return pv_get_null(msg, param, res);
 		}
-		return pv_get_strval(msg, param, res, &(get_ppi(msg)->display));
+		return pv_get_strval(msg, param, res, &(ppi_uri->display));
     }
 
-    if((uri=parse_ppi_uri(msg))==NULL) {
-		LM_ERR("cannot parse P-Preferred-Identity URI\n");
-		return pv_get_null(msg, param, res);
-    }
+	uri = &ppi_uri->parsed_uri;
+	if (uri->host.s == NULL && uri->user.s == NULL)
+	{
+		if (parse_uri(ppi_uri->uri.s, ppi_uri->uri.len, uri) < 0)
+		{
+			LM_ERR("cannot parse P-Preferred-Identity URI\n");
+			return pv_get_null(msg, param, res);
+		}
+	}
 
     if(param->pvn.u.isname.name.n==2) { /* username */
 		if(uri->user.s==NULL || uri->user.len<=0) {
@@ -920,21 +963,62 @@ int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param,
 int pv_get_pai(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 {
+    int idxf;
+    int idx;
+    p_id_body_t *pai_body = NULL;
+	to_body_t *pai_uri = NULL;
+	int i, cur_id;
+
     if(msg==NULL)
 		return -1;
     
-    if(parse_pai_header(msg)==-1)
+	if(parse_pai_header(msg) < 0)
     {
 		LM_DBG("no P-Asserted-Identity header\n");
 		return pv_get_null(msg, param, res);
     }
-	
-    if(msg->pai==NULL || get_pai(msg)==NULL) {
-		LM_DBG("no P-Asserted-Identity header\n");
-		return pv_get_null(msg, param, res);
+
+    if (pv_get_spec_index(msg, param, &idx, &idxf) != 0)
+    {
+    	LM_ERR("Invalid index\n");
+		return -1;
     }
-    
-	return pv_get_strval(msg, param, res, &(get_pai(msg)->uri));
+
+    if (idxf == PV_IDX_ALL)
+	{
+		LM_ERR("Unable to return 'all' PAI values\n");
+		return -1;
+	}
+
+	pai_body = get_pai(msg);
+	pai_uri = &pai_body->id[0];
+	cur_id = 0;
+	i = 0;
+	while (i < idx)
+	{
+		cur_id++;
+		if (cur_id < pai_body->num_ids)
+		{
+			pai_uri = &pai_body->id[cur_id];
+			i++;
+		}
+		else if (pai_body->next != NULL)
+		{
+			pai_body = pai_body->next;
+			pai_uri = &pai_body->id[0];
+			cur_id = 0;
+			i++;
+		}
+		else
+		{
+			/* No more PAIs */
+			return pv_get_null(msg, param, res);
+		}
+
+	}
+	/* Found the ID at index 'idx' */
+
+	return pv_get_strval(msg, param, res, &(pai_uri->uri));
 }
 
 /* proto of received message: $pr or $proto*/
@@ -1272,7 +1356,7 @@ int pv_get_branch(struct sip_msg *msg, pv_param_t *param,
 		return pv_get_null(msg, param, res);
 
 
-	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0);
+	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0, 0, 0);
 	if (!branch.s) {
 		return pv_get_null(msg, param, res);
 	}
@@ -1291,7 +1375,7 @@ int pv_get_branches(struct sip_msg *msg, pv_param_t *param,
 	qvalue_t q;
 	int cnt, i;
 	unsigned int qlen;
-	char *p, *qbuf;
+	char *p, *qbuf, *p_ini;
 
 	if(msg==NULL || res==NULL)
 		return -1;
@@ -1301,7 +1385,7 @@ int pv_get_branches(struct sip_msg *msg, pv_param_t *param,
   
 	cnt = s.len = 0;
 
-	while ((uri.s = get_branch(cnt, &uri.len, &q, 0, 0, 0, 0)))
+	while ((uri.s = get_branch(cnt, &uri.len, &q, 0, 0, 0, 0, 0, 0, 0)))
 	{
 		cnt++;
 		s.len += uri.len;
@@ -1315,17 +1399,17 @@ int pv_get_branches(struct sip_msg *msg, pv_param_t *param,
 		return pv_get_null(msg, param, res);   
 
 	s.len += (cnt - 1) * PV_FIELD_DELIM_LEN;
-
-	if (s.len + 1 > PV_LOCAL_BUF_SIZE)
+	if (s.len + 1 > pv_get_buffer_size())
 	{
 		LM_ERR("local buffer length exceeded\n");
 		return pv_get_null(msg, param, res);
 	}
 
 	i = 0;
-	p = pv_local_buf;
+	p_ini = pv_get_buffer();
+	p = p_ini;
 
-	while ((uri.s = get_branch(i, &uri.len, &q, 0, 0, 0, 0)))
+	while ((uri.s = get_branch(i, &uri.len, &q, 0, 0, 0, 0, 0, 0, 0)))
 	{
 		if (i)
 		{
@@ -1352,7 +1436,7 @@ int pv_get_branches(struct sip_msg *msg, pv_param_t *param,
 		i++;
 	}
 
-	s.s = &(pv_local_buf[0]);
+	s.s = &(p_ini[0]);
 	return pv_get_strval(msg, param, res, &s);
 }
 
@@ -1366,7 +1450,8 @@ int pv_get_avp(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 	struct usr_avp *avp0;
 	int idx;
 	int idxf;
-	char *p;
+	char *p, *p_ini;
+	int p_size;
 	int n=0;
 	struct search_state state;
 
@@ -1404,11 +1489,13 @@ int pv_get_avp(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 	}
 	if(idxf==PV_IDX_ALL)
 	{
-		p = pv_local_buf;
+		p_ini = pv_get_buffer();
+		p = p_ini;
+		p_size = pv_get_buffer_size();
 		do {
-			if(p!=pv_local_buf)
+			if(p!=p_ini)
 			{
-				if(p-pv_local_buf+PV_FIELD_DELIM_LEN+1>PV_LOCAL_BUF_SIZE)
+				if(p-p_ini+PV_FIELD_DELIM_LEN+1>p_size)
 				{
 					LM_ERR("local buffer length exceeded\n");
 					return pv_get_null(msg, param, res);
@@ -1423,7 +1510,7 @@ int pv_get_avp(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 				res->rs.s = int2str(avp_value.n, &res->rs.len);
 			}
 			
-			if(p-pv_local_buf+res->rs.len+1>PV_LOCAL_BUF_SIZE)
+			if(p-p_ini+res->rs.len+1>p_size)
 			{
 				LM_ERR("local buffer length exceeded!\n");
 				return pv_get_null(msg, param, res);
@@ -1431,9 +1518,8 @@ int pv_get_avp(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 			memcpy(p, res->rs.s, res->rs.len);
 			p += res->rs.len;
 		} while ((avp=search_next_avp(&state, &avp_value))!=0);
-		*p = 0;
-		res->rs.s = pv_local_buf;
-		res->rs.len = p - pv_local_buf;
+		res->rs.s = p_ini;
+		res->rs.len = p - p_ini;
 		return 0;
 	}
 
@@ -1492,8 +1578,8 @@ int pv_get_hdr(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 	pv_value_t tv;
 	struct hdr_field *hf;
 	struct hdr_field *hf0;
-	char *p;
-	int n;
+	char *p, *p_ini;
+	int n, p_size;
 
 	if(msg==NULL || res==NULL || param==NULL)
 		return -1;
@@ -1552,11 +1638,13 @@ int pv_get_hdr(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 	}
 	if(idxf==PV_IDX_ALL)
 	{
-		p = pv_local_buf;
+		p_ini = pv_get_buffer();
+		p = p_ini;
+		p_size = pv_get_buffer_size();
 		do {
-			if(p!=pv_local_buf)
+			if(p!=p_ini)
 			{
-				if(p-pv_local_buf+PV_FIELD_DELIM_LEN+1>PV_LOCAL_BUF_SIZE)
+				if(p-p_ini+PV_FIELD_DELIM_LEN+1>p_size)
 				{
 					LM_ERR("local buffer length exceeded\n");
 					return pv_get_null(msg, param, res);
@@ -1564,10 +1652,10 @@ int pv_get_hdr(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 				memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN);
 				p += PV_FIELD_DELIM_LEN;
 			}
-			if(p-pv_local_buf+hf->body.len+1>PV_LOCAL_BUF_SIZE)
+			if(p-p_ini+hf->body.len+1>p_size)
 			{
 				LM_ERR("local buffer length exceeded [%d/%d]!\n",
-						(int)(p-pv_local_buf+hf->body.len+1),
+						(int)(p-p_ini+hf->body.len+1),
 						hf->body.len);
 				return pv_get_null(msg, param, res);
 			}
@@ -1586,9 +1674,8 @@ int pv_get_hdr(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 				}
 			}
 		} while (hf);
-		*p = 0;
-		res->rs.s = pv_local_buf;
-		res->rs.len = p - pv_local_buf;
+		res->rs.s = p_ini;
+		res->rs.len = p - p_ini;
 		return 0;
 	}
 
@@ -1718,6 +1805,56 @@ int pv_get_cnt(struct sip_msg *msg, pv_param_t *param,
 	return pv_get_uintval(msg, param, res, n);
 }
 
+int pv_get_ruid(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REPLY)
+		return pv_get_null(msg, param, res);
+
+	if(msg->ruid.len==0) 
+	{
+		LM_DBG("no ruid\n");
+		return pv_get_null(msg, param, res);
+	}
+	
+	return pv_get_strval(msg, param, res, &msg->ruid);
+}
+
+int pv_get_location_ua(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REPLY)
+		return pv_get_null(msg, param, res);
+
+	if(msg->location_ua.len==0) 
+	{
+		LM_DBG("no location_ua\n");
+		return pv_get_null(msg, param, res);
+	}
+	
+	return pv_get_strval(msg, param, res, &msg->location_ua);
+}
+
+int pv_get_tcpconn_id(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	struct tcp_connection *con;
+
+	if (msg == NULL)
+		return -1;
+
+	if ((con = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, 0, 0)) == NULL)
+		return pv_get_null(msg, param, res);
+
+	return pv_get_sintval(msg, param, res, con->id);
+}
+
 
 /********* end PV get functions *********/
 
@@ -2603,14 +2740,15 @@ int pv_parse_hdr_name(pv_spec_p sp, str *in)
 		return 0;
 	}
 
-	if(in->len>=PV_LOCAL_BUF_SIZE-1)
+	if(in->len>=pv_get_buffer_size()-1)
 	{
 		LM_ERR("name too long\n");
 		return -1;
 	}
-	memcpy(pv_local_buf, in->s, in->len);
-	pv_local_buf[in->len] = ':';
-	s.s = pv_local_buf;
+	p = pv_get_buffer();
+	memcpy(p, in->s, in->len);
+	p[in->len] = ':';
+	s.s = p;
 	s.len = in->len+1;
 
 	if (parse_hname2(s.s, s.s + ((s.len<4)?4:s.len), &hdr)==0)
@@ -2761,3 +2899,44 @@ int pv_get_K(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
 			return pv_get_uintval(msg, param, res, AF_INET);
 	}
 }
+
+/**
+ *
+ */
+int pv_parse__s_name(pv_spec_p sp, str *in)
+{
+	pv_elem_t *fmt = NULL;
+
+	if(in->s==NULL || in->len<=0)
+		return -1;
+	if(pv_parse_format(in, &fmt)<0 || fmt==NULL)
+	{
+		LM_ERR("wrong format[%.*s]\n", in->len, in->s);
+		return -1;
+	}
+	sp->pvp.pvn.u.dname = (void*)fmt;
+	sp->pvp.pvn.type = PV_NAME_OTHER;
+	return 0;
+}
+
+/**
+ *
+ */
+int pv_get__s(sip_msg_t *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	str sdata = {0};
+	pv_elem_t *fmt = NULL;
+	fmt = (pv_elem_t*)param->pvn.u.dname;
+
+	if(fmt==NULL)
+	{
+		return pv_get_null(msg, param, res);
+	}
+	if(pv_printf_s(msg, fmt, &sdata)!=0)
+	{
+		LM_ERR("cannot evaluate the string\n");
+		return -1;
+	}
+	return pv_get_strval(msg, param, res, &sdata);
+}
diff --git a/modules/pv/pv_core.h b/modules/pv/pv_core.h
index a8d36bb..83eac5a 100644
--- a/modules/pv/pv_core.h
+++ b/modules/pv/pv_core.h
@@ -214,6 +214,15 @@ int pv_get_server_id(struct sip_msg *msg, pv_param_t *param,
 int pv_get_cnt(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 
+int pv_get_ruid(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
+
+int pv_get_location_ua(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
+
+int pv_get_tcpconn_id(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
+
 /********* end PV get functions *********/
 
 /********* start PV set functions *********/
@@ -306,5 +315,10 @@ int pv_get_K(sip_msg_t *msg, pv_param_t *param,
 
 int pv_parse_flag_param(pv_spec_p sp, str *in);
 
+int pv_parse__s_name(pv_spec_p sp, str *in);
+
+int pv_get__s(sip_msg_t *msg, pv_param_t *param,
+		pv_value_t *res);
+
 #endif
 
diff --git a/modules/pv/pv_shv.c b/modules/pv/pv_shv.c
index 548ab04..dc0109f 100644
--- a/modules/pv/pv_shv.c
+++ b/modules/pv/pv_shv.c
@@ -2,6 +2,7 @@
  * $Id$
  *
  * Copyright (C) 2007 Elena-Ramona Modroiu
+ * Copyright (C) 2013 Olle E. Johansson
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -615,6 +616,152 @@ error:
 	return NULL;
 }
 
+
+void rpc_shv_get(rpc_t* rpc, void* c)
+{
+	str varname;
+	int allvars = 0;
+	sh_var_t *shv = NULL;
+	void* th;
+        void* ih;
+        void* vh;
+
+	if (rpc->scan(c, "S", &varname) != 1) {
+		allvars = 1;
+        }
+
+	if (!allvars) {
+		/* Get one variable value */
+		shv = get_shvar_by_name(&varname);
+		if(shv==NULL) {
+			rpc->fault(c, 404, "Variable not found");
+			return;
+		}
+		if (rpc->add(c, "{",  &ih) < 0)
+        	{
+               		rpc->fault(c, 500, "Internal error creating rpc");
+                	return;
+        	}
+		
+		lock_shvar(shv);
+		if(shv->v.flags&VAR_VAL_STR)
+		{
+			if(rpc->struct_add(ih, "sss", "name", varname.s, "type", "string", "value", shv->v.value.s.s) < 0)
+			{
+				rpc->fault(c, 500, "Internal error creating rpc data (str)");
+				unlock_shvar(shv);
+				return;
+			}
+		} else {
+			if(rpc->struct_add(ih, "ssd", "name", varname.s, "type", "int", "value", shv->v.value.n) < 0)
+			{
+				rpc->fault(c, 500, "Internal error creating rpc data (int)");
+				unlock_shvar(shv);
+				return;
+			}
+		}
+		unlock_shvar(shv);
+
+		return;
+	}
+	if (rpc->add(c, "{", &th) < 0)
+       	{
+         	rpc->fault(c, 500, "Internal error creating rpc");
+               	return;
+       	}
+
+	if(rpc->struct_add(th, "{", "items", &ih) < 0)
+               {
+                         rpc->fault(c, 500, "Internal error creating rpc th");
+                         return;
+               }
+
+	for(shv=sh_vars; shv; shv=shv->next)
+	{
+		lock_shvar(shv);
+		if(rpc->struct_add(ih, "{", "shv", &vh) < 0)
+               {
+                         rpc->fault(c, 500, "Internal error creating rpc th");
+                         return;
+               }
+		if(shv->v.flags&VAR_VAL_STR)
+		{
+			if(rpc->struct_add(vh, "sss", "name", shv->name.s, "type", "string", "value", shv->v.value.s.s) < 0)
+			{
+				rpc->fault(c, 500, "Internal error creating rpc data");
+				unlock_shvar(shv);
+				return;
+			}
+		} else {
+			if(rpc->struct_add(vh, "ssd", "name", shv->name.s, "type", "int", "value", shv->v.value.n) < 0)
+			{
+				rpc->fault(c, 500, "Internal error creating rpc data");
+				unlock_shvar(shv);
+				return;
+			}
+		}
+		unlock_shvar(shv);
+	}
+
+	return ;
+}
+
+void rpc_shv_set(rpc_t* rpc, void* c)
+{
+	str varname, type, value;
+	int ival = 0;
+	int_str isv;
+	sh_var_t *shv = NULL;
+	int flags = 0;
+	LM_DBG("Entering SHV_set\n");
+
+	if (rpc->scan(c, "S", &varname) != 1) {
+		rpc->fault(c, 500, "Missing parameter varname (Parameters: varname type value)");
+		return;
+        }
+	LM_DBG("SHV_set Varname %.*s \n", varname.len, varname.s);
+	if (rpc->scan(c, "S", &type) != 1) {
+		rpc->fault(c, 500, "Missing parameter type (Parameters: varname type value)");
+		return;
+        }
+	if (strcasecmp(type.s, "int") == 0 ) {
+		if (rpc->scan(c, "d", &ival) != 1) {
+			rpc->fault(c, 500, "Missing integer parameter value (Parameters: varname type value)");
+			return;
+        	}
+		isv.n = ival;
+	} else  if (strcasecmp(type.s, "str") == 0 ) {
+		/* String value */
+		if (rpc->scan(c, "S", &value) != 1) {
+			rpc->fault(c, 500, "Missing parameter value (Parameters: varname type value)");
+			return;
+        	}
+		isv.s = value;
+		flags = VAR_VAL_STR;
+	} else {
+		rpc->fault(c, 500, "Unknown parameter type (Types: int or str)");
+		return;
+	}
+
+	shv = get_shvar_by_name(&varname);
+	if(shv==NULL) {
+		rpc->fault(c, 404, "Variable not found");
+		return;
+	}
+		
+	lock_shvar(shv);
+	if(set_shvar_value(shv, &isv, flags)==NULL)
+	{
+		rpc->fault(c, 500, "Cannot set shared variable value");
+		LM_ERR("cannot set shv value\n");
+	} else {
+		rpc->printf(c, "Ok. Variable set to new value.");
+	}
+
+	unlock_shvar(shv);
+	return;
+}
+
 int param_set_xvar( modparam_t type, void* val, int mode)
 {
 	str s;
diff --git a/modules/pv/pv_shv.h b/modules/pv/pv_shv.h
index d47b0ac..0db4800 100644
--- a/modules/pv/pv_shv.h
+++ b/modules/pv/pv_shv.h
@@ -69,5 +69,8 @@ struct mi_root* mi_shvar_set(struct mi_root* cmd_tree, void* param);
 int param_set_var( modparam_t type, void* val);
 int param_set_shvar( modparam_t type, void* val);
 
+void rpc_shv_get(rpc_t* rpc, void* c);
+void rpc_shv_set(rpc_t* rpc, void* c);
+
 #endif
 
diff --git a/modules/pv/pv_trans.c b/modules/pv/pv_trans.c
index 8f54cd0..738efca 100644
--- a/modules/pv/pv_trans.c
+++ b/modules/pv/pv_trans.c
@@ -39,6 +39,7 @@
 #include "../../trim.h" 
 #include "../../pvapi.h"
 #include "../../dset.h"
+#include "../../basex.h"
 
 #include "../../parser/parse_param.h"
 #include "../../parser/parse_uri.h"
@@ -103,6 +104,82 @@ char *tr_set_crt_buffer(void)
 		val->rs.s = _tr_buffer; \
 	} while(0);
 
+/* -- helper functions */
+
+/* Converts a hex character to its integer value */
+static char pv_from_hex(char ch)
+{
+	return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+/* Converts an integer value to its hex character */
+static char pv_to_hex(char code)
+{
+	static char hex[] = "0123456789abcdef";
+	return hex[code & 15];
+}
+
+/*! \brief
+ *  URL Encodes a string for use in a HTTP query
+ */
+static int urlencode_param(str *sin, str *sout)
+{
+	char *at, *p;
+
+	at = sout->s;
+	p  = sin->s;
+
+	if (sin==NULL || sout==NULL || sin->s==NULL || sout->s==NULL ||
+			sin->len<0 || sout->len < 3*sin->len+1)
+		return -1;
+
+	while (p < sin->s+sin->len) {
+		if (isalnum(*p) || *p == '-' || *p == '_' || *p == '.' || *p == '~')
+			*at++ = *p;
+		else if (*p == ' ')
+			*at++ = '+';
+		else
+			*at++ = '%', *at++ = pv_to_hex(*p >> 4), *at++ = pv_to_hex(*p & 15);
+		p++;
+	}
+
+	*at = 0;
+	sout->len = at - sout->s;
+	LM_DBG("urlencoded string is <%s>\n", sout->s);
+
+	return 0;
+}
+
+/* URL Decode a string */
+static int urldecode_param(str *sin, str *sout) {
+	char *at, *p;
+
+	at = sout->s;
+	p  = sin->s;
+
+	while (p < sin->s+sin->len) {
+		if (*p == '%') {
+			if (p[1] && p[2]) {
+				*at++ = pv_from_hex(p[1]) << 4 | pv_from_hex(p[2]);
+				p += 2;
+			}
+		} else if (*p == '+') {
+			*at++ = ' ';
+		} else {
+			*at++ = *p;
+		}
+		p++;
+	}
+
+	*at = 0;
+	sout->len = at - sout->s;
+
+	LM_DBG("urldecoded string is <%s>\n", sout->s);
+	return 0;
+}
+
+/* -- transformations functions */
+
 /*!
  * \brief Evaluate string transformations
  * \param msg SIP message
@@ -204,6 +281,32 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 			val->rs.s = _tr_buffer;
 			val->rs.len = i;
 			break;
+		case TR_S_ENCODEBASE64:
+			if(!(val->flags&PV_VAL_STR))
+				val->rs.s = int2str(val->ri, &val->rs.len);
+			i = base64_enc((unsigned char *) val->rs.s, val->rs.len,
+					(unsigned char *) _tr_buffer, TR_BUFFER_SIZE-1);
+			if (i < 0)
+				return -1;
+			_tr_buffer[i] = '\0';
+			memset(val, 0, sizeof(pv_value_t));
+			val->flags = PV_VAL_STR;
+			val->rs.s = _tr_buffer;
+			val->rs.len = i;
+			break;
+		case TR_S_DECODEBASE64:
+			if(!(val->flags&PV_VAL_STR))
+				val->rs.s = int2str(val->ri, &val->rs.len);
+			i = base64_dec((unsigned char *) val->rs.s, val->rs.len,
+					(unsigned char *) _tr_buffer, TR_BUFFER_SIZE-1);
+			if (i < 0 || (i == 0 && val->rs.len > 0))
+				return -1;
+			_tr_buffer[i] = '\0';
+			memset(val, 0, sizeof(pv_value_t));
+			val->flags = PV_VAL_STR;
+			val->rs.s = _tr_buffer;
+			val->rs.len = i;
+			break;
 		case TR_S_ESCAPECOMMON:
 			if(!(val->flags&PV_VAL_STR))
 				val->rs.s = int2str(val->ri, &val->rs.len);
@@ -800,6 +903,34 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 			val->rs.len = j;
 			break;
 
+		case TR_S_URLENCODEPARAM:
+			if(!(val->flags&PV_VAL_STR))
+				val->rs.s = int2str(val->ri, &val->rs.len);
+			if(val->rs.len>TR_BUFFER_SIZE-1)
+				return -1;
+			st.s = _tr_buffer;
+			st.len = TR_BUFFER_SIZE;
+			if (urlencode_param(&val->rs, &st) < 0)
+				return -1;
+			memset(val, 0, sizeof(pv_value_t));
+			val->flags = PV_VAL_STR;
+			val->rs = st;
+			break;
+
+		case TR_S_URLDECODEPARAM:
+			if(!(val->flags&PV_VAL_STR))
+				val->rs.s = int2str(val->ri, &val->rs.len);
+			if(val->rs.len>TR_BUFFER_SIZE-1)
+				return -1;
+			st.s = _tr_buffer;
+			st.len = TR_BUFFER_SIZE;
+			if (urldecode_param(&val->rs, &st) < 0)
+				return -1;
+			memset(val, 0, sizeof(pv_value_t));
+			val->flags = PV_VAL_STR;
+			val->rs = st;
+			break;
+
 		default:
 			LM_ERR("unknown subtype %d\n",
 					subtype);
@@ -982,6 +1113,7 @@ done:
 
 static str _tr_params_str = {0, 0};
 static param_t* _tr_params_list = NULL;
+static char _tr_params_separator = ';';
 
 
 /*!
@@ -998,15 +1130,38 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype,
 	pv_value_t v;
 	str sv;
 	int n, i;
+	char separator = ';';
 	param_hooks_t phooks;
 	param_t *pit=NULL;
 
 	if(val==NULL || (!(val->flags&PV_VAL_STR)) || val->rs.len<=0)
 		return -1;
 
+	if (tp != NULL)
+	{
+		if (subtype == TR_PL_COUNT)
+		{
+			if(tp->type != TR_PARAM_STRING || tp->v.s.len != 1)
+				return -1;
+
+				separator = tp->v.s.s[0];
+		}
+		else if (tp->next != NULL)
+		{
+			if(tp->next->type != TR_PARAM_STRING
+					|| tp->next->v.s.len != 1)
+				return -1;
+
+			separator = tp->next->v.s.s[0];
+		}
+	}
+
 	if(_tr_params_str.len==0 || _tr_params_str.len!=val->rs.len ||
-			strncmp(_tr_params_str.s, val->rs.s, val->rs.len)!=0)
+			strncmp(_tr_params_str.s, val->rs.s, val->rs.len)!=0 ||
+			_tr_params_separator != separator)
 	{
+		_tr_params_separator = separator;
+
 		if(val->rs.len>_tr_params_str.len)
 		{
 			if(_tr_params_str.s) pkg_free(_tr_params_str.s);
@@ -1036,7 +1191,8 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype,
 		
 		/* parse params */
 		sv = _tr_params_str;
-		if (parse_params(&sv, CLASS_ANY, &phooks, &_tr_params_list)<0)
+		if (parse_params2(&sv, CLASS_ANY, &phooks, &_tr_params_list,
+					_tr_params_separator)<0)
 			return -1;
 	}
 	
@@ -1764,6 +1920,12 @@ char* tr_parse_string(str* in, trans_t *t)
 	} else if(name.len==11 && strncasecmp(name.s, "decode.hexa", 11)==0) {
 		t->subtype = TR_S_DECODEHEXA;
 		goto done;
+	} else if(name.len==13 && strncasecmp(name.s, "encode.base64", 13)==0) {
+		t->subtype = TR_S_ENCODEBASE64;
+		goto done;
+	} else if(name.len==13 && strncasecmp(name.s, "decode.base64", 13)==0) {
+		t->subtype = TR_S_DECODEBASE64;
+		goto done;
 	} else if(name.len==13 && strncasecmp(name.s, "escape.common", 13)==0) {
 		t->subtype = TR_S_ESCAPECOMMON;
 		goto done;
@@ -2028,6 +2190,12 @@ char* tr_parse_string(str* in, trans_t *t)
 			goto error;
 		}
 		goto done;
+	} else if(name.len==15 && strncasecmp(name.s, "urlencode.param", 15)==0) {
+		t->subtype = TR_S_URLENCODEPARAM;
+		goto done;
+	} else if(name.len==15 && strncasecmp(name.s, "urldecode.param", 15)==0) {
+		t->subtype = TR_S_URLDECODEPARAM;
+		goto done;
 	}
 
 	LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s,
@@ -2164,6 +2332,7 @@ char* tr_parse_paramlist(str* in, trans_t *t)
 	char *p;
 	char *p0;
 	char *ps;
+	char *start_pos;
 	str s;
 	str name;
 	int n;
@@ -2204,6 +2373,22 @@ char* tr_parse_paramlist(str* in, trans_t *t)
 		t->params = tp;
 		tp = 0;
 		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+
+		if(*p==TR_PARAM_MARKER)
+		{
+			start_pos = ++p;
+			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
+			t->params->next = tp;
+			tp = 0;
+			if (p - start_pos != 1)
+			{
+				LM_ERR("invalid separator in transformation: "
+					"%.*s\n", in->len, in->s);
+				goto error;
+			}
+			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+		}
+
 		if(*p!=TR_RBRACKET)
 		{
 			LM_ERR("invalid value transformation: %.*s!\n",
@@ -2224,6 +2409,22 @@ char* tr_parse_paramlist(str* in, trans_t *t)
 		t->params = tp;
 		tp = 0;
 		while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+
+		if(*p==TR_PARAM_MARKER)
+		{
+			start_pos = ++p;
+			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
+			t->params->next = tp;
+			tp = 0;
+			if (p - start_pos != 1)
+			{
+				LM_ERR("invalid separator in transformation: "
+					"%.*s\n", in->len, in->s);
+				goto error;
+			}
+			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+		}
+
 		if(*p!=TR_RBRACKET)
 		{
 			LM_ERR("invalid name transformation: %.*s!\n",
@@ -2244,6 +2445,22 @@ char* tr_parse_paramlist(str* in, trans_t *t)
 		t->params = tp;
 		tp = 0;
 		while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+
+		if(*p==TR_PARAM_MARKER)
+		{
+			start_pos = ++p;
+			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
+			t->params->next = tp;
+			tp = 0;
+			if (p - start_pos != 1)
+			{
+				LM_ERR("invalid separator in transformation: "
+					"%.*s\n", in->len, in->s);
+				goto error;
+			}
+			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+		}
+
 		if(*p!=TR_RBRACKET)
 		{
 			LM_ERR("invalid name transformation: %.*s!\n",
@@ -2253,6 +2470,28 @@ char* tr_parse_paramlist(str* in, trans_t *t)
 		goto done;
 	} else if(name.len==5 && strncasecmp(name.s, "count", 5)==0) {
 		t->subtype = TR_PL_COUNT;
+		if(*p==TR_PARAM_MARKER)
+		{
+			start_pos = ++p;
+			_tr_parse_sparam(p, p0, tp, spec, ps, in, s);
+			t->params = tp;
+			tp = 0;
+			if (p - start_pos != 1)
+			{
+				LM_ERR("invalid separator in transformation: "
+					"%.*s\n", in->len, in->s);
+				goto error;
+			}
+
+			while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+			if(*p!=TR_RBRACKET)
+			{
+				LM_ERR("invalid name transformation: %.*s!\n",
+					in->len, in->s);
+				goto error;
+			}
+		}
+
 		goto done;
 	}
 
diff --git a/modules/pv/pv_trans.h b/modules/pv/pv_trans.h
index a34eca2..8544d8c 100644
--- a/modules/pv/pv_trans.h
+++ b/modules/pv/pv_trans.h
@@ -37,10 +37,12 @@ enum _tr_type { TR_NONE=0, TR_STRING, TR_URI, TR_PARAMLIST, TR_NAMEADDR,
 enum _tr_s_subtype { 
 	TR_S_NONE=0, TR_S_LEN, TR_S_INT, TR_S_MD5, TR_S_SUBSTR,
 	TR_S_SELECT, TR_S_ENCODEHEXA, TR_S_DECODEHEXA,
+	TR_S_ENCODEBASE64, TR_S_DECODEBASE64,
 	TR_S_ESCAPECOMMON, TR_S_UNESCAPECOMMON, TR_S_ESCAPEUSER, TR_S_UNESCAPEUSER,
 	TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER,
 	TR_S_STRIP, TR_S_STRIPTAIL, TR_S_PREFIXES, TR_S_PREFIXES_QUOT, TR_S_REPLACE,
-	TR_S_TIMEFORMAT, TR_S_TRIM, TR_S_RTRIM, TR_S_LTRIM, TR_S_RM, TR_S_STRIPTO
+	TR_S_TIMEFORMAT, TR_S_TRIM, TR_S_RTRIM, TR_S_LTRIM, TR_S_RM, TR_S_STRIPTO,
+	TR_S_URLENCODEPARAM, TR_S_URLDECODEPARAM
 };
 enum _tr_uri_subtype {
 	TR_URI_NONE=0, TR_URI_USER, TR_URI_HOST, TR_URI_PASSWD, TR_URI_PORT,
diff --git a/modules/pv/pv_xavp.c b/modules/pv/pv_xavp.c
index b434794..3ba737b 100644
--- a/modules/pv/pv_xavp.c
+++ b/modules/pv/pv_xavp.c
@@ -22,9 +22,13 @@
 
 #include "../../dprint.h"
 #include "../../xavp.h"
+#include "../../pvapi.h"
 
 #include "pv_xavp.h"
 
+#define PV_FIELD_DELIM ", "
+#define PV_FIELD_DELIM_LEN (sizeof(PV_FIELD_DELIM) - 1)
+
 int pv_xavp_get_value(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res, sr_xavp_t *avp)
 {
@@ -78,6 +82,8 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	int idxf = 0;
 	int idx = 0;
 	int count;
+	char *p, *p_ini;
+	int p_size;
 
 	if(param==NULL)
 	{
@@ -127,6 +133,40 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp);
 	if(avp==NULL)
 		return pv_get_null(msg, param, res);
+	/* get all values of second key */
+	if(idxf==PV_IDX_ALL)
+	{
+		p_ini = pv_get_buffer();
+		p = p_ini;
+		p_size = pv_get_buffer_size();
+		do {
+			if(p!=p_ini)
+			{
+				if(p-p_ini+PV_FIELD_DELIM_LEN+1>p_size)
+				{
+					LM_ERR("local buffer length exceeded\n");
+					return pv_get_null(msg, param, res);
+				}
+				memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN);
+				p += PV_FIELD_DELIM_LEN;
+			}
+			if(pv_xavp_get_value(msg, param, res, avp)<0)
+			{
+				LM_ERR("can get value\n");
+				return pv_get_null(msg, param, res);
+			}
+			if(p-p_ini+res->rs.len+1>p_size)
+			{
+				LM_ERR("local buffer length exceeded!\n");
+				return pv_get_null(msg, param, res);
+			}
+			memcpy(p, res->rs.s, res->rs.len);
+			p += res->rs.len;
+		} while ((avp=xavp_get_next(avp))!=0);
+		res->rs.s = p_ini;
+		res->rs.len = p - p_ini;
+		return 0;
+	}
 	return pv_xavp_get_value(msg, param, res, avp);
 }
 
diff --git a/modules/pv/pv_xavp.h b/modules/pv/pv_xavp.h
index 2e12870..4851b3f 100644
--- a/modules/pv/pv_xavp.h
+++ b/modules/pv/pv_xavp.h
@@ -23,12 +23,6 @@
 
 #include "../../pvar.h"
 
-typedef struct _pv_xavp_name {
-	str name;
-	pv_spec_t index;
-	struct _pv_xavp_name *next;
-} pv_xavp_name_t;
-
 int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 int pv_set_xavp(struct sip_msg* msg, pv_param_t *param,
diff --git a/modules/ratelimit/README b/modules/ratelimit/README
index f3f131b..3051560 100644
--- a/modules/ratelimit/README
+++ b/modules/ratelimit/README
@@ -327,7 +327,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    6.1. rl_check([pvar])
    6.2. rl_check_pipe([pipe_no])
 
-6.1. rl_check([pvar])
+6.1.  rl_check([pvar])
 
    Check the current request against the matched ratelimit algorithm. If
    no parameter is provided, the queue will be matched based on method
@@ -374,7 +374,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
         };
 ...
 
-6.2. rl_check_pipe([pipe_no])
+6.2.  rl_check_pipe([pipe_no])
 
    Check the current request against the matched ratelimit algorithm. If
    no parameter is provided, the queue will be matched based on method
@@ -419,7 +419,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    7.8. rl.push_load
    7.9. rl.set_dbg
 
-7.1. rl.stats
+7.1.  rl.stats
 
    Lists the parameters and variables in the ratelimit module.
 
@@ -430,7 +430,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.stats
 
-7.2. rl.set_pipe
+7.2.  rl.set_pipe
 
    Sets the pipe parameters for the given pipe id.
 
@@ -444,7 +444,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.set_pipe 2 RED 10
 
-7.3. rl.get_pipes
+7.3.  rl.get_pipes
 
    Gets the list of in use pipes.
 
@@ -455,7 +455,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.get_pipes
 
-7.4. rl.set_queue
+7.4.  rl.set_queue
 
    Sets the queue parameters for the given queue id.
 
@@ -469,7 +469,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.set_queue 3 INVITE 2
 
-7.5. rl.get_queues
+7.5.  rl.get_queues
 
    Gets the list of in use queues.
 
@@ -480,7 +480,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.get_queues
 
-7.6. rl.set_pid
+7.6.  rl.set_pid
 
    Sets the PID Controller parameters for the Feedback Algorithm.
 
@@ -494,7 +494,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.set_pid 0.5 0.5 0.5
 
-7.7. rl.get_pid
+7.7.  rl.get_pid
 
    Gets the list of in use PID Controller parameters.
 
@@ -505,7 +505,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.get_pid
 
-7.8. rl.push_load
+7.8.  rl.push_load
 
    Force the value of the load parameter. This method is useful for
    testing the Feedback algorithm.
@@ -519,7 +519,7 @@ modparam("ratelimit", "pipe", "4:NETWORK:10000")
    RPC Command Format:
                 kamcmd rl.push_load 0.85
 
-7.9. rl.set_dbg
+7.9.  rl.set_dbg
 
    This function will enable/disable a WARNING debug log exposing the
    internal counters for each pipe (useful in monitoring the ratelimit
diff --git a/modules/registrar/README b/modules/registrar/README
index c60c0ae..cc074fc 100644
--- a/modules/registrar/README
+++ b/modules/registrar/README
@@ -59,7 +59,8 @@ Bogdan-Andre Iancu
               3.22. xavp_rcd (string)
               3.23. gruu_enabled (integer)
               3.24. outbound_mode (integer)
-              3.25. flow_timer (integer)
+              3.25. regid_mode (integer)
+              3.26. flow_timer (integer)
 
         4. Functions
 
@@ -68,7 +69,7 @@ Bogdan-Andre Iancu
               4.3. lookup_branches(domain)
               4.4. registered(domain [, uri])
               4.5. add_sock_hdr(hdr_name)
-              4.6. unregister(domain, uri)
+              4.6. unregister(domain, uri[, ruid])
               4.7. reg_fetch_contacts(domain, uri, profile)
               4.8. reg_free_contacts(profile)
 
@@ -115,17 +116,18 @@ Bogdan-Andre Iancu
    1.21. Set xavp_rcd parameter
    1.22. Set gruu_enabled parameter
    1.23. Set outbound_mode parameter
-   1.24. Set flow_timer parameter
-   1.25. save usage
-   1.26. lookup usage
-   1.27. lookup_branches usage
-   1.28. registered usage
-   1.29. add_sock_hdr usage
-   1.30. unregister usage
-   1.31. reg_fetch_contacts usage
-   1.32. reg_free_contacts usage
-   1.33. event_route[usrloc:contact-expired] usage
-   1.34. $ulc(name) usage
+   1.24. Set regid_mode parameter
+   1.25. Set flow_timer parameter
+   1.26. save usage
+   1.27. lookup usage
+   1.28. lookup_branches usage
+   1.29. registered usage
+   1.30. add_sock_hdr usage
+   1.31. unregister usage
+   1.32. reg_fetch_contacts usage
+   1.33. reg_free_contacts usage
+   1.34. event_route[usrloc:contact-expired] usage
+   1.35. $ulc(name) usage
 
 Chapter 1. Admin Guide
 
@@ -167,7 +169,8 @@ Chapter 1. Admin Guide
         3.22. xavp_rcd (string)
         3.23. gruu_enabled (integer)
         3.24. outbound_mode (integer)
-        3.25. flow_timer (integer)
+        3.25. regid_mode (integer)
+        3.26. flow_timer (integer)
 
    4. Functions
 
@@ -176,7 +179,7 @@ Chapter 1. Admin Guide
         4.3. lookup_branches(domain)
         4.4. registered(domain [, uri])
         4.5. add_sock_hdr(hdr_name)
-        4.6. unregister(domain, uri)
+        4.6. unregister(domain, uri[, ruid])
         4.7. reg_fetch_contacts(domain, uri, profile)
         4.8. reg_free_contacts(profile)
 
@@ -286,7 +289,8 @@ Chapter 1. Admin Guide
    3.22. xavp_rcd (string)
    3.23. gruu_enabled (integer)
    3.24. outbound_mode (integer)
-   3.25. flow_timer (integer)
+   3.25. regid_mode (integer)
+   3.26. flow_timer (integer)
 
 3.1. default_expires (integer)
 
@@ -643,28 +647,23 @@ modparam("registrar", "gruu_enabled", 0)
 
 3.24. outbound_mode (integer)
 
-   If set to 0 then this module will accept REGISTER requests that do not
+   If set to 0 this module will accept REGISTER requests that do not
    contain a Supported: header with the outbound options-tag. The 200 OK
    response to REGISTER requests that this module generates will not
-   contain Require: or Supported: headers with the outbound options tag.
+   contain Require: or Supported: headers with the outbound options-tag.
+   If the client has a Require: header with the outbound options tag the
+   REGISTER will be rejected with a 420 Bad Extension response.
 
    If set to 1 this module will accept REGISTER requests that do not
    contain a Supported: header with the outbound options-tag and REGISTER
-   requests that do contain a Supported: or a Requires: header with the
-   outbound options-tag. The 200 OK response that this module generates,
-   will contain a Supported: header with the outbound options tag. The 200
-   OK response will also contain a Require: header with the outbound
-   options tag if the REGISTER request contained a Supported: header with
-   the outbound options-tag.
-
-   If set to 2 then this module will reject REGISTER requests that do not
-   contain a Supported: header with the outbound options-tag. The 200 OK
-   response to REGISTER requests that this module generates will contain
-   Require: and Supported: headers with the outbound options tag.
+   requests that do contain a Supported: or Requires: header with the
+   outbound options-tag. When the client supports outbound the appropriate
+   RFC5626 procedures will be followed.
 
-   Set this parameter to 2 if you are using SIP Outbound (RFC 5626) and
-   want your Edge Proxy to insert a Flow-Timer: header into the 200 OK
-   response to REGISTERs (as per RFC 5626 section 5.4).
+   If set to 2 this module will reject REGISTER requests that do not
+   contain a Supported: header with the outbound options-tag. When the
+   client supports outbound the appropriate RFC5626 procedures will be
+   followed.
 
    Default value is 0.
 
@@ -673,28 +672,45 @@ modparam("registrar", "gruu_enabled", 0)
 modparam("registrar", "outbound_mode", 2)
 ...
 
-3.25. flow_timer (integer)
+3.25. regid_mode (integer)
+
+   If set to 0 this module will ignore regid contact param when saving
+   REGISTER request if REGISTER request does not indicate support for
+   outbound.
+
+   If set to 1 this module will use regid contact param (if present) when
+   saving REGISTER request even if REGISTER request does not indicate
+   support for outbound.
+
+   Default value is 0.
+
+   Example 1.24. Set regid_mode parameter
+...
+modparam("registrar", "regid_mode", 1)
+...
+
+3.26. flow_timer (integer)
 
    If set to 0 then this module will not add a Flow-Timer: header to 200
    OK responses to REGISTER requests.
 
    If set to > 0 then this module will add a Flow-Timer: header containing
    this value to 200 OK responses to REGISTER requests. This parameter may
-   only be set to a value > 0 when outbound_mode is set to 2.
+   only be set to a value > 0 when outbound_mode is set to 1 or 2.
 
    When set to a value > 0 this parameter should be set to slightly less
    than the connection timeout value between the UAC and the network (this
    corresponds to the core tcp_connection_lifetime option and websocket
    keepalive_timeout modparam). This parameter is most useful when you
-   have a single edge proxy/registrar. If you are using a separate SIP
-   Outbound Edge Proxy you should consider leaving this parameter set to 0
-   and adding the Flow-Timer: header on the Edge Proxy (as this allows you
-   to keep all of the timer values for a specific flow in one
-   configuration - that of the Edge Proxy).
+   have a single edge proxy/registrar or if you have an edge proxy that
+   cannot modify responses. If you are using a separate edge proxy you
+   should consider leaving this parameter set to 0 and adding the
+   Flow-Timer: header on the edge proxy as this allows you to keep all of
+   the timer values for a specific flow in one configuration.
 
    Default value is 0.
 
-   Example 1.24. Set flow_timer parameter
+   Example 1.25. Set flow_timer parameter
 ...
 modparam("registrar", "flow_timer", 25)
 ...
@@ -706,7 +722,7 @@ modparam("registrar", "flow_timer", 25)
    4.3. lookup_branches(domain)
    4.4. registered(domain [, uri])
    4.5. add_sock_hdr(hdr_name)
-   4.6. unregister(domain, uri)
+   4.6. unregister(domain, uri[, ruid])
    4.7. reg_fetch_contacts(domain, uri, profile)
    4.8. reg_free_contacts(profile)
 
@@ -745,9 +761,10 @@ modparam("registrar", "flow_timer", 25)
        3 - contacts deleted.
        4 - contacts returned.
 
-   This function can be used from REQUEST_ROUTE and REPLY_ROUTE.
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and
+   REPLY_ROUTE.
 
-   Example 1.25. save usage
+   Example 1.26. save usage
 ...
 save("location");
 save("location", "0x01");
@@ -780,7 +797,7 @@ save("location", "0x00", "sip:test at kamailio.org");
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.26. lookup usage
+   Example 1.27. lookup usage
 ...
 lookup("location");
 switch ($retcode) {
@@ -806,7 +823,7 @@ switch ($retcode) {
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.27. lookup_branches usage
+   Example 1.28. lookup_branches usage
 ...
 lookup_branches("location");
 ...
@@ -825,7 +842,7 @@ lookup_branches("location");
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.28. registered usage
+   Example 1.29. registered usage
 ...
 if (registered("location")) {
         sl_send_reply("100", "Trying");
@@ -845,14 +862,17 @@ if (registered("location")) {
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.29. add_sock_hdr usage
+   Example 1.30. add_sock_hdr usage
 ...
 add_sock_hdr("Sock-Info");
 ...
 
-4.6. unregister(domain, uri)
+4.6. unregister(domain, uri[, ruid])
 
-   The function remove all the contact associated to 'uri'.
+   The function removes contacts associated with 'uri'. If 'ruid' is
+   provided a specific contact is removed, if 'ruid' is not provided all
+   contacts are removed. If 'ruid' is provided and usrloc is using
+   db_mode=3, 'uri' does not need to be given and can be empty string.
 
    Meaning of the parameters is as follows:
      * domain - Name of table that should be used for the lookup or
@@ -860,13 +880,17 @@ add_sock_hdr("Sock-Info");
      * uri - The SIP URI address of the user which to remove the contact
        addresses for. It can contain pseudo-variables that are evaluated
        at runtime.
+     * ruid - The record unique ID for a a specific contact to be removed.
+       It can contain pseudo-variables that are evaluated at runtime.
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.30. unregister usage
+   Example 1.31. unregister usage
 ...
 unregister("location", "$ru");
 unregister("location", "sip:user at kamailio.org");
+unregister("location", "$ru", "$ulc(caller=>ruid)");
+unregister("location", "", "$ruid");
 ...
 
 4.7. reg_fetch_contacts(domain, uri, profile)
@@ -885,7 +909,7 @@ unregister("location", "sip:user at kamailio.org");
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.31. reg_fetch_contacts usage
+   Example 1.32. reg_fetch_contacts usage
 ...
 reg_fetch_contacts("location", "$ru", "callee");
 reg_fetch_contacts("location", "sip:user at kamailio.org", "caller");
@@ -904,7 +928,7 @@ reg_fetch_contacts("location", "sip:user at kamailio.org", "caller");
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.32. reg_free_contacts usage
+   Example 1.33. reg_free_contacts usage
 ...
 reg_free_contacts("callee");
 ...
@@ -918,7 +942,7 @@ reg_free_contacts("callee");
    Executed when a contact in location table has expired. The variable
    $ulc(exp=>...) is filled with the attributes of the expired contact.
 
-   Example 1.33. event_route[usrloc:contact-expired] usage
+   Example 1.34. event_route[usrloc:contact-expired] usage
 ...
 event_route[usrloc:contact-expired] {
     xlog("expired contact for $ulc(exp->aor)\n");
@@ -969,24 +993,28 @@ event_route[usrloc:contact-expired] {
      * aor - address of record
      * domain - use location domain name
      * aorhash - hash id for the record
-     * count - number of contacts
      * addr - contact address
      * path - path vector
      * received - received address
      * expires - expires value
      * callid - call-id header value
      * q - the q value
+     * cseq - the cseq value
      * flags - flags value
      * cflags - cflags value
      * user_agent - user agent
      * socket - local socket
      * modified - last modified time
      * methods - methods value
+     * count - number of contacts
+     * ruid - record unique ID
+     * reg-id - reg-id value
+     * instance - instance value
 
    The pseudo-variable accepts positive index value to access a specific
    contact record.
 
-   Example 1.34. $ulc(name) usage
+   Example 1.35. $ulc(name) usage
 ...
 if(reg_fetch_contacts("location", "$fu", "caller"))
 {
diff --git a/modules/registrar/api.c b/modules/registrar/api.c
index adce1be..04fdc0e 100644
--- a/modules/registrar/api.c
+++ b/modules/registrar/api.c
@@ -111,6 +111,20 @@ int regapi_registered(struct sip_msg *msg, char *table)
 /**
  *
  */
+int regapi_set_q_override(struct sip_msg *msg, str *new_q)
+{
+	int _q;
+	if (str2q(&_q, new_q->s, new_q->len) < 0)
+	{
+		LM_ERR("invalid q parameter\n");
+		return -1;
+	}
+	return set_q_override(msg, _q);
+}
+
+/**
+ *
+ */
 int bind_registrar(registrar_api_t* api)
 {
 	if (!api) {
@@ -122,6 +136,7 @@ int bind_registrar(registrar_api_t* api)
 	api->lookup     = regapi_lookup;
 	api->lookup_uri = regapi_lookup_uri;
 	api->registered = regapi_registered;
+	api->set_q_override = regapi_set_q_override;
 
 	return 0;
 }
diff --git a/modules/registrar/api.h b/modules/registrar/api.h
index 006c596..2968ded 100644
--- a/modules/registrar/api.h
+++ b/modules/registrar/api.h
@@ -43,6 +43,9 @@ int regapi_lookup(struct sip_msg *msg, char *table);
 typedef int (*regapi_lookup_uri_f)(struct sip_msg *msg, char *table, str *uri);
 int regapi_lookup_uri(struct sip_msg *msg, char *table, str *uri);
 
+typedef int (*regapi_set_q_override_f)(struct sip_msg *msg, str *new_q);
+int regapi_set_q_override(struct sip_msg *msg, str *new_q);
+
 /**
  * @brief REGISTRAR API structure
  */
@@ -52,6 +55,7 @@ typedef struct registrar_api {
 	regapi_lookup_f     lookup;
 	regapi_lookup_uri_f lookup_uri;
 	regapi_lookup_f     registered;
+	regapi_set_q_override_f set_q_override;
 } registrar_api_t;
 
 typedef int (*bind_registrar_f)(registrar_api_t* api);
diff --git a/modules/registrar/doc/registrar_admin.xml b/modules/registrar/doc/registrar_admin.xml
index bf2bdef..a165c27 100644
--- a/modules/registrar/doc/registrar_admin.xml
+++ b/modules/registrar/doc/registrar_admin.xml
@@ -725,35 +725,27 @@ modparam("registrar", "gruu_enabled", 0)
 	<section>
 		<title><varname>outbound_mode</varname> (integer)</title>
 		<para>
-		If set to 0 then this module will accept REGISTER requests
-		that do not contain a Supported: header with the outbound
-		options-tag. The 200 OK response to REGISTER requests that this
-		module generates will not contain Require: or Supported: headers
-		with the outbound options tag.
+		If set to 0 this module will accept REGISTER requests that do
+		not contain a Supported: header with the outbound options-tag.
+		The 200 OK response to REGISTER requests that this module
+		generates will not contain Require: or Supported: headers with
+		the outbound options-tag. If the client has a Require: header
+		with the outbound options tag the REGISTER will be rejected
+		with a 420 Bad Extension response.
 		</para>
 		<para>
-                If set to 1 this module will accept REGISTER requests that do
-		not contain a Supported: header with the outbound options-tag
-		and REGISTER requests that do contain a Supported: or a
-		Requires: header with the outbound options-tag.  The 200 OK
-		response that this module generates, will contain a Supported:
-		header with the outbound options tag.  The 200 OK response
-		will also contain a Require: header with the outbound options
-		tag if the REGISTER request contained a Supported:
-		header with the outbound options-tag.
+		If set to 1 this module will accept REGISTER requests that
+		do not contain a Supported: header with the outbound
+		options-tag and REGISTER requests that do contain a Supported:
+		or Requires: header with the outbound options-tag. When the
+		client supports outbound the appropriate RFC5626 procedures
+		will be followed.
 		</para>
 		<para>
-		If set to 2 then this module will reject REGISTER requests
-		that do not contain a Supported: header with the outbound
-		options-tag. The 200 OK response to REGISTER requests that this
-		module generates will contain Require: and Supported: headers
-		with the outbound options tag.
-		</para>
-		<para>
-		Set this parameter to 2 if you are using SIP Outbound (RFC
-		5626) and want your Edge Proxy to insert a Flow-Timer: header
-		into the 200 OK response to REGISTERs (as per RFC 5626 section
-		5.4).
+		If set to 2 this module will reject REGISTER requests that
+		do not contain a Supported: header with the outbound
+		options-tag. When the client supports outbound the appropriate
+		RFC5626 procedures will be followed.
 		</para>
 		<para>
 		<emphasis>
@@ -771,6 +763,33 @@ modparam("registrar", "outbound_mode", 2)
 	</section>
 
 	<section>
+		<title><varname>regid_mode</varname> (integer)</title>
+		<para>
+		If set to 0 this module will ignore regid contact param
+		when saving REGISTER request if REGISTER request does not
+		indicate support for outbound.
+		</para>
+		<para>
+		If set to 1 this module will use regid contact param
+		(if present) when saving REGISTER request even if 
+		REGISTER request does not indicate support for outbound.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>regid_mode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("registrar", "regid_mode", 1)
+...
+		</programlisting>
+		</example>
+	</section>
+
+	<section>
 		<title><varname>flow_timer</varname> (integer)</title>
 		<para>
 		If set to 0 then this module will not add a Flow-Timer: header
@@ -780,7 +799,7 @@ modparam("registrar", "outbound_mode", 2)
 		If set to > 0 then this module will add a Flow-Timer: header
 		containing this value to 200 OK responses to REGISTER requests.
 		This parameter may only be set to a value > 0 when
-		<emphasis>outbound_mode</emphasis> is set to 2.
+		<emphasis>outbound_mode</emphasis> is set to 1 or 2.
 		</para>
 		<para>
 		When set to a value > 0 this parameter should be set to slightly
@@ -788,13 +807,14 @@ modparam("registrar", "outbound_mode", 2)
 		network (this corresponds to the core
 		<emphasis>tcp_connection_lifetime</emphasis> option and
 		<emphasis>websocket</emphasis>
-		<emphasis>keepalive_timeout</emphasis> modparam). This parameter
-		is most useful when you have a single edge proxy/registrar. If
-		you are using a separate SIP Outbound Edge Proxy you should
+		<emphasis>keepalive_timeout</emphasis> modparam). This
+		parameter is most useful when you have a single edge
+		proxy/registrar or if you have an edge proxy that cannot modify
+		responses. If you are using a separate edge proxy you should
 		consider leaving this parameter set to 0 and adding the
-		Flow-Timer: header on the Edge Proxy (as this allows you to
+		Flow-Timer: header on the edge proxy as this allows you to
 		keep all of the timer values for a specific flow in one
-		configuration - that of the Edge Proxy).
+		configuration.
 		</para>
 		<para>
 		<emphasis>
@@ -892,7 +912,7 @@ modparam("registrar", "flow_timer", 25)
 		</listitem>
 		</itemizedlist>
 		<para>
-		This function can be used from REQUEST_ROUTE and REPLY_ROUTE.
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and REPLY_ROUTE.
 		</para>
 		<example>
 		<title><function>save</function> usage</title>
@@ -1085,10 +1105,14 @@ add_sock_hdr("Sock-Info");
 	</section>
 	<section>
 		<title>
-		<function moreinfo="none">unregister(domain, uri)</function>
+		<function moreinfo="none">unregister(domain, uri[, ruid])</function>
 		</title>
 		<para>
-		The function remove all the contact associated to 'uri'.
+		The function removes contacts associated with 'uri'. If 'ruid' is
+		provided a specific contact is removed, if 'ruid' is not provided
+		all contacts are removed.  If 'ruid' is provided and usrloc is
+		using db_mode=3, 'uri' does not need to be given and can be
+		empty string.
 		</para>
 		<para>Meaning of the parameters is as follows:</para>
 		<itemizedlist>
@@ -1105,6 +1129,13 @@ add_sock_hdr("Sock-Info");
 			pseudo-variables that are evaluated at runtime.
 			</para>
 		</listitem>
+		<listitem>
+			<para>
+			<emphasis>ruid</emphasis> - The record unique ID for a
+			a specific contact to be removed. It can contain
+			pseudo-variables that are evaluated at runtime.
+			</para>
+		</listitem>
 		</itemizedlist>
 		<para>
 		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
@@ -1115,6 +1146,8 @@ add_sock_hdr("Sock-Info");
 ...
 unregister("location", "$ru");
 unregister("location", "sip:user at kamailio.org");
+unregister("location", "$ru", "$ulc(caller=>ruid)");
+unregister("location", "", "$ruid");
 ...
 </programlisting>
 		</example>
@@ -1282,11 +1315,7 @@ event_route[usrloc:contact-expired] {
 				<listitem>
 				<para><emphasis>aorhash</emphasis> - hash id for the record
 				</para>
-				</listitem>	  
-				<listitem>
-				<para><emphasis>count</emphasis> - number of contacts
-				</para>
-				</listitem>	  
+				</listitem>
 				<listitem>
 				<para><emphasis>addr</emphasis> - contact address
 				</para>
@@ -1312,6 +1341,10 @@ event_route[usrloc:contact-expired] {
 				</para>
 				</listitem>	  
 				<listitem>
+				<para><emphasis>cseq</emphasis> - the cseq value
+				</para>
+				</listitem>	  
+				<listitem>
 				<para><emphasis>flags</emphasis> - flags value
 				</para>
 				</listitem>	  
@@ -1335,6 +1368,22 @@ event_route[usrloc:contact-expired] {
 				<para><emphasis>methods</emphasis> - methods value
 				</para>
 				</listitem>	  
+				<listitem>
+				<para><emphasis>count</emphasis> - number of contacts
+				</para>
+				</listitem>	  
+				<listitem>
+				<para><emphasis>ruid</emphasis> - record unique ID
+				</para>
+				</listitem>	  
+				<listitem>
+				<para><emphasis>reg-id</emphasis> - reg-id value
+				</para>
+				</listitem>	  
+				<listitem>
+				<para><emphasis>instance</emphasis> - instance value
+				</para>
+				</listitem>	  
 			</itemizedlist>
 			<para>
 				The pseudo-variable accepts positive index value to access
diff --git a/modules/registrar/lookup.c b/modules/registrar/lookup.c
index f9bbad3..0e298e7 100644
--- a/modules/registrar/lookup.c
+++ b/modules/registrar/lookup.c
@@ -273,6 +273,20 @@ int lookup(struct sip_msg* _m, udomain_t* _d, str* _uri)
 		
 		_m->reg_id = ptr->reg_id;
 
+		if (ptr->ruid.len) {
+		    if (set_ruid(_m, &(ptr->ruid)) < 0) {
+				ret = -3;
+				goto done;
+		    }
+		}
+
+		if (ptr->user_agent.len) {
+		    if (set_ua(_m, &(ptr->user_agent)) < 0) {
+				ret = -3;
+				goto done;
+		    }
+		}
+
 		set_ruri_q(ptr->q);
 
 		old_bflags = 0;
@@ -316,7 +330,8 @@ int lookup(struct sip_msg* _m, udomain_t* _d, str* _uri)
 					  &ptr->path, ptr->q, ptr->cflags,
 					  ptr->sock,
 					  ptr->instance.len?&(ptr->instance):0,
-				          ptr->instance.len?ptr->reg_id:0)
+				          ptr->instance.len?ptr->reg_id:0,
+					  &ptr->ruid, &ptr->user_agent)
 			    == -1) {
 				LM_ERR("failed to append a branch\n");
 				/* Also give a chance to the next branches*/
@@ -351,6 +366,8 @@ int reset_ruri_branch(sip_msg_t *msg)
 	setbflagsval(0, 0);
 	reset_instance(msg);
 	msg->reg_id = 0;
+	reset_ruid(msg);
+	reset_ua(msg);
 	return 0;
 }
 
@@ -375,6 +392,8 @@ int lookup_branches(sip_msg_t *msg, udomain_t *d)
 	flag_t ruri_b_flags = 0;
 	str ruri_b_instance = {0};
 	unsigned int ruri_b_reg_id = 0;
+	str ruri_b_ruid = {0};
+	str ruri_b_ua = {0};
 	branch_t *crt = NULL;
 
 	ret = 1;
@@ -399,6 +418,8 @@ int lookup_branches(sip_msg_t *msg, udomain_t *d)
 	getbflagsval(0, &ruri_b_flags);
 	ruri_b_instance = msg->instance;
 	ruri_b_reg_id = msg->reg_id;
+	ruri_b_ruid = msg->ruid;
+	ruri_b_ua = msg->location_ua;
 	reset_ruri_branch(msg);
 	/* set new uri buf to null, otherwise is freed or overwritten by
 	 * rewrite_uri() during branch lookup */
@@ -487,6 +508,8 @@ done:
 	setbflagsval(0, ruri_b_flags);
 	msg->instance = ruri_b_instance;
 	msg->reg_id = ruri_b_reg_id;
+	msg->ruid = ruri_b_ruid;
+	msg->location_ua = ruri_b_ua;
 
 	return (found)?1:ret;
 }
diff --git a/modules/registrar/path.c b/modules/registrar/path.c
index a4fd485..cefd59a 100644
--- a/modules/registrar/path.c
+++ b/modules/registrar/path.c
@@ -32,15 +32,19 @@
 #include "../../data_lump.h"
 #include "../../parser/parse_rr.h"
 #include "../../parser/parse_uri.h"
+#include "../../lib/kcore/strcommon.h"
 #include "path.h"
 #include "reg_mod.h"
 
+
 /*! \brief
  * Combines all Path HF bodies into one string.
  */
 int build_path_vector(struct sip_msg *_m, str *path, str *received)
 {
 	static char buf[MAX_PATH_SIZE];
+	static char uri_buf[MAX_URI_SIZE];
+	static str uri_str;
 	char *p;
 	struct hdr_field *hdr;
 	struct sip_uri puri;
@@ -92,8 +96,18 @@ int build_path_vector(struct sip_msg *_m, str *path, str *received)
 				LM_ERR("failed to parse parameters of first hop\n");
 				goto error;
 			}
-			if (hooks.contact.received)
-				*received = hooks.contact.received->body;
+
+			if (hooks.contact.received) {
+			        uri_str.s = uri_buf;
+				uri_str.len = MAX_URI_SIZE;
+			        if (unescape_user(&(hooks.contact.received->body), &uri_str) < 0) {
+				        LM_ERR("unescaping received failed\n");
+				        goto error;
+				}
+				*received = uri_str;
+				LM_DBG("received is <%.*s>\n", received->len, received->s);
+			}
+				
 			/*for (;params; params = params->next) {
 				if (params->type == P_RECEIVED) {
 					*received = hooks.contact.received->body;
@@ -107,6 +121,7 @@ int build_path_vector(struct sip_msg *_m, str *path, str *received)
 
 	path->s = buf;
 	path->len = p-buf;
+	LM_DBG("path is <%.*s>\n", path->len, path->s);
 	return 0;
 error:
 	if(route) free_rr(&route);
diff --git a/modules/registrar/reg_mod.c b/modules/registrar/reg_mod.c
index d3fd4f2..4539f67 100644
--- a/modules/registrar/reg_mod.c
+++ b/modules/registrar/reg_mod.c
@@ -94,6 +94,7 @@ static int w_lookup(struct sip_msg* _m, char* _d, char* _p2);
 static int w_lookup_branches(struct sip_msg* _m, char* _d, char* _p2);
 static int w_registered(struct sip_msg* _m, char* _d, char* _uri);
 static int w_unregister(struct sip_msg* _m, char* _d, char* _uri);
+static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid);
 
 /*! \brief Fixup functions */
 static int domain_fixup(void** param, int param_no);
@@ -120,6 +121,7 @@ sruid_t _reg_sruid;
 
 int reg_gruu_enabled = 1;
 int reg_outbound_mode = 0;
+int reg_regid_mode = 0;
 int reg_flow_timer = 0;
 
 /* Populate this AVP if testing for specific registration instance. */
@@ -169,11 +171,11 @@ static pv_export_t mod_pvs[] = {
  */
 static cmd_export_t cmds[] = {
 	{"save",         (cmd_function)w_save2,       1,  save_fixup, 0,
-			REQUEST_ROUTE | ONREPLY_ROUTE },
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 	{"save",         (cmd_function)w_save2,       2,  save_fixup, 0,
-			REQUEST_ROUTE | ONREPLY_ROUTE },
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 	{"save",         (cmd_function)w_save3,       3,  save_fixup, 0,
-			REQUEST_ROUTE | ONREPLY_ROUTE },
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 	{"lookup",       (cmd_function)w_lookup,      1,  domain_uri_fixup, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"lookup",       (cmd_function)w_lookup,      2,  domain_uri_fixup, 0,
@@ -186,6 +188,8 @@ static cmd_export_t cmds[] = {
 			REQUEST_ROUTE },
 	{"unregister",   (cmd_function)w_unregister,  2,  unreg_fixup, 0,
 			REQUEST_ROUTE| FAILURE_ROUTE },
+	{"unregister",   (cmd_function)w_unregister2, 3, unreg_fixup, 0,
+			REQUEST_ROUTE| FAILURE_ROUTE },
 	{"reg_fetch_contacts", (cmd_function)pv_fetch_contacts, 3, 
 			fetchc_fixup, 0,
 			REQUEST_ROUTE| FAILURE_ROUTE },
@@ -228,6 +232,7 @@ static param_export_t params[] = {
 	{"xavp_rcd",           STR_PARAM, &reg_xavp_rcd.s     					},
 	{"gruu_enabled",       INT_PARAM, &reg_gruu_enabled    					},
 	{"outbound_mode",      INT_PARAM, &reg_outbound_mode					},
+	{"regid_mode",         INT_PARAM, &reg_regid_mode					},
 	{"flow_timer",         INT_PARAM, &reg_flow_timer					},
 	{0, 0, 0}
 };
@@ -399,8 +404,13 @@ static int mod_init(void)
 		return -1;
 	}
 
+	if (reg_regid_mode < 0 || reg_regid_mode > 1) {
+		LM_ERR("regid_mode modparam must be 0 (use with outbound), 1 (use always)\n");
+		return -1;
+	}
+
 	if (reg_flow_timer < 0 || reg_flow_timer > REG_FLOW_TIMER_MAX
-			|| (reg_flow_timer > 0 && reg_outbound_mode != REG_OUTBOUND_REQUIRE)) {
+			|| (reg_flow_timer > 0 && reg_outbound_mode == REG_OUTBOUND_NONE)) {
 		LM_ERR("bad value for flow_timer\n");
 		return -1;
 	}
@@ -501,7 +511,26 @@ static int w_unregister(struct sip_msg* _m, char* _d, char* _uri)
 		return -1;
 	}
 
-	return unregister(_m, (udomain_t*)_d, &uri);
+	return unregister(_m, (udomain_t*)_d, &uri, NULL);
+}
+
+static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid)
+{
+        str uri = {0, 0};
+	str ruid = {0};
+	if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0)
+	{
+	        LM_ERR("invalid uri parameter\n");
+		return -1;
+	}
+	if(fixup_get_svalue(_m, (gparam_p)_ruid, &ruid)!=0 || ruid.len<=0)
+	{
+		LM_ERR("invalid ruid parameter\n");
+		return -1;
+	}
+
+
+	return unregister(_m, (udomain_t*)_d, &uri, &ruid);
 }
 
 /*! \brief
@@ -546,6 +575,8 @@ static int unreg_fixup(void** param, int param_no)
 		return domain_fixup(param, 1);
 	} else if (param_no == 2) {
 		return fixup_spve_null(param, 1);
+	} else if (param_no == 3) {
+		return fixup_spve_null(param, 1);
 	}
 	return 0;
 }
diff --git a/modules/registrar/reg_mod.h b/modules/registrar/reg_mod.h
index b970511..6992233 100644
--- a/modules/registrar/reg_mod.h
+++ b/modules/registrar/reg_mod.h
@@ -56,7 +56,6 @@
 #define USERNAME_MAX_SIZE      64
 #define DOMAIN_MAX_SIZE        128
 #define CALLID_MAX_SIZE        255
-#define UA_MAX_SIZE            255
 
 #define PATH_MODE_STRICT	2
 #define PATH_MODE_LAZY		1
@@ -71,6 +70,9 @@
 #define REG_OUTBOUND_SUPPORTED	1
 #define REG_OUTBOUND_REQUIRE	2
 
+#define REG_REGID_OUTBOUND      0
+#define REG_REGID_ALWAYS        1
+
 /* Maximum of 999 to keep flow-timer to 3 digits
    - make sure to update reply.c:add_flow_timer() if the number of digits
      increases! */
@@ -94,6 +96,7 @@ extern int path_mode;
 extern int path_use_params;
 extern int reg_gruu_enabled;
 extern int reg_outbound_mode;
+extern int reg_regid_mode;
 extern int reg_flow_timer;
 
 extern str sock_hdr_name;
diff --git a/modules/registrar/reply.c b/modules/registrar/reply.c
index 9d1bdfc..93c86a8 100644
--- a/modules/registrar/reply.c
+++ b/modules/registrar/reply.c
@@ -39,7 +39,8 @@
 #include "../../ut.h"
 #include "../../xavp.h"
 #include "../../parser/msg_parser.h"
-#include "../../lib/kcore/parse_supported.h"
+#include "../../parser/parse_require.h"
+#include "../../parser/parse_supported.h"
 #include "../../data_lump_rpl.h"
 #include "../usrloc/usrloc.h"
 #include "rerrno.h"
@@ -188,7 +189,7 @@ int build_contact(sip_msg_t *msg, ucontact_t* c, str *host)
 
 
 	if(msg!=NULL && parse_supported(msg)==0
-			&& (get_supported(msg) & F_SUPPORTED_GRUU))
+			&& (get_supported(msg) & F_OPTION_TAG_GRUU))
 		mode = 1;
 	else
 		mode = 0;
@@ -379,6 +380,7 @@ int build_contact(sip_msg_t *msg, ucontact_t* c, str *host)
 #define MSG_400 "Bad Request"
 #define MSG_420 "Bad Extension"
 #define MSG_421 "Extension Required"
+#define MSG_439 "First Hop Lacks Outbound Support"
 #define MSG_500 "Server Internal Error"
 #define MSG_503 "Service Unavailable"
 
@@ -413,6 +415,9 @@ int build_contact(sip_msg_t *msg, ucontact_t* c, str *host)
 #define EI_R_PARSE_PATH  "Path parse error"                         /* R_PARSE_PATH */
 #define EI_R_PATH_UNSUP  "No support for found Path indicated"      /* R_PATH_UNSUP */
 #define EI_R_OB_UNSUP    "No support for Outbound indicated"        /* R_OB_UNSUP */
+#define EI_R_OB_REQD     "No support for Outbound on server"        /* R_OB_REQD */
+#define EI_R_OB_UNSUP_EDGE "No support for Outbound on edge proxy"  /* R_OB_UNSUP_EDGE */
+
 
 str error_info[] = {
 	{EI_R_FINE,       sizeof(EI_R_FINE) - 1},
@@ -446,7 +451,8 @@ str error_info[] = {
 	{EI_R_PARSE_PATH, sizeof(EI_R_PARSE_PATH) - 1},
 	{EI_R_PATH_UNSUP, sizeof(EI_R_PATH_UNSUP) - 1},
 	{EI_R_OB_UNSUP,   sizeof(EI_R_OB_UNSUP) - 1},
-
+	{EI_R_OB_REQD,    sizeof(EI_R_OB_REQD) - 1},
+	{EI_R_OB_UNSUP_EDGE, sizeof(EI_R_OB_UNSUP_EDGE) - 1},
 };
 
 int codes[] = {
@@ -480,8 +486,9 @@ int codes[] = {
 	400, /* R_CALLID_LEN */
 	400, /* R_PARSE_PATH */
 	420, /* R_PATH_UNSUP */
-	421  /* R_OB_UNSUP */
-
+	421, /* R_OB_UNSUP */
+	420, /* R_OB_REQD */
+	439, /* R_OB_UNSUP_EDGE */
 };
 
 
@@ -615,8 +622,8 @@ static int add_flow_timer(struct sip_msg* _m)
  */
 int reg_send_reply(struct sip_msg* _m)
 {
-	str unsup = str_init(SUPPORTED_PATH_STR);
-	str outbound_str = str_init(SUPPORTED_OUTBOUND_STR);
+	str unsup = str_init(OPTION_TAG_PATH_STR);
+	str outbound_str = str_init(OPTION_TAG_OUTBOUND_STR);
 	long code;
 	str msg = str_init(MSG_200); /* makes gcc shut up */
 	char* buf;
@@ -637,7 +644,7 @@ int reg_send_reply(struct sip_msg* _m)
 					if (add_path(_m, &_m->path_vec) < 0)
 						return -1;
 				}
-				else if (get_supported(_m) & F_SUPPORTED_PATH) {
+				else if (get_supported(_m) & F_OPTION_TAG_PATH) {
 					if (add_path(_m, &_m->path_vec) < 0)
 						return -1;
 				} else if (path_mode == PATH_MODE_STRICT) {
@@ -659,22 +666,29 @@ int reg_send_reply(struct sip_msg* _m)
 			if (add_require(_m, &outbound_str) < 0)
 				return -1;
 
+			if (add_supported(_m, &outbound_str) < 0)
+				return -1;
+
 			if (reg_flow_timer > 0) {
 				if (add_flow_timer(_m) < 0)
 					return -1;
 			}
-			if (add_supported(_m, &outbound_str) < 0)
-			    return -1;
 			break;
 		case REG_OUTBOUND_SUPPORTED:
-		    if ((parse_supported(_m) == 0) &&
-			(((struct supported_body *)_m->supported->parsed)->supported_all & F_SUPPORTED_OUTBOUND)) {
-			if (add_require(_m, &outbound_str) < 0)
-			    return -1;
-		    }
-		    if (add_supported(_m, &outbound_str) < 0)
-			return -1;
-		    break;
+			if (add_supported(_m, &outbound_str) < 0)
+				return -1;
+
+			if ((get_require(_m) & F_OPTION_TAG_OUTBOUND)
+			    || (get_supported(_m) & F_OPTION_TAG_OUTBOUND)) {
+				if (add_require(_m, &outbound_str) < 0)
+					return -1;
+
+				if (reg_flow_timer > 0) {
+					if (add_flow_timer(_m) < 0)
+						return -1;
+				}
+			}
+			break;
 		}
 		break;
 	case R_OB_UNSUP:
@@ -683,6 +697,10 @@ int reg_send_reply(struct sip_msg* _m)
 		if (add_supported(_m, &outbound_str) < 0)
 			return -1;
 		break;
+	case R_OB_REQD:
+		if (add_unsupported(_m, &outbound_str) < 0)
+			return -1;
+		break;
 	default:
 		break;
 	}
@@ -692,7 +710,8 @@ int reg_send_reply(struct sip_msg* _m)
 	case 200: msg.s = MSG_200; msg.len = sizeof(MSG_200)-1;break;
 	case 400: msg.s = MSG_400; msg.len = sizeof(MSG_400)-1;break;
 	case 420: msg.s = MSG_420; msg.len = sizeof(MSG_420)-1;break;
-	case 421: msg.s = MSG_420; msg.len = sizeof(MSG_421)-1;break;
+	case 421: msg.s = MSG_421; msg.len = sizeof(MSG_421)-1;break;
+	case 439: msg.s = MSG_439; msg.len = sizeof(MSG_439)-1;break;
 	case 500: msg.s = MSG_500; msg.len = sizeof(MSG_500)-1;break;
 	case 503: msg.s = MSG_503; msg.len = sizeof(MSG_503)-1;break;
 	}
diff --git a/modules/registrar/rerrno.h b/modules/registrar/rerrno.h
index 63add5a..535be04 100644
--- a/modules/registrar/rerrno.h
+++ b/modules/registrar/rerrno.h
@@ -64,7 +64,9 @@ typedef enum rerr {
 	R_CALLID_LEN, /*!< Callid too long */
 	R_PARSE_PATH, /*!< Error while parsing Path */
 	R_PATH_UNSUP, /*!< Path not supported by UAC */
-	R_OB_UNSUP    /*!< Outbound not supported by UAC */
+	R_OB_UNSUP,   /*!< Outbound not supported by UAC */
+	R_OB_REQD,    /*!< Outbound required by UAC but not supported on server */
+	R_OB_UNSUP_EDGE, /*!< Outbound needed for this registration but not supported on edge proxy */
 
 } rerr_t;
 
diff --git a/modules/registrar/save.c b/modules/registrar/save.c
index cd637c3..fc5d564 100644
--- a/modules/registrar/save.c
+++ b/modules/registrar/save.c
@@ -50,6 +50,7 @@
 #include "../../parser/parse_allow.h"
 #include "../../parser/parse_methods.h"
 #include "../../parser/msg_parser.h"
+#include "../../parser/parse_rr.h"
 #include "../../parser/parse_to.h"
 #include "../../parser/parse_uri.h"
 #include "../../dprint.h"
@@ -61,7 +62,8 @@
 #include "../../mod_fix.h"
 #include "../../lib/srutils/sruid.h"
 #include "../../lib/kcore/cmpapi.h"
-#include "../../lib/kcore/parse_supported.h"
+#include "../../parser/parse_require.h"
+#include "../../parser/parse_supported.h"
 #include "../../lib/kcore/statistics.h"
 #ifdef USE_TCP
 #include "../../tcp_server.h"
@@ -81,6 +83,9 @@ static int mem_only = 0;
 
 extern sruid_t _reg_sruid;
 
+static int q_override_msg_id;
+static qvalue_t q_override_value;
+
 /*! \brief
  * Process request that contained a star, in that case, 
  * we will remove all bindings with the given username 
@@ -129,37 +134,50 @@ static inline int star(sip_msg_t *_m, udomain_t* _d, str* _a, str *_h)
 
 /*! \brief
  */
-static struct socket_info *get_sock_hdr(struct sip_msg *msg)
+static struct socket_info *get_sock_val(struct sip_msg *msg)
 {
 	struct socket_info *sock;
 	struct hdr_field *hf;
+	str xsockname = str_init("socket");
+	sr_xavp_t *vavp = NULL;
 	str socks;
 	str hosts;
 	int port;
 	int proto;
-	char c;
+	char c = 0;
 
-	if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
-		LM_ERR("failed to parse message\n");
-		return 0;
-	}
+	if(sock_hdr_name.len>0) {
+		if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
+			LM_ERR("failed to parse message\n");
+			return 0;
+		}
 
-	for (hf=msg->headers; hf; hf=hf->next) {
-		if (cmp_hdrname_str(&hf->name, &sock_hdr_name)==0)
-			break;
-	}
+		for (hf=msg->headers; hf; hf=hf->next) {
+			if (cmp_hdrname_str(&hf->name, &sock_hdr_name)==0)
+				break;
+		}
 
-	/* hdr found? */
-	if (hf==0)
-		return 0;
+		/* hdr found? */
+		if (hf==0)
+			return 0;
 
-	trim_len( socks.len, socks.s, hf->body );
-	if (socks.len==0)
-		return 0;
+		trim_len( socks.len, socks.s, hf->body );
+		if (socks.len==0)
+			return 0;
 
-	/*FIXME: This is a hack */
-	c = socks.s[socks.len];
-	socks.s[socks.len] = '\0';
+		/*FIXME: This is a hack */
+		c = socks.s[socks.len];
+		socks.s[socks.len] = '\0';
+	} else {
+		/* xavp */
+		if(reg_xavp_cfg.s!=NULL)
+		{
+			vavp = xavp_get_child_with_sval(&reg_xavp_cfg, &xsockname);
+			if(vavp==NULL || vavp->val.v.s.len<=0)
+				return 0;
+		}
+		socks = vavp->val.v.s;
+	}
 	if (parse_phostport( socks.s, &hosts.s, &hosts.len,
 	&port, &proto)!=0) {
 		socks.s[socks.len] = c;
@@ -167,7 +185,9 @@ static struct socket_info *get_sock_hdr(struct sip_msg *msg)
 			socks.len, socks.s);
 		return 0;
 	}
-	socks.s[socks.len] = c;
+	if(sock_hdr_name.len>0 && c!=0) {
+		socks.s[socks.len] = c;
+	}
 	sock = grep_sock_info(&hosts,(unsigned short)port,(unsigned short)proto);
 	if (sock==0) {
 		LM_ERR("non-local socket <%.*s>\n",	socks.len, socks.s);
@@ -216,8 +236,7 @@ static inline int no_contacts(sip_msg_t *_m, udomain_t* _d, str* _a, str* _h)
 /*! \brief
  * Fills the common part (for all contacts) of the info structure
  */
-static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
-											unsigned int _e, unsigned int _f)
+static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, unsigned int _e, unsigned int _f, int _use_regid)
 {
 	static ucontact_info_t ci;
 	static str no_ua = str_init("n/a");
@@ -252,16 +271,24 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
 
 		/* set received socket */
 		if (_m->flags&sock_flag) {
-			ci.sock = get_sock_hdr(_m);
+			ci.sock = get_sock_val(_m);
 			if (ci.sock==0)
 				ci.sock = _m->rcv.bind_address;
 		} else {
 			ci.sock = _m->rcv.bind_address;
 		}
 
+		/* set tcp connection id */
+		if (_m->rcv.proto==PROTO_TCP || _m->rcv.proto==PROTO_TLS
+		        || _m->rcv.proto==PROTO_WS  || _m->rcv.proto==PROTO_WSS) {
+			ci.tcpconn_id = _m->rcv.proto_reserved1;
+		} else {
+			ci.tcpconn_id = -1;
+		}
+
 		/* additional info from message */
 		if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent &&
-		_m->user_agent->body.len>0 && _m->user_agent->body.len<UA_MAX_SIZE) {
+		_m->user_agent->body.len>0 && _m->user_agent->body.len<MAX_UA_SIZE) {
 			ci.user_agent = &_m->user_agent->body;
 		} else {
 			ci.user_agent = &no_ua;
@@ -301,6 +328,9 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
 		received_found = 0; /* not found yet */
 		m = _m; /* remember the message */
 	}
+	else {
+		memset( &ci.instance, 0, sizeof(str));
+	}
 
 	if(_c!=0) {
 		/* hook uri address - should be more than 'sip:' chars */
@@ -308,7 +338,11 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
 			ci.c = &_c->uri;
 
 		/* Calculate q value of the contact */
-		if (calc_contact_q(_c->q, &ci.q) < 0) {
+		if (m && m->id == q_override_msg_id)
+		{
+			ci.q = q_override_value;
+		}
+		else if (calc_contact_q(_c->q, &ci.q) < 0) {
 			rerrno = R_INV_Q;
 			LM_ERR("failed to calculate q\n");
 			goto error;
@@ -364,7 +398,7 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
 		}
 		if(_c->instance!=NULL && _c->instance->body.len>0)
 			ci.instance = _c->instance->body;
-		if(_c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) {
+		if(_use_regid && _c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) {
 			if(str2int(&_c->reg_id->body, &ci.reg_id)<0 || ci.reg_id==0)
 			{
 				LM_ERR("invalid reg-id value\n");
@@ -386,7 +420,6 @@ error:
 int reg_get_crt_max_contacts(void)
 {
 	int n;
-	sr_xavp_t *ravp=NULL;
 	sr_xavp_t *vavp=NULL;
 	str vname = {"max_contacts", 12};
 
@@ -394,23 +427,15 @@ int reg_get_crt_max_contacts(void)
 
 	if(reg_xavp_cfg.s!=NULL)
 	{
-		ravp = xavp_get(&reg_xavp_cfg, NULL);
-		if(ravp!=NULL && ravp->val.type==SR_XTYPE_XAVP)
+		vavp = xavp_get_child_with_ival(&reg_xavp_cfg, &vname);
+		if(vavp!=NULL)
 		{
-			vavp = xavp_get(&vname, ravp->val.v.xavp);
-			if(vavp!=NULL && vavp->val.type==SR_XTYPE_INT)
-			{
-				n = vavp->val.v.i;
-				LM_ERR("using max contacts value from xavp: %d\n", n);
-			} else {
-				ravp = NULL;
-			}
-		} else {
-			ravp = NULL;
+			n = vavp->val.v.i;
+			LM_DBG("using max contacts value from xavp: %d\n", n);
 		}
 	}
 
-	if(ravp==NULL)
+	if(vavp==NULL)
 	{
 		n = cfg_get(registrar, registrar_cfg, max_contacts);
 	}
@@ -424,7 +449,7 @@ int reg_get_crt_max_contacts(void)
  * and insert all contacts from the message that have expires
  * > 0
  */
-static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
+static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a, int _use_regid)
 {
 	ucontact_info_t* ci;
 	urecord_t* r = NULL;
@@ -481,14 +506,14 @@ static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
 		}
 
 		/* pack the contact_info */
-		if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags))==0 ) {
+		if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags, _use_regid))==0 ) {
 			LM_ERR("failed to extract contact info\n");
 			goto error;
 		}
 
 		/* hack to work with buggy clients having many contacts with same
 		 * address in one REGISTER - increase CSeq to detect if there was
-		 * one alredy added, then update */
+		 * one already added, then update */
 		ci->cseq++;
 		if ( r->contacts==0
 				|| ul.get_ucontact_by_instance(r, &_c->uri, ci, &c) != 0) {
@@ -608,8 +633,7 @@ static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c,
  * 3) If contact in usrloc exists and expires
  *    == 0, delete contact
  */
-static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
-										int _mode)
+static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, int _mode, int _use_regid)
 {
 	ucontact_info_t *ci;
 	ucontact_t *c, *ptr, *ptr0;
@@ -628,7 +652,7 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
 
 	rc = 0;
 	/* pack the contact_info */
-	if ( (ci=pack_ci( _m, 0, 0, flags))==0 ) {
+	if ( (ci=pack_ci( _m, 0, 0, flags, _use_regid))==0 ) {
 		LM_ERR("failed to initial pack contact info\n");
 		goto error;
 	}
@@ -659,7 +683,7 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
 		calc_contact_expires(_m, _c->expires, &expires);
 
 		/* pack the contact info */
-		if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
+		if ( (ci=pack_ci( 0, _c, expires, 0, _use_regid))==0 ) {
 			LM_ERR("failed to pack contact specific info\n");
 			goto error;
 		}
@@ -692,10 +716,10 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
 				ptr=_r->contacts;
 				while(ptr)
 				{
-					ptr0 = ptr;
+					ptr0 = ptr->next;
 					if(ptr!=c)
 						ul.delete_ucontact(_r, ptr);
-					ptr=ptr0->next;
+					ptr=ptr0;
 				}
 				updated=1;
 			}
@@ -722,13 +746,32 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
 					ptr=_r->contacts;
 					while(ptr)
 					{
-						ptr0 = ptr;
+						ptr0 = ptr->next;
 						if(ptr!=c)
 							ul.delete_ucontact(_r, ptr);
-						ptr=ptr0->next;
+						ptr=ptr0;
 					}
 					updated=1;
 				}
+				/* If call-id has changed then delete all records with this sip.instance
+				   then insert new record */
+				if (ci->instance.s != NULL &&
+					(ci->callid->len != c->callid.len ||
+						strncmp(ci->callid->s, c->callid.s, ci->callid->len) != 0))
+				{
+					ptr = _r->contacts;
+					while (ptr)
+					{
+						ptr0 = ptr->next;
+						if ((ptr != c) && ptr->instance.len == c->instance.len &&
+							strncmp(ptr->instance.s, c->instance.s, ptr->instance.len) == 0)
+						{
+							ul.delete_ucontact(_r, ptr);
+						}
+						ptr = ptr0;
+					}
+					updated = 1;
+				}
 				if (ul.update_ucontact(_r, c, ci) < 0) {
 					rerrno = R_UL_UPD_C;
 					LM_ERR("failed to update contact\n");
@@ -775,7 +818,7 @@ error:
  * contained some contact header fields
  */
 static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
-		str* _a, int _mode)
+		str* _a, int _mode, int _use_regid)
 {
 	int res;
 	int ret;
@@ -797,7 +840,7 @@ static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
 	}
 
 	if (res == 0) { /* Contacts found */
-		if ((ret=update_contacts(_m, r, _mode)) < 0) {
+		if ((ret=update_contacts(_m, r, _mode, _use_regid)) < 0) {
 			build_contact(_m, r->contacts, &u->host);
 			ul.release_urecord(r);
 			ul.unlock_udomain(_d, _a);
@@ -806,7 +849,7 @@ static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
 		build_contact(_m, r->contacts, &u->host);
 		ul.release_urecord(r);
 	} else {
-		if (insert_contacts(_m, _d, _a) < 0) {
+		if (insert_contacts(_m, _d, _a, _use_regid) < 0) {
 			ul.unlock_udomain(_d, _a);
 			return -4;
 		}
@@ -828,6 +871,12 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	str aor;
 	int ret;
 	sip_uri_t *u;
+	rr_t *route;
+	struct sip_uri puri;
+	param_hooks_t hooks;
+	param_t *params;
+	contact_t *contact;
+	int use_ob = 1, use_regid = 1;
 
 	u = parse_to_uri(_m);
 	if(u==NULL)
@@ -845,13 +894,71 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	}
 
 	if (parse_supported(_m) == 0) {
-		if (!(((struct supported_body *)_m->supported->parsed)->supported_all
-				& F_SUPPORTED_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_REQUIRE) {
+		if (!(get_supported(_m)	& F_OPTION_TAG_OUTBOUND)
+				&& reg_outbound_mode == REG_OUTBOUND_REQUIRE) {
 			LM_WARN("Outbound required by server and not supported by UAC\n");
 			rerrno = R_OB_UNSUP;
 			goto error;
 		}
 	}
+
+	if (parse_require(_m) == 0) {
+		if ((get_require(_m) & F_OPTION_TAG_OUTBOUND)
+				&& reg_outbound_mode == REG_OUTBOUND_NONE) {
+			LM_WARN("Outbound required by UAC and not supported by server\n");
+			rerrno = R_OB_REQD;
+			goto error;
+		}
+	}
+
+	if (reg_outbound_mode != REG_OUTBOUND_NONE
+		&& !(parse_headers(_m, HDR_VIA2_F, 0) == -1 || _m->via2 == 0
+			|| _m->via2->error != PARSE_OK)) {
+		/* Outbound supported on server, and more than one Via: - not the first hop */
+
+		if (!(parse_headers(_m, HDR_PATH_F, 0) == -1 || _m->path == 0)) {
+		        route = (rr_t *)0;
+			if (parse_rr_body(_m->path->body.s, _m->path->body.len, &route) < 0) {
+				LM_ERR("Failed to parse Path: header body\n");
+				goto error;
+			}
+			if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) {
+				LM_ERR("Failed to parse Path: URI\n");
+				goto error;
+			}
+			if (parse_params(&puri.params, CLASS_URI, &hooks, &params) != 0) {
+				LM_ERR("Failed to parse Path: URI parameters\n");
+				goto error;
+			}
+			if (!hooks.uri.ob) {
+				/* No ;ob parameter to top Path: URI - no outbound */
+				use_ob = 0;
+			}
+
+		} else {
+			/* No Path: header - no outbound */
+			use_ob = 0;
+
+		}
+
+		contact = ((contact_body_t *) _m->contact->parsed)->contacts;
+		if (!contact) {
+			LM_ERR("empty Contact:\n");
+			goto error;
+		}
+
+		if ((use_ob == 0) && (reg_regid_mode == REG_REGID_OUTBOUND)) {
+			if ((get_supported(_m) & F_OPTION_TAG_OUTBOUND)
+			    && contact->reg_id) {
+				LM_WARN("Outbound used by UAC but not supported by edge proxy\n");
+				rerrno = R_OB_UNSUP_EDGE;
+				goto error;
+			} else {
+				/* ignore ;reg-id parameter */
+				use_regid = 0;
+			}
+		}
+	}
 	
 	get_act_time();
 	c = get_first_contact(_m);
@@ -873,7 +980,7 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 		}
 	} else {
 		mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
-		if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode)) < 0)
+		if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode, use_regid)) < 0)
 			goto error;
 		ret = (ret==0)?1:ret;
 	}
@@ -881,7 +988,8 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
 	update_stat(accepted_registrations, 1);
 
 	/* Only send reply upon request, not upon reply */
-	if ((is_route_type(REQUEST_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0))
+	if ((is_route_type(REQUEST_ROUTE) || is_route_type(FAILURE_ROUTE))
+			&& !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0))
 		return -1;
 
 	return ret;
@@ -893,26 +1001,82 @@ error:
 	return 0;
 }
 
-int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri)
+int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri, str *_ruid)
 {
 	str aor = {0, 0};
 	sip_uri_t *u;
+	urecord_t *r;
+	ucontact_t *c;
+	int res;
 
-	u = parse_to_uri(_m);
-	if(u==NULL)
-		return -2;
+	if (_ruid == NULL) {
+		/* No ruid provided - remove all contacts for aor */
 
+	        if (extract_aor(_uri, &aor, NULL) < 0) {
+		        LM_ERR("failed to extract Address Of Record\n");
+		        return -1;
+		}
 
-	if (extract_aor(_uri, &aor, NULL) < 0) {
-		LM_ERR("failed to extract Address Of Record\n");
-		return -1;
+		u = parse_to_uri(_m);
+		if(u==NULL)
+			return -2;
+
+		if (star(_m, _d, &aor, &u->host) < 0)
+		{
+			LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s);
+			return -1;
+		}
+	} else {
+		/* ruid provided - remove a specific contact */
+
+	        if (_uri->len > 0) {
+
+		        if (extract_aor(_uri, &aor, NULL) < 0) {
+		                LM_ERR("failed to extract Address Of Record\n");
+		                return -1;
+		        }
+
+		        if (ul.get_urecord_by_ruid(_d, ul.get_aorhash(&aor),
+						   _ruid, &r, &c) != 0) {
+			        LM_WARN("AOR/Contact not found\n");
+			        return -1;
+			}
+			if (ul.delete_ucontact(r, c) != 0) {
+			        LM_WARN("could not delete contact\n");
+			        return -1;
+			}
+			ul.unlock_udomain(_d, &aor);
+
+		} else {
+
+   		        res = ul.delete_urecord_by_ruid(_d, _ruid);
+			switch (res) {
+			case -1:
+			        LM_ERR("could not delete contact\n");
+			        return -1;
+			case -2:
+			        LM_WARN("contact not found\n");
+			        return -1;
+			default:
+			        return 1;
+			}
+
+		}
 	}
 
-	if (star(_m, _d, &aor, &u->host) < 0)
+	return 1;
+}
+
+int set_q_override(struct sip_msg* _m, int _q)
+{
+	if ((_q < 0) || (_q > 1000))
 	{
-		LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s);
+		LM_ERR("Invalid q value\n");
 		return -1;
 	}
+	q_override_msg_id = _m->id;
+	q_override_value = _q;
 	return 1;
 }
 
+
diff --git a/modules/registrar/save.h b/modules/registrar/save.h
index 69e1352..973e03f 100644
--- a/modules/registrar/save.h
+++ b/modules/registrar/save.h
@@ -47,7 +47,7 @@
  * Process REGISTER request and save it's contacts
  */
 int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str* _uri);
-int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri);
-
+int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri, str *_ruid);
+int set_q_override(struct sip_msg* _m, int _q);
 
 #endif /* SAVE_H */
diff --git a/modules/rls/notify.c b/modules/rls/notify.c
index 6738f91..eb6a0e1 100644
--- a/modules/rls/notify.c
+++ b/modules/rls/notify.c
@@ -1028,6 +1028,7 @@ int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
 			uri.len = strlen(uri.s);
 			if (uri.len > MAX_URI_SIZE-1) {
 			    LM_ERR("XCAP URI is too long\n");
+			    xmlFree(uri.s);
 			    return -1;
 			}
 			LM_DBG("got resource-list uri <%.*s>\n", uri.len, uri.s);
@@ -1036,6 +1037,7 @@ int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
 			unescaped_uri.len = 0;
 			if (un_escape(&uri, &unescaped_uri) < 0) {
 			    LM_ERR("Error un-escaping XCAP URI\n");
+			    xmlFree(uri.s);
 			    return -1;
 			}
 			unescaped_uri.s[unescaped_uri.len] = 0;
@@ -1047,7 +1049,7 @@ int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
 					&& (hostname.len == 0
 						|| check_self(&hostname, 0, PROTO_NONE) == 1))
 				{
-					LM_DBG("fetching local <resource-list/>\n");
+					LM_DBG("fetching local <resource-list - %.*s>\n", uri.len, uri.s);
 					if (rls_get_resource_list(&rl_uri, &username, &domain, &rl_node, &rl_doc)>0)
 					{
 						LM_DBG("calling myself for rl_node\n");
@@ -1057,7 +1059,7 @@ int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
 					}
 					else
 					{
-						LM_ERR("<resource-list/> not found\n");
+						LM_ERR("<resource-list - %.*s> not found\n", uri.len, uri.s);
 						xmlFree(uri.s);
 						return -1;
 					}
@@ -1065,14 +1067,14 @@ int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
 				}
 				else
 				{
-					LM_ERR("<resource-list/> is not local - unsupported at this time\n");
+					LM_ERR("<resource-list - %.*s> is not local - unsupported at this time\n", uri.len, uri.s);
 					xmlFree(uri.s);
 					return -1;
 				}
 			}
 			else
 			{
-				LM_ERR("unable to parse URI for <resource-list/>\n");
+				LM_ERR("unable to parse URI for <resource-list - %.*s>\n", uri.len, uri.s);
 				xmlFree(uri.s);
 				return -1;
 			}
diff --git a/modules/rls/subscribe.c b/modules/rls/subscribe.c
index 5ebd739..d15a601 100644
--- a/modules/rls/subscribe.c
+++ b/modules/rls/subscribe.c
@@ -35,7 +35,7 @@
 #include "../../data_lump_rpl.h"
 #include "../../lib/kcore/cmpapi.h"
 #include "../../hashes.h"
-#include "../../lib/kcore/parse_supported.h"
+#include "../../parser/parse_supported.h"
 #include "../../parser/msg_parser.h"
 #include "../../parser/parse_event.h"
 #include "../../parser/parse_expires.h"
@@ -551,7 +551,7 @@ int rls_handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_doma
 		return -1;
 	}
 
-	if(!(get_supported(msg) & F_SUPPORTED_EVENTLIST))
+	if(!(get_supported(msg) & F_OPTION_TAG_EVENTLIST))
 	{
 		LM_DBG("No support for 'eventlist' - not for rls\n");
 		goto forpresence;
diff --git a/modules/rr/README b/modules/rr/README
index 6f41420..d3b2dda 100644
--- a/modules/rr/README
+++ b/modules/rr/README
@@ -20,11 +20,11 @@ Edited by
 
 Bogdan-Andrei Iancu
 
-   Copyright � 2003 FhG FOKUS
+   Copyright (c) 2003 FhG FOKUS
 
-   Copyright � 2005 Voice Sistem SRL
+   Copyright (c) 2005 Voice Sistem SRL
 
-   Copyright � 2011 Carsten Bock, carsten at ng-voice.com
+   Copyright (c) 2011 Carsten Bock, carsten at ng-voice.com
      __________________________________________________________________
 
    Table of Contents
@@ -336,7 +336,9 @@ record_route();
 
    When the "outbound" module was loaded before this module and the Route:
    header contains a username part this function will attempt to use the
-   username part as a flow-token for routing.
+   username part as a flow-token for routing. If route calculation based
+   on flow-token succeeds, function returns TRUE even if there is only one
+   Route: header indicating the local proxy.
 
    Make sure your loose_routing function can't be used by attackers to
    bypass proxy authorization.
@@ -347,6 +349,7 @@ record_route();
 
    Return codes:
      * 1 - route calculation has been successful
+     * 2 - route calculation based on flow-token has been successful
      * -1 - route calculation has been unsuccessful
      * -2 - outbound flow-token shows evidence of tampering
 
@@ -554,7 +557,7 @@ Chapter 2. Developer Guide
    1.6. get_route_param( msg, name, val)
    1.7. register_rrcb( callback, param)
 
-1.1. record_route(string)
+1.1.  record_route(string)
 
    The function adds a new Record-Route header field. The header field
    will be inserted in the message before any other Record-Route header
@@ -572,7 +575,7 @@ Chapter 2. Developer Guide
 record_route();
 ...
 
-1.2. record_route_advertised_address(string)
+1.2.  record_route_advertised_address(string)
 
    This function will add the string into a new Record-Route header field.
    Don't use unless you know what you are doing. The header field will be
@@ -590,7 +593,7 @@ record_route();
 record_route_advertised_address("1.2.3.4:5090");
 ...
 
-1.3. add_rr_param( msg, param)
+1.3.  add_rr_param( msg, param)
 
    Adds a parameter to the requests's Record-Route URI (param must be in
    ";name=value" format).
@@ -603,7 +606,7 @@ record_route_advertised_address("1.2.3.4:5090");
      * str* param - parameter to be added to the Record-Route header - it
        must be in ";name=value" format.
 
-1.4. check_route_param( msg, re)
+1.4.  check_route_param( msg, re)
 
    The function checks for the request "msg" if the URI parameters of the
    local Route header (corresponding to the local server) matches the
@@ -618,7 +621,7 @@ record_route_advertised_address("1.2.3.4:5090");
      * regex_t* param - compiled regular expression to be checked against
        the Route header parameters.
 
-1.5. is_direction( msg, dir)
+1.5.  is_direction( msg, dir)
 
    The function checks the flow direction of the request "msg". As for
    checking it's used the "ftag" Route header parameter, the
@@ -634,7 +637,7 @@ record_route_advertised_address("1.2.3.4:5090");
      * int dir - direction to be checked against. It may be
        "RR_FLOW_UPSTREAM" or "RR_FLOW_DOWNSTREAM".
 
-1.6. get_route_param( msg, name, val)
+1.6.  get_route_param( msg, name, val)
 
    The function search in to the "msg"'s Route header parameters the
    parameter called "name" and returns its value into "val". It must be
@@ -650,7 +653,7 @@ record_route_advertised_address("1.2.3.4:5090");
      * str *val - returns the value of the searched Route header parameter
        if found. It might be empty string if the parameter had no value.
 
-1.7. register_rrcb( callback, param)
+1.7.  register_rrcb( callback, param)
 
    The function register a new callback (along with its parameter). The
    callback will be called when a loose route will be performed for the
diff --git a/modules/rr/doc/rr_admin.xml b/modules/rr/doc/rr_admin.xml
index 7c073ad..52f24dc 100644
--- a/modules/rr/doc/rr_admin.xml
+++ b/modules/rr/doc/rr_admin.xml
@@ -280,7 +280,9 @@ record_route();
 
       <para>When the <quote>outbound</quote> module was loaded before this
       module and the Route: header contains a username part this function will
-      attempt to use the username part as a flow-token for routing.</para>
+      attempt to use the username part as a flow-token for routing.  If route
+      calculation based on flow-token succeeds, function returns TRUE even
+      if there is only one Route: header indicating the local proxy.</para>
 
       <para>Make sure your loose_routing function can't be used by attackers
       to bypass proxy authorization.</para>
@@ -298,6 +300,11 @@ record_route();
         </listitem>
 
         <listitem>
+          <para><emphasis>2</emphasis> - route calculation based on
+	  flow-token has been successful</para>
+        </listitem>
+
+        <listitem>
           <para><emphasis>-1</emphasis> - route calculation has been
           unsuccessful</para>
         </listitem>
diff --git a/modules/rr/loose.c b/modules/rr/loose.c
index 8141bd0..bf0080e 100644
--- a/modules/rr/loose.c
+++ b/modules/rr/loose.c
@@ -47,6 +47,7 @@
 
 #define RR_ERROR -1		/*!< An error occured while processing route set */
 #define RR_DRIVEN 1		/*!< The next hop is determined from the route set */
+#define RR_OB_DRIVEN 2		/*!< The next hop is determined from the route set based on flow-token */
 #define NOT_RR_DRIVEN -1	/*!< The next hop is not determined from the route set */
 #define FLOW_TOKEN_BROKEN -2	/*!< Outbound flow-token shows evidence of tampering */
 
@@ -367,7 +368,7 @@ static inline int get_maddr_uri(str *uri, struct sip_uri *puri)
 		return 0;
 
 	/* sip: + maddr + : + port */
-	if( (puri->maddr_val.len) > (127 - 6 - puri->port.len) )
+	if( (puri->maddr_val.len) > (127 - 10) )
 	{
 		LM_ERR( "Too long maddr parameter\n");
 		return RR_ERROR;
@@ -500,58 +501,67 @@ static char uri_buf[MAX_ROUTE_URI_LEN];
  * \param dst_uri string to write the destination URI to (extracted from flow-token)
  * \return -1 on error, 0 when outbound not in use, 1 when outbound in use
  */
-static inline int process_outbound(struct sip_msg *_m, str flow_token,
-		str *dst_uri)
+static inline int process_outbound(struct sip_msg *_m, str flow_token)
 {
 	int ret;
-	struct receive_info rcv;
+	struct receive_info *rcv = NULL;
 	struct socket_info *si;
+	str dst_uri;
 
 	if (!rr_obb.decode_flow_token)
 		return 0;
 
-	ret = rr_obb.decode_flow_token(&rcv, flow_token);
+	ret = rr_obb.decode_flow_token(_m, &rcv, flow_token);
 
 	if (ret == -2) {
 		LM_DBG("no flow token found - outbound not in use\n");
 		return 0;
 	} else if (ret == -1) {
-		LM_ERR("failed to decode flow token\n");
+		LM_INFO("failed to decode flow token\n");
 		return -1;
-	} else if (!ip_addr_cmp(&rcv.src_ip, &_m->rcv.src_ip)
-			|| rcv.src_port != _m->rcv.src_port) {
+	} else if (!ip_addr_cmp(&rcv->src_ip, &_m->rcv.src_ip)
+			|| rcv->src_port != _m->rcv.src_port) {
 		LM_DBG("\"incoming\" request found. Using flow-token for"
 			"routing\n");
 
 		/* First, force the local socket */
-		si = find_si(&rcv.dst_ip, rcv.dst_port, rcv.proto);
+		si = find_si(&rcv->dst_ip, rcv->dst_port, rcv->proto);
 		if (si)
 			set_force_socket(_m, si);
 		else {
-			LM_ERR("cannot find socket from flow-token\n");
+			LM_INFO("cannot find socket from flow-token\n");
 			return -1;
 		}
 
 		/* Second, override the destination URI */
-		dst_uri->s = uri_buf;
-		dst_uri->len = 0;
+		dst_uri.s = uri_buf;
+		dst_uri.len = 0;
 
-		dst_uri->len += snprintf(dst_uri->s + dst_uri->len,
-					MAX_ROUTE_URI_LEN - dst_uri->len,
+		dst_uri.len += snprintf(dst_uri.s + dst_uri.len,
+					MAX_ROUTE_URI_LEN - dst_uri.len,
 					"sip:%s",
-					rcv.src_ip.af == AF_INET6 ? "[" : "");
-		dst_uri->len += ip_addr2sbuf(&rcv.src_ip,
-					dst_uri->s + dst_uri->len,
-					MAX_ROUTE_URI_LEN - dst_uri->len);
-		dst_uri->len += snprintf(dst_uri->s + dst_uri->len,
-					MAX_ROUTE_URI_LEN - dst_uri->len,
+					rcv->src_ip.af == AF_INET6 ? "[" : "");
+		dst_uri.len += ip_addr2sbuf(&rcv->src_ip,
+					dst_uri.s + dst_uri.len,
+					MAX_ROUTE_URI_LEN - dst_uri.len);
+		dst_uri.len += snprintf(dst_uri.s + dst_uri.len,
+					MAX_ROUTE_URI_LEN - dst_uri.len,
 					"%s:%d;transport=%s",
-					rcv.src_ip.af == AF_INET6 ? "]" : "",
-					rcv.src_port,
-					get_proto_name(rcv.proto));
+					rcv->src_ip.af == AF_INET6 ? "]" : "",
+					rcv->src_port,
+					get_proto_name(rcv->proto));
+
+		if (set_dst_uri(_m, &dst_uri) < 0) {
+			LM_ERR("failed to set dst_uri\n");
+			return -1;
+		}
+		ruri_mark_new();
+
+		return 1;
 	}
 
-	return 1;
+	LM_DBG("Not using flow-token for routing\n");
+	return 0;
 }
 
 /*!
@@ -620,7 +630,7 @@ static inline int after_strict(struct sip_msg* _m)
 			LM_ERR("failed to parse URI\n");
 			return RR_ERROR;
 		}
-	} 
+	}
 
 	/* set the hooks for the param
 	 * important note: RURI is already parsed by the above function, so 
@@ -746,10 +756,11 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
 	struct sip_uri puri;
 	rr_t* rt;
 	int res;
-	int status;
+	int status = RR_DRIVEN;
 	str uri;
 	struct socket_info *si;
-	int uri_is_myself, use_ob, next_is_strict;
+	int uri_is_myself, next_is_strict;
+	int use_ob = 0;
 
 	hdr = _m->route;
 	rt = (rr_t*)hdr->parsed;
@@ -766,10 +777,6 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
 	next_is_strict = is_strict(&puri.params);
 	routed_params = puri.params;
 	uri_is_myself = is_myself(&puri);
-	if ((use_ob = process_outbound(_m, puri.user, &uri)) < 0) {
-		LM_ERR("processing outbound flow-token\n");
-		return FLOW_TOKEN_BROKEN;
-	}
 
 	/* IF the URI was added by me, remove it */
 	if (uri_is_myself>0)
@@ -779,6 +786,11 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
 		/* set the hooks for the params */
 		routed_msg_id = _m->id;
 
+		if ((use_ob = process_outbound(_m, puri.user)) < 0) {
+			LM_INFO("failed to process outbound flow-token\n");
+			return FLOW_TOKEN_BROKEN;
+		}
+
 		if (!rt->next) {
 			/* No next route in the same header, remove the whole header
 			 * field immediately
@@ -788,10 +800,6 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
 				return RR_ERROR;
 			}
 
-			/* When using outbound skip past all this stuff and just set
- 			   the destination */
-			if (use_ob) goto got_uri;
-
 			res = find_next_route(_m, &hdr);
 			if (res < 0) {
 				LM_ERR("failed to find next route\n");
@@ -805,14 +813,15 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
 			rt = (rr_t*)hdr->parsed;
 		} else rt = rt->next;
 
-		if (!use_ob) {
-			if (enable_double_rr && is_2rr(&puri.params)) {
-				/* double route may occure due different IP and port, so force as
-				 * send interface the one advertise in second Route */
-				if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) {
-					LM_ERR("failed to parse the double route URI\n");
-					return RR_ERROR;
-				}
+		if (enable_double_rr && is_2rr(&puri.params)) {
+			/* double route may occure due different IP and port, so force as
+			 * send interface the one advertise in second Route */
+			if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) {
+				LM_ERR("failed to parse the double route URI\n");
+				return RR_ERROR;
+			}
+
+			if (!use_ob) {
 				si = grep_sock_info( &puri.host, puri.port_no, puri.proto);
 				if (si) {
 					set_force_socket(_m, si);
@@ -820,33 +829,33 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
 					if (enable_socket_mismatch_warning)
 						LM_WARN("no socket found for match second RR\n");
 				}
-	
-				if (!rt->next) {
-					/* No next route in the same header, remove the whole header
-					 * field immediately */
-					if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
-						LM_ERR("failed to remove Route HF\n");
-						return RR_ERROR;
-					}
-					res = find_next_route(_m, &hdr);
-					if (res < 0) {
-						LM_ERR("failed to find next route\n");
-						return RR_ERROR;
-						}
-					if (res > 0) { /* No next route found */
-						LM_DBG("no next URI found\n");
-						status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN);
-						goto done;
-					}
-					rt = (rr_t*)hdr->parsed;
-				} else rt = rt->next;
-			}
-			
-			uri = rt->nameaddr.uri;
-			if (parse_uri(uri.s, uri.len, &puri) < 0) {
-				LM_ERR("failed to parse the first route URI\n");
-				return RR_ERROR;
 			}
+
+			if (!rt->next) {
+				/* No next route in the same header, remove the whole header
+				 * field immediately */
+				if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
+					LM_ERR("failed to remove Route HF\n");
+					return RR_ERROR;
+				}
+				res = find_next_route(_m, &hdr);
+				if (res < 0) {
+					LM_ERR("failed to find next route\n");
+					return RR_ERROR;
+					}
+				if (res > 0) { /* No next route found */
+					LM_DBG("no next URI found\n");
+					status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN);
+					goto done;
+				}
+				rt = (rr_t*)hdr->parsed;
+			} else rt = rt->next;
+		}
+		
+		uri = rt->nameaddr.uri;
+		if (parse_uri(uri.s, uri.len, &puri) < 0) {
+			LM_ERR("failed to parse the first route URI\n");
+			return RR_ERROR;
 		}
 	} else {
 #ifdef ENABLE_USER_CHECK
@@ -869,21 +878,21 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
 	} else {
 		/* Next hop is loose router */
 		LM_DBG("Next URI is a loose router\n");
-got_uri:
 
 		if (!use_ob) {
 			if(get_maddr_uri(&uri, &puri)!=0) {
 				LM_ERR("checking maddr failed\n");
 				return RR_ERROR;
 			}
-		}
-		if (set_dst_uri(_m, &uri) < 0) {
-			LM_ERR("failed to set dst_uri\n");
-			return RR_ERROR;
-		}
-		/* dst_uri changed, so it makes sense to re-use the current uri for
+		
+			if (set_dst_uri(_m, &uri) < 0) {
+				LM_ERR("failed to set dst_uri\n");
+				return RR_ERROR;
+			}
+			/* dst_uri changed, so it makes sense to re-use the current uri for
 			forking */
-		ruri_mark_new(); /* re-use uri for serial forking */
+			ruri_mark_new(); /* re-use uri for serial forking */
+		}
 
 		/* There is a previous route uri which was 2nd uri of mine
 		 * and must be removed here */
@@ -895,9 +904,11 @@ got_uri:
 			}
 		}
 	}
-	status = RR_DRIVEN;
 
 done:
+	if (use_ob == 1)
+		status = RR_OB_DRIVEN;
+
 	/* run RR callbacks only if we have Route URI parameters */
 	if(routed_params.len > 0)
 		run_rr_callbacks( _m, &routed_params );
diff --git a/modules/rr/record.c b/modules/rr/record.c
index 41a3245..c160e98 100644
--- a/modules/rr/record.c
+++ b/modules/rr/record.c
@@ -200,7 +200,7 @@ static inline struct lump *insert_rr_param_lump(struct lump *before,
  * \return 0 on success, negative on failure
  */
 static inline int build_rr(struct lump* _l, struct lump* _l2, str* user,
-				str *tag, str *params, int _inbound, int _use_ob, int _sips)
+				str *tag, str *params, int _inbound, int _sips)
 {
 	char* prefix, *suffix, *term, *r2;
 	int suffix_len, prefix_len;
@@ -284,7 +284,7 @@ static inline int build_rr(struct lump* _l, struct lump* _l2, str* user,
 	_l = insert_subst_lump_after(_l, _inbound?SUBST_RCV_ALL:SUBST_SND_ALL, 0);
 	if (_l ==0 )
 		goto lump_err;
-	if (enable_double_rr && !_use_ob) {
+	if (enable_double_rr) {
 		if (!(_l = insert_cond_lump_after(_l, COND_IF_DIFF_REALMS, 0)))
 			goto lump_err;
 		if (!(_l = insert_new_lump_after(_l, r2, RR_R2_LEN, 0)))
@@ -421,7 +421,7 @@ int record_route(struct sip_msg* _m, str *params)
 
 	sips = rr_is_sips(_m);
 
-	if (enable_double_rr && !use_ob) {
+	if (enable_double_rr) {
 		l = anchor_lump(_m, _m->headers->name.s - _m->buf,0,HDR_RECORDROUTE_T);
 		l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
 		if (!l || !l2) {
@@ -434,7 +434,7 @@ int record_route(struct sip_msg* _m, str *params)
 			LM_ERR("failed to insert conditional lump\n");
 			return -6;
 		}
-		if (build_rr(l, l2, &user, tag, params, OUTBOUND, 0, sips) < 0) {
+		if (build_rr(l, l2, &user, tag, params, OUTBOUND, sips) < 0) {
 			LM_ERR("failed to insert outbound Record-Route\n");
 			return -7;
 		}
@@ -447,8 +447,7 @@ int record_route(struct sip_msg* _m, str *params)
 		return -3;
 	}
 	
-	if (build_rr(l, l2, &user, tag, params, use_ob ? OUTBOUND : INBOUND,
-			use_ob, sips) < 0) {
+	if (build_rr(l, l2, &user, tag, params, INBOUND, sips) < 0) {
 		LM_ERR("failed to insert inbound Record-Route\n");
 		return -4;
 	}
@@ -601,7 +600,7 @@ int record_route_preset(struct sip_msg* _m, str* _data)
 #define RR_TRANS_LEN 11
 #define RR_TRANS ";transport="
 static inline int build_advertised_rr(struct lump* _l, struct lump* _l2, str *_data,
-				str* user, str *tag, int _inbound, int _use_ob, int _sips)
+				str* user, str *tag, int _inbound, int _sips)
 {
 	char *p;
 	char *hdr, *trans, *r2, *suffix, *term;
@@ -693,7 +692,7 @@ static inline int build_advertised_rr(struct lump* _l, struct lump* _l2, str *_d
 		goto lump_err;
 	if (!(_l = insert_subst_lump_after(_l, _inbound?SUBST_RCV_PROTO:SUBST_SND_PROTO, 0)))
 		goto lump_err;
-	if (enable_double_rr && !_use_ob) {
+	if (enable_double_rr) {
 		if (!(_l = insert_cond_lump_after(_l, COND_IF_DIFF_REALMS, 0)))
 			goto lump_err;
 		if (!(_l = insert_new_lump_after(_l, r2, RR_R2_LEN, 0)))
@@ -760,7 +759,7 @@ int record_route_advertised_address(struct sip_msg* _m, str* _data)
 
 	sips = rr_is_sips(_m);
 
-	if (enable_double_rr && !use_ob) {
+	if (enable_double_rr) {
 		l = anchor_lump(_m, _m->headers->name.s - _m->buf,0,HDR_RECORDROUTE_T);
 		l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
 		if (!l || !l2) {
@@ -774,7 +773,7 @@ int record_route_advertised_address(struct sip_msg* _m, str* _data)
 			return -4;
 		}
 		if (build_advertised_rr(l, l2, _data, &user, tag, OUTBOUND,
-					0, sips) < 0) {
+					sips) < 0) {
 			LM_ERR("failed to insert outbound Record-Route\n");
 			return -5;
 		}
@@ -787,9 +786,7 @@ int record_route_advertised_address(struct sip_msg* _m, str* _data)
 		return -6;
 	}
 	
-	if (build_advertised_rr(l, l2, _data, &user, tag,
-				use_ob ? OUTBOUND: INBOUND,
-				use_ob, sips) < 0) {
+	if (build_advertised_rr(l, l2, _data, &user, tag, INBOUND, sips) < 0) {
 		LM_ERR("failed to insert outbound Record-Route\n");
 		return -7;
 	}
@@ -841,7 +838,7 @@ int add_rr_param(struct sip_msg* msg, str* rr_param)
 			goto error;
 		}
 		/* double routing enabled? */
-		if (enable_double_rr && !(rr_obb.use_outbound && rr_obb.use_outbound(msg))) {
+		if (enable_double_rr) {
 			if (root==0 || (last_param=get_rr_param_lump(&root))==0) {
 				LM_CRIT("failed to locate double RR lump\n");
 				goto error;
diff --git a/modules/rr/rr_mod.c b/modules/rr/rr_mod.c
index 5782c26..1628f3b 100644
--- a/modules/rr/rr_mod.c
+++ b/modules/rr/rr_mod.c
@@ -153,7 +153,7 @@ struct module_exports exports = {
 static int mod_init(void)
 {
 	if (ob_load_api(&rr_obb) == 0)
-		LM_INFO("Bound rr module to outbound module\n");
+		LM_DBG("Bound rr module to outbound module\n");
 	else
 	{
 		LM_INFO("outbound module not available\n");
diff --git a/modules/rtpproxy-ng/Makefile b/modules/rtpproxy-ng/Makefile
new file mode 100644
index 0000000..16aa3ca
--- /dev/null
+++ b/modules/rtpproxy-ng/Makefile
@@ -0,0 +1,19 @@
+# $Id$
+#
+# print example module makefile
+#
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=rtpproxy-ng.so
+LIBS=
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+include ../../Makefile.modules
+
diff --git a/modules/rtpproxy-ng/README b/modules/rtpproxy-ng/README
new file mode 100644
index 0000000..6e14ecf
--- /dev/null
+++ b/modules/rtpproxy-ng/README
@@ -0,0 +1,652 @@
+rtpproxy-ng Module
+
+Maxim Sobolev
+
+   Sippy Software, Inc.
+
+Juha Heinanen
+
+   TuTPro, Inc.
+
+Edited by
+
+Maxim Sobolev
+
+Edited by
+
+Bogdan-Andrei Iancu
+
+Edited by
+
+Juha Heinanen
+
+Edited by
+
+Sas Ovidiu
+
+Edited by
+
+Carsten Bock
+
+   ng-voice GmbH
+
+Edited by
+
+Richard Fuchs
+
+   Sipwise GmbH
+
+   Copyright © 2003-2008 Sippy Software, Inc.
+
+   Copyright © 2005 Voice Sistem SRL
+
+   Copyright © 2009-2012 TuTPro Inc.
+
+   Copyright © 2010 VoIPEmbedded Inc.
+
+   Copyright © 2013 Sipwise GmbH
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Multiple RTPProxy usage
+        3. Dependencies
+
+              3.1. Kamailio Modules
+              3.2. External Libraries or Applications
+
+        4. Parameters
+
+              4.1. rtpproxy_sock (string)
+              4.2. rtpproxy_disable_tout (integer)
+              4.3. rtpproxy_tout (integer)
+              4.4. rtpproxy_retr (integer)
+              4.5. extra_id_pv (string)
+
+        5. Functions
+
+              5.1. set_rtp_proxy_set(setid)
+              5.2. rtpproxy_offer([flags [, ip_address]])
+              5.3. rtpproxy_answer([flags [, ip_address]])
+              5.4. rtpproxy_destroy([flags])
+              5.5. unforce_rtp_proxy()
+              5.6. rtpproxy_manage([flags [, ip_address]])
+              5.7. start_recording()
+
+        6. Exported Pseudo Variables
+
+              6.1. $rtpstat
+
+        7. MI Commands
+
+              7.1. nh_enable_rtpp
+              7.2. nh_show_rtpp
+
+   2. Frequently Asked Questions
+
+   List of Examples
+
+   1.1. Set rtpproxy_sock parameter
+   1.2. Set rtpproxy_disable_tout parameter
+   1.3. Set rtpproxy_tout parameter
+   1.4. Set rtpproxy_retr parameter
+   1.5. Set extra_id_pv parameter
+   1.6. set_rtp_proxy_set usage
+   1.7. rtpproxy_offer usage
+   1.8. rtpproxy_answer usage
+   1.9. rtpproxy_destroy usage
+   1.10. rtpproxy_manage usage
+   1.11. start_recording usage
+   1.12. $rtpstat Usage
+   1.13. nh_enable_rtpp usage
+   1.14. nh_show_rtpp usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Multiple RTPProxy usage
+   3. Dependencies
+
+        3.1. Kamailio Modules
+        3.2. External Libraries or Applications
+
+   4. Parameters
+
+        4.1. rtpproxy_sock (string)
+        4.2. rtpproxy_disable_tout (integer)
+        4.3. rtpproxy_tout (integer)
+        4.4. rtpproxy_retr (integer)
+        4.5. extra_id_pv (string)
+
+   5. Functions
+
+        5.1. set_rtp_proxy_set(setid)
+        5.2. rtpproxy_offer([flags [, ip_address]])
+        5.3. rtpproxy_answer([flags [, ip_address]])
+        5.4. rtpproxy_destroy([flags])
+        5.5. unforce_rtp_proxy()
+        5.6. rtpproxy_manage([flags [, ip_address]])
+        5.7. start_recording()
+
+   6. Exported Pseudo Variables
+
+        6.1. $rtpstat
+
+   7. MI Commands
+
+        7.1. nh_enable_rtpp
+        7.2. nh_show_rtpp
+
+1. Overview
+
+   This is a module that enables media streams to be proxied via an RTP
+   proxy. The only RTP proxy currently known to work with this module is
+   the Sipwise ngcp-rtpproxy-ng https://github.com/sipwise/mediaproxy-ng.
+   The rtpproxy-ng module is a modified version of the original rtpproxy
+   module using a new control protocol. The module is designed to be a
+   drop-in replacement for the old module from a configuration file point
+   of view, however due to the incompatible control protocol, it only
+   works with RTP proxies which specifically support it.
+
+2. Multiple RTPProxy usage
+
+   The rtpproxy-ng module can support multiple RTP proxies for
+   balancing/distribution and control/selection purposes.
+
+   The module allows definition of several sets of rtpproxies.
+   Load-balancing will be performed over a set and the admin has the
+   ability to choose what set should be used. The set is selected via its
+   id - the id being defined with the set. Refer to the “rtpproxy_sock”
+   module parameter definition for syntax description.
+
+   The balancing inside a set is done automatically by the module based on
+   the weight of each rtpproxy from the set.
+
+   The selection of the set is done from script prior using
+   unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() functions -
+   see the set_rtp_proxy_set() function.
+
+   For backward compatibility reasons, a set with no id take by default
+   the id 0. Also if no set is explicitly set before unforce_rtp_proxy(),
+   rtpproxy_offer() or rtpproxy_answer() the 0 id set will be used.
+
+   IMPORTANT: if you use multiple sets, take care and use the same set for
+   both rtpproxy_offer()/rtpproxy_answer() and unforce_rtpproxy()!!
+
+3. Dependencies
+
+   3.1. Kamailio Modules
+   3.2. External Libraries or Applications
+
+3.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * tm module - (optional) if you want to have rtpproxy_manage() fully
+       functional
+
+3.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None.
+
+4. Parameters
+
+   4.1. rtpproxy_sock (string)
+   4.2. rtpproxy_disable_tout (integer)
+   4.3. rtpproxy_tout (integer)
+   4.4. rtpproxy_retr (integer)
+   4.5. extra_id_pv (string)
+
+4.1. rtpproxy_sock (string)
+
+   Definition of socket(s) used to connect to (a set) RTPProxy. It may
+   specify a UNIX socket or an IPv4/IPv6 UDP socket.
+
+   Default value is “NONE” (disabled).
+
+   Example 1.1. Set rtpproxy_sock parameter
+...
+# single rtproxy
+modparam("rtpproxy-ng", "rtpproxy_sock", "udp:localhost:12221")
+# multiple rtproxies for LB
+modparam("rtpproxy-ng", "rtpproxy_sock",
+        "udp:localhost:12221 udp:localhost:12222")
+# multiple sets of multiple rtproxies
+modparam("rtpproxy-ng", "rtpproxy_sock",
+        "1 == udp:localhost:12221 udp:localhost:12222")
+modparam("rtpproxy-ng", "rtpproxy_sock",
+        "2 == udp:localhost:12225")
+...
+
+4.2. rtpproxy_disable_tout (integer)
+
+   Once an RTP proxy was found unreachable and marked as disabled, the
+   rtpproxy-ng module will not attempt to establish communication to that
+   RTP proxy for rtpproxy_disable_tout seconds.
+
+   Default value is “60”.
+
+   Example 1.2. Set rtpproxy_disable_tout parameter
+...
+modparam("rtpproxy-ng", "rtpproxy_disable_tout", 20)
+...
+
+4.3. rtpproxy_tout (integer)
+
+   Timeout value in waiting for reply from RTP proxy.
+
+   Default value is “1”.
+
+   Example 1.3. Set rtpproxy_tout parameter
+...
+modparam("rtpproxy-ng", "rtpproxy_tout", 2)
+...
+
+4.4. rtpproxy_retr (integer)
+
+   How many times the module should retry to send and receive after
+   timeout was generated.
+
+   Default value is “5”.
+
+   Example 1.4. Set rtpproxy_retr parameter
+...
+modparam("rtpproxy-ng", "rtpproxy_retr", 2)
+...
+
+4.5. extra_id_pv (string)
+
+   The parameter sets the PV defination to use when the “b” parameter is
+   used on unforce_rtp_proxy(), rtpproxy_offer(), rtpproxy_answer() or
+   rtpproxy_manage() command.
+
+   Default is empty, the “b” parameter may not be used then.
+
+   Example 1.5. Set extra_id_pv parameter
+...
+modparam("rtpproxy-ng", "extra_id_pv", "$avp(extra_id)")
+...
+
+5. Functions
+
+   5.1. set_rtp_proxy_set(setid)
+   5.2. rtpproxy_offer([flags [, ip_address]])
+   5.3. rtpproxy_answer([flags [, ip_address]])
+   5.4. rtpproxy_destroy([flags])
+   5.5. unforce_rtp_proxy()
+   5.6. rtpproxy_manage([flags [, ip_address]])
+   5.7. start_recording()
+
+5.1.  set_rtp_proxy_set(setid)
+
+   Sets the Id of the rtpproxy set to be used for the next
+   unforce_rtp_proxy(), rtpproxy_offer(), rtpproxy_answer() or
+   rtpproxy_manage() command. The parameter can be an integer or a config
+   variable holding an integer.
+
+   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   BRANCH_ROUTE.
+
+   Example 1.6. set_rtp_proxy_set usage
+...
+set_rtp_proxy_set("2");
+rtpproxy_offer();
+...
+
+5.2.  rtpproxy_offer([flags [, ip_address]])
+
+   Rewrites SDP body to ensure that media is passed through an RTP proxy.
+   To be invoked on INVITE for the cases the SDPs are in INVITE and 200 OK
+   and on 200 OK when SDPs are in 200 OK and ACK.
+
+   Meaning of the parameters is as follows:
+     * flags - flags to turn on some features.
+          + 1 - append first Via branch to Call-ID when sending command to
+            rtpproxy. This can be used to create one media session per
+            branch on the rtpproxy. When sending a subsequent “delete”
+            command to the rtpproxy, you can then stop just the session
+            for a specific branch when passing the flag '1' or '2' in the
+            “unforce_rtpproxy”, or stop all sessions for a call when not
+            passing one of those two flags there. This is especially
+            useful if you have serially forked call scenarios where
+            rtpproxy gets an “offer” command for a new branch, and then a
+            “delete” command for the previous branch, which would
+            otherwise delete the full call, breaking the subsequent
+            “answer” for the new branch. This flag is only supported by
+            the ngcp-mediaproxy-ng rtpproxy at the moment!
+          + 2 - append second Via branch to Call-ID when sending command
+            to rtpproxy. See flag '1' for its meaning.
+          + 3 - behave like flag 1 is set for a request and like flag 2 is
+            set for a reply.
+          + a - flags that UA from which message is received doesn't
+            support symmetric RTP. (automatically sets the 'r' flag)
+          + b - append branch specific variable to Call-ID when sending
+            command to rtpproxy. This creates one rtpproxy session per
+            unique variable. Works similar to the 1, 2 and 3 parameter,
+            but is usefull when forking to multiple destinations on
+            different address families or network segments, requiring
+            different rtpproxy parameters. The variable value is taken
+            from the “extra_id_pv”. When used, it must be used in every
+            call to rtpproxy_manage(), rtpproxy_offer(), rtpproxy_answer()
+            and rtpproxy_destroy() with the same contents of the PV. The b
+            parameter may not be used in conjunction with the 1, 2 or 3
+            parameter to use the Via branch in the Call-ID.
+          + l - force “lookup”, that is, only rewrite SDP when
+            corresponding session already exists in the RTP proxy. By
+            default is on when the session is to be completed.
+          + i, e - these flags specify the direction of the SIP message.
+            These flags only make sense when rtpproxy is running in bridge
+            mode. 'i' means internal network (LAN), 'e' means external
+            network (WAN). 'i' corresponds to rtpproxy's first interface,
+            'e' corresponds to rtpproxy's second interface. You always
+            have to specify two flags to define the incoming network and
+            the outgoing network. For example, 'ie' should be used for SIP
+            message received from the local interface and sent out on the
+            external interface, and 'ei' vice versa. Other options are
+            'ii' and 'ee'. So, for example if a SIP requests is processed
+            with 'ie' flags, the corresponding response must be processed
+            with 'ie' flags.
+            For ngcp-mediaproxy-ng, these flags are used to select between
+            IPv4 and IPv6 addresses, corresponding to 'i' and 'e'
+            respectively. For example, if the request is coming from an
+            IPv4 host and is going to an IPv6 host, the flags should be
+            specified as 'ie'.
+            Note: As rtpproxy in bridge mode s per default asymmetric, you
+            have to specify the 'w' flag for clients behind NAT! See also
+            above notes!
+          + x - this flag an alternative to the 'ie' or 'ei'-flags in
+            order to do automatic bridging between IPv4 on the "internal
+            network" and IPv6 on the "external network". Instead of
+            explicitly instructing the RTP proxy to select a particular
+            address family, the distinction is done by the given IP in the
+            SDP body by the RTP proxy itself. Not supported by
+            ngcp-mediaproxy-ng.
+            Note: Please note, that this will only work properly with
+            non-dual-stack user-agents or with dual-stack clients
+            according to RFC6157 (which suggest ICE for Dual-Stack
+            implementations). This short-cut will not work properly with
+            RFC4091 (ANAT) compatible clients, which suggests having
+            different m-lines with different IP-protocols grouped
+            together.
+          + f - instructs rtpproxy to ignore marks inserted by another
+            rtpproxy in transit to indicate that the session is already
+            goes through another proxy. Allows creating a chain of
+            proxies.
+          + r - flags that IP address in SDP should be trusted. Without
+            this flag, rtpproxy ignores address in the SDP and uses source
+            address of the SIP message as media address which is passed to
+            the RTP proxy.
+          + o - flags that IP from the origin description (o=) should be
+            also changed.
+          + c - flags to change the session-level SDP connection (c=) IP
+            if media-description also includes connection information.
+          + w - flags that for the UA from which message is received,
+            support symmetric RTP must be forced.
+          + zNN - requests the RTPproxy to perform re-packetization of RTP
+            traffic coming from the UA which has sent the current message
+            to increase or decrease payload size per each RTP packet
+            forwarded if possible. The NN is the target payload size in
+            ms, for the most codecs its value should be in 10ms
+            increments, however for some codecs the increment could differ
+            (e.g. 30ms for GSM or 20ms for G.723). The RTPproxy would
+            select the closest value supported by the codec. This feature
+            could be used for significantly reducing bandwith overhead for
+            low bitrate codecs, for example with G.729 going from 10ms to
+            100ms saves two thirds of the network bandwith.
+          + + - instructs the RTP proxy to discard any ICE attributes
+            already present in the SDP body and then generate and insert
+            new ICE data, leaving itself as the only ICE candidates.
+            Without this flag, new ICE data will only be generated if no
+            ICE was present in the SDP originally; otherwise the RTP proxy
+            will only insert itself as an additional ICE candidate. Other
+            SDP substitutions (c=, m=, etc) are unaffected by this flag.
+          + - - instructs the RTP proxy to discard any ICE attributes and
+            not insert any new ones into the SDP. Mutually exclusive with
+            the '+' flag.
+          + s, S, p, P - These flags control the RTP transport protocol
+            that should be used towards the recipient of the SDP. If none
+            of them are specified, the protocol given in the SDP is left
+            untouched. Otherwise, the "S" flag indicates that SRTP should
+            be used, while "s" indicates that SRTP should not be used. "P"
+            indicates that the advanced RTCP profile with feedback
+            messages should be used, and "p" indicates that the regular
+            RTCP profile should be used. As such, the combinations "sp",
+            "sP", "Sp" and "SP" select between RTP/AVP, RTP/AVPF, RTP/SAVP
+            and RTP/SAVPF, respectively.
+     * ip_address - new SDP IP address.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.7. rtpproxy_offer usage
+route {
+...
+    if (is_method("INVITE")) {
+        if (has_body("application/sdp")) {
+            if (rtpproxy_offer())
+                t_on_reply("1");
+        } else {
+            t_on_reply("2");
+        }
+    }
+    if (is_method("ACK") && has_body("application/sdp"))
+        rtpproxy_answer();
+...
+}
+
+onreply_route[1]
+{
+...
+    if (has_body("application/sdp"))
+        rtpproxy_answer();
+...
+}
+
+onreply_route[2]
+{
+...
+    if (has_body("application/sdp"))
+        rtpproxy_offer();
+...
+}
+
+5.3.  rtpproxy_answer([flags [, ip_address]])
+
+   Rewrites SDP body to ensure that media is passed through an RTP proxy.
+   To be invoked on 200 OK for the cases the SDPs are in INVITE and 200 OK
+   and on ACK when SDPs are in 200 OK and ACK.
+
+   See rtpproxy_answer() function description above for the meaning of the
+   parameters.
+
+   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   FAILURE_ROUTE, BRANCH_ROUTE.
+
+   Example 1.8. rtpproxy_answer usage
+
+   See rtpproxy_offer() function example above for example.
+
+5.4.  rtpproxy_destroy([flags])
+
+   Tears down the RTPProxy session for the current call.
+
+   This function can be used from ANY_ROUTE.
+
+   Meaning of the parameters is as follows:
+     * flags - flags to turn on some features.
+          + 1 - append first Via branch to Call-ID when sending command to
+            rtpproxy. This can be used to create one media session per
+            branch on the rtpproxy. When sending a subsequent “delete”
+            command to the rtpproxy, you can then stop just the session
+            for a specific branch when passing the flag '1' or '2' in the
+            “unforce_rtpproxy”, or stop all sessions for a call when not
+            passing one of those two flags there. This is especially
+            useful if you have serially forked call scenarios where
+            rtpproxy gets an “update” command for a new branch, and then a
+            “delete” command for the previous branch, which would
+            otherwise delete the full call, breaking the subsequent
+            “lookup” for the new branch. This flag is only supported by
+            the ngcp-mediaproxy-ng rtpproxy at the moment!
+          + 2 - append second Via branch to Call-ID when sending command
+            to rtpproxy. See flag '1' for its meaning.
+          + b - append branch specific variable to Call-ID when sending
+            command to rtpproxy. See rtpproxy_offer() for details.
+            <listitem>
+            </listitem>
+            t - do not include To tag to “delete” command to rtpproxy thus
+            causing full call to be deleted. Useful for deleting unused
+            rtpproxy call when 200 OK is received on a branch, where
+            rtpproxy is not needed.
+
+   Example 1.9. rtpproxy_destroy usage
+...
+rtpproxy_destroy();
+...
+
+5.5.  unforce_rtp_proxy()
+
+   Same as rtpproxy_destroy().
+
+5.6.  rtpproxy_manage([flags [, ip_address]])
+
+   Manage the RTPProxy session - it combines the functionality of
+   rtpproxy_offer(), rtpproxy_answer() and unforce_rtpproxy(), detecting
+   internally based on message type and method which one to execute.
+
+   It can take the same parameters as rtpproxy_offer(). The flags
+   parameter to rtpproxy_manage() can be a configuration variable
+   containing the flags as a string.
+
+   Functionality:
+     * If INVITE with SDP, then do rtpproxy_offer()
+     * If INVITE with SDP, when the tm module is loaded, mark transaction
+       with internal flag FL_SDP_BODY to know that the 1xx and 2xx are for
+       rtpproxy_answer()
+     * If ACK with SDP, then do rtpproxy_answer()
+     * If BYE or CANCEL, or called within a FAILURE_ROUTE[], then do
+       unforce_rtpproxy()
+     * If reply to INVITE with code >= 300 do unforce_rtpproxy()
+     * If reply with SDP to INVITE having code 1xx and 2xx, then do
+       rtpproxy_answer() if the request had SDP or tm is not loaded,
+       otherwise do rtpproxy_offer()
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.10. rtpproxy_manage usage
+...
+rtpproxy_manage();
+...
+
+5.7.  start_recording()
+
+   This function will send a signal to the RTP Proxy to record the RTP
+   stream on the RTP Proxy. This function is not supported by
+   ngcp-mediaproxy-ng at the moment!
+
+   This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
+
+   Example 1.11. start_recording usage
+...
+start_recording();
+...
+
+6. Exported Pseudo Variables
+
+   6.1. $rtpstat
+
+6.1. $rtpstat
+
+   Returns the RTP Statistics from the RTP Proxy. The RTP Statistics from
+   the RTP Proxy are provided as a string and it does contain several
+   packet counters. The statistics must be retrieved before the session is
+   deleted (before unforce_rtpproxy()).
+
+   Example 1.12. $rtpstat Usage
+...
+    append_hf("X-RTP-Statistics: $rtpstat\r\n");
+...
+
+7. MI Commands
+
+   7.1. nh_enable_rtpp
+   7.2. nh_show_rtpp
+
+7.1. nh_enable_rtpp
+
+   Enables a rtp proxy if parameter value is greater than 0. Disables it
+   if a zero value is given.
+
+   The first parameter is the rtp proxy url (exactly as defined in the
+   config file).
+
+   The second parameter value must be a number in decimal.
+
+   NOTE: if a rtpproxy is defined multiple times (in the same or diferente
+   sete), all of its instances will be enables/disabled.
+
+   Example 1.13.  nh_enable_rtpp usage
+...
+$ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
+...
+
+7.2. nh_show_rtpp
+
+   Displays all the rtp proxies and their information: set and status
+   (disabled or not, weight and recheck_ticks).
+
+   No parameter.
+
+   Example 1.14.  nh_show_rtpp usage
+...
+$ kamctl fifo nh_show_rtpp
+...
+
+Chapter 2. Frequently Asked Questions
+
+   2.1. What happend with “rtpproxy_disable” parameter?
+   2.2. Where can I find more about Kamailio?
+   2.3. Where can I post a question about this module?
+   2.4. How can I report a bug?
+
+   2.1.
+
+       What happend with “rtpproxy_disable” parameter?
+
+       It was removed as it became obsolete - now “rtpproxy_sock” can take
+       empty value to disable the rtpproxy functionality.
+
+   2.2.
+
+       Where can I find more about Kamailio?
+
+       Take a look at http://www.kamailio.org/.
+
+   2.3.
+
+       Where can I post a question about this module?
+
+       First at all check if your question was already answered on one of our
+       mailing lists:
+         * User Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+         * Developer Mailing List -
+           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+
+       E-mails regarding any stable Kamailio release should be sent to
+       <sr-users at lists.sip-router.org> and e-mails regarding development
+       versions should be sent to <sr-dev at lists.sip-router.org>.
+
+       If you want to keep the mail private, send it to
+       <sr-users at lists.sip-router.org>.
+
+   2.4.
+
+       How can I report a bug?
+
+       Please follow the guidelines provided at:
+       http://sip-router.org/tracker.
diff --git a/modules/rtpproxy-ng/bencode.c b/modules/rtpproxy-ng/bencode.c
new file mode 100644
index 0000000..7a4b2ed
--- /dev/null
+++ b/modules/rtpproxy-ng/bencode.c
@@ -0,0 +1,703 @@
+#include "bencode.h"
+#include <stdio.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+
+/* set to 0 for alloc debugging, e.g. through valgrind */
+#define BENCODE_MIN_BUFFER_PIECE_LEN	512
+
+#define BENCODE_HASH_BUCKETS		31 /* prime numbers work best */
+
+struct __bencode_buffer_piece {
+	char *tail;
+	unsigned int left;
+	struct __bencode_buffer_piece *next;
+	char buf[0];
+};
+struct __bencode_free_list {
+	void *ptr;
+	free_func_t func;
+	struct __bencode_free_list *next;
+};
+struct __bencode_hash {
+	struct bencode_item *buckets[BENCODE_HASH_BUCKETS];
+};
+
+
+
+
+
+static bencode_item_t __bencode_end_marker = {
+	.type = BENCODE_END_MARKER,
+	.iov[0].iov_base = "e",
+	.iov[0].iov_len = 1,
+	.iov_cnt = 1,
+	.str_len = 1,
+};
+
+
+
+
+static bencode_item_t *__bencode_decode(bencode_buffer_t *buf, const char *s, const char *end);
+
+
+
+static void __bencode_item_init(bencode_item_t *item) {
+	item->last_child = item->parent = item->child = item->sibling = NULL;
+}
+
+static void __bencode_container_init(bencode_item_t *cont) {
+	cont->iov[0].iov_len = 1;
+	cont->iov[1].iov_base = "e";
+	cont->iov[1].iov_len = 1;
+	cont->iov_cnt = 2;
+	cont->str_len = 2;
+}
+
+static void __bencode_dictionary_init(bencode_item_t *dict) {
+	dict->type = BENCODE_DICTIONARY;
+	dict->iov[0].iov_base = "d";
+	dict->value = 0;
+	__bencode_container_init(dict);
+}
+
+static void __bencode_list_init(bencode_item_t *list) {
+	list->type = BENCODE_LIST;
+	list->iov[0].iov_base = "l";
+	__bencode_container_init(list);
+}
+
+static struct __bencode_buffer_piece *__bencode_piece_new(unsigned int size) {
+	struct __bencode_buffer_piece *ret;
+
+	if (size < BENCODE_MIN_BUFFER_PIECE_LEN)
+		size = BENCODE_MIN_BUFFER_PIECE_LEN;
+	ret = BENCODE_MALLOC(sizeof(*ret) + size);
+	if (!ret)
+		return NULL;
+
+	ret->tail = ret->buf;
+	ret->left = size;
+	ret->next = NULL;
+
+	return ret;
+}
+
+int bencode_buffer_init(bencode_buffer_t *buf) {
+	buf->pieces = __bencode_piece_new(0);
+	if (!buf->pieces)
+		return -1;
+	buf->free_list = NULL;
+	buf->error = 0;
+	return 0;
+}
+
+static void *__bencode_alloc(bencode_buffer_t *buf, unsigned int size) {
+	struct __bencode_buffer_piece *piece;
+	void *ret;
+
+	if (!buf)
+		return NULL;
+	if (buf->error)
+		return NULL;
+
+	piece = buf->pieces;
+
+	if (size <= piece->left)
+		goto alloc;
+
+	piece = __bencode_piece_new(size);
+	if (!piece) {
+		buf->error = 1;
+		return NULL;
+	}
+	piece->next = buf->pieces;
+	buf->pieces = piece;
+
+	assert(size <= piece->left);
+
+alloc:
+	piece->left -= size;
+	ret = piece->tail;
+	piece->tail += size;
+	return ret;
+}
+
+void bencode_buffer_free(bencode_buffer_t *buf) {
+	struct __bencode_free_list *fl;
+	struct __bencode_buffer_piece *piece, *next;
+
+	for (fl = buf->free_list; fl; fl = fl->next)
+		fl->func(fl->ptr);
+
+	for (piece = buf->pieces; piece; piece = next) {
+		next = piece->next;
+		BENCODE_FREE(piece);
+	}
+}
+
+static bencode_item_t *__bencode_item_alloc(bencode_buffer_t *buf, unsigned int payload) {
+	bencode_item_t *ret;
+
+	ret = __bencode_alloc(buf, sizeof(struct bencode_item) + payload);
+	if (!ret)
+		return NULL;
+	ret->buffer = buf;
+	__bencode_item_init(ret);
+	return ret;
+}
+
+bencode_item_t *bencode_dictionary(bencode_buffer_t *buf) {
+	bencode_item_t *ret;
+
+	ret = __bencode_item_alloc(buf, 0);
+	if (!ret)
+		return NULL;
+	__bencode_dictionary_init(ret);
+	return ret;
+}
+
+bencode_item_t *bencode_list(bencode_buffer_t *buf) {
+	bencode_item_t *ret;
+
+	ret = __bencode_item_alloc(buf, 0);
+	if (!ret)
+		return NULL;
+	__bencode_list_init(ret);
+	return ret;
+}
+
+static void __bencode_container_add(bencode_item_t *parent, bencode_item_t *child) {
+	if (!parent)
+		return;
+	if (!child)
+		return;
+
+	assert(child->parent == NULL);
+	assert(child->sibling == NULL);
+
+	child->parent = parent;
+	if (parent->last_child)
+		parent->last_child->sibling = child;
+	parent->last_child = child;
+	if (!parent->child)
+		parent->child = child;
+
+	while (parent) {
+		parent->iov_cnt += child->iov_cnt;
+		parent->str_len += child->str_len;
+		parent = parent->parent;
+	}
+}
+
+static bencode_item_t *__bencode_string_alloc(bencode_buffer_t *buf, const void *base,
+		int str_len, int iov_len, int iov_cnt, bencode_type_t type)
+{
+	bencode_item_t *ret;
+	int len_len;
+
+	assert((str_len <= 99999) && (str_len >= 0));
+	ret = __bencode_item_alloc(buf, 7);
+	if (!ret)
+		return NULL;
+	len_len = sprintf(ret->__buf, "%d:", str_len);
+
+	ret->type = type;
+	ret->iov[0].iov_base = ret->__buf;
+	ret->iov[0].iov_len = len_len;
+	ret->iov[1].iov_base = (void *) base;
+	ret->iov[1].iov_len = iov_len;
+	ret->iov_cnt = iov_cnt + 1;
+	ret->str_len = len_len + str_len;
+
+	return ret;
+}
+
+bencode_item_t *bencode_string_len_dup(bencode_buffer_t *buf, const char *s, int len) {
+	char *sd = __bencode_alloc(buf, len);
+	if (!sd)
+		return NULL;
+	memcpy(sd, s, len);
+	return bencode_string_len(buf, sd, len);
+}
+
+bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len) {
+	return __bencode_string_alloc(buf, s, len, len, 1, BENCODE_STRING);
+}
+
+bencode_item_t *bencode_string_iovec(bencode_buffer_t *buf, const struct iovec *iov, int iov_cnt, int str_len) {
+	int i;
+
+	if (iov_cnt < 0)
+		return NULL;
+	if (str_len < 0) {
+		str_len = 0;
+		for (i = 0; i < iov_cnt; i++)
+			str_len += iov[i].iov_len;
+	}
+
+	return __bencode_string_alloc(buf, iov, str_len, iov_cnt, iov_cnt, BENCODE_IOVEC);
+}
+
+bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i) {
+	bencode_item_t *ret;
+	int alen, rlen;
+
+	alen = 8;
+	while (1) {
+		ret = __bencode_item_alloc(buf, alen + 3);
+		if (!ret)
+			return NULL;
+		rlen = snprintf(ret->__buf, alen, "i%llde", i);
+		if (rlen < alen)
+			break;
+		alen <<= 1;
+	}
+
+	ret->type = BENCODE_INTEGER;
+	ret->iov[0].iov_base = ret->__buf;
+	ret->iov[0].iov_len = rlen;
+	ret->iov[1].iov_base = NULL;
+	ret->iov[1].iov_len = 0;
+	ret->iov_cnt = 1;
+	ret->str_len = rlen;
+
+	return ret;
+}
+
+bencode_item_t *bencode_dictionary_add_len(bencode_item_t *dict, const char *key, int keylen, bencode_item_t *val) {
+	bencode_item_t *str;
+
+	if (!dict || !val)
+		return NULL;
+	assert(dict->type == BENCODE_DICTIONARY);
+
+	str = bencode_string_len(dict->buffer, key, keylen);
+	if (!str)
+		return NULL;
+	__bencode_container_add(dict, str);
+	__bencode_container_add(dict, val);
+	return val;
+}
+
+bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item) {
+	if (!list || !item)
+		return NULL;
+	assert(list->type == BENCODE_LIST);
+	__bencode_container_add(list, item);
+	return item;
+}
+
+static int __bencode_iovec_cpy(struct iovec *out, const struct iovec *in, int num) {
+	memcpy(out, in, num * sizeof(*out));
+	return num;
+}
+
+static int __bencode_str_cpy(char *out, const struct iovec *in, int num) {
+	char *orig = out;
+
+	while (--num >= 0) {
+		memcpy(out, in->iov_base, in->iov_len);
+		out += in->iov_len;
+		in++;
+	}
+	return out - orig;
+}
+
+static int __bencode_iovec_dump(struct iovec *out, bencode_item_t *item) {
+	bencode_item_t *child;
+	struct iovec *orig = out;
+
+	assert(item->iov[0].iov_base != NULL);
+	out += __bencode_iovec_cpy(out, &item->iov[0], 1);
+
+	child = item->child;
+	while (child) {
+		out += __bencode_iovec_dump(out, child);
+		child = child->sibling;
+	}
+
+	if (item->type == BENCODE_IOVEC)
+		out += __bencode_iovec_cpy(out, item->iov[1].iov_base, item->iov[1].iov_len);
+	else if (item->iov[1].iov_base)
+		out += __bencode_iovec_cpy(out, &item->iov[1], 1);
+
+	assert((out - orig) == item->iov_cnt);
+	return item->iov_cnt;
+}
+
+static int __bencode_str_dump(char *out, bencode_item_t *item) {
+	char *orig = out;
+	bencode_item_t *child;
+
+	assert(item->iov[0].iov_base != NULL);
+	out += __bencode_str_cpy(out, &item->iov[0], 1);
+
+	child = item->child;
+	while (child) {
+		out += __bencode_str_dump(out, child);
+		child = child->sibling;
+	}
+
+	if (item->type == BENCODE_IOVEC)
+		out += __bencode_str_cpy(out, item->iov[1].iov_base, item->iov[1].iov_len);
+	else if (item->iov[1].iov_base)
+		out += __bencode_str_cpy(out, &item->iov[1], 1);
+
+	assert((out - orig) == item->str_len);
+	*out = '\0';
+	return item->str_len;
+}
+
+struct iovec *bencode_iovec(bencode_item_t *root, int *cnt, unsigned int head, unsigned int tail) {
+	struct iovec *ret;
+
+	if (!root)
+		return NULL;
+	assert(cnt != NULL);
+	assert(root->iov_cnt > 0);
+
+	ret = __bencode_alloc(root->buffer, sizeof(*ret) * (root->iov_cnt + head + tail));
+	if (!ret)
+		return NULL;
+	*cnt = __bencode_iovec_dump(ret + head, root);
+	return ret;
+}
+
+char *bencode_collapse(bencode_item_t *root, int *len) {
+	char *ret;
+	int l;
+
+	if (!root)
+		return NULL;
+	assert(root->str_len > 0);
+
+	ret = __bencode_alloc(root->buffer, root->str_len + 1);
+	if (!ret)
+		return NULL;
+	l = __bencode_str_dump(ret, root);
+	if (len)
+		*len = l;
+	return ret;
+}
+
+char *bencode_collapse_dup(bencode_item_t *root, int *len) {
+	char *ret;
+	int l;
+
+	if (!root)
+		return NULL;
+	assert(root->str_len > 0);
+
+	ret = BENCODE_MALLOC(root->str_len + 1);
+	if (!ret)
+		return NULL;
+
+	l = __bencode_str_dump(ret, root);
+	if (len)
+		*len = l;
+	return ret;
+}
+
+static unsigned int __bencode_hash_str_len(const unsigned char *s, int len) {
+	unsigned long *ul;
+	unsigned int *ui;
+	unsigned short *us;
+
+	if (len >= sizeof(*ul)) {
+		ul = (void *) s;
+		return *ul % BENCODE_HASH_BUCKETS;
+	}
+	if (len >= sizeof(*ui)) {
+		ui = (void *) s;
+		return *ui % BENCODE_HASH_BUCKETS;
+	}
+	if (len >= sizeof(*us)) {
+		us = (void *) s;
+		return *us % BENCODE_HASH_BUCKETS;
+	}
+	if (len >= sizeof(*s))
+		return *s % BENCODE_HASH_BUCKETS;
+
+	return 0;
+}
+
+static unsigned int __bencode_hash_str(bencode_item_t *str) {
+	assert(str->type == BENCODE_STRING);
+	return __bencode_hash_str_len(str->iov[1].iov_base, str->iov[1].iov_len);
+}
+
+static void __bencode_hash_insert(bencode_item_t *key, struct __bencode_hash *hash) {
+	unsigned int bucket, i;
+
+	i = bucket = __bencode_hash_str(key);
+
+	while (1) {
+		if (!hash->buckets[i]) {
+			hash->buckets[i] = key;
+			break;
+		}
+		i++;
+		if (i >= BENCODE_HASH_BUCKETS)
+			i = 0;
+		if (i == bucket)
+			break;
+	}
+}
+
+static bencode_item_t *__bencode_decode_dictionary(bencode_buffer_t *buf, const char *s, const char *end) {
+	bencode_item_t *ret, *key, *value;
+	struct __bencode_hash *hash;
+
+	if (*s != 'd')
+		return NULL;
+	s++;
+
+	ret = __bencode_item_alloc(buf, sizeof(*hash));
+	if (!ret)
+		return NULL;
+	__bencode_dictionary_init(ret);
+	ret->value = 1;
+	hash = (void *) ret->__buf;
+	memset(hash, 0, sizeof(*hash));
+
+	while (s < end) {
+		key = __bencode_decode(buf, s, end);
+		if (!key)
+			return NULL;
+		s += key->str_len;
+		if (key->type == BENCODE_END_MARKER)
+			break;
+		if (key->type != BENCODE_STRING)
+			return NULL;
+		__bencode_container_add(ret, key);
+
+		if (s >= end)
+			return NULL;
+		value = __bencode_decode(buf, s, end);
+		if (!value)
+			return NULL;
+		s += value->str_len;
+		if (value->type == BENCODE_END_MARKER)
+			return NULL;
+		__bencode_container_add(ret, value);
+
+		__bencode_hash_insert(key, hash);
+	}
+
+	return ret;
+}
+
+static bencode_item_t *__bencode_decode_list(bencode_buffer_t *buf, const char *s, const char *end) {
+	bencode_item_t *ret, *item;
+
+	if (*s != 'l')
+		return NULL;
+	s++;
+
+	ret = __bencode_item_alloc(buf, 0);
+	if (!ret)
+		return NULL;
+	__bencode_list_init(ret);
+
+	while (s < end) {
+		item = __bencode_decode(buf, s, end);
+		if (!item)
+			return NULL;
+		s += item->str_len;
+		if (item->type == BENCODE_END_MARKER)
+			break;
+		__bencode_container_add(ret, item);
+	}
+
+	return ret;
+}
+
+static bencode_item_t *__bencode_decode_integer(bencode_buffer_t *buf, const char *s, const char *end) {
+	long long int i;
+	const char *orig = s;
+	char *convend;
+	bencode_item_t *ret;
+
+	if (*s != 'i')
+		return NULL;
+	s++;
+
+	if (s >= end)
+		return NULL;
+
+	if (*s == '0') {
+		i = 0;
+		s++;
+		goto done;
+	}
+
+	i = strtoll(s, &convend, 10);
+	if (convend == s)
+		return NULL;
+	s += (convend - s);
+
+done:
+	if (s >= end)
+		return NULL;
+	if (*s != 'e')
+		return NULL;
+	s++;
+
+	ret = __bencode_item_alloc(buf, 0);
+	if (!ret)
+		return NULL;
+	ret->type = BENCODE_INTEGER;
+	ret->iov[0].iov_base = (void *) orig;
+	ret->iov[0].iov_len = s - orig;
+	ret->iov[1].iov_base = NULL;
+	ret->iov[1].iov_len = 0;
+	ret->iov_cnt = 1;
+	ret->str_len = s - orig;
+	ret->value = i;
+
+	return ret;
+}
+
+static bencode_item_t *__bencode_decode_string(bencode_buffer_t *buf, const char *s, const char *end) {
+	unsigned long int sl;
+	char *convend;
+	const char *orig = s;
+	bencode_item_t *ret;
+
+	if (*s == '0') {
+		sl = 0;
+		s++;
+		goto colon;
+	}
+
+	sl = strtoul(s, &convend, 10);
+	if (convend == s)
+		return NULL;
+	s += (convend - s);
+
+colon:
+	if (s >= end)
+		return NULL;
+	if (*s != ':')
+		return NULL;
+	s++;
+
+	if (s + sl > end)
+		return NULL;
+
+	ret = __bencode_item_alloc(buf, 0);
+	if (!ret)
+		return NULL;
+	ret->type = BENCODE_STRING;
+	ret->iov[0].iov_base = (void *) orig;
+	ret->iov[0].iov_len = s - orig;
+	ret->iov[1].iov_base = (void *) s;
+	ret->iov[1].iov_len = sl;
+	ret->iov_cnt = 2;
+	ret->str_len = s - orig + sl;
+
+	return ret;
+}
+
+static bencode_item_t *__bencode_decode(bencode_buffer_t *buf, const char *s, const char *end) {
+	if (s >= end)
+		return NULL;
+
+	switch (*s) {
+		case 'd':
+			return __bencode_decode_dictionary(buf, s, end);
+		case 'l':
+			return __bencode_decode_list(buf, s, end);
+		case 'i':
+			return __bencode_decode_integer(buf, s, end);
+		case 'e':
+			return &__bencode_end_marker;
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			return __bencode_decode_string(buf, s, end);
+		default:
+			return NULL;
+	}
+}
+
+bencode_item_t *bencode_decode(bencode_buffer_t *buf, const char *s, int len) {
+	assert(s != NULL);
+	return __bencode_decode(buf, s, s + len);
+}
+
+
+static int __bencode_dictionary_key_match(bencode_item_t *key, const char *keystr, int keylen) {
+	assert(key->type == BENCODE_STRING);
+
+	if (keylen != key->iov[1].iov_len)
+		return 0;
+	if (memcmp(keystr, key->iov[1].iov_base, keylen))
+		return 0;
+
+	return 1;
+}
+
+bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *keystr, int keylen) {
+	bencode_item_t *key;
+	unsigned int bucket, i;
+	struct __bencode_hash *hash;
+
+	if (!dict)
+		return NULL;
+	if (dict->type != BENCODE_DICTIONARY)
+		return NULL;
+
+	/* try hash lookup first if possible */
+	if (dict->value == 1) {
+		hash = (void *) dict->__buf;
+		i = bucket = __bencode_hash_str_len((const unsigned char *) keystr, keylen);
+		while (1) {
+			key = hash->buckets[i];
+			if (!key)
+				return NULL; /* would be there, but isn't */
+			assert(key->sibling != NULL);
+			if (__bencode_dictionary_key_match(key, keystr, keylen))
+				return key->sibling;
+			i++;
+			if (i >= BENCODE_HASH_BUCKETS)
+				i = 0;
+			if (i == bucket)
+				break; /* fall back to regular lookup */
+		}
+	}
+
+	for (key = dict->child; key; key = key->sibling->sibling) {
+		assert(key->sibling != NULL);
+		if (__bencode_dictionary_key_match(key, keystr, keylen))
+			return key->sibling;
+	}
+
+	return NULL;
+}
+
+void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t func, void *p) {
+	struct __bencode_free_list *li;
+
+	if (!p)
+		return;
+	li = __bencode_alloc(buf, sizeof(*li));
+	if (!li)
+		return;
+	li->ptr = p;
+	li->func = func;
+	li->next = buf->free_list;
+	buf->free_list = li;
+}
diff --git a/modules/rtpproxy-ng/bencode.h b/modules/rtpproxy-ng/bencode.h
new file mode 100644
index 0000000..5628db9
--- /dev/null
+++ b/modules/rtpproxy-ng/bencode.h
@@ -0,0 +1,530 @@
+#ifndef _BENCODE_H_
+#define _BENCODE_H_
+
+#include <sys/uio.h>
+#include <string.h>
+
+#if defined(PKG_MALLOC) || defined(pkg_malloc)
+/* kamailio */
+# include "../../mem/mem.h"
+# include "../../str.h"
+# ifndef BENCODE_MALLOC
+# define BENCODE_MALLOC pkg_malloc
+# define BENCODE_FREE pkg_free
+# endif
+#else
+/* mediaproxy-ng */
+# include "str.h"
+# ifndef BENCODE_MALLOC
+# define BENCODE_MALLOC malloc
+# define BENCODE_FREE free
+# endif
+#endif
+
+struct bencode_buffer;
+enum bencode_type;
+struct bencode_item;
+struct __bencode_buffer_piece;
+struct __bencode_free_list;
+
+typedef enum bencode_type bencode_type_t;
+typedef struct bencode_buffer bencode_buffer_t;
+typedef struct bencode_item bencode_item_t;
+typedef void (*free_func_t)(void *);
+
+enum bencode_type {
+	BENCODE_INVALID = 0,
+	BENCODE_STRING,		/* byte string */
+	BENCODE_INTEGER,	/* long long int */
+	BENCODE_LIST,		/* flat list of other objects */
+	BENCODE_DICTIONARY,	/* dictionary of key/values pairs. keys are always strings */
+	BENCODE_IOVEC,		/* special case of a string, built through bencode_string_iovec() */
+	BENCODE_END_MARKER,	/* used internally only */
+};
+
+struct bencode_item {
+	bencode_type_t type;
+	struct iovec iov[2];	/* when decoding, iov[1] contains the contents of a string object */
+	unsigned int iov_cnt;
+	unsigned int str_len;	/* length of the whole ENCODED object. NOT the length of a byte string */
+	long long int value;	/* when decoding an integer, contains the value; otherwise used internally */
+	bencode_item_t *parent, *child, *last_child, *sibling;
+	bencode_buffer_t *buffer;
+	char __buf[0];
+};
+
+struct bencode_buffer {
+	struct __bencode_buffer_piece *pieces;
+	struct __bencode_free_list *free_list;
+	int error:1;		/* set to !0 if allocation failed at any point */
+};
+
+
+
+
+
+/*** INIT & DESTROY ***/
+
+/* Initializes a bencode_buffer_t object. This object is used to group together all memory allocations
+ * made when encoding or decoding. Its memory usage is always growing, until it is freed, at which point
+ * all objects created through it become invalid. The actual object must be allocated separately, for
+ * example by being put on the stack.
+ * Returns 0 on success or -1 on failure (if no memory could be allocated). */
+int bencode_buffer_init(bencode_buffer_t *buf);
+
+/* Destroys a previously initialized bencode_buffer_t object. All memory used by the object is freed
+ * and all objects created through it become invalid. */
+void bencode_buffer_free(bencode_buffer_t *buf);
+
+/* Creates a new empty dictionary object. Memory will be allocated from the bencode_buffer_t object.
+ * Returns NULL if no memory could be allocated. */
+bencode_item_t *bencode_dictionary(bencode_buffer_t *buf);
+
+/* Creates a new empty list object. Memory will be allocated from the bencode_buffer_t object.
+ * Returns NULL if no memory could be allocated. */
+bencode_item_t *bencode_list(bencode_buffer_t *buf);
+
+/* Adds a pointer to the bencode_buffer_t object's internal free list. When the bencode_buffer_t
+ * object is destroyed, the specified function will be called on this pointer. */
+void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t, void *);
+
+/* Returns the buffer associated with an item, or NULL if pointer given is NULL */
+static inline bencode_buffer_t *bencode_item_buffer(bencode_item_t *);
+
+
+
+
+
+/*** DICTIONARY BUILDING ***/
+
+/* Adds a new key/value pair to a dictionary. Memory will be allocated from the same bencode_buffer_t
+ * object as the dictionary was allocated from. Returns NULL if no memory could be allocated, otherwise
+ * returns "val".
+ * The function does not check whether the key being added is already present in the dictionary.
+ * Also, the function does not reorder keys into lexicographical order; keys will be encoded in
+ * the same order as they've been added. The key must a null-terminated string.
+ * The value to be added must not have been previously linked into any other dictionary or list. */
+static inline bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val);
+
+/* Identical to bencode_dictionary_add() but doesn't require the key string to be null-terminated */
+bencode_item_t *bencode_dictionary_add_len(bencode_item_t *dict, const char *key, int keylen, bencode_item_t *val);
+
+/* Convenience function to add a string value to a dictionary, possibly duplicated into the
+ * bencode_buffer_t object. */
+static inline bencode_item_t *bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val);
+static inline bencode_item_t *bencode_dictionary_add_string_dup(bencode_item_t *dict, const char *key, const char *val);
+
+/* Ditto, but for a "str" object */
+static inline bencode_item_t *bencode_dictionary_add_str(bencode_item_t *dict, const char *key, const str *val);
+static inline bencode_item_t *bencode_dictionary_add_str_dup(bencode_item_t *dict, const char *key, const str *val);
+
+/* Ditto, but adds a string created through an iovec array to the dictionary. See
+ * bencode_string_iovec(). */
+static inline bencode_item_t *bencode_dictionary_add_iovec(bencode_item_t *dict, const char *key,
+	const struct iovec *iov, int iov_cnt, int str_len);
+
+/* Convenience functions to add the respective (newly created) objects to a dictionary */
+static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val);
+static inline bencode_item_t *bencode_dictionary_add_dictionary(bencode_item_t *dict, const char *key);
+static inline bencode_item_t *bencode_dictionary_add_list(bencode_item_t *dict, const char *key);
+
+
+
+
+
+/*** LIST BUILDING ***/
+
+/* Adds a new item to a list. Returns "item".
+ * The item to be added must not have been previously linked into any other dictionary or list. */
+bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item);
+
+/* Convenience function to add the respective (newly created) objects to a list */
+static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, const char *s);
+static inline bencode_item_t *bencode_list_add_list(bencode_item_t *list);
+static inline bencode_item_t *bencode_list_add_dictionary(bencode_item_t *list);
+
+
+
+
+
+/*** STRING BUILDING & HANDLING ***/
+
+/* Creates a new byte-string object. The given string does not have to be null-terminated, instead
+ * the length of the string is specified by the "len" parameter. Returns NULL if no memory could
+ * be allocated.
+ * Strings are not copied or duplicated, so the string pointed to by "s" must remain valid until
+ * the complete document is finally encoded or sent out. */
+bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len);
+
+/* Creates a new byte-string object. The given string must be null-terminated. Otherwise identical
+ * to bencode_string_len(). */
+static inline bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s);
+
+/* Creates a new byte-string object from a "str" object. The string does not have to be null-
+ * terminated. */
+static inline bencode_item_t *bencode_str(bencode_buffer_t *buf, const str *s);
+
+/* Identical to the above three functions, but copies the string into the bencode_buffer_t object.
+ * Thus, the given string doesn't have to remain valid and accessible afterwards. */
+bencode_item_t *bencode_string_len_dup(bencode_buffer_t *buf, const char *s, int len);
+static inline bencode_item_t *bencode_string_dup(bencode_buffer_t *buf, const char *s);
+static inline bencode_item_t *bencode_str_dup(bencode_buffer_t *buf, const str *s);
+
+/* Creates a new byte-string object from an iovec array. The created object has different internal
+ * semantics (not a BENCODE_STRING, but a BENCODE_IOVEC) and must not be treated like other string
+ * objects. The array pointer and contents must still be valid and accessible when the complete
+ * document is encoded. The full length of the string composed of the iovec array is given in the
+ * "str_len" parameter, which can be negative, in which case the array is iterated to calculate the
+ * length. */
+bencode_item_t *bencode_string_iovec(bencode_buffer_t *buf, const struct iovec *iov, int iov_cnt, int str_len);
+
+/* Convenience function to compare a string object to a regular C string. Returns 2 if object
+ * isn't a string object, otherwise returns according to strcmp(). */
+static inline int bencode_strcmp(bencode_item_t *a, const char *b);
+
+/* Converts the string object "in" into a str object "out". Returns "out" on success, or NULL on
+ * error ("in" was NULL or not a string object). */
+static inline str *bencode_get_str(bencode_item_t *in, str *out);
+
+
+
+
+
+/*** INTEGER BUILDING ***/
+
+/* Creates a new integer object. Returns NULL if no memory could be allocated. */
+bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i);
+
+
+
+
+
+/*** COLLAPSING & ENCODING ***/
+
+/* Collapses and encodes the complete document structure under the "root" element (which normally
+ * is either a dictionary or a list) into an array of "iovec" structures. This array can then be
+ * passed to functions ala writev() or sendmsg() to output the encoded document as a whole. Memory
+ * is allocated from the same bencode_buffer_t object as the "root" object was allocated from.
+ * The "head" and "tail" parameters specify additional "iovec" structures that should be included
+ * in the allocated array before or after (respectively) the iovec structures used by the encoded
+ * document. Both parameters can be zero if no additional elements in the array are required.
+ * Returns a pointer to the allocated array or NULL if no memory could be allocated. The number of
+ * array elements is returned in "cnt" which must be a valid pointer to an int. This number does
+ * not include any additional elements allocated through the "head" or "tail" parameters.
+ *
+ * Therefore, the contents of the returned array are:
+ * [0 .. (head - 1)]                         = unused and uninitialized iovec structures
+ * [(head) .. (head + cnt - 1)]              = the encoded document
+ * [(head + cnt) .. (head + cnt + tail - 1)] = unused and uninitialized iovec structures
+ *
+ * The returned array will be freed when the corresponding bencode_buffer_t object is destroyed. */
+struct iovec *bencode_iovec(bencode_item_t *root, int *cnt, unsigned int head, unsigned int tail);
+
+/* Similar to bencode_iovec(), but instead returns the encoded document as a null-terminated string.
+ * Memory for the string is allocated from the same bencode_buffer_t object as the "root" object
+ * was allocated from. If "len" is a non-NULL pointer, the length of the genrated string is returned
+ * in *len. This is important if the encoded document contains binary data, in which case null
+ * termination cannot be trusted. The returned string is freed when the corresponding
+ * bencode_buffer_t object is destroyed. */
+char *bencode_collapse(bencode_item_t *root, int *len);
+
+/* Identical to bencode_collapse() but fills in a "str" object. Returns "out". */
+static str *bencode_collapse_str(bencode_item_t *root, str *out);
+
+/* Identical to bencode_collapse(), but the memory for the returned string is not allocated from
+ * a bencode_buffer_t object, but instead using the function defined as BENCODE_MALLOC (normally
+ * malloc() or pkg_malloc()), similar to strdup(). Using this function, the bencode_buffer_t
+ * object can be destroyed, but the returned string remains valid and usable. */
+char *bencode_collapse_dup(bencode_item_t *root, int *len);
+
+
+
+
+
+/*** DECODING ***/
+
+/* Decodes an encoded document from a string into a tree of bencode_item_t objects. The string does
+ * not need to be null-terminated, instead the length of the string is given through the "len"
+ * parameter. Memory is allocated from the bencode_buffer_t object. Returns NULL if no memory could
+ * be allocated or if the document could not be successfully decoded.
+ *
+ * The returned element is the "root" of the document tree and normally is either a list object or
+ * a dictionary object, but can also be a single string or integer object with no other objects
+ * underneath or besides it (no childred and no siblings). The type of the object can be determined
+ * by its ->type property.
+ *
+ * The number of bytes that could successfully be decoded into an object tree can be accessed through
+ * the root element's ->str_len property. Normally, this number should be equal to the "len" parameter
+ * passed, in which case the full string could be decoded. If ->str_len is less than "len", then there
+ * was additional stray byte data after the end of the encoded document.
+ *
+ * The document tree can be traversed through the ->child and ->sibling pointers in each object. The
+ * ->child pointer will be NULL for string and integer objects, as they don't contain other objects.
+ * For lists and dictionaries, ->child will be a pointer to the first contained object. This first
+ * contained object's ->sibling pointer will point to the next (second) contained object of the list
+ * or the dictionary, and so on. The last contained element of a list of dictionary will have a
+ * NULL ->sibling pointer.
+ *
+ * Dictionaries are like lists with ordered key/value pairs. When traversing dictionaries like
+ * lists, the following applies: The first element in the list (where ->child points to) will be the
+ * key of the first key/value pair (guaranteed to be a string and guaranteed to be present). The
+ * next element (following one ->sibling) will be the value of the first key/value pair. Following
+ * another ->sibling will point to the key of the next (second) key/value pair, and so on.
+ *
+ * However, to access children objects of dictionaries, the special functions following the naming
+ * scheme bencode_dictionary_get_* below should be used. They perform key lookup through a simple
+ * hash built into the dictionary object and so perform the lookup much faster. Only dictionaries
+ * created through a decoding process (i.e. not ones created from bencode_dictionary()) have this
+ * property. The hash is efficient only up to a certain number of elements (BENCODE_HASH_BUCKETS
+ * in bencode.c) contained in the dictionary. If the number of children object exceeds this number,
+ * key lookup will be slower than simply linearily traversing the list.
+ *
+ * The decoding function for dictionary object does not check whether keys are unique within the
+ * dictionary. It also does not care about lexicographical order of the keys.
+ *
+ * Decoded string objects will contain the raw decoded byte string in ->iov[1] (including the correct
+ * length). Strings are NOT null-terminated. Decoded integer objects will contain the decoded value
+ * in ->value.
+ *
+ * All memory is freed when the bencode_buffer_t object is destroyed.
+ */
+bencode_item_t *bencode_decode(bencode_buffer_t *buf, const char *s, int len);
+
+/* Identical to bencode_decode(), but returns successfully only if the type of the decoded object match
+ * "expect". */
+static inline bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, int len, bencode_type_t expect);
+
+/* Identical to bencode_decode_expect() but takes a "str" argument. */
+static inline bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect);
+
+
+
+
+
+/*** DICTIONARY LOOKUP & EXTRACTION ***/
+
+/* Searches the given dictionary object for the given key and returns the respective value. Returns
+ * NULL if the given object isn't a dictionary or if the key doesn't exist. The key must be a
+ * null-terminated string. */
+static inline bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key);
+
+/* Identical to bencode_dictionary_get() but doesn't require the key to be null-terminated. */
+bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *key, int key_len);
+
+/* Identical to bencode_dictionary_get() but returns the value only if its type is a string, and
+ * returns it as a pointer to the string itself. Returns NULL if the value is of some other type. The
+ * returned string is NOT null-terminated. Length of the string is returned in *len, which must be a
+ * valid pointer. The returned string will be valid until dict's bencode_buffer_t object is destroyed. */
+static inline char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, int *len);
+
+/* Identical to bencode_dictionary_get_string() but fills in a "str" struct. Returns str->s, which
+ * may be NULL. */
+static inline char *bencode_dictionary_get_str(bencode_item_t *dict, const char *key, str *str);
+
+/* Looks up the given key in the dictionary and compares the corresponding value to the given
+ * null-terminated string. Returns 2 if the key isn't found or if the value isn't a string, otherwise
+ * returns according to strcmp(). */
+static inline int bencode_dictionary_get_strcmp(bencode_item_t *dict, const char *key, const char *str);
+
+/* Identical to bencode_dictionary_get() but returns the string in a newly allocated buffer (using the
+ * BENCODE_MALLOC function), which remains valid even after bencode_buffer_t is destroyed. */
+static inline char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, int *len);
+
+/* Combines bencode_dictionary_get_str() and bencode_dictionary_get_string_dup(). Fills in a "str"
+ * struct, but copies the string into a newly allocated buffer. Returns str->s. */
+static inline char *bencode_dictionary_get_str_dup(bencode_item_t *dict, const char *key, str *str);
+
+/* Identical to bencode_dictionary_get_string() but expects an integer object. The parameter "defval"
+ * specified which value should be returned if the key is not found or if the value is not an integer. */
+static inline long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval);
+
+/* Identical to bencode_dictionary_get(), but returns the object only if its type matches "expect". */
+static inline bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect);
+
+
+
+
+
+/**************************/
+
+static inline bencode_buffer_t *bencode_item_buffer(bencode_item_t *i) {
+	if (!i)
+		return NULL;
+	return i->buffer;
+}
+
+static inline bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s) {
+	return bencode_string_len(buf, s, strlen(s));
+}
+
+static inline bencode_item_t *bencode_string_dup(bencode_buffer_t *buf, const char *s) {
+	return bencode_string_len_dup(buf, s, strlen(s));
+}
+
+static inline bencode_item_t *bencode_str(bencode_buffer_t *buf, const str *s) {
+	return bencode_string_len(buf, s->s, s->len);
+}
+
+static inline bencode_item_t *bencode_str_dup(bencode_buffer_t *buf, const str *s) {
+	return bencode_string_len_dup(buf, s->s, s->len);
+}
+
+static inline bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val) {
+	if (!key)
+		return NULL;
+	return bencode_dictionary_add_len(dict, key, strlen(key), val);
+}
+
+static inline bencode_item_t *bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val) {
+	if (!val)
+		return NULL;
+	return bencode_dictionary_add(dict, key, bencode_string(bencode_item_buffer(dict), val));
+}
+
+static inline bencode_item_t *bencode_dictionary_add_string_dup(bencode_item_t *dict, const char *key, const char *val) {
+	if (!val)
+		return NULL;
+	return bencode_dictionary_add(dict, key, bencode_string_dup(bencode_item_buffer(dict), val));
+}
+
+static inline bencode_item_t *bencode_dictionary_add_str(bencode_item_t *dict, const char *key, const str *val) {
+	if (!val)
+		return NULL;
+	return bencode_dictionary_add(dict, key, bencode_str(bencode_item_buffer(dict), val));
+}
+
+static inline bencode_item_t *bencode_dictionary_add_str_dup(bencode_item_t *dict, const char *key, const str *val) {
+	if (!val)
+		return NULL;
+	return bencode_dictionary_add(dict, key, bencode_str_dup(bencode_item_buffer(dict), val));
+}
+
+static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val) {
+	return bencode_dictionary_add(dict, key, bencode_integer(bencode_item_buffer(dict), val));
+}
+
+static inline bencode_item_t *bencode_dictionary_add_dictionary(bencode_item_t *dict, const char *key) {
+	return bencode_dictionary_add(dict, key, bencode_dictionary(bencode_item_buffer(dict)));
+}
+
+static inline bencode_item_t *bencode_dictionary_add_list(bencode_item_t *dict, const char *key) {
+	return bencode_dictionary_add(dict, key, bencode_list(bencode_item_buffer(dict)));
+}
+
+static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, const char *s) {
+	return bencode_list_add(list, bencode_string(bencode_item_buffer(list), s));
+}
+
+static inline bencode_item_t *bencode_list_add_list(bencode_item_t *list) {
+	return bencode_list_add(list, bencode_list(bencode_item_buffer(list)));
+}
+
+static inline bencode_item_t *bencode_list_add_dictionary(bencode_item_t *list) {
+	return bencode_list_add(list, bencode_dictionary(bencode_item_buffer(list)));
+}
+
+static inline bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key) {
+	if (!key)
+		return NULL;
+	return bencode_dictionary_get_len(dict, key, strlen(key));
+}
+
+static inline char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, int *len) {
+	bencode_item_t *val;
+	val = bencode_dictionary_get(dict, key);
+	if (!val || val->type != BENCODE_STRING)
+		return NULL;
+	*len = val->iov[1].iov_len;
+	return val->iov[1].iov_base;
+}
+
+static inline char *bencode_dictionary_get_str(bencode_item_t *dict, const char *key, str *str) {
+	str->s = bencode_dictionary_get_string(dict, key, &str->len);
+	if (!str->s)
+		str->len = 0;
+	return str->s;
+}
+
+static inline char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, int *len) {
+	const char *s;
+	char *ret;
+	s = bencode_dictionary_get_string(dict, key, len);
+	if (!s)
+		return NULL;
+	ret = BENCODE_MALLOC(*len);
+	if (!ret)
+		return NULL;
+	memcpy(ret, s, *len);
+	return ret;
+}
+
+static inline char *bencode_dictionary_get_str_dup(bencode_item_t *dict, const char *key, str *str) {
+	str->s = bencode_dictionary_get_string_dup(dict, key, &str->len);
+	return str->s;
+}
+
+static inline long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval) {
+	bencode_item_t *val;
+	val = bencode_dictionary_get(dict, key);
+	if (!val || val->type != BENCODE_INTEGER)
+		return defval;
+	return val->value;
+}
+
+static inline bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, int len, bencode_type_t expect) {
+	bencode_item_t *ret;
+	ret = bencode_decode(buf, s, len);
+	if (!ret || ret->type != expect)
+		return NULL;
+	return ret;
+}
+
+static inline bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect) {
+	return bencode_decode_expect(buf, s->s, s->len, expect);
+}
+
+static inline bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect) {
+	bencode_item_t *ret;
+	ret = bencode_dictionary_get(dict, key);
+	if (!ret || ret->type != expect)
+		return NULL;
+	return ret;
+}
+static inline str *bencode_collapse_str(bencode_item_t *root, str *out) {
+	out->s = bencode_collapse(root, &out->len);
+	return out;
+}
+static inline int bencode_strcmp(bencode_item_t *a, const char *b) {
+	int len;
+	if (a->type != BENCODE_STRING)
+		return 2;
+	len = strlen(b);
+	if (a->iov[1].iov_len < len)
+		return -1;
+	if (a->iov[1].iov_len > len)
+		return 1;
+	return memcmp(a->iov[1].iov_base, b, len);
+}
+static inline int bencode_dictionary_get_strcmp(bencode_item_t *dict, const char *key, const char *str) {
+	bencode_item_t *i;
+	i = bencode_dictionary_get(dict, key);
+	if (!i)
+		return 2;
+	return bencode_strcmp(i, str);
+}
+
+static inline str *bencode_get_str(bencode_item_t *in, str *out) {
+	if (!in || in->type != BENCODE_STRING)
+		return NULL;
+	out->s = in->iov[1].iov_base;
+	out->len = in->iov[1].iov_len;
+	return out;
+}
+
+static inline bencode_item_t *bencode_dictionary_add_iovec(bencode_item_t *dict, const char *key,
+		const struct iovec *iov, int iov_cnt, int str_len)
+{
+	return bencode_dictionary_add(dict, key, bencode_string_iovec(bencode_item_buffer(dict), iov, iov_cnt, str_len));
+}
+
+#endif
diff --git a/modules/rtpproxy-ng/doc/Makefile b/modules/rtpproxy-ng/doc/Makefile
new file mode 100644
index 0000000..f8b032f
--- /dev/null
+++ b/modules/rtpproxy-ng/doc/Makefile
@@ -0,0 +1,4 @@
+docs = rtpproxy-ng.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/rtpproxy-ng/doc/rtpproxy-ng.xml b/modules/rtpproxy-ng/doc/rtpproxy-ng.xml
new file mode 100644
index 0000000..58eadd2
--- /dev/null
+++ b/modules/rtpproxy-ng/doc/rtpproxy-ng.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>rtpproxy-ng Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+		<author>
+		<firstname>Maxim</firstname>
+		<surname>Sobolev</surname>
+		<affiliation><orgname>Sippy Software, Inc.</orgname></affiliation>
+		<address>
+			<email>sobomax at sippysoft.com</email>
+		</address>
+		</author>
+		<author>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<affiliation><orgname>TuTPro, Inc.</orgname></affiliation>
+		<address>
+			<email>jh at tutpro.com</email>
+		</address>
+		</author>
+		<editor>
+		<firstname>Maxim</firstname>
+		<surname>Sobolev</surname>
+		<address>
+			<email>sobomax at sippysoft.com</email>
+		</address>
+		</editor>
+		<editor>
+		<firstname>Bogdan-Andrei</firstname>
+		<surname>Iancu</surname>
+		<address>
+			<email>bogdan at voice-system.ro</email>
+		</address>
+		</editor>
+		<editor>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<address>
+			<email>jh at tutpro.com</email>
+		</address>
+		</editor>
+		<editor>
+		<firstname>Sas</firstname>
+		<surname>Ovidiu</surname>
+		<address>
+			<email>osas at voipembedded.com</email>
+		</address>
+		</editor>
+		<editor>
+		<firstname>Carsten</firstname>
+		<surname>Bock</surname>
+		<affiliation><orgname>ng-voice GmbH</orgname></affiliation>
+		<address>
+			<email>carsten at ng-voice.com</email>
+		</address>
+		</editor>
+		<editor>
+		<firstname>Richard</firstname>
+		<surname>Fuchs</surname>
+		<affiliation><orgname>Sipwise GmbH</orgname></affiliation>
+		<address>
+			<email>rfuchs at sipwise.com</email>
+		</address>
+		</editor>
+	</authorgroup>
+	<copyright>
+		<year>2003-2008</year>
+		<holder>Sippy Software, Inc.</holder>
+	</copyright>
+	<copyright>
+		<year>2005</year>
+		<holder>Voice Sistem SRL</holder>
+	</copyright>
+	<copyright>
+		<year>2009-2012</year>
+		<holder>TuTPro Inc.</holder>
+	</copyright>
+	<copyright>
+		<year>2010</year>
+		<holder><ulink url='http://www.voipembedded.com'>VoIPEmbedded Inc.</ulink></holder>
+	</copyright>
+	<copyright>
+		<year>2013</year>
+		<holder>Sipwise GmbH</holder>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+
+	<xi:include href="rtpproxy_admin.xml"/>
+	<xi:include href="rtpproxy_faq.xml"/>
+
+</book>
diff --git a/modules/rtpproxy-ng/doc/rtpproxy_admin.xml b/modules/rtpproxy-ng/doc/rtpproxy_admin.xml
new file mode 100644
index 0000000..e566fe2
--- /dev/null
+++ b/modules/rtpproxy-ng/doc/rtpproxy_admin.xml
@@ -0,0 +1,823 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Module User's Guide -->
+
+<chapter>
+
+	<title>&adminguide;</title>
+
+	<section>
+	<title>Overview</title>
+	<para>
+		This is a module that enables media streams to be proxied
+		via an RTP proxy. The only RTP proxy currently known to work
+		with this module is the Sipwise ngcp-rtpproxy-ng
+		<ulink url="https://github.com/sipwise/mediaproxy-ng"></ulink>.
+		The rtpproxy-ng module is a modified version of the original
+		rtpproxy module using a new control protocol. The module is
+		designed to be a drop-in replacement for the old module from
+		a configuration file point of view, however due to the
+		incompatible control protocol, it only works with RTP proxies
+		which specifically support it.
+	</para>
+	</section>
+
+	<section>
+	<title>Multiple RTPProxy usage</title>
+	<para>
+		The rtpproxy-ng module can support multiple RTP proxies for
+		balancing/distribution and control/selection purposes.
+	</para>
+	<para>
+		The module allows definition of several sets of rtpproxies.
+		Load-balancing will be performed over a set and the admin has the
+		ability to choose what set should be used. The set is selected via
+		its id - the id being defined with the set. Refer to the
+		<quote>rtpproxy_sock</quote> module parameter definition for syntax
+		description.
+	</para>
+	<para>
+		The balancing inside a set is done automatically by the module based on
+		the weight of each rtpproxy from the set.
+	</para>
+	<para>
+		The selection of the set is done from script prior using
+		unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer()
+		functions - see the set_rtp_proxy_set() function.
+	</para>
+	<para>
+		For backward compatibility reasons, a set with no id take by default
+		the id 0. Also if no set is explicitly set before
+		unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer()
+		the 0 id set will be used.
+	</para>
+	<para>
+		IMPORTANT: if you use multiple sets, take care and use the same set for
+		both rtpproxy_offer()/rtpproxy_answer() and unforce_rtpproxy()!!
+	</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>tm module</emphasis> - (optional) if you want to
+				have rtpproxy_manage() fully functional
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before
+		running &kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>None</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+
+	<section>
+	<title>Parameters</title>
+	<section id="rtpproxy-ng.p.rtpproxy_sock">
+		<title><varname>rtpproxy_sock</varname> (string)</title>
+		<para>
+		Definition of socket(s) used to connect to (a set) RTPProxy. It may
+		specify a UNIX socket or an IPv4/IPv6 UDP socket.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>NONE</quote> (disabled).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>rtpproxy_sock</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+# single rtproxy
+modparam("rtpproxy-ng", "rtpproxy_sock", "udp:localhost:12221")
+# multiple rtproxies for LB
+modparam("rtpproxy-ng", "rtpproxy_sock",
+	"udp:localhost:12221 udp:localhost:12222")
+# multiple sets of multiple rtproxies
+modparam("rtpproxy-ng", "rtpproxy_sock",
+	"1 == udp:localhost:12221 udp:localhost:12222")
+modparam("rtpproxy-ng", "rtpproxy_sock",
+	"2 == udp:localhost:12225")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="rtpproxy-ng.p.rtpproxy_disable_tout">
+		<title><varname>rtpproxy_disable_tout</varname> (integer)</title>
+		<para>
+		Once an RTP proxy was found unreachable and marked as disabled, the rtpproxy-ng
+		module will not attempt to establish communication to that RTP proxy for
+		rtpproxy_disable_tout seconds.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>60</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>rtpproxy_disable_tout</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy-ng", "rtpproxy_disable_tout", 20)
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="rtpproxy-ng.p.rtpproxy_tout">
+		<title><varname>rtpproxy_tout</varname> (integer)</title>
+		<para>
+		Timeout value in waiting for reply from RTP proxy.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>1</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>rtpproxy_tout</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy-ng", "rtpproxy_tout", 2)
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="rtpproxy-ng.p.rtpproxy_retr">
+		<title><varname>rtpproxy_retr</varname> (integer)</title>
+		<para>
+		How many times the module should retry to send and receive after
+		timeout was generated.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>5</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>rtpproxy_retr</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy-ng", "rtpproxy_retr", 2)
+...
+</programlisting>
+		</example>
+	</section>
+<!--
+	<section>
+		<title><varname>timeout_socket</varname> (string)</title>
+		<para>
+		The parameter sets the RTP timeout socket, which is transmitted to the RTP Proxy.
+		It will be used by the RTP proxy to signal back that a media stream timed
+		out.
+		</para>
+		<para>
+		If it is an empty string, no timeout socket will be transmitted to the RTP-Proxy.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote></quote> (nothing).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>timeout_socket</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
+...
+</programlisting>
+		</example>
+	</section>
+-->
+	<section id="rtpproxy-ng.p.extra_id_pv">
+		<title><varname>extra_id_pv</varname> (string)</title>
+		<para>
+			The parameter sets the PV defination to use when the <quote>b</quote>
+			parameter is used on unforce_rtp_proxy(), rtpproxy_offer(),
+			rtpproxy_answer() or rtpproxy_manage() command.
+		</para><para>
+			Default is empty, the <quote>b</quote> parameter may not be used then.
+		</para>
+		<example>
+		<title>Set <varname>extra_id_pv</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy-ng", "extra_id_pv", "$avp(extra_id)")
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>Functions</title>
+	<section id="rtpproxy-ng.f.set_rtp_proxy_set">
+		<title>
+		<function moreinfo="none">set_rtp_proxy_set(setid)</function>
+		</title>
+		<para>
+		Sets the Id of the rtpproxy set to be used for the next
+		unforce_rtp_proxy(), rtpproxy_offer(), rtpproxy_answer()
+		or rtpproxy_manage() command. The parameter can be an integer or
+		a config variable holding an integer.
+		</para>
+		<para>
+		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+		BRANCH_ROUTE.
+		</para>
+		<example>
+		<title><function>set_rtp_proxy_set</function> usage</title>
+		<programlisting format="linespecific">
+...
+set_rtp_proxy_set("2");
+rtpproxy_offer();
+...
+</programlisting>
+		</example>
+	</section>
+        <section id="rtpproxy-ng.f.rtpproxy_offer">
+                <title>
+                <function moreinfo="none">rtpproxy_offer([flags [, ip_address]])</function>
+                </title>
+                <para>
+                Rewrites &sdp; body to ensure that media is passed through
+                an &rtp; proxy. To be invoked
+		on INVITE for the cases the SDPs are in INVITE and 200 OK and on 200 OK
+		when SDPs are in 200 OK and ACK.
+                </para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+			<emphasis>flags</emphasis> - flags to turn on some features.
+			</para>
+			<itemizedlist>
+				<listitem><para>
+				<emphasis>1</emphasis> - append first Via branch to Call-ID when sending
+				command to rtpproxy. This can be used to create one media session per branch
+				on the rtpproxy. When sending a subsequent <quote>delete</quote> command to
+				the rtpproxy, you can then stop just the session for a specific branch when
+				passing the flag '1' or '2' in the <quote>unforce_rtpproxy</quote>, or stop
+				all sessions for a call when not passing one of those two flags there. This is
+				especially useful if you have serially forked call scenarios where rtpproxy
+				gets an <quote>offer</quote> command for a new branch, and then a
+				<quote>delete</quote> command for the previous branch, which would otherwise
+				delete the full call, breaking the subsequent <quote>answer</quote> for the
+				new branch. <emphasis>This flag is only supported by the ngcp-mediaproxy-ng
+				rtpproxy at the moment!</emphasis>
+				</para></listitem>
+				<listitem><para>
+				<emphasis>2</emphasis> - append second Via branch to Call-ID when sending
+				command to rtpproxy. See flag '1' for its meaning.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>3</emphasis> - behave like flag 1 is set for a request and
+				like flag 2 is set for a reply.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>a</emphasis> - flags that UA from which message is
+				received doesn't support symmetric RTP. (automatically sets the 'r' flag)
+				</para></listitem>
+				<listitem><para>
+				<emphasis>b</emphasis> - append branch specific variable to Call-ID when sending
+				command to rtpproxy. This creates one rtpproxy session per unique variable.
+
+				Works similar to the 1, 2 and 3 parameter, but is usefull when forking to multiple
+				destinations on different address families or network segments, requiring different
+				rtpproxy parameters.
+
+				The variable value is taken from the <quote>extra_id_pv</quote>.
+
+				When used, it must be used in every call to rtpproxy_manage(), rtpproxy_offer(),
+				rtpproxy_answer() and rtpproxy_destroy() with the same contents of the PV.
+				The b parameter may not be used in conjunction with the 1, 2 or 3 parameter
+				to use the Via branch in the Call-ID.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>l</emphasis> - force <quote>lookup</quote>, that is,
+				only rewrite SDP when corresponding session already exists
+				in the RTP proxy. By default is on when the session is to be
+				completed.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>i, e</emphasis> - these flags specify the direction of the SIP
+				message. These flags only make sense when rtpproxy is running in bridge mode.
+				'i' means internal network (LAN), 'e' means external network (WAN). 'i'
+				corresponds to rtpproxy's first interface, 'e' corresponds to rtpproxy's
+				second interface. You always have to specify two flags to define
+				the incoming network and the outgoing network. For example, 'ie' should be
+				used for SIP message received from the local interface and sent out on the
+				external interface, and 'ei' vice versa. Other options are 'ii' and 'ee'.
+				So, for example if a SIP requests is processed with 'ie' flags, the corresponding
+				response must be processed with 'ie' flags.
+				</para><para>
+				For ngcp-mediaproxy-ng, these flags are used to select between IPv4
+				and IPv6 addresses, corresponding to 'i' and 'e' respectively. For example,
+				if the request is coming from an IPv4 host and is going to an IPv6 host,
+				the flags should be specified as 'ie'.
+				</para><para>
+				Note: As rtpproxy in bridge mode s per default asymmetric, you have to specify
+				the 'w' flag for clients behind NAT! See also above notes!
+				</para></listitem>
+				<listitem><para>
+				<emphasis>x</emphasis> - this flag an alternative to the 'ie' or 'ei'-flags
+				in order to do automatic bridging between IPv4 on the
+				"internal network" and IPv6 on the "external network". Instead of
+				explicitly instructing the RTP proxy to select a particular address
+				family, the distinction is done by the given IP in the SDP body by
+				the RTP proxy itself. Not supported by ngcp-mediaproxy-ng.
+				</para><para>
+				Note: Please note, that this will only work properly with non-dual-stack user-agents or with
+				dual-stack clients according to RFC6157 (which suggest ICE for Dual-Stack implementations).
+				This short-cut will not work properly with RFC4091 (ANAT) compatible clients, which suggests
+				having different m-lines with different IP-protocols grouped together.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>f</emphasis> - instructs rtpproxy to ignore marks
+				inserted by another rtpproxy in transit to indicate that the
+				session is already goes through another proxy. Allows creating
+				a chain of proxies.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>r</emphasis> - flags that IP address in SDP should
+				be trusted. Without this flag, rtpproxy ignores address in
+				the SDP and uses source address of the SIP message as media
+				address which is passed to the RTP proxy.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>o</emphasis> - flags that IP from the origin
+				description (o=) should be also changed.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>c</emphasis> - flags to change the session-level
+				SDP connection (c=) IP if media-description also includes
+				connection information.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>w</emphasis> - flags that for the UA from which
+				message is received, support symmetric RTP must be forced.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>zNN</emphasis> - requests the RTPproxy to perform
+				re-packetization of RTP traffic coming from the UA which
+				has sent the current message to increase or decrease payload
+				size per each RTP packet forwarded if possible.  The NN is the
+				target payload size in ms, for the most codecs its value should
+				be in 10ms increments, however for some codecs the increment
+				could differ (e.g. 30ms for GSM or 20ms for G.723).  The
+				RTPproxy would select the closest value supported by the codec.
+				This feature could be used for significantly reducing bandwith
+				overhead for low bitrate codecs, for example with G.729 going
+				from 10ms to 100ms saves two thirds of the network bandwith.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>+</emphasis> - instructs the RTP proxy to
+				discard any ICE attributes already present in the SDP body
+				and then generate and insert new ICE data, leaving itself
+				as the <emphasis>only</emphasis> ICE candidates. Without
+				this flag, new ICE data will only be generated
+				if no ICE was present in the SDP originally; otherwise
+				the RTP proxy will only insert itself as an
+				<emphasis>additional</emphasis> ICE candidate. Other
+				SDP substitutions (c=, m=, etc) are unaffected by this flag.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>-</emphasis> - instructs the RTP proxy to discard
+				any ICE attributes and not insert any new ones into the SDP.
+				Mutually exclusive with the '+' flag.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>s, S, p, P</emphasis> - These flags control the RTP
+				transport protocol that should be used towards the recipient of
+				the SDP. If none of them are specified, the protocol given in
+				the SDP is left untouched. Otherwise, the "S" flag indicates that
+				SRTP should be used, while "s" indicates that SRTP should not be used.
+				"P" indicates that the advanced RTCP profile with feedback messages
+				should be used, and "p" indicates that the regular RTCP profile
+				should be used. As such, the combinations "sp", "sP", "Sp" and "SP"
+				select between RTP/AVP, RTP/AVPF, RTP/SAVP and RTP/SAVPF,
+				respectively.
+				</para></listitem>
+			</itemizedlist>
+		</listitem>
+		<listitem><para>
+		<emphasis>ip_address</emphasis> - new SDP IP address.
+		</para></listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from ANY_ROUTE.
+                </para>
+		<example>
+		<title><function>rtpproxy_offer</function> usage</title>
+		<programlisting format="linespecific">
+route {
+...
+    if (is_method("INVITE")) {
+        if (has_body("application/sdp")) {
+            if (rtpproxy_offer())
+                t_on_reply("1");
+        } else {
+            t_on_reply("2");
+        }
+    }
+    if (is_method("ACK") && has_body("application/sdp"))
+        rtpproxy_answer();
+...
+}
+
+onreply_route[1]
+{
+...
+    if (has_body("application/sdp"))
+        rtpproxy_answer();
+...
+}
+
+onreply_route[2]
+{
+...
+    if (has_body("application/sdp"))
+        rtpproxy_offer();
+...
+}
+</programlisting>
+                </example>
+	</section>
+        <section id="rtpproxy-ng.f.rtpproxy_answer">
+                <title>
+                <function moreinfo="none">rtpproxy_answer([flags [, ip_address]])</function>
+                </title>
+		<para>
+		Rewrites &sdp; body to ensure that media is passed through
+		an &rtp; proxy. To be invoked
+		on 200 OK for the cases the SDPs are in INVITE and 200 OK and on ACK
+		when SDPs are in 200 OK and ACK.
+		</para>
+		<para>
+		See rtpproxy_answer() function description above for the meaning of the
+		parameters.
+		</para>
+		<para>
+		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+		FAILURE_ROUTE, BRANCH_ROUTE.
+		</para>
+		<example>
+		 <title><function>rtpproxy_answer</function> usage</title>
+		<para>
+		See rtpproxy_offer() function example above for example.
+		</para>
+		</example>
+        </section>
+	<section id="rtpproxy-ng.f.rtpproxy_destroy">
+		<title>
+		<function moreinfo="none">rtpproxy_destroy([flags])</function>
+		</title>
+		<para>
+		Tears down the RTPProxy session for the current call.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+			<emphasis>flags</emphasis> - flags to turn on some features.
+			</para>
+			<itemizedlist>
+				<listitem><para>
+				<emphasis>1</emphasis> - append first Via branch to Call-ID when sending
+				command to rtpproxy. This can be used to create one media session per branch
+				on the rtpproxy. When sending a subsequent <quote>delete</quote> command to
+				the rtpproxy, you can then stop just the session for a specific branch when
+				passing the flag '1' or '2' in the <quote>unforce_rtpproxy</quote>, or stop
+				all sessions for a call when not passing one of those two flags there. This is
+				especially useful if you have serially forked call scenarios where rtpproxy
+				gets an <quote>update</quote> command for a new branch, and then a
+				<quote>delete</quote> command for the previous branch, which would otherwise
+				delete the full call, breaking the subsequent <quote>lookup</quote> for the
+				new branch. <emphasis>This flag is only supported by the ngcp-mediaproxy-ng
+				rtpproxy at the moment!</emphasis>
+				</para></listitem>
+				<listitem><para>
+				<emphasis>2</emphasis> - append second Via branch to Call-ID when sending
+				command to rtpproxy. See flag '1' for its meaning.
+				</para></listitem>
+				<listitem><para>
+				<emphasis>b</emphasis> - append branch specific variable to Call-ID when sending
+				command to rtpproxy. See rtpproxy_offer() for details.
+				<listitem><para>
+				</para></listitem>
+				<emphasis>t</emphasis> - do not include To tag to <quote>delete</quote> command to rtpproxy thus causing full call to be deleted. Useful for deleting unused rtpproxy call when 200 OK is received on a branch, where rtpproxy is not needed.
+				</para></listitem>
+			</itemizedlist>
+		</listitem>
+		</itemizedlist>
+		<example>
+		<title><function>rtpproxy_destroy</function> usage</title>
+		<programlisting format="linespecific">
+...
+rtpproxy_destroy();
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="rtpproxy-ng.f.unforce_rtp_proxy">
+		<title>
+		<function moreinfo="none">unforce_rtp_proxy()</function>
+		</title>
+		<para>
+			Same as rtpproxy_destroy().
+		</para>
+	</section>
+
+    <section id="rtpproxy-ng.f.rtpproxy_manage">
+        <title>
+        <function moreinfo="none">rtpproxy_manage([flags [, ip_address]])</function>
+        </title>
+		<para>
+		Manage the RTPProxy session - it combines the functionality of
+		rtpproxy_offer(), rtpproxy_answer() and unforce_rtpproxy(), detecting
+		internally based on message type and method which one to execute.
+		</para>
+		<para>
+		It can take the same parameters as <function>rtpproxy_offer().</function>
+		The flags parameter to rtpproxy_manage() can be a configuration variable
+		containing the flags as a string.
+		</para>
+		<para>
+		Functionality:
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+			If INVITE with SDP, then do <function>rtpproxy_offer()</function>
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			If INVITE with SDP, when the tm module is loaded, mark transaction with
+			internal flag FL_SDP_BODY to know that the 1xx and 2xx are for
+			<function>rtpproxy_answer()</function>
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			If ACK with SDP, then do <function>rtpproxy_answer()</function>
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			If BYE or CANCEL, or called within a FAILURE_ROUTE[], then do <function>unforce_rtpproxy()</function>
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			If reply to INVITE with code >= 300 do <function>unforce_rtpproxy()</function>
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+			If reply with SDP to INVITE having code 1xx and 2xx, then
+			do <function>rtpproxy_answer()</function> if the request had SDP or tm is not loaded,
+			otherwise do <function>rtpproxy_offer()</function>
+			</para>
+		</listitem>
+	</itemizedlist>
+
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		 <title><function>rtpproxy_manage</function> usage</title>
+		<programlisting format="linespecific">
+...
+rtpproxy_manage();
+...
+</programlisting>
+		</example>
+        </section>
+
+<!--
+	<section id="rtpproxy_stream2uac">
+	<title>
+	    <function>rtpproxy_stream2uac(prompt_name, count)</function>,
+	</title>
+	<para>
+	    Instruct the RTPproxy to stream prompt/announcement pre-encoded with
+	    the makeann command from the RTPproxy distribution. The uac/uas
+	    suffix selects who will hear the announcement relatively to the current
+	    transaction - UAC or UAS. For example invoking the
+	    <function>rtpproxy_stream2uac</function> in the request processing
+	    block on ACK transaction will play the prompt to the UA that has
+	    generated original INVITE and ACK while
+	    <function>rtpproxy_stop_stream2uas</function> on 183 in reply
+	    processing block will play the prompt to the UA that has generated 183.
+	</para>
+	<para>
+	    Apart from generating announcements, another possible application
+	    of this function is implementing music on hold (MOH) functionality.
+	    When count is -1, the streaming will be in loop indefinitely until
+	    the appropriate <function>rtpproxy_stop_stream2xxx</function> is issued.
+	</para>
+	<para>
+	    In order to work correctly, these functions require that a session in the
+	    RTPproxy already exists. Also those functions don't alter the SDP, so that
+	    they are not a substitute for calling <function>rtpproxy_offer</function>
+	    or <function>rtpproxy_answer</function>.
+	</para>
+	<para>
+	    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE.
+	</para>
+	<para>Meaning of the parameters is as follows:</para>
+	<itemizedlist>
+	    <listitem>
+		<para>
+		    <emphasis>prompt_name</emphasis> - name of the prompt to
+		    stream. Should be either absolute pathname or pathname
+		    relative to the directory where RTPproxy runs.
+		</para>
+	    </listitem>
+	    <listitem>
+		<para>
+		    <emphasis>count</emphasis> - number of times the prompt
+		    should be repeated. A value of -1 means that it will
+		    be streaming in a loop indefinitely, until the appropriate
+		    <function>rtpproxy_stop_stream2xxx</function> is issued.
+		</para>
+	    </listitem>
+	</itemizedlist>
+	<example>
+	    <title><function>rtpproxy_stream2xxx</function> usage</title>
+	    <programlisting>
+...
+    if (is_method("INVITE")) {
+        rtpproxy_offer();
+        if (detect_hold()) {
+            rtpproxy_stream2uas("/var/rtpproxy/prompts/music_on_hold", "-1");
+        } else {
+            rtpproxy_stop_stream2uas();
+        };
+    };
+...
+	    </programlisting>
+	</example>
+	</section>
+	<section id="rtpproxy_stream2uas">
+	<title>
+	    <function>rtpproxy_stream2uas(prompt_name, count)</function>
+	</title>
+	<para>
+		See function <function>rtpproxy_stream2uac(prompt_name, count)</function>.
+	</para>
+	</section>
+	<section id="rtpproxy_stop_stream2uac">
+	<title>
+	    <function>rtpproxy_stop_stream2uac()</function>,
+	</title>
+	<para>
+	    Stop streaming of announcement/prompt/MOH started previously by the
+	    respective <function>rtpproxy_stream2xxx</function>.  The uac/uas
+	    suffix selects whose announcement relatively to tha current
+	    transaction should be stopped - UAC or UAS.
+	</para>
+	<para>
+	    These functions can be used from REQUEST_ROUTE, ONREPLY_ROUTE.
+	</para>
+	</section>
+-->
+	<section id="rtpproxy-ng.f.start_recording">
+		<title>
+		<function moreinfo="none">start_recording()</function>
+		</title>
+		<para>
+		This function will send a signal to the RTP Proxy to record
+		the RTP stream on the RTP Proxy.
+		<emphasis>This function is not supported by ngcp-mediaproxy-ng at the moment!</emphasis>
+		</para>
+		<para>
+		This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
+		</para>
+		<example>
+		<title><function>start_recording</function> usage</title>
+		<programlisting format="linespecific">
+...
+start_recording();
+...
+		</programlisting>
+		</example>
+	</section>
+<!--
+	<section id="rtpproxy_stop_stream2uas">
+	<title>
+	    <function>rtpproxy_stop_stream2uas(prompt_name, count)</function>
+	</title>
+	<para>
+		See function <function>rtpproxy_stop_stream2uac(prompt_name, count)</function>.
+	</para>
+	</section>
+-->
+
+
+	</section>
+
+	<section>
+		<title>Exported Pseudo Variables</title>
+		<section>
+			<title><function moreinfo="none">$rtpstat</function></title>
+			<para>
+			Returns the RTP Statistics from the RTP Proxy. The RTP Statistics from the RTP Proxy
+			are provided as a string and it does contain several packet counters. The statistics
+			must be retrieved before the session is deleted	(before <function>unforce_rtpproxy()</function>).
+			</para>
+
+		<example>
+		<title>$rtpstat Usage</title>
+		<programlisting format="linespecific">
+...
+    append_hf("X-RTP-Statistics: $rtpstat\r\n");
+...
+		</programlisting>
+		</example>
+	        </section>
+
+	</section>
+
+	<section>
+		<title><acronym>MI</acronym> Commands</title>
+		<section id="rtpproxy-ng.m.nh_enable_rtpp">
+			<title><function moreinfo="none">nh_enable_rtpp</function></title>
+			<para>
+			Enables a rtp proxy if parameter value is greater than 0.
+			Disables it if a zero value is given.
+			</para>
+			<para>
+			The first parameter is the rtp proxy url (exactly as defined in
+			the config file).
+			</para>
+			<para>
+			The second parameter value must be a number in decimal.
+			</para>
+			<para>
+			NOTE: if a rtpproxy is defined multiple times (in the same or
+			diferente sete), all of its instances will be enables/disabled.
+			</para>
+			<example>
+			<title>
+			<function moreinfo="none">nh_enable_rtpp</function> usage</title>
+			<programlisting format="linespecific">
+...
+$ &ctltool; fifo nh_enable_rtpp udp:192.168.2.133:8081 0
+...
+			</programlisting>
+			</example>
+		</section>
+
+			<section id="rtpproxy-ng.m.nh_show_rtpp">
+			<title><function moreinfo="none">nh_show_rtpp</function></title>
+			<para>
+			Displays all the rtp proxies and their information: set and
+			status (disabled or not, weight and recheck_ticks).
+			</para>
+			<para>
+			No parameter.
+			</para>
+			<example>
+			<title>
+				<function moreinfo="none">nh_show_rtpp</function> usage</title>
+			<programlisting format="linespecific">
+...
+$ &ctltool; fifo nh_show_rtpp
+...
+			</programlisting>
+			</example>
+		</section>
+	</section>
+
+</chapter>
+
diff --git a/modules/rtpproxy-ng/doc/rtpproxy_faq.xml b/modules/rtpproxy-ng/doc/rtpproxy_faq.xml
new file mode 100644
index 0000000..264c71b
--- /dev/null
+++ b/modules/rtpproxy-ng/doc/rtpproxy_faq.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module FAQ -->
+
+<chapter>
+
+    <title>&faqguide;</title>
+    <qandaset defaultlabel="number">
+	<qandaentry>
+	    <question>
+		<para>What happend with <quote>rtpproxy_disable</quote> parameter?</para>
+	    </question>
+	    <answer>
+		<para>
+			It was removed as it became obsolete - now
+			<quote>rtpproxy_sock</quote> can take empty value to disable the
+			rtpproxy functionality.
+		</para>
+	    </answer>
+	</qandaentry>
+	<qandaentry>
+	    <question>
+		<para>Where can I find more about &kamailio;?</para>
+	    </question>
+	    <answer>
+		<para>
+			Take a look at &kamailiohomelink;.
+		</para>
+	    </answer>
+	</qandaentry>
+	<qandaentry>
+	    <question>
+		<para>Where can I post a question about this module?</para>
+	    </question>
+	    <answer>
+		<para>
+			First at all check if your question was already answered on one of
+			our mailing lists:
+		</para>
+		<itemizedlist>
+		    <listitem>
+			<para>User Mailing List - &kamailiouserslink;</para>
+		    </listitem>
+		    <listitem>
+			<para>Developer Mailing List - &kamailiodevlink;</para>
+		    </listitem>
+		</itemizedlist>
+		<para>
+			E-mails regarding any stable &kamailio; release should be sent to
+			&kamailiousersmail; and e-mails regarding development versions
+			should be sent to &kamailiodevmail;.
+		</para>
+		<para>
+			If you want to keep the mail private, send it to
+			&kamailiohelpmail;.
+		</para>
+	    </answer>
+	</qandaentry>
+	<qandaentry>
+	    <question>
+		<para>How can I report a bug?</para>
+	    </question>
+	    <answer>
+		<para>
+			Please follow the guidelines provided at:
+			&kamailiobugslink;.
+		</para>
+	    </answer>
+	</qandaentry>
+    </qandaset>
+</chapter>
+
diff --git a/modules/rtpproxy-ng/rtpproxy.c b/modules/rtpproxy-ng/rtpproxy.c
new file mode 100644
index 0000000..a8b5da7
--- /dev/null
+++ b/modules/rtpproxy-ng/rtpproxy.c
@@ -0,0 +1,1941 @@
+/* $Id$
+ *
+ * Copyright (C) 2003-2008 Sippy Software, Inc., http://www.sippysoft.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * ---------
+ * 2003-10-09	nat_uac_test introduced (jiri)
+ *
+ * 2003-11-06   nat_uac_test permitted from onreply_route (jiri)
+ *
+ * 2003-12-01   unforce_rtp_proxy introduced (sobomax)
+ *
+ * 2004-01-07	RTP proxy support updated to support new version of the
+ *		RTP proxy (20040107).
+ *
+ *		force_rtp_proxy() now inserts a special flag
+ *		into the SDP body to indicate that this session already
+ *		proxied and ignores sessions with such flag.
+ *
+ *		Added run-time check for version of command protocol
+ *		supported by the RTP proxy.
+ *
+ * 2004-01-16   Integrated slightly modified patch from Tristan Colgate,
+ *		force_rtp_proxy function with IP as a parameter (janakj)
+ *
+ * 2004-01-28	nat_uac_test extended to allow testing SDP body (sobomax)
+ *
+ *		nat_uac_test extended to allow testing top Via (sobomax)
+ *
+ * 2004-02-21	force_rtp_proxy now accepts option argument, which
+ *		consists of string of chars, each of them turns "on"
+ *		some feature, currently supported ones are:
+ *
+ *		 `a' - flags that UA from which message is received
+ *		       doesn't support symmetric RTP;
+ *		 `l' - force "lookup", that is, only rewrite SDP when
+ *		       corresponding session is already exists in the
+ *		       RTP proxy. Only makes sense for SIP requests,
+ *		       replies are always processed in "lookup" mode;
+ *		 `i' - flags that message is received from UA in the
+ *		       LAN. Only makes sense when RTP proxy is running
+ *		       in the bridge mode.
+ *
+ *		force_rtp_proxy can now be invoked without any arguments,
+ *		as previously, with one argument - in this case argument
+ *		is treated as option string and with two arguments, in
+ *		which case 1st argument is option string and the 2nd
+ *		one is IP address which have to be inserted into
+ *		SDP (IP address on which RTP proxy listens).
+ *
+ * 2004-03-12	Added support for IPv6 addresses in SDPs. Particularly,
+ *		force_rtp_proxy now can work with IPv6-aware RTP proxy,
+ *		replacing IPv4 address in SDP with IPv6 one and vice versa.
+ *		This allows creating full-fledged IPv4<->IPv6 gateway.
+ *		See 4to6.cfg file for example.
+ *
+ *		Two new options added into force_rtp_proxy:
+ *
+ *		 `f' - instructs nathelper to ignore marks inserted
+ *		       by another nathelper in transit to indicate
+ *		       that the session is already goes through another
+ *		       proxy. Allows creating chain of proxies.
+ *		 `r' - flags that IP address in SDP should be trusted.
+ *		       Without this flag, nathelper ignores address in the
+ *		       SDP and uses source address of the SIP message
+ *		       as media address which is passed to the RTP proxy.
+ *
+ *		Protocol between nathelper and RTP proxy in bridge
+ *		mode has been slightly changed. Now RTP proxy expects SER
+ *		to provide 2 flags when creating or updating session
+ *		to indicate direction of this session. Each of those
+ *		flags can be either `e' or `i'. For example `ei' means
+ *		that we received INVITE from UA on the "external" network
+ *		network and will send it to the UA on "internal" one.
+ *		Also possible `ie' (internal->external), `ii'
+ *		(internal->internal) and `ee' (external->external). See
+ *		example file alg.cfg for details.
+ *
+ * 2004-03-15	If the rtp proxy test failed (wrong version or not started)
+ *		retry test from time to time, when some *rtpproxy* function
+ *		is invoked. Minimum interval between retries can be
+ *		configured via rtpproxy_disable_tout module parameter (default
+ *		is 60 seconds). Setting it to -1 will disable periodic
+ *		rechecks completely, setting it to 0 will force checks
+ *		for each *rtpproxy* function call. (andrei)
+ *
+ * 2004-03-22	Fix assignment of rtpproxy_retr and rtpproxy_tout module
+ *		parameters.
+ *
+ * 2004-03-22	Fix get_body position (should be called before get_callid)
+ * 				(andrei)
+ *
+ * 2004-03-24	Fix newport for null ip address case (e.g onhold re-INVITE)
+ * 				(andrei)
+ *
+ * 2004-09-30	added received port != via port test (andrei)
+ *
+ * 2004-10-10   force_socket option introduced (jiri)
+ *
+ * 2005-02-24	Added support for using more than one rtp proxy, in which
+ *		case traffic will be distributed evenly among them. In addition,
+ *		each such proxy can be assigned a weight, which will specify
+ *		which share of the traffic should be placed to this particular
+ *		proxy.
+ *
+ *		Introduce failover mechanism, so that if SER detects that one
+ *		of many proxies is no longer available it temporarily decreases
+ *		its weight to 0, so that no traffic will be assigned to it.
+ *		Such "disabled" proxies are periodically checked to see if they
+ *		are back to normal in which case respective weight is restored
+ *		resulting in traffic being sent to that proxy again.
+ *
+ *		Those features can be enabled by specifying more than one "URI"
+ *		in the rtpproxy_sock parameter, optionally followed by the weight,
+ *		which if absent is assumed to be 1, for example:
+ *
+ *		rtpproxy_sock="unix:/foo/bar=4 udp:1.2.3.4:3456=3 udp:5.6.7.8:5432=1"
+ *
+ * 2005-02-25	Force for pinging the socket returned by USRLOC (bogdan)
+ *
+ * 2005-03-22	support for multiple media streams added (netch)
+ *
+ * 2005-07-11  SIP ping support added (bogdan)
+ *
+ * 2005-07-14  SDP origin (o=) IP may be also changed (bogdan)
+ *
+ * 2006-03-08  fix_nated_sdp() may take one more param to force a specific IP;
+ *             force_rtp_proxy() accepts a new flag 's' to swap creation/
+ *              confirmation between requests/replies;
+ *             add_rcv_param() may take as parameter a flag telling if the
+ *              parameter should go to the contact URI or contact header;
+ *             (bogdan)
+ * 2006-03-28 Support for changing session-level SDP connection (c=) IP when
+ *            media-description also includes connection information (bayan)
+ * 2007-04-13 Support multiple sets of rtpproxies and set selection added
+ *            (ancuta)
+ * 2007-04-26 Added some MI commands:
+ *             nh_enable_ping used to enable or disable natping
+ *             nh_enable_rtpp used to enable or disable a specific rtp proxy
+ *             nh_show_rtpp   used to display information for all rtp proxies
+ *             (ancuta)
+ * 2007-05-09 New function start_recording() allowing to start recording RTP
+ *             session in the RTP proxy (Carsten Bock - ported from SER)
+ * 2007-09-11 Separate timer process and support for multiple timer processes
+ *             (bogdan)
+ * 2008-12-12 Support for RTCP attribute in the SDP
+ *              (Min Wang/BASIS AudioNet - ported from SER)
+ * 2010-08-05 Core SDP parser integrated into nathelper (osas)
+ * 2010-10-08 Removal of deprecated force_rtp_proxy and swap flag (osas)
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#ifndef __USE_BSD
+#define  __USE_BSD
+#endif
+#include <netinet/ip.h>
+#ifndef __FAVOR_BSD
+#define __FAVOR_BSD
+#endif
+#include <netinet/udp.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../../flags.h"
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../data_lump.h"
+#include "../../data_lump_rpl.h"
+#include "../../error.h"
+#include "../../forward.h"
+#include "../../mem/mem.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/parser_f.h"
+#include "../../parser/sdp/sdp.h"
+#include "../../resolve.h"
+#include "../../timer.h"
+#include "../../trim.h"
+#include "../../ut.h"
+#include "../../pt.h"
+#include "../../timer_proc.h"
+#include "../../lib/kmi/mi.h"
+#include "../../pvar.h"
+#include "../../lvalue.h"
+#include "../../msg_translator.h"
+#include "../../usr_avp.h"
+#include "../../socket_info.h"
+#include "../../mod_fix.h"
+#include "../../dset.h"
+#include "../../route.h"
+#include "../../modules/tm/tm_load.h"
+#include "rtpproxy.h"
+#include "rtpproxy_funcs.h"
+#include "bencode.h"
+
+MODULE_VERSION
+
+#if !defined(AF_LOCAL)
+#define	AF_LOCAL AF_UNIX
+#endif
+#if !defined(PF_LOCAL)
+#define	PF_LOCAL PF_UNIX
+#endif
+
+/* NAT UAC test constants */
+#define	NAT_UAC_TEST_C_1918	0x01
+#define	NAT_UAC_TEST_RCVD	0x02
+#define	NAT_UAC_TEST_V_1918	0x04
+#define	NAT_UAC_TEST_S_1918	0x08
+#define	NAT_UAC_TEST_RPORT	0x10
+
+
+#define DEFAULT_RTPP_SET_ID		0
+
+#define MI_SET_NATPING_STATE		"nh_enable_ping"
+#define MI_DEFAULT_NATPING_STATE	1
+
+#define MI_ENABLE_RTP_PROXY			"nh_enable_rtpp"
+#define MI_MIN_RECHECK_TICKS		0
+#define MI_MAX_RECHECK_TICKS		(unsigned int)-1
+
+#define MI_SHOW_RTP_PROXIES			"nh_show_rtpp"
+
+#define MI_RTP_PROXY_NOT_FOUND		"RTP proxy not found"
+#define MI_RTP_PROXY_NOT_FOUND_LEN	(sizeof(MI_RTP_PROXY_NOT_FOUND)-1)
+#define MI_PING_DISABLED			"NATping disabled from script"
+#define MI_PING_DISABLED_LEN		(sizeof(MI_PING_DISABLED)-1)
+#define MI_SET						"set"
+#define MI_SET_LEN					(sizeof(MI_SET)-1)
+#define MI_INDEX					"index"
+#define MI_INDEX_LEN				(sizeof(MI_INDEX)-1)
+#define MI_DISABLED					"disabled"
+#define MI_DISABLED_LEN				(sizeof(MI_DISABLED)-1)
+#define MI_WEIGHT					"weight"
+#define MI_WEIGHT_LEN				(sizeof(MI_WEIGHT)-1)
+#define MI_RECHECK_TICKS			"recheck_ticks"
+#define MI_RECHECK_T_LEN			(sizeof(MI_RECHECK_TICKS)-1)
+
+
+
+/* Supported version of the RTP proxy command protocol */
+#define	SUP_CPROTOVER	20040107
+/* Required additional version of the RTP proxy command protocol */
+#define	REQ_CPROTOVER	"20050322"
+/* Additional version necessary for re-packetization support */
+#define	REP_CPROTOVER	"20071116"
+#define	PTL_CPROTOVER	"20081102"
+
+#define	CPORT		"22222"
+
+enum rtpp_operation {
+	OP_OFFER = 1,
+	OP_ANSWER,
+	OP_DELETE,
+	OP_START_RECORDING,
+	OP_QUERY,
+};
+
+static const char *command_strings[] = {
+	[OP_OFFER]		= "offer",
+	[OP_ANSWER]		= "answer",
+	[OP_DELETE]		= "delete",
+	[OP_START_RECORDING]	= "start recording",
+	[OP_QUERY]		= "query",
+};
+
+static char *gencookie();
+static int rtpp_test(struct rtpp_node*, int, int);
+static int unforce_rtp_proxy_f(struct sip_msg *, const char *, char *);
+static int unforce_rtp_proxy1_f(struct sip_msg *, char *, char *);
+static int force_rtp_proxy(struct sip_msg *, const char *, const str *, int);
+static int start_recording_f(struct sip_msg *, char *, char *);
+static int rtpproxy_answer1_f(struct sip_msg *, char *, char *);
+static int rtpproxy_answer2_f(struct sip_msg *, char *, char *);
+static int rtpproxy_offer1_f(struct sip_msg *, char *, char *);
+static int rtpproxy_offer2_f(struct sip_msg *, char *, char *);
+static int rtpproxy_manage0(struct sip_msg *msg, char *flags, char *ip);
+static int rtpproxy_manage1(struct sip_msg *msg, char *flags, char *ip);
+static int rtpproxy_manage2(struct sip_msg *msg, char *flags, char *ip);
+
+static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, char * rtpproxy);
+static int fixup_set_id(void ** param, int param_no);
+static int set_rtp_proxy_set_f(struct sip_msg * msg, char * str1, char * str2);
+static struct rtpp_set * select_rtpp_set(int id_set);
+static struct rtpp_node *select_rtpp_node(str, int);
+static char *send_rtpp_command(struct rtpp_node *, bencode_item_t *, int *);
+static int get_extra_id(struct sip_msg* msg, str *id_str);
+
+static int rtpproxy_set_store(modparam_t type, void * val);
+static int rtpproxy_add_rtpproxy_set( char * rtp_proxies);
+
+static int mod_init(void);
+static int child_init(int);
+static void mod_destroy(void);
+
+/* Pseudo-Variables */
+static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *);
+
+/*mi commands*/
+static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree,
+		void* param );
+static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree,
+		void* param);
+
+
+static int rtpproxy_disable_tout = 60;
+static int rtpproxy_retr = 5;
+static int rtpproxy_tout = 1;
+static pid_t mypid;
+static unsigned int myseqn = 0;
+static str extra_id_pv_param = {NULL, 0};
+
+static char ** rtpp_strings=0;
+static int rtpp_sets=0; /*used in rtpproxy_set_store()*/
+static int rtpp_set_count = 0;
+static unsigned int current_msg_id = (unsigned int)-1;
+/* RTP proxy balancing list */
+struct rtpp_set_head * rtpp_set_list =0;
+struct rtpp_set * selected_rtpp_set =0;
+struct rtpp_set * default_rtpp_set=0;
+
+/* array with the sockets used by rtpporxy (per process)*/
+static unsigned int rtpp_no = 0;
+static int *rtpp_socks = 0;
+
+
+typedef struct rtpp_set_link {
+	struct rtpp_set *rset;
+	pv_spec_t *rpv;
+} rtpp_set_link_t;
+
+/* tm */
+static struct tm_binds tmb;
+
+/*0-> disabled, 1 ->enabled*/
+unsigned int *natping_state=0;
+
+#if 0
+static str timeout_socket_str = {0, 0};
+#endif
+static pv_elem_t *extra_id_pv = NULL;
+
+static cmd_export_t cmds[] = {
+	{"set_rtp_proxy_set",  (cmd_function)set_rtp_proxy_set_f,    1,
+		fixup_set_id, 0,
+		ANY_ROUTE},
+	{"unforce_rtp_proxy",  (cmd_function)unforce_rtp_proxy_f,    0,
+		0, 0,
+		ANY_ROUTE},
+	{"rtpproxy_destroy",   (cmd_function)unforce_rtp_proxy_f,    0,
+		0, 0,
+		ANY_ROUTE},
+	{"unforce_rtp_proxy",  (cmd_function)unforce_rtp_proxy1_f,    1,
+		fixup_spve_null, 0,
+		ANY_ROUTE},
+	{"rtpproxy_destroy",   (cmd_function)unforce_rtp_proxy1_f,    1,
+		fixup_spve_null, 0,
+		ANY_ROUTE},
+	{"start_recording",    (cmd_function)start_recording_f,      0,
+		0, 0,
+		ANY_ROUTE },
+	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer1_f,     0,
+		0, 0,
+		ANY_ROUTE},
+	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer1_f,     1,
+		fixup_spve_null, 0,
+		ANY_ROUTE},
+	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer2_f,     2,
+		fixup_spve_spve, 0,
+		ANY_ROUTE},
+	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer1_f,    0,
+		0, 0,
+		ANY_ROUTE},
+	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer1_f,    1,
+		fixup_spve_null, 0,
+		ANY_ROUTE},
+	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer2_f,    2,
+		fixup_spve_spve, 0,
+		ANY_ROUTE},
+#if 0
+	{"rtpproxy_stream2uac",(cmd_function)rtpproxy_stream2uac2_f, 2,
+		fixup_var_str_int, 0,
+		ANY_ROUTE },
+	{"rtpproxy_stream2uas",(cmd_function)rtpproxy_stream2uas2_f, 2,
+		fixup_var_str_int, 0,
+		ANY_ROUTE },
+	{"rtpproxy_stop_stream2uac",(cmd_function)rtpproxy_stop_stream2uac2_f,0,
+		NULL, 0,
+		ANY_ROUTE },
+	{"rtpproxy_stop_stream2uas",(cmd_function)rtpproxy_stop_stream2uas2_f,0,
+		NULL, 0,
+		ANY_ROUTE },
+#endif
+	{"rtpproxy_manage",	(cmd_function)rtpproxy_manage0,     0,
+		0, 0,
+		ANY_ROUTE},
+	{"rtpproxy_manage",	(cmd_function)rtpproxy_manage1,     1,
+		fixup_spve_null, fixup_free_spve_null,
+		ANY_ROUTE},
+	{"rtpproxy_manage",	(cmd_function)rtpproxy_manage2,     2,
+		fixup_spve_spve, fixup_free_spve_spve,
+		ANY_ROUTE},
+	{0, 0, 0, 0, 0, 0}
+};
+
+static pv_export_t mod_pvs[] = {
+    {{"rtpstat", (sizeof("rtpstat")-1)}, /* RTP-Statistics */
+     PVT_OTHER, pv_get_rtpstat_f, 0, 0, 0, 0, 0},
+    {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[] = {
+	{"rtpproxy_sock",         STR_PARAM|USE_FUNC_PARAM,
+	                         (void*)rtpproxy_set_store          },
+	{"rtpproxy_disable_tout", INT_PARAM, &rtpproxy_disable_tout },
+	{"rtpproxy_retr",         INT_PARAM, &rtpproxy_retr         },
+	{"rtpproxy_tout",         INT_PARAM, &rtpproxy_tout         },
+#if 0
+	{"timeout_socket",    	  STR_PARAM, &timeout_socket_str.s  },
+#endif
+	{"extra_id_pv",           STR_PARAM, &extra_id_pv_param.s },
+	{0, 0, 0}
+};
+
+static mi_export_t mi_cmds[] = {
+	{MI_ENABLE_RTP_PROXY,     mi_enable_rtp_proxy,  0,                0, 0},
+	{MI_SHOW_RTP_PROXIES,     mi_show_rtpproxies,   MI_NO_INPUT_FLAG, 0, 0},
+	{ 0, 0, 0, 0, 0}
+};
+
+
+struct module_exports exports = {
+	"rtpproxy-ng",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,           /* exported statistics */
+	mi_cmds,     /* exported MI functions */
+	mod_pvs,     /* exported pseudo-variables */
+	0,           /* extra processes */
+	mod_init,
+	0,           /* reply processing */
+	mod_destroy, /* destroy function */
+	child_init
+};
+
+
+static int rtpproxy_set_store(modparam_t type, void * val){
+
+	char * p;
+	int len;
+
+	p = (char* )val;
+
+	if(p==0 || *p=='\0'){
+		return 0;
+	}
+
+	if(rtpp_sets==0){
+		rtpp_strings = (char**)pkg_malloc(sizeof(char*));
+		if(!rtpp_strings){
+			LM_ERR("no pkg memory left\n");
+			return -1;
+		}
+	} else {/*realloc to make room for the current set*/
+		rtpp_strings = (char**)pkg_realloc(rtpp_strings,
+										  (rtpp_sets+1)* sizeof(char*));
+		if(!rtpp_strings){
+			LM_ERR("no pkg memory left\n");
+			return -1;
+		}
+	}
+
+	/*allocate for the current set of urls*/
+	len = strlen(p);
+	rtpp_strings[rtpp_sets] = (char*)pkg_malloc((len+1)*sizeof(char));
+
+	if(!rtpp_strings[rtpp_sets]){
+		LM_ERR("no pkg memory left\n");
+		return -1;
+	}
+
+	memcpy(rtpp_strings[rtpp_sets], p, len);
+	rtpp_strings[rtpp_sets][len] = '\0';
+	rtpp_sets++;
+
+	return 0;
+}
+
+
+static int add_rtpproxy_socks(struct rtpp_set * rtpp_list,
+										char * rtpproxy){
+	/* Make rtp proxies list. */
+	char *p, *p1, *p2, *plim;
+	struct rtpp_node *pnode;
+	int weight;
+
+	p = rtpproxy;
+	plim = p + strlen(p);
+
+	for(;;) {
+			weight = 1;
+		while (*p && isspace((int)*p))
+			++p;
+		if (p >= plim)
+			break;
+		p1 = p;
+		while (*p && !isspace((int)*p))
+			++p;
+		if (p <= p1)
+			break; /* may happen??? */
+		/* Have weight specified? If yes, scan it */
+		p2 = memchr(p1, '=', p - p1);
+		if (p2 != NULL) {
+			weight = strtoul(p2 + 1, NULL, 10);
+		} else {
+			p2 = p;
+		}
+		pnode = shm_malloc(sizeof(struct rtpp_node));
+		if (pnode == NULL) {
+			LM_ERR("no shm memory left\n");
+			return -1;
+		}
+		memset(pnode, 0, sizeof(*pnode));
+		pnode->idx = rtpp_no++;
+		pnode->rn_recheck_ticks = 0;
+		pnode->rn_weight = weight;
+		pnode->rn_umode = 0;
+		pnode->rn_disabled = 0;
+		pnode->rn_url.s = shm_malloc(p2 - p1 + 1);
+		if (pnode->rn_url.s == NULL) {
+			shm_free(pnode);
+			LM_ERR("no shm memory left\n");
+			return -1;
+		}
+		memmove(pnode->rn_url.s, p1, p2 - p1);
+		pnode->rn_url.s[p2 - p1] 	= 0;
+		pnode->rn_url.len 			= p2-p1;
+
+		LM_DBG("url is %s, len is %i\n", pnode->rn_url.s, pnode->rn_url.len);
+		/* Leave only address in rn_address */
+		pnode->rn_address = pnode->rn_url.s;
+		if (strncasecmp(pnode->rn_address, "udp:", 4) == 0) {
+			pnode->rn_umode = 1;
+			pnode->rn_address += 4;
+		} else if (strncasecmp(pnode->rn_address, "udp6:", 5) == 0) {
+			pnode->rn_umode = 6;
+			pnode->rn_address += 5;
+		} else if (strncasecmp(pnode->rn_address, "unix:", 5) == 0) {
+			pnode->rn_umode = 0;
+			pnode->rn_address += 5;
+		}
+
+		if (rtpp_list->rn_first == NULL) {
+			rtpp_list->rn_first = pnode;
+		} else {
+			rtpp_list->rn_last->rn_next = pnode;
+		}
+
+		rtpp_list->rn_last = pnode;
+		rtpp_list->rtpp_node_count++;
+	}
+	return 0;
+}
+
+
+/*	0-succes
+ *  -1 - erorr
+ * */
+static int rtpproxy_add_rtpproxy_set( char * rtp_proxies)
+{
+	char *p,*p2;
+	struct rtpp_set * rtpp_list;
+	unsigned int my_current_id;
+	str id_set;
+	int new_list;
+
+	/* empty definition? */
+	p= rtp_proxies;
+	if(!p || *p=='\0'){
+		return 0;
+	}
+
+	for(;*p && isspace(*p);p++);
+	if(*p=='\0'){
+		return 0;
+	}
+
+	rtp_proxies = strstr(p, "==");
+	if(rtp_proxies){
+		if(*(rtp_proxies +2)=='\0'){
+			LM_ERR("script error -invalid rtp proxy list!\n");
+			return -1;
+		}
+
+		*rtp_proxies = '\0';
+		p2 = rtp_proxies-1;
+		for(;isspace(*p2); *p2 = '\0',p2--);
+		id_set.s = p;	id_set.len = p2 - p+1;
+
+		if(id_set.len <= 0 ||str2int(&id_set, &my_current_id)<0 ){
+		LM_ERR("script error -invalid set_id value!\n");
+			return -1;
+		}
+
+		rtp_proxies+=2;
+	}else{
+		rtp_proxies = p;
+		my_current_id = DEFAULT_RTPP_SET_ID;
+	}
+
+	for(;*rtp_proxies && isspace(*rtp_proxies);rtp_proxies++);
+
+	if(!(*rtp_proxies)){
+		LM_ERR("script error -empty rtp_proxy list\n");
+		return -1;;
+	}
+
+	/*search for the current_id*/
+	rtpp_list = rtpp_set_list ? rtpp_set_list->rset_first : 0;
+	while( rtpp_list != 0 && rtpp_list->id_set!=my_current_id)
+		rtpp_list = rtpp_list->rset_next;
+
+	if(rtpp_list==NULL){	/*if a new id_set : add a new set of rtpp*/
+		rtpp_list = shm_malloc(sizeof(struct rtpp_set));
+		if(!rtpp_list){
+			LM_ERR("no shm memory left\n");
+			return -1;
+		}
+		memset(rtpp_list, 0, sizeof(struct rtpp_set));
+		rtpp_list->id_set = my_current_id;
+		new_list = 1;
+	} else {
+		new_list = 0;
+	}
+
+	if(add_rtpproxy_socks(rtpp_list, rtp_proxies)!= 0){
+		/*if this list will not be inserted, clean it up*/
+		goto error;
+	}
+
+	if (new_list) {
+		if(!rtpp_set_list){/*initialize the list of set*/
+			rtpp_set_list = shm_malloc(sizeof(struct rtpp_set_head));
+			if(!rtpp_set_list){
+				LM_ERR("no shm memory left\n");
+				return -1;
+			}
+			memset(rtpp_set_list, 0, sizeof(struct rtpp_set_head));
+		}
+
+		/*update the list of set info*/
+		if(!rtpp_set_list->rset_first){
+			rtpp_set_list->rset_first = rtpp_list;
+		}else{
+			rtpp_set_list->rset_last->rset_next = rtpp_list;
+		}
+
+		rtpp_set_list->rset_last = rtpp_list;
+		rtpp_set_count++;
+
+		if(my_current_id == DEFAULT_RTPP_SET_ID){
+			default_rtpp_set = rtpp_list;
+		}
+	}
+
+	return 0;
+error:
+	return -1;
+}
+
+
+static int fixup_set_id(void ** param, int param_no)
+{
+	int int_val, err;
+	struct rtpp_set* rtpp_list;
+	rtpp_set_link_t *rtpl = NULL;
+	str s;
+
+	rtpl = (rtpp_set_link_t*)pkg_malloc(sizeof(rtpp_set_link_t));
+	if(rtpl==NULL) {
+		LM_ERR("no more pkg memory\n");
+		return -1;
+	}
+	memset(rtpl, 0, sizeof(rtpp_set_link_t));
+	s.s = (char*)*param;
+	s.len = strlen(s.s);
+
+	if(s.s[0] == PV_MARKER) {
+		int_val = pv_locate_name(&s);
+		if(int_val<0 || int_val!=s.len) {
+			LM_ERR("invalid parameter %s\n", s.s);
+			return -1;
+		}
+		rtpl->rpv = pv_cache_get(&s);
+		if(rtpl->rpv == NULL) {
+			LM_ERR("invalid pv parameter %s\n", s.s);
+			return -1;
+		}
+	} else {
+		int_val = str2s(*param, strlen(*param), &err);
+		if (err == 0) {
+			pkg_free(*param);
+			if((rtpp_list = select_rtpp_set(int_val)) ==0){
+				LM_ERR("rtpp_proxy set %i not configured\n", int_val);
+				return E_CFG;
+			}
+			rtpl->rset = rtpp_list;
+		} else {
+			LM_ERR("bad number <%s>\n",	(char *)(*param));
+			return E_CFG;
+		}
+	}
+	*param = (void*)rtpl;
+	return 0;
+}
+
+static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree,
+												void* param )
+{	struct mi_node* node;
+	str rtpp_url;
+	unsigned int enable;
+	struct rtpp_set * rtpp_list;
+	struct rtpp_node * crt_rtpp;
+	int found;
+
+	found = 0;
+
+	if(rtpp_set_list ==NULL)
+		goto end;
+
+	node = cmd_tree->node.kids;
+	if(node == NULL)
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+
+	if(node->value.s == NULL || node->value.len ==0)
+		return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+
+	rtpp_url = node->value;
+
+	node = node->next;
+	if(node == NULL)
+		return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+
+	enable = 0;
+	if( strno2int( &node->value, &enable) <0)
+		goto error;
+
+	for(rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL;
+					rtpp_list = rtpp_list->rset_next){
+
+		for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL;
+						crt_rtpp = crt_rtpp->rn_next){
+			/*found a matching rtpp*/
+
+			if(crt_rtpp->rn_url.len == rtpp_url.len){
+
+				if(strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0){
+					/*set the enabled/disabled status*/
+					found = 1;
+					crt_rtpp->rn_recheck_ticks =
+						enable? MI_MIN_RECHECK_TICKS : MI_MAX_RECHECK_TICKS;
+					crt_rtpp->rn_disabled = enable?0:1;
+				}
+			}
+		}
+	}
+
+end:
+	if(found)
+		return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+	return init_mi_tree(404,MI_RTP_PROXY_NOT_FOUND,MI_RTP_PROXY_NOT_FOUND_LEN);
+error:
+	return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
+}
+
+
+
+#define add_rtpp_node_int_info(_parent, _name, _name_len, _value, _child,\
+								_len, _string, _error)\
+	do {\
+		(_string) = int2str((_value), &(_len));\
+		if((_string) == 0){\
+			LM_ERR("cannot convert int value\n");\
+				goto _error;\
+		}\
+		if(((_child) = add_mi_node_child((_parent), MI_DUP_VALUE, (_name), \
+				(_name_len), (_string), (_len))   ) == 0)\
+			goto _error;\
+	}while(0);
+
+static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree,
+												void* param)
+{
+	struct mi_node* node, *crt_node, *child;
+	struct mi_root* root;
+	struct mi_attr * attr;
+	struct rtpp_set * rtpp_list;
+	struct rtpp_node * crt_rtpp;
+	char * string, *id;
+	int id_len, len;
+
+	string = id = 0;
+
+	root = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+	if (!root) {
+		LM_ERR("the MI tree cannot be initialized!\n");
+		return 0;
+	}
+
+	if(rtpp_set_list ==NULL)
+		return root;
+
+	node = &root->node;
+
+	for(rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL;
+					rtpp_list = rtpp_list->rset_next){
+
+		for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL;
+						crt_rtpp = crt_rtpp->rn_next){
+
+			id =  int2str(rtpp_list->id_set, &id_len);
+			if(!id){
+				LM_ERR("cannot convert set id\n");
+				goto error;
+			}
+
+			if(!(crt_node = add_mi_node_child(node, 0, crt_rtpp->rn_url.s,
+					crt_rtpp->rn_url.len, 0,0)) ) {
+				LM_ERR("cannot add the child node to the tree\n");
+				goto error;
+			}
+
+			LM_DBG("adding node name %s \n",crt_rtpp->rn_url.s );
+
+			if((attr = add_mi_attr(crt_node, MI_DUP_VALUE, MI_SET, MI_SET_LEN,
+									id, id_len))== 0){
+				LM_ERR("cannot add attributes to the node\n");
+				goto error;
+			}
+
+			add_rtpp_node_int_info(crt_node, MI_INDEX, MI_INDEX_LEN,
+				crt_rtpp->idx, child, len,string,error);
+			add_rtpp_node_int_info(crt_node, MI_DISABLED, MI_DISABLED_LEN,
+				crt_rtpp->rn_disabled, child, len,string,error);
+			add_rtpp_node_int_info(crt_node, MI_WEIGHT, MI_WEIGHT_LEN,
+				crt_rtpp->rn_weight,  child, len, string,error);
+			add_rtpp_node_int_info(crt_node, MI_RECHECK_TICKS,MI_RECHECK_T_LEN,
+				crt_rtpp->rn_recheck_ticks, child, len, string, error);
+		}
+	}
+
+	return root;
+error:
+	if (root)
+		free_mi_tree(root);
+	return 0;
+}
+
+
+static int
+mod_init(void)
+{
+	int i;
+
+	if(register_mi_mod(exports.name, mi_cmds)!=0)
+	{
+		LM_ERR("failed to register MI commands\n");
+		return -1;
+	}
+
+	/* any rtpproxy configured? */
+	if(rtpp_set_list)
+		default_rtpp_set = select_rtpp_set(DEFAULT_RTPP_SET_ID);
+
+	/* storing the list of rtp proxy sets in shared memory*/
+	for(i=0;i<rtpp_sets;i++){
+		if(rtpproxy_add_rtpproxy_set(rtpp_strings[i]) !=0){
+			for(;i<rtpp_sets;i++)
+				if(rtpp_strings[i])
+					pkg_free(rtpp_strings[i]);
+			pkg_free(rtpp_strings);
+			return -1;
+		}
+		if(rtpp_strings[i])
+			pkg_free(rtpp_strings[i]);
+	}
+#if 0
+	if (timeout_socket_str.s==NULL || timeout_socket_str.s[0]==0) {
+		timeout_socket_str.len = 0;
+		timeout_socket_str.s = NULL;
+	} else {
+		timeout_socket_str.len = strlen(timeout_socket_str.s);
+	}
+#endif
+
+	if (extra_id_pv_param.s && *extra_id_pv_param.s) {
+		extra_id_pv_param.len = strlen(extra_id_pv_param.s);
+		if(pv_parse_format(&extra_id_pv_param, &extra_id_pv) < 0) {
+			LM_ERR("malformed PV string: %s\n", extra_id_pv_param.s);
+			return -1;
+		}
+	} else {
+		extra_id_pv = NULL;
+	}
+
+	if (rtpp_strings)
+		pkg_free(rtpp_strings);
+
+	if (load_tm_api( &tmb ) < 0)
+	{
+		LM_DBG("could not load the TM-functions - answer-offer model"
+				" auto-detection is disabled\n");
+		memset(&tmb, 0, sizeof(struct tm_binds));
+	}
+
+	return 0;
+}
+
+
+static int
+child_init(int rank)
+{
+	int n;
+	char *cp;
+	struct addrinfo hints, *res;
+	struct rtpp_set  *rtpp_list;
+	struct rtpp_node *pnode;
+
+	if(rtpp_set_list==NULL )
+		return 0;
+
+	/* Iterate known RTP proxies - create sockets */
+	mypid = getpid();
+
+	rtpp_socks = (int*)pkg_malloc( sizeof(int)*rtpp_no );
+	if (rtpp_socks==NULL) {
+		LM_ERR("no more pkg memory\n");
+		return -1;
+	}
+
+	for(rtpp_list = rtpp_set_list->rset_first; rtpp_list != 0;
+		rtpp_list = rtpp_list->rset_next){
+
+		for (pnode=rtpp_list->rn_first; pnode!=0; pnode = pnode->rn_next){
+			char *hostname;
+
+			if (pnode->rn_umode == 0) {
+				rtpp_socks[pnode->idx] = -1;
+				goto rptest;
+			}
+
+			/*
+			 * This is UDP or UDP6. Detect host and port; lookup host;
+			 * do connect() in order to specify peer address
+			 */
+			hostname = (char*)pkg_malloc(sizeof(char) * (strlen(pnode->rn_address) + 1));
+			if (hostname==NULL) {
+				LM_ERR("no more pkg memory\n");
+				return -1;
+			}
+			strcpy(hostname, pnode->rn_address);
+
+			cp = strrchr(hostname, ':');
+			if (cp != NULL) {
+				*cp = '\0';
+				cp++;
+			}
+			if (cp == NULL || *cp == '\0')
+				cp = CPORT;
+
+			memset(&hints, 0, sizeof(hints));
+			hints.ai_flags = 0;
+			hints.ai_family = (pnode->rn_umode == 6) ? AF_INET6 : AF_INET;
+			hints.ai_socktype = SOCK_DGRAM;
+			if ((n = getaddrinfo(hostname, cp, &hints, &res)) != 0) {
+				LM_ERR("%s\n", gai_strerror(n));
+				pkg_free(hostname);
+				return -1;
+			}
+			pkg_free(hostname);
+
+			rtpp_socks[pnode->idx] = socket((pnode->rn_umode == 6)
+			    ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
+			if ( rtpp_socks[pnode->idx] == -1) {
+				LM_ERR("can't create socket\n");
+				freeaddrinfo(res);
+				return -1;
+			}
+
+			if (connect( rtpp_socks[pnode->idx], res->ai_addr, res->ai_addrlen) == -1) {
+				LM_ERR("can't connect to a RTP proxy\n");
+				close( rtpp_socks[pnode->idx] );
+				rtpp_socks[pnode->idx] = -1;
+				freeaddrinfo(res);
+				return -1;
+			}
+			freeaddrinfo(res);
+rptest:
+			pnode->rn_disabled = rtpp_test(pnode, 0, 1);
+		}
+	}
+
+	return 0;
+}
+
+
+static void mod_destroy(void)
+{
+	struct rtpp_set * crt_list, * last_list;
+	struct rtpp_node * crt_rtpp, *last_rtpp;
+
+	/*free the shared memory*/
+	if (natping_state)
+		shm_free(natping_state);
+
+	if(rtpp_set_list == NULL)
+		return;
+
+	for(crt_list = rtpp_set_list->rset_first; crt_list != NULL; ){
+
+		for(crt_rtpp = crt_list->rn_first; crt_rtpp != NULL;  ){
+
+			if(crt_rtpp->rn_url.s)
+				shm_free(crt_rtpp->rn_url.s);
+
+			last_rtpp = crt_rtpp;
+			crt_rtpp = last_rtpp->rn_next;
+			shm_free(last_rtpp);
+		}
+
+		last_list = crt_list;
+		crt_list = last_list->rset_next;
+		shm_free(last_list);
+	}
+
+	shm_free(rtpp_set_list);
+}
+
+
+
+static char * gencookie(void)
+{
+	static char cook[34];
+
+	sprintf(cook, "%d_%u ", (int)mypid, myseqn);
+	myseqn++;
+	return cook;
+}
+
+
+
+static const char *transports[] = {
+	[0x00]	= "RTP/AVP",
+	[0x01]	= "RTP/SAVP",
+	[0x02]	= "RTP/AVPF",
+	[0x03]	= "RTP/SAVPF",
+};
+
+static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_msg *msg,
+	enum rtpp_operation op, const char *flags_str, const str *force_addr, str *body_out)
+{
+	bencode_item_t *dict, *flags, *direction, *replace, *item;
+	str callid, from_tag, to_tag, body, viabranch, error;
+	int via, to, ret, packetize, transport;
+	struct rtpp_node *node;
+	char *cp;
+
+	/*** get & init basic stuff needed ***/
+
+	if (get_callid(msg, &callid) == -1 || callid.len == 0) {
+		LM_ERR("can't get Call-Id field\n");
+		return NULL;
+	}
+	if (get_to_tag(msg, &to_tag) == -1) {
+		LM_ERR("can't get To tag\n");
+		return NULL;
+	}
+	if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
+		LM_ERR("can't get From tag\n");
+		return NULL;
+	}
+	if (bencode_buffer_init(bencbuf)) {
+		LM_ERR("could not initialized bencode_buffer_t\n");
+		return NULL;
+	}
+	dict = bencode_dictionary(bencbuf);
+
+	flags = direction = replace = NULL;
+	if (op == OP_OFFER || op == OP_ANSWER) {
+		flags = bencode_list(bencbuf);
+		direction = bencode_list(bencbuf);
+		replace = bencode_list(bencbuf);
+
+		if (extract_body(msg, &body) == -1) {
+			LM_ERR("can't extract body from the message\n");
+			goto error;
+		}
+		bencode_dictionary_add_str(dict, "sdp", &body);
+	}
+
+	/*** parse flags & build dictionary ***/
+
+	via = 0;
+	to = (op == OP_DELETE) ? 0 : 1;
+	transport = 0;
+
+	for (; flags_str && *flags_str; flags_str++) {
+		switch (*flags_str) {
+		case '1':
+		case '2':
+			via = *flags_str - '0';
+			break;
+
+		case '3':
+			if(msg && msg->first_line.type == SIP_REPLY)
+				via = 2;
+			else
+				via = 1;
+			break;
+
+		case 'b':
+		case 'B':
+			via = -1;
+			break;
+
+		case 'a':
+		case 'A':
+			bencode_list_add_string(flags, "asymmetric");
+			bencode_list_add_string(flags, "trust-address");
+			break;
+
+		case 'i':
+		case 'I':
+			bencode_list_add_string(direction, "internal");
+			break;
+
+		case 'e':
+		case 'E':
+			bencode_list_add_string(direction, "external");
+			break;
+
+		case 'l':
+		case 'L':
+			if (op != OP_OFFER) {
+				LM_ERR("Cannot force answer in non-offer command\n");
+				goto error;
+			}
+			op = OP_ANSWER;
+			break;
+
+		case 'r':
+		case 'R':
+			bencode_list_add_string(flags, "trust-address");
+			break;
+
+		case 'o':
+		case 'O':
+			bencode_list_add_string(replace, "origin");
+			break;
+
+		case 'c':
+		case 'C':
+			bencode_list_add_string(replace, "session-connection");
+			break;
+
+		case 'f':
+		case 'F':
+			bencode_list_add_string(flags, "force");
+			break;
+
+		case 'w':
+		case 'W':
+			bencode_list_add_string(flags, "symmetric");
+			break;
+
+		case 'x':
+		case 'X':
+			bencode_list_add_string(flags, "auto-bridge");
+			break;
+
+		case 't':
+		case 'T':
+			to = 1;
+			break;
+
+		case 'z':
+		case 'Z':
+			packetize = 0;
+			flags_str++;
+			while (isdigit(*flags_str)) {
+				packetize *= 10;
+				packetize += *flags_str - '0';
+				flags_str++;
+			}
+			if (packetize)
+				bencode_dictionary_add_integer(dict, "repacketize", packetize);
+			break;
+
+		case '-':
+			bencode_dictionary_add_string(dict, "ICE", "remove");
+			break;
+
+		case '+':
+			bencode_dictionary_add_string(dict, "ICE", "force");
+			break;
+
+		case 's':
+			transport |= 0x100;
+			transport &= ~0x001;
+			break;
+		case 'S':
+			transport |= 0x101;
+			break;
+		case 'p':
+			transport |= 0x100;
+			transport &= ~0x002;
+			break;
+		case 'P':
+			transport |= 0x102;
+			break;
+
+		default:
+			LM_ERR("unknown option `%c'\n", *flags_str);
+			goto error;
+		}
+	}
+
+	/* only add those if any flags were given at all */
+	if (direction && direction->child)
+		bencode_dictionary_add(dict, "direction", direction);
+	if (flags && flags->child)
+		bencode_dictionary_add(dict, "flags", flags);
+	if (replace && replace->child)
+		bencode_dictionary_add(dict, "replace", replace);
+	if ((transport & 0x100))
+		bencode_dictionary_add_string(dict, "transport-protocol", transports[transport & 0x003]);
+
+	bencode_dictionary_add_str(dict, "call-id", &callid);
+
+	if (via) {
+		if (via == 1 || via == 2)
+			ret = get_via_branch(msg, via, &viabranch);
+		else if (via == -1 && extra_id_pv)
+			ret = get_extra_id(msg, &viabranch);
+		else
+			ret = -1;
+		if (ret == -1 || viabranch.len == 0) {
+			LM_ERR("can't get Via branch/extra ID\n");
+			goto error;
+		}
+		bencode_dictionary_add_str(dict, "via-branch", &viabranch);
+	}
+
+	item = bencode_list(bencbuf);
+	bencode_dictionary_add(dict, "received-from", item);
+	bencode_list_add_string(item, (msg->rcv.src_ip.af == AF_INET) ? "IP4" : (
+		(msg->rcv.src_ip.af == AF_INET6) ? "IP6" :
+		"?"
+	) );
+	bencode_list_add_string(item, ip_addr2a(&msg->rcv.src_ip));
+
+	if (force_addr && force_addr->len)
+		bencode_dictionary_add_str(dict, "media address", force_addr);
+
+	if ((msg->first_line.type == SIP_REQUEST && op != OP_ANSWER)
+		|| (msg->first_line.type == SIP_REPLY && op == OP_ANSWER))
+	{
+		bencode_dictionary_add_str(dict, "from-tag", &from_tag);
+		if (to && to_tag.s && to_tag.len)
+			bencode_dictionary_add_str(dict, "to-tag", &to_tag);
+	}
+	else {
+		if (!to_tag.s || !to_tag.len) {
+			LM_ERR("No to-tag present\n");
+			goto error;
+		}
+		bencode_dictionary_add_str(dict, "from-tag", &to_tag);
+		bencode_dictionary_add_str(dict, "to-tag", &from_tag);
+	}
+
+	bencode_dictionary_add_string(dict, "command", command_strings[op]);
+
+	/*** send it out ***/
+
+	if (bencbuf->error) {
+		LM_ERR("out of memory - bencode failed\n");
+		goto error;
+	}
+
+	if(msg->id != current_msg_id)
+		selected_rtpp_set = default_rtpp_set;
+
+	do {
+		node = select_rtpp_node(callid, 1);
+		if (!node) {
+			LM_ERR("no available proxies\n");
+			goto error;
+		}
+
+		cp = send_rtpp_command(node, dict, &ret);
+	} while (cp == NULL);
+	LM_DBG("proxy reply: %.*s\n", ret, cp);
+
+	/*** process reply ***/
+
+	dict = bencode_decode_expect(bencbuf, cp, ret, BENCODE_DICTIONARY);
+	if (!dict) {
+		LM_ERR("failed to decode bencoded reply from proxy: %.*s\n", ret, cp);
+		goto error;
+	}
+	if (!bencode_dictionary_get_strcmp(dict, "result", "error")) {
+		if (!bencode_dictionary_get_str(dict, "error-reason", &error))
+			LM_ERR("proxy return error but didn't give an error reason: %.*s\n", ret, cp);
+		else
+			LM_ERR("proxy replied with error: %.*s\n", error.len, error.s);
+		goto error;
+	}
+
+	if (body_out)
+		*body_out = body;
+
+	return dict;
+
+error:
+	bencode_buffer_free(bencbuf);
+	return NULL;
+}
+
+static int rtpp_function_call_simple(struct sip_msg *msg, enum rtpp_operation op, const char *flags_str) {
+	bencode_buffer_t bencbuf;
+
+	if (!rtpp_function_call(&bencbuf, msg, op, flags_str, NULL, NULL))
+		return -1;
+
+	bencode_buffer_free(&bencbuf);
+	return 1;
+}
+
+static bencode_item_t *rtpp_function_call_ok(bencode_buffer_t *bencbuf, struct sip_msg *msg,
+		enum rtpp_operation op, const char *flags_str, const str *force_addr, str *body) {
+	bencode_item_t *ret;
+
+	ret = rtpp_function_call(bencbuf, msg, op, flags_str, force_addr, body);
+	if (!ret)
+		return NULL;
+
+	if (bencode_dictionary_get_strcmp(ret, "result", "ok")) {
+		LM_ERR("proxy didn't return \"ok\" result\n");
+		bencode_buffer_free(bencbuf);
+		return NULL;
+	}
+
+	return ret;
+}
+
+
+
+static int
+rtpp_test(struct rtpp_node *node, int isdisabled, int force)
+{
+	bencode_buffer_t bencbuf;
+	bencode_item_t *dict;
+	char *cp;
+	int ret;
+
+	if(node->rn_recheck_ticks == MI_MAX_RECHECK_TICKS){
+	    LM_DBG("rtpp %s disabled for ever\n", node->rn_url.s);
+		return 1;
+	}
+	if (force == 0) {
+		if (isdisabled == 0)
+			return 0;
+		if (node->rn_recheck_ticks > get_ticks())
+			return 1;
+	}
+
+	if (bencode_buffer_init(&bencbuf)) {
+		LM_ERR("could not initialized bencode_buffer_t\n");
+		return 1;
+	}
+	dict = bencode_dictionary(&bencbuf);
+	bencode_dictionary_add_string(dict, "command", "ping");
+	if (bencbuf.error)
+		goto benc_error;
+
+	cp = send_rtpp_command(node, dict, &ret);
+	if (!cp) {
+		LM_ERR("proxy did not respond to ping\n");
+		goto error;
+	}
+
+	dict = bencode_decode_expect(&bencbuf, cp, ret, BENCODE_DICTIONARY);
+	if (!dict || bencode_dictionary_get_strcmp(dict, "result", "pong")) {
+		LM_ERR("proxy responded with invalid response\n");
+		goto error;
+	}
+
+	LM_INFO("rtp proxy <%s> found, support for it %senabled\n",
+	    node->rn_url.s, force == 0 ? "re-" : "");
+
+	bencode_buffer_free(&bencbuf);
+	return 0;
+
+benc_error:
+        LM_ERR("out of memory - bencode failed\n");
+error:
+	bencode_buffer_free(&bencbuf);
+	return 1;
+}
+
+static char *
+send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen)
+{
+	struct sockaddr_un addr;
+	int fd, len, i, vcnt;
+	char *cp;
+	static char buf[4096];
+	struct pollfd fds[1];
+	struct iovec *v;
+
+	v = bencode_iovec(dict, &vcnt, 1, 0);
+	if (!v) {
+		LM_ERR("error converting bencode to iovec\n");
+		return NULL;
+	}
+
+	len = 0;
+	cp = buf;
+	if (node->rn_umode == 0) {
+		memset(&addr, 0, sizeof(addr));
+		addr.sun_family = AF_LOCAL;
+		strncpy(addr.sun_path, node->rn_address,
+		    sizeof(addr.sun_path) - 1);
+#ifdef HAVE_SOCKADDR_SA_LEN
+		addr.sun_len = strlen(addr.sun_path);
+#endif
+
+		fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+		if (fd < 0) {
+			LM_ERR("can't create socket\n");
+			goto badproxy;
+		}
+		if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+			close(fd);
+			LM_ERR("can't connect to RTP proxy\n");
+			goto badproxy;
+		}
+
+		do {
+			len = writev(fd, v + 1, vcnt);
+		} while (len == -1 && errno == EINTR);
+		if (len <= 0) {
+			close(fd);
+			LM_ERR("can't send command to a RTP proxy\n");
+			goto badproxy;
+		}
+		do {
+			len = read(fd, buf, sizeof(buf) - 1);
+		} while (len == -1 && errno == EINTR);
+		close(fd);
+		if (len <= 0) {
+			LM_ERR("can't read reply from a RTP proxy\n");
+			goto badproxy;
+		}
+	} else {
+		fds[0].fd = rtpp_socks[node->idx];
+		fds[0].events = POLLIN;
+		fds[0].revents = 0;
+		/* Drain input buffer */
+		while ((poll(fds, 1, 0) == 1) &&
+		    ((fds[0].revents & POLLIN) != 0)) {
+			recv(rtpp_socks[node->idx], buf, sizeof(buf) - 1, 0);
+			fds[0].revents = 0;
+		}
+		v[0].iov_base = gencookie();
+		v[0].iov_len = strlen(v[0].iov_base);
+		for (i = 0; i < rtpproxy_retr; i++) {
+			do {
+				len = writev(rtpp_socks[node->idx], v, vcnt + 1);
+			} while (len == -1 && (errno == EINTR || errno == ENOBUFS));
+			if (len <= 0) {
+				LM_ERR("can't send command to a RTP proxy\n");
+				goto badproxy;
+			}
+			while ((poll(fds, 1, rtpproxy_tout * 1000) == 1) &&
+			    (fds[0].revents & POLLIN) != 0) {
+				do {
+					len = recv(rtpp_socks[node->idx], buf, sizeof(buf)-1, 0);
+				} while (len == -1 && errno == EINTR);
+				if (len <= 0) {
+					LM_ERR("can't read reply from a RTP proxy\n");
+					goto badproxy;
+				}
+				if (len >= (v[0].iov_len - 1) &&
+				    memcmp(buf, v[0].iov_base, (v[0].iov_len - 1)) == 0) {
+					len -= (v[0].iov_len - 1);
+					cp += (v[0].iov_len - 1);
+					if (len != 0) {
+						len--;
+						cp++;
+					}
+					goto out;
+				}
+				fds[0].revents = 0;
+			}
+		}
+		if (i == rtpproxy_retr) {
+			LM_ERR("timeout waiting reply from a RTP proxy\n");
+			goto badproxy;
+		}
+	}
+
+out:
+	cp[len] = '\0';
+	*outlen = len;
+	return cp;
+badproxy:
+	LM_ERR("proxy <%s> does not respond, disable it\n", node->rn_url.s);
+	node->rn_disabled = 1;
+	node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout;
+
+	return NULL;
+}
+
+/*
+ * select the set with the id_set id
+ */
+
+static struct rtpp_set * select_rtpp_set(int id_set ){
+
+	struct rtpp_set * rtpp_list;
+	/*is it a valid set_id?*/
+
+	if(!rtpp_set_list || !rtpp_set_list->rset_first){
+		LM_ERR("no rtp_proxy configured\n");
+		return 0;
+	}
+
+	for(rtpp_list=rtpp_set_list->rset_first; rtpp_list!=0 &&
+		rtpp_list->id_set!=id_set; rtpp_list=rtpp_list->rset_next);
+	if(!rtpp_list){
+		LM_ERR(" script error-invalid id_set to be selected\n");
+	}
+
+	return rtpp_list;
+}
+/*
+ * Main balancing routine. This does not try to keep the same proxy for
+ * the call if some proxies were disabled or enabled; proxy death considered
+ * too rare. Otherwise we should implement "mature" HA clustering, which is
+ * too expensive here.
+ */
+static struct rtpp_node *
+select_rtpp_node(str callid, int do_test)
+{
+	unsigned sum, sumcut, weight_sum;
+	struct rtpp_node* node;
+	int was_forced;
+
+	if(!selected_rtpp_set){
+		LM_ERR("script error -no valid set selected\n");
+		return NULL;
+	}
+	/* Most popular case: 1 proxy, nothing to calculate */
+	if (selected_rtpp_set->rtpp_node_count == 1) {
+		node = selected_rtpp_set->rn_first;
+		if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks())
+			node->rn_disabled = rtpp_test(node, 1, 0);
+		return node->rn_disabled ? NULL : node;
+	}
+
+	/* XXX Use quick-and-dirty hashing algo */
+	for(sum = 0; callid.len > 0; callid.len--)
+		sum += callid.s[callid.len - 1];
+	sum &= 0xff;
+
+	was_forced = 0;
+retry:
+	weight_sum = 0;
+	for (node=selected_rtpp_set->rn_first; node!=NULL; node=node->rn_next) {
+
+		if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()){
+			/* Try to enable if it's time to try. */
+			node->rn_disabled = rtpp_test(node, 1, 0);
+		}
+		if (!node->rn_disabled)
+			weight_sum += node->rn_weight;
+	}
+	if (weight_sum == 0) {
+		/* No proxies? Force all to be redetected, if not yet */
+		if (was_forced)
+			return NULL;
+		was_forced = 1;
+		for(node=selected_rtpp_set->rn_first; node!=NULL; node=node->rn_next) {
+			node->rn_disabled = rtpp_test(node, 1, 1);
+		}
+		goto retry;
+	}
+	sumcut = sum % weight_sum;
+	/*
+	 * sumcut here lays from 0 to weight_sum-1.
+	 * Scan proxy list and decrease until appropriate proxy is found.
+	 */
+	for (node=selected_rtpp_set->rn_first; node!=NULL; node=node->rn_next) {
+		if (node->rn_disabled)
+			continue;
+		if (sumcut < node->rn_weight)
+			goto found;
+		sumcut -= node->rn_weight;
+	}
+	/* No node list */
+	return NULL;
+found:
+	if (do_test) {
+		node->rn_disabled = rtpp_test(node, node->rn_disabled, 0);
+		if (node->rn_disabled)
+			goto retry;
+	}
+	return node;
+}
+
+static int
+get_extra_id(struct sip_msg* msg, str *id_str) {
+	if(msg==NULL || extra_id_pv==NULL || id_str==NULL) {
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+	if (pv_printf_s(msg, extra_id_pv, id_str)<0) {
+		LM_ERR("cannot print the additional id\n");
+		return -1;
+	}
+
+	return 1;
+
+}
+
+
+
+static int
+unforce_rtp_proxy_f(struct sip_msg* msg, const char* str1, char* str2)
+{
+	return rtpp_function_call_simple(msg, OP_DELETE, str1);
+}
+
+static int
+unforce_rtp_proxy1_f(struct sip_msg* msg, char* str1, char* str2)
+{
+	str flags;
+	get_str_fparam(&flags, msg, (fparam_t *) str1);
+	return rtpp_function_call_simple(msg, OP_DELETE, flags.s);
+}
+
+/* This function assumes p points to a line of requested type. */
+
+static int
+set_rtp_proxy_set_f(struct sip_msg * msg, char * str1, char * str2)
+{
+	rtpp_set_link_t *rtpl;
+	pv_value_t val;
+
+	rtpl = (rtpp_set_link_t*)str1;
+
+	current_msg_id = 0;
+	selected_rtpp_set = 0;
+
+	if(rtpl->rset != NULL) {
+		current_msg_id = msg->id;
+		selected_rtpp_set = rtpl->rset;
+	} else {
+		if(pv_get_spec_value(msg, rtpl->rpv, &val)<0) {
+			LM_ERR("cannot evaluate pv param\n");
+			return -1;
+		}
+		if(!(val.flags & PV_VAL_INT)) {
+			LM_ERR("pv param must hold an integer value\n");
+			return -1;
+		}
+		selected_rtpp_set = select_rtpp_set(val.ri);
+		if(selected_rtpp_set==NULL) {
+			LM_ERR("could not locate rtpproxy set %d\n", val.ri);
+			return -1;
+		}
+		current_msg_id = msg->id;
+	}
+	return 1;
+}
+
+static int
+rtpproxy_manage(struct sip_msg *msg, const char *flags, const str *force_addr)
+{
+	int method;
+	int nosdp;
+
+	if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1)
+				|| (msg->cseq==NULL)))
+	{
+		LM_ERR("no CSEQ header\n");
+		return -1;
+	}
+
+	method = get_cseq(msg)->method_id;
+
+	if(!(method==METHOD_INVITE || method==METHOD_ACK || method==METHOD_CANCEL
+				|| method==METHOD_BYE || method==METHOD_UPDATE))
+		return -1;
+
+	if(method==METHOD_CANCEL || method==METHOD_BYE)
+		return unforce_rtp_proxy_f(msg, flags, 0);
+
+	if(msg->msg_flags & FL_SDP_BODY)
+		nosdp = 0;
+	else
+		nosdp = parse_sdp(msg);
+
+	if(msg->first_line.type == SIP_REQUEST) {
+		if(method==METHOD_ACK && nosdp==0)
+			return force_rtp_proxy(msg, flags, force_addr, OP_ANSWER);
+		if(method==METHOD_UPDATE && nosdp==0)
+			return force_rtp_proxy(msg, flags, force_addr, OP_OFFER);
+		if(method==METHOD_INVITE && nosdp==0) {
+			msg->msg_flags |= FL_SDP_BODY;
+			if(tmb.t_gett!=NULL && tmb.t_gett()!=NULL
+					&& tmb.t_gett()!=T_UNDEFINED)
+				tmb.t_gett()->uas.request->msg_flags |= FL_SDP_BODY;
+			if(route_type==FAILURE_ROUTE)
+				return unforce_rtp_proxy_f(msg, flags, 0);
+			return force_rtp_proxy(msg, flags, force_addr, OP_OFFER);
+		}
+	} else if(msg->first_line.type == SIP_REPLY) {
+		if(msg->first_line.u.reply.statuscode>=300)
+			return unforce_rtp_proxy_f(msg, flags, 0);
+		if(nosdp==0) {
+			if(method==METHOD_UPDATE)
+				return force_rtp_proxy(msg, flags, force_addr, OP_ANSWER);
+			if(tmb.t_gett==NULL || tmb.t_gett()==NULL
+					|| tmb.t_gett()==T_UNDEFINED)
+				return force_rtp_proxy(msg, flags, force_addr, OP_ANSWER);
+			if(tmb.t_gett()->uas.request->msg_flags & FL_SDP_BODY)
+				return force_rtp_proxy(msg, flags, force_addr, OP_ANSWER);
+			return force_rtp_proxy(msg, flags, force_addr, OP_OFFER);
+		}
+	}
+	return -1;
+}
+
+static int
+rtpproxy_manage0(struct sip_msg *msg, char *flags, char *ip)
+{
+	return rtpproxy_manage(msg, 0, 0);
+}
+
+static int
+rtpproxy_manage1(struct sip_msg *msg, char *flags, char *ip)
+{
+	str flag_str;
+	fixup_get_svalue(msg, (gparam_p)flags, &flag_str);
+	return rtpproxy_manage(msg, flag_str.s, 0);
+}
+
+static int
+rtpproxy_manage2(struct sip_msg *msg, char *flags, char *ip)
+{
+	str flag_str;
+	str ip_str;
+	fixup_get_svalue(msg, (gparam_p)flags, &flag_str);
+	fixup_get_svalue(msg, (gparam_p)ip, &ip_str);
+	return rtpproxy_manage(msg, flag_str.s, &ip_str);
+}
+
+static int
+rtpproxy_offer1_f(struct sip_msg *msg, char *str1, char *str2)
+{
+	str flags;
+
+	if (str1)
+		get_str_fparam(&flags, msg, (fparam_t *) str1);
+	else
+		flags.s = NULL;
+	return force_rtp_proxy(msg, flags.s, NULL, OP_OFFER);
+}
+
+static int
+rtpproxy_offer2_f(struct sip_msg *msg, char *param1, char *param2)
+{
+	str flags, new_ip;
+
+	get_str_fparam(&flags, msg, (fparam_t *) param1);
+	get_str_fparam(&new_ip, msg, (fparam_t *) param2);
+	return force_rtp_proxy(msg, flags.s, &new_ip, OP_OFFER);
+}
+
+static int
+rtpproxy_answer1_f(struct sip_msg *msg, char *str1, char *str2)
+{
+	str flags;
+
+	if (msg->first_line.type == SIP_REQUEST)
+		if (msg->first_line.u.request.method_value != METHOD_ACK)
+			return -1;
+
+	if (str1)
+		get_str_fparam(&flags, msg, (fparam_t *) str1);
+	else
+		flags.s = NULL;
+	return force_rtp_proxy(msg, flags.s, NULL, OP_ANSWER);
+}
+
+static int
+rtpproxy_answer2_f(struct sip_msg *msg, char *param1, char *param2)
+{
+
+	str flags, new_ip;
+
+	if (msg->first_line.type == SIP_REQUEST)
+		if (msg->first_line.u.request.method_value != METHOD_ACK)
+			return -1;
+
+	get_str_fparam(&flags, msg, (fparam_t *) param1);
+	get_str_fparam(&new_ip, msg, (fparam_t *) param2);
+	return force_rtp_proxy(msg, flags.s, &new_ip, OP_ANSWER);
+}
+
+static int
+force_rtp_proxy(struct sip_msg *msg, const char *flags, const str *force_addr, int op)
+{
+	bencode_buffer_t bencbuf;
+	bencode_item_t *dict;
+	str body, newbody;
+	struct lump *anchor;
+
+	dict = rtpp_function_call_ok(&bencbuf, msg, op, flags, force_addr, &body);
+	if (!dict)
+		return -1;
+
+	if (!bencode_dictionary_get_str_dup(dict, "sdp", &newbody)) {
+		LM_ERR("failed to extract sdp body from proxy reply\n");
+		goto error;
+	}
+
+	anchor = del_lump(msg, body.s - msg->buf, body.len, 0);
+	if (!anchor) {
+		LM_ERR("del_lump failed\n");
+		goto error_free;
+	}
+	if (!insert_new_lump_after(anchor, newbody.s, newbody.len, 0)) {
+		LM_ERR("insert_new_lump_after failed\n");
+		goto error_free;
+	}
+
+	bencode_buffer_free(&bencbuf);
+	return 1;
+
+error_free:
+	pkg_free(newbody.s);
+error:
+	bencode_buffer_free(&bencbuf);
+	return -1;
+}
+
+
+static int
+start_recording_f(struct sip_msg* msg, char *foo, char *bar)
+{
+	return rtpp_function_call_simple(msg, OP_START_RECORDING, NULL);
+}
+
+/*
+ * Returns the current RTP-Statistics from the RTP-Proxy
+ */
+static int
+pv_get_rtpstat_f(struct sip_msg *msg, pv_param_t *param,
+		  pv_value_t *res)
+{
+	bencode_buffer_t bencbuf;
+	bencode_item_t *dict, *tot, *in, *out;
+	static char buf[256];
+	str ret;
+
+	dict = rtpp_function_call_ok(&bencbuf, msg, OP_QUERY, NULL, NULL, NULL);
+	if (!dict)
+		return -1;
+
+	tot = bencode_dictionary_get_expect(dict, "totals", BENCODE_DICTIONARY);
+	in = bencode_dictionary_get_expect(tot, "input", BENCODE_DICTIONARY);
+	in = bencode_dictionary_get_expect(in, "rtp", BENCODE_DICTIONARY);
+	out = bencode_dictionary_get_expect(tot, "output", BENCODE_DICTIONARY);
+	out = bencode_dictionary_get_expect(out, "rtp", BENCODE_DICTIONARY);
+
+	if (!in || !out)
+		goto error;
+
+	ret.s = buf;
+	ret.len = snprintf(buf, sizeof(buf),
+			"Input: %lli bytes, %lli packets, %lli errors; "
+			"Output: %lli bytes, %lli packets, %lli errors",
+			bencode_dictionary_get_integer(in, "bytes", -1),
+			bencode_dictionary_get_integer(in, "packets", -1),
+			bencode_dictionary_get_integer(in, "errors", -1),
+			bencode_dictionary_get_integer(out, "bytes", -1),
+			bencode_dictionary_get_integer(out, "packets", -1),
+			bencode_dictionary_get_integer(out, "errors", -1));
+
+	bencode_buffer_free(&bencbuf);
+	return pv_get_strval(msg, param, res, &ret);
+
+error:
+	bencode_buffer_free(&bencbuf);
+	return -1;
+}
+
diff --git a/modules/rtpproxy-ng/rtpproxy.h b/modules/rtpproxy-ng/rtpproxy.h
new file mode 100644
index 0000000..6fbc43e
--- /dev/null
+++ b/modules/rtpproxy-ng/rtpproxy.h
@@ -0,0 +1,64 @@
+/* $Id: nathelper.c 1808 2007-03-10 17:36:19Z bogdan_iancu $
+ *
+ * Copyright (C) 2003 Porta Software Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * ---------
+ * 2007-04-13   splitted from nathelper.c (ancuta)
+*/
+
+
+#ifndef _RTPPROXY_H
+#define _RTPPROXY_H
+
+#include "bencode.h"
+#include "../../str.h"
+
+struct rtpp_node {
+	unsigned int		idx;			/* overall index */
+	str					rn_url;			/* unparsed, deletable */
+	int					rn_umode;
+	char				*rn_address;	/* substring of rn_url */
+	int					rn_disabled;	/* found unaccessible? */
+	unsigned			rn_weight;		/* for load balancing */
+	unsigned int		rn_recheck_ticks;
+        int                     rn_rep_supported;
+        int                     rn_ptl_supported;
+	struct rtpp_node	*rn_next;
+};
+
+
+struct rtpp_set{
+	unsigned int 		id_set;
+	unsigned			weight_sum;
+	unsigned int		rtpp_node_count;
+	int 				set_disabled;
+	unsigned int		set_recheck_ticks;
+	struct rtpp_node	*rn_first;
+	struct rtpp_node	*rn_last;
+	struct rtpp_set     *rset_next;
+};
+
+
+struct rtpp_set_head{
+	struct rtpp_set		*rset_first;
+	struct rtpp_set		*rset_last;
+};
+
+#endif
diff --git a/modules/rtpproxy-ng/rtpproxy_funcs.c b/modules/rtpproxy-ng/rtpproxy_funcs.c
new file mode 100644
index 0000000..3f7079e
--- /dev/null
+++ b/modules/rtpproxy-ng/rtpproxy_funcs.c
@@ -0,0 +1,434 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ *  2003-11-06  body len is computed using the message len (it's
+ *               not taken any more from the msg. content-length) (andrei)
+ *  2008-08-30  body len is taken from Conent-length header as it is more
+ *               reliable (UDP packages may contain garbage at the end)(bogdan)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "rtpproxy_funcs.h"
+#include "../../dprint.h"
+#include "../../config.h"
+#include "../../ut.h"
+#include "../../forward.h"
+#include "../../resolve.h"
+#include "../../globals.h"
+#include "../../udp_server.h"
+#include "../../pt.h"
+#include "../../parser/msg_parser.h"
+#include "../../trim.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/contact/parse_contact.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/parse_content.h"
+#include "../../parser/parser_f.h"
+#include "../../parser/sdp/sdp_helpr_funcs.h"
+
+#define READ(val) \
+	(*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
+#define advance(_ptr,_n,_str,_error) \
+	do{\
+		if ((_ptr)+(_n)>(_str).s+(_str).len)\
+			goto _error;\
+		(_ptr) = (_ptr) + (_n);\
+	}while(0);
+#define one_of_16( _x , _t ) \
+	(_x==_t[0]||_x==_t[15]||_x==_t[8]||_x==_t[2]||_x==_t[3]||_x==_t[4]\
+	||_x==_t[5]||_x==_t[6]||_x==_t[7]||_x==_t[1]||_x==_t[9]||_x==_t[10]\
+	||_x==_t[11]||_x==_t[12]||_x==_t[13]||_x==_t[14])
+#define one_of_8( _x , _t ) \
+	(_x==_t[0]||_x==_t[7]||_x==_t[1]||_x==_t[2]||_x==_t[3]||_x==_t[4]\
+	||_x==_t[5]||_x==_t[6])
+
+
+
+/**
+ * return:
+ * -1: error
+ *  1: text or sdp
+ *  2: multipart
+ */
+int check_content_type(struct sip_msg *msg)
+{
+	static unsigned int appl[16] = {
+		0x6c707061/*appl*/,0x6c707041/*Appl*/,0x6c705061/*aPpl*/,
+		0x6c705041/*APpl*/,0x6c507061/*apPl*/,0x6c507041/*ApPl*/,
+		0x6c505061/*aPPl*/,0x6c505041/*APPl*/,0x4c707061/*appL*/,
+		0x4c707041/*AppL*/,0x4c705061/*aPpL*/,0x4c705041/*APpL*/,
+		0x4c507061/*apPL*/,0x4c507041/*ApPL*/,0x4c505061/*aPPL*/,
+		0x4c505041/*APPL*/};
+	static unsigned int icat[16] = {
+		0x74616369/*icat*/,0x74616349/*Icat*/,0x74614369/*iCat*/,
+		0x74614349/*ICat*/,0x74416369/*icAt*/,0x74416349/*IcAt*/,
+		0x74414369/*iCAt*/,0x74414349/*ICAt*/,0x54616369/*icaT*/,
+		0x54616349/*IcaT*/,0x54614369/*iCaT*/,0x54614349/*ICaT*/,
+		0x54416369/*icAT*/,0x54416349/*IcAT*/,0x54414369/*iCAT*/,
+		0x54414349/*ICAT*/};
+	static unsigned int ion_[8] = {
+		0x006e6f69/*ion_*/,0x006e6f49/*Ion_*/,0x006e4f69/*iOn_*/,
+		0x006e4f49/*IOn_*/,0x004e6f69/*ioN_*/,0x004e6f49/*IoN_*/,
+		0x004e4f69/*iON_*/,0x004e4f49/*ION_*/};
+	static unsigned int sdp_[8] = {
+		0x00706473/*sdp_*/,0x00706453/*Sdp_*/,0x00704473/*sDp_*/,
+		0x00704453/*SDp_*/,0x00506473/*sdP_*/,0x00506453/*SdP_*/,
+		0x00504473/*sDP_*/,0x00504453/*SDP_*/};
+	str           str_type;
+	unsigned int  x;
+	char          *p;
+
+	if (!msg->content_type)
+	{
+		LM_WARN("the header Content-TYPE is absent!"
+			"let's assume the content is text/plain ;-)\n");
+		return 1;
+	}
+
+	trim_len(str_type.len,str_type.s,msg->content_type->body);
+	if (str_type.len>=15 && (*str_type.s=='m' || *str_type.s=='M')
+			&& strncasecmp(str_type.s, "multipart/mixed", 15) == 0) {
+		return 2;
+    }
+	p = str_type.s;
+	advance(p,4,str_type,error_1);
+	x = READ(p-4);
+	if (!one_of_16(x,appl))
+		goto other;
+	advance(p,4,str_type,error_1);
+	x = READ(p-4);
+	if (!one_of_16(x,icat))
+		goto other;
+	advance(p,3,str_type,error_1);
+	x = READ(p-3) & 0x00ffffff;
+	if (!one_of_8(x,ion_))
+		goto other;
+
+	/* skip spaces and tabs if any */
+	while (*p==' ' || *p=='\t')
+		advance(p,1,str_type,error_1);
+	if (*p!='/')
+	{
+		LM_ERR("no / found after primary type\n");
+		goto error;
+	}
+	advance(p,1,str_type,error_1);
+	while ((*p==' ' || *p=='\t') && p+1<str_type.s+str_type.len)
+		advance(p,1,str_type,error_1);
+
+	advance(p,3,str_type,error_1);
+	x = READ(p-3) & 0x00ffffff;
+	if (!one_of_8(x,sdp_))
+		goto other;
+
+	if (*p==';'||*p==' '||*p=='\t'||*p=='\n'||*p=='\r'||*p==0) {
+		LM_DBG("type <%.*s> found valid\n", (int)(p-str_type.s), str_type.s);
+		return 1;
+	} else {
+		LM_ERR("bad end for type!\n");
+		return -1;
+	}
+
+error_1:
+	LM_ERR("body ended :-(!\n");
+error:
+	return -1;
+other:
+	LM_ERR("invalid type for a message\n");
+	return -1;
+}
+
+
+/*
+ * Get message body and check Content-Type header field
+ */
+int extract_body(struct sip_msg *msg, str *body )
+{
+	char c;
+	int ret;
+	str mpdel;
+	char *rest, *p1, *p2;
+	struct hdr_field hf;
+	unsigned int mime;
+
+	body->s = get_body(msg);
+	if (body->s==0) {
+		LM_ERR("failed to get the message body\n");
+		goto error;
+	}
+
+	/*
+	 * Better use the content-len value - no need of any explicit
+	 * parcing as get_body() parsed all headers and Conten-Length
+	 * body header is automaticaly parsed when found.
+	 */
+	if (msg->content_length==0) {
+		LM_ERR("failed to get the content length in message\n");
+		goto error;
+	}
+
+	body->len = get_content_length(msg);
+	if (body->len==0) {
+		LM_ERR("message body has length zero\n");
+		goto error;
+	}
+
+	if (body->len + body->s > msg->buf + msg->len) {
+		LM_ERR("content-length exceeds packet-length by %d\n",
+				(int)((body->len + body->s) - (msg->buf + msg->len)));
+		goto error;
+	}
+
+	/* no need for parse_headers(msg, EOH), get_body will
+	 * parse everything */
+	/*is the content type correct?*/
+	if((ret = check_content_type(msg))==-1)
+	{
+		LM_ERR("content type mismatching\n");
+		goto error;
+	}
+
+	if(ret!=2)
+		goto done;
+
+	/* multipart body */
+	if(get_mixed_part_delimiter(&msg->content_type->body,&mpdel) < 0) {
+		goto error;
+	}
+	p1 = find_sdp_line_delimiter(body->s, body->s+body->len, mpdel);
+	if (p1 == NULL) {
+		LM_ERR("empty multipart content\n");
+		return -1;
+	}
+	p2=p1;
+	c = 0;
+	for(;;)
+	{
+		p1 = p2;
+		if (p1 == NULL || p1 >= body->s+body->len)
+			break; /* No parts left */
+		p2 = find_next_sdp_line_delimiter(p1, body->s+body->len,
+				mpdel, body->s+body->len);
+		/* p2 is text limit for application parsing */
+		rest = eat_line(p1 + mpdel.len + 2, p2 - p1 - mpdel.len - 2);
+		if ( rest > p2 ) {
+			LM_ERR("Unparsable <%.*s>\n", (int)(p1-p1), p1);
+			return -1;
+		}
+		while( rest<p2 ) {
+			memset(&hf,0, sizeof(struct hdr_field));
+			rest = get_sdp_hdr_field(rest, p2, &hf);
+			if(hf.type==HDR_EOH_T)
+				break;
+			if(hf.type==HDR_ERROR_T)
+				return -1;
+			if(hf.type==HDR_CONTENTTYPE_T) {
+				if(decode_mime_type(hf.body.s, hf.body.s + hf.body.len,
+						&mime)==NULL)
+					return -1;
+				if (((((unsigned int)mime)>>16) == TYPE_APPLICATION)
+						&& ((mime&0x00ff) == SUBTYPE_SDP)) {
+					c = 1;
+				}
+			}
+		} /* end of while */
+		if(c==1)
+		{
+			if (rest < p2 && *rest == '\r') rest++;
+			if (rest < p2 && *rest == '\n') rest++;
+			if (rest < p2 && p2[-1] == '\n') p2--;
+			if (rest < p2 && p2[-1] == '\r') p2--;
+			body->s = rest;
+			body->len = p2-rest;
+			goto done;
+		}
+	}
+
+error:
+	return -1;
+
+done:
+	/*LM_DBG("DEBUG:extract_body:=|%.*s|\n",body->len,body->s);*/
+	return 1;
+}
+
+/*
+ * ser_memmem() returns the location of the first occurrence of data
+ * pattern b2 of size len2 in memory block b1 of size len1 or
+ * NULL if none is found. Obtained from NetBSD.
+ */
+void *
+ser_memmem(const void *b1, const void *b2, size_t len1, size_t len2)
+{
+        /* Initialize search pointer */
+        char *sp = (char *) b1;
+
+        /* Initialize pattern pointer */
+        char *pp = (char *) b2;
+
+        /* Initialize end of search address space pointer */
+        char *eos = sp + len1 - len2;
+
+        /* Sanity check */
+        if(!(b1 && b2 && len1 && len2))
+                return NULL;
+
+        while (sp <= eos) {
+                if (*sp == *pp)
+                        if (memcmp(sp, pp, len2) == 0)
+                                return sp;
+
+                        sp++;
+        }
+
+        return NULL;
+}
+
+/*
+ * Some helper functions taken verbatim from tm module.
+ */
+
+/*
+ * Extract Call-ID value
+ * assumes the callid header is already parsed
+ * (so make sure it is, before calling this function or
+ *  it might fail even if the message _has_ a callid)
+ */
+int
+get_callid(struct sip_msg* _m, str* _cid)
+{
+
+        if ((parse_headers(_m, HDR_CALLID_F, 0) == -1)) {
+                LM_ERR("failed to parse call-id header\n");
+                return -1;
+        }
+
+        if (_m->callid == NULL) {
+                LM_ERR("call-id not found\n");
+                return -1;
+        }
+
+        _cid->s = _m->callid->body.s;
+        _cid->len = _m->callid->body.len;
+        trim(_cid);
+        return 0;
+}
+
+/*
+ * Extract tag from To header field of a response
+ */
+int
+get_to_tag(struct sip_msg* _m, str* _tag)
+{
+
+        if (parse_to_header(_m) < 0) {
+                LM_ERR("To header field missing\n");
+                return -1;
+        }
+
+        if (get_to(_m)->tag_value.len) {
+                _tag->s = get_to(_m)->tag_value.s;
+                _tag->len = get_to(_m)->tag_value.len;
+        } else {
+                _tag->s = NULL; /* fixes gcc 4.0 warnings */
+                _tag->len = 0;
+        }
+
+        return 0;
+}
+
+/*
+ * Extract tag from From header field of a request
+ */
+int
+get_from_tag(struct sip_msg* _m, str* _tag)
+{
+
+        if (parse_from_header(_m)<0) {
+                LM_ERR("failed to parse From header\n");
+                return -1;
+        }
+
+        if (get_from(_m)->tag_value.len) {
+                _tag->s = get_from(_m)->tag_value.s;
+                _tag->len = get_from(_m)->tag_value.len;
+        } else {
+                _tag->s = NULL; /* fixes gcc 4.0 warnings */
+                _tag->len = 0;
+        }
+
+        return 0;
+}
+
+/*
+ * Extract URI from the Contact header field
+ */
+int
+get_contact_uri(struct sip_msg* _m, struct sip_uri *uri, contact_t** _c)
+{
+
+        if ((parse_headers(_m, HDR_CONTACT_F, 0) == -1) || !_m->contact)
+                return -1;
+        if (!_m->contact->parsed && parse_contact(_m->contact) < 0) {
+                LM_ERR("failed to parse Contact body\n");
+                return -1;
+        }
+        *_c = ((contact_body_t*)_m->contact->parsed)->contacts;
+        if (*_c == NULL)
+                /* no contacts found */
+                return -1;
+
+        if (parse_uri((*_c)->uri.s, (*_c)->uri.len, uri) < 0 || uri->host.len <= 0) {
+                LM_ERR("failed to parse Contact URI [%.*s]\n",
+                        (*_c)->uri.len, ((*_c)->uri.s)?(*_c)->uri.s:"");
+                return -1;
+        }
+        return 0;
+}
+
+/*
+ * Extract branch from Via header
+ */
+int
+get_via_branch(struct sip_msg* msg, int vianum, str* _branch)
+{
+	struct via_body *via;
+	struct via_param *p;
+
+	if (parse_via_header(msg, vianum, &via) < 0)
+		return -1;
+
+	for (p = via->param_lst; p; p = p->next)
+	{
+		if (p->name.len == strlen("branch")
+				&& strncasecmp(p->name.s, "branch", strlen("branch")) == 0) {
+			_branch->s = p->value.s;
+			_branch->len = p->value.len;
+			return 0;
+		}
+	}
+	return -1;
+}
diff --git a/modules/rtpproxy-ng/rtpproxy_funcs.h b/modules/rtpproxy-ng/rtpproxy_funcs.h
new file mode 100644
index 0000000..1d2bca9
--- /dev/null
+++ b/modules/rtpproxy-ng/rtpproxy_funcs.h
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _RTPPROXY_FUNCS_H
+#define _RTPPROXY_FUNCS_H
+
+#include "../../str.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/contact/contact.h"
+
+int extract_body(struct sip_msg * , str *);
+int check_content_type(struct sip_msg * );
+void *ser_memmem(const void *, const void *, size_t, size_t);
+int get_callid(struct sip_msg *, str *);
+int get_to_tag(struct sip_msg *, str *);
+int get_from_tag(struct sip_msg *, str *);
+int get_contact_uri(struct sip_msg *, struct sip_uri *, contact_t **);
+int get_via_branch(struct sip_msg *, int, str *);
+
+#endif
diff --git a/modules/rtpproxy/Makefile b/modules/rtpproxy/Makefile
index 4e72fdd..e0d53f4 100644
--- a/modules/rtpproxy/Makefile
+++ b/modules/rtpproxy/Makefile
@@ -15,5 +15,6 @@ DEFS+=-DKAMAILIO_MOD_INTERFACE
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
 include ../../Makefile.modules
 
diff --git a/modules/rtpproxy/README b/modules/rtpproxy/README
index b2b304b..43b57df 100644
--- a/modules/rtpproxy/README
+++ b/modules/rtpproxy/README
@@ -1,3 +1,4 @@
+
 rtpproxy Module
 
 Maxim Sobolev
@@ -37,7 +38,7 @@ Carsten Bock
    Copyright � 2009-2012 TuTPro Inc.
 
    Copyright � 2010 VoIPEmbedded Inc.
-     __________________________________________________________________
+     _________________________________________________________________
 
    Table of Contents
 
@@ -60,20 +61,22 @@ Carsten Bock
               4.6. timeout_socket (string)
               4.7. ice_candidate_priority_avp (string)
               4.8. extra_id_pv (string)
+              4.9. db_url (string)
+              4.10. table_name (string)
 
         5. Functions
 
-              5.1. set_rtp_proxy_set(setid)
-              5.2. rtpproxy_offer([flags [, ip_address]])
-              5.3. rtpproxy_answer([flags [, ip_address]])
-              5.4. rtpproxy_destroy([flags])
-              5.5. unforce_rtp_proxy()
-              5.6. rtpproxy_manage([flags [, ip_address]])
-              5.7. rtpproxy_stream2uac(prompt_name, count),
-              5.8. rtpproxy_stream2uas(prompt_name, count)
-              5.9. rtpproxy_stop_stream2uac(),
-              5.10. start_recording()
-              5.11. rtpproxy_stop_stream2uas(prompt_name, count)
+              5.1. set_rtp_proxy_set(setid) 
+              5.2. rtpproxy_offer([flags [, ip_address]]) 
+              5.3. rtpproxy_answer([flags [, ip_address]]) 
+              5.4. rtpproxy_destroy([flags]) 
+              5.5. unforce_rtp_proxy() 
+              5.6. rtpproxy_manage([flags [, ip_address]]) 
+              5.7. rtpproxy_stream2uac(prompt_name, count), 
+              5.8. rtpproxy_stream2uas(prompt_name, count) 
+              5.9. rtpproxy_stop_stream2uac(), 
+              5.10. start_recording() 
+              5.11. rtpproxy_stop_stream2uas(prompt_name, count) 
 
         6. Exported Pseudo Variables
 
@@ -96,16 +99,18 @@ Carsten Bock
    1.6. Set timeout_socket parameter
    1.7. Set ice_candidate_priority_avp parameter
    1.8. Set extra_id_pv parameter
-   1.9. set_rtp_proxy_set usage
-   1.10. rtpproxy_offer usage
-   1.11. rtpproxy_answer usage
-   1.12. rtpproxy_destroy usage
-   1.13. rtpproxy_manage usage
-   1.14. rtpproxy_stream2xxx usage
-   1.15. start_recording usage
-   1.16. $rtpstat-Usage
-   1.17. nh_enable_rtpp usage
-   1.18. nh_show_rtpp usage
+   1.9. Set db_url parameter
+   1.10. Set table_name parameter
+   1.11. set_rtp_proxy_set usage
+   1.12. rtpproxy_offer usage
+   1.13. rtpproxy_answer usage
+   1.14. rtpproxy_destroy usage
+   1.15. rtpproxy_manage usage
+   1.16. rtpproxy_stream2xxx usage
+   1.17. start_recording usage
+   1.18. $rtpstat-Usage
+   1.19. nh_enable_rtpp usage
+   1.20. nh_show_rtpp usage
 
 Chapter 1. Admin Guide
 
@@ -128,20 +133,22 @@ Chapter 1. Admin Guide
         4.6. timeout_socket (string)
         4.7. ice_candidate_priority_avp (string)
         4.8. extra_id_pv (string)
+        4.9. db_url (string)
+        4.10. table_name (string)
 
    5. Functions
 
-        5.1. set_rtp_proxy_set(setid)
-        5.2. rtpproxy_offer([flags [, ip_address]])
-        5.3. rtpproxy_answer([flags [, ip_address]])
-        5.4. rtpproxy_destroy([flags])
-        5.5. unforce_rtp_proxy()
-        5.6. rtpproxy_manage([flags [, ip_address]])
-        5.7. rtpproxy_stream2uac(prompt_name, count),
-        5.8. rtpproxy_stream2uas(prompt_name, count)
-        5.9. rtpproxy_stop_stream2uac(),
-        5.10. start_recording()
-        5.11. rtpproxy_stop_stream2uas(prompt_name, count)
+        5.1. set_rtp_proxy_set(setid) 
+        5.2. rtpproxy_offer([flags [, ip_address]]) 
+        5.3. rtpproxy_answer([flags [, ip_address]]) 
+        5.4. rtpproxy_destroy([flags]) 
+        5.5. unforce_rtp_proxy() 
+        5.6. rtpproxy_manage([flags [, ip_address]]) 
+        5.7. rtpproxy_stream2uac(prompt_name, count), 
+        5.8. rtpproxy_stream2uas(prompt_name, count) 
+        5.9. rtpproxy_stop_stream2uac(), 
+        5.10. start_recording() 
+        5.11. rtpproxy_stop_stream2uas(prompt_name, count) 
 
    6. Exported Pseudo Variables
 
@@ -154,37 +161,37 @@ Chapter 1. Admin Guide
 
 1. Overview
 
-   This is a module that enables media streams to be proxied via an
-   rtpproxy. Rtpproxies know to work with this module are Sippy RTPproxy
+   This  is  a  module  that  enables  media streams to be proxied via an
+   rtpproxy.  Rtpproxies know to work with this module are Sippy RTPproxy
    http://www.rtpproxy.org and ngcp-rtpproxy-ng
-   http://deb.sipwise.com/spce/2.6/pool/main/n/ngcp-mediaproxy-ng. Some
-   features of the rtpproxy module apply only to one of the two
+   http://deb.sipwise.com/spce/2.6/pool/main/n/ngcp-mediaproxy-ng.   Some
+   features  of  the  rtpproxy  module  apply  only  to  one  of  the two
    rtpproxies.
 
 2. Multiple RTPProxy usage
 
-   The rtpproxy module can support multiple rtpproxies for
+   The    rtpproxy   module   can   support   multiple   rtpproxies   for
    balancing/distribution and control/selection purposes.
 
-   The module allows definition of several sets of rtpproxies.
-   Load-balancing will be performed over a set and the admin has the
+   The   module   allows   definition  of  several  sets  of  rtpproxies.
+   Load-balancing  will  be  performed  over  a set and the admin has the
    ability to choose what set should be used. The set is selected via its
-   id - the id being defined with the set. Refer to the "rtpproxy_sock"
+   id  -  the id being defined with the set. Refer to the "rtpproxy_sock"
    module parameter definition for syntax description.
 
-   The balancing inside a set is done automatically by the module based on
-   the weight of each rtpproxy from the set.
+   The  balancing  inside a set is done automatically by the module based
+   on the weight of each rtpproxy from the set.
 
-   The selection of the set is done from script prior using
+   The   selection   of   the   set  is  done  from  script  prior  using
    unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() functions -
    see the set_rtp_proxy_set() function.
 
-   For backward compatibility reasons, a set with no id take by default
+   For  backward  compatibility reasons, a set with no id take by default
    the id 0. Also if no set is explicitly set before unforce_rtp_proxy(),
    rtpproxy_offer() or rtpproxy_answer() the 0 id set will be used.
 
-   IMPORTANT: if you use multiple sets, take care and use the same set for
-   both rtpproxy_offer()/rtpproxy_answer() and unforce_rtpproxy()!!
+   IMPORTANT:  if  you  use multiple sets, take care and use the same set
+   for both rtpproxy_offer()/rtpproxy_answer() and unforce_rtpproxy()!!
 
 3. Dependencies
 
@@ -199,7 +206,7 @@ Chapter 1. Admin Guide
 
 3.2. External Libraries or Applications
 
-   The following libraries or applications must be installed before
+   The  following  libraries  or  applications  must  be installed before
    running Kamailio with this module loaded:
      * None.
 
@@ -213,21 +220,31 @@ Chapter 1. Admin Guide
    4.6. timeout_socket (string)
    4.7. ice_candidate_priority_avp (string)
    4.8. extra_id_pv (string)
+   4.9. db_url (string)
+   4.10. table_name (string)
 
 4.1. rtpproxy_sock (string)
 
-   Definition of socket(s) used to connect to (a set) RTPProxy. It may
-   specify a UNIX socket or an IPv4/IPv6 UDP socket.
+   Used to define the list of RTPPRoxy instances to connect to. These can
+   be  UNIX  sockets  or  IPv4/IPv6 UDP sockets. Each modparam entry will
+   insert  sockets  into a single set. If no set ID is given, the default
+   set ID '0' will be used. To define multiple sets add the set number at
+   the  beginning  of  each  parameter  followed  by '=='. Sockets can be
+   weighted  by  adding  '=#' to a socket where # is an integer. A socket
+   with  a weight of 2 will be chosen twice as often as one with a weight
+   of 1.
 
-   Default value is "NONE" (disabled).
+   Default value is "NONE" (disabled). 
 
    Example 1.1. Set rtpproxy_sock parameter
 ...
 # single rtproxy
 modparam("rtpproxy", "rtpproxy_sock", "udp:localhost:12221")
+
 # multiple rtproxies for LB
 modparam("rtpproxy", "rtpproxy_sock",
         "udp:localhost:12221 udp:localhost:12222")
+
 # multiple sets of multiple rtproxies
 modparam("rtpproxy", "rtpproxy_sock",
         "1 == udp:localhost:12221 udp:localhost:12222")
@@ -237,11 +254,11 @@ modparam("rtpproxy", "rtpproxy_sock",
 
 4.2. rtpproxy_disable_tout (integer)
 
-   Once RTPProxy was found unreachable and marked as disabled, the
-   rtpproxy module will not attempt to establish communication to RTPProxy
-   for rtpproxy_disable_tout seconds.
+   Once  RTPProxy  was  found  unreachable  and  marked  as disabled, the
+   rtpproxy  module  will  not  attempt  to  establish  communication  to
+   RTPProxy for rtpproxy_disable_tout seconds.
 
-   Default value is "60".
+   Default value is "60". 
 
    Example 1.2. Set rtpproxy_disable_tout parameter
 ...
@@ -252,7 +269,7 @@ modparam("rtpproxy", "rtpproxy_disable_tout", 20)
 
    Timeout value in waiting for reply from RTPProxy.
 
-   Default value is "1".
+   Default value is "1". 
 
    Example 1.3. Set rtpproxy_tout parameter
 ...
@@ -261,10 +278,10 @@ modparam("rtpproxy", "rtpproxy_tout", 2)
 
 4.4. rtpproxy_retr (integer)
 
-   How many times the module should retry to send and receive after
+   How  many  times  the  module  should  retry to send and receive after
    timeout was generated.
 
-   Default value is "5".
+   Default value is "5". 
 
    Example 1.4. Set rtpproxy_retr parameter
 ...
@@ -273,8 +290,8 @@ modparam("rtpproxy", "rtpproxy_retr", 2)
 
 4.5. nortpproxy_str (string)
 
-   This parameter sets the SDP attribute used by rtpproxy to mark the
-   message's SDP attachemnt with information that it have already been
+   This  parameter  sets  the  SDP attribute used by rtpproxy to mark the
+   message's  SDP  attachemnt  with information that it have already been
    changed.
 
    If empty string, no marker will be added or checked.
@@ -283,7 +300,7 @@ Note
 
    The string must be a complete SDP line, including the EOH (\r\n).
 
-   Default value is "a=nortpproxy:yes\r\n".
+   Default value is "a=nortpproxy:yes\r\n". 
 
    Example 1.5. Set nortpproxy_str parameter
 ...
@@ -293,30 +310,30 @@ modparam("rtpproxy", "nortpproxy_str", "a=sdpmangled:yes\r\n")
 4.6. timeout_socket (string)
 
    The parameter sets the RTP timeout socket, which is transmitted to the
-   RTP-Proxy. It will be used by the RTP proxy to signal back that a media
-   stream timed out.
+   RTP-Proxy.  It  will  be  used  by the RTP proxy to signal back that a
+   media stream timed out.
 
    If it is an empty string, no timeout socket will be transmitted to the
    RTP-Proxy.
 
-   Default value is "" (nothing).
+   Default value is "" (nothing). 
 
    Example 1.6. Set timeout_socket parameter
 ...
-modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
+modparam("rtpproxy", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 
 4.7. ice_candidate_priority_avp (string)
 
-   If specified and if value of the avp value is not 0, rtpproxy_manage
-   function adds ICE relay candidate attributes to sdp stream(s)
+   If  specified  and if value of the avp value is not 0, rtpproxy_manage
+   function   adds  ICE  relay  candidate  attributes  to  sdp  stream(s)
    containing ICE candidate attributes.
 
-   If value of the avp is 1, added candidates have high priority. If value
-   of the avp is 2 (default), added candidates have low priority.
+   If  value  of  the  avp  is 1, added candidates have high priority. If
+   value of the avp is 2 (default), added candidates have low priority.
 
-   There is no default value meaning that no ICE relay candidates are
-   added in any circumstance.
+   There  is  no  default  value meaning that no ICE relay candidates are
+   added in any circumstance. 
 
    Example 1.7. Set ice_candidate_priority_avp parameter
 ...
@@ -325,8 +342,8 @@ modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
 
 4.8. extra_id_pv (string)
 
-   The parameter sets the PV defination to use when the "b" parameter is
-   used on unforce_rtp_proxy(), rtpproxy_offer(), rtpproxy_answer() or
+   The  parameter sets the PV defination to use when the "b" parameter is
+   used  on  unforce_rtp_proxy(),  rtpproxy_offer(), rtpproxy_answer() or
    rtpproxy_manage() command.
 
    Default is empty, the "b" parameter may not be used then.
@@ -336,147 +353,172 @@ modparam("rtpproxy", "ice_candidate_priority_avp", "$avp(ice_priority)")
 modparam("rtpproxy", "extra_id_pv", "$avp(extra_id)")
 ...
 
+4.9. db_url (string)
+
+   The  database  URL  to  load rtp_proxy sets from. If this parameter is
+   set,  the  module  will  attempt  to  load  the rtpproxy sets from the
+   specified database and will ignore any 'rtpproxy_sock' modparams.
+
+   Default is empty, a database will not be used.
+
+   Example 1.9. Set db_url parameter
+...
+modparam("rtpproxy", "db_url", "mysql://user:passwb@localhost/database")
+...
+
+4.10. table_name (string)
+
+   The name of the table containing the rtpproxy sets.
+
+   Default value is "rtpproxy".
+
+   Example 1.10. Set table_name parameter
+...
+modparam("rtpproxy", "table_name", "my_rtpp_sets")
+...
+
 5. Functions
 
-   5.1. set_rtp_proxy_set(setid)
-   5.2. rtpproxy_offer([flags [, ip_address]])
-   5.3. rtpproxy_answer([flags [, ip_address]])
-   5.4. rtpproxy_destroy([flags])
-   5.5. unforce_rtp_proxy()
-   5.6. rtpproxy_manage([flags [, ip_address]])
-   5.7. rtpproxy_stream2uac(prompt_name, count),
-   5.8. rtpproxy_stream2uas(prompt_name, count)
-   5.9. rtpproxy_stop_stream2uac(),
-   5.10. start_recording()
-   5.11. rtpproxy_stop_stream2uas(prompt_name, count)
-
-5.1. set_rtp_proxy_set(setid)
-
-   Sets the Id of the rtpproxy set to be used for the next
-   unforce_rtp_proxy(), rtpproxy_offer(), rtpproxy_answer() or
+   5.1. set_rtp_proxy_set(setid) 
+   5.2. rtpproxy_offer([flags [, ip_address]]) 
+   5.3. rtpproxy_answer([flags [, ip_address]]) 
+   5.4. rtpproxy_destroy([flags]) 
+   5.5. unforce_rtp_proxy() 
+   5.6. rtpproxy_manage([flags [, ip_address]]) 
+   5.7. rtpproxy_stream2uac(prompt_name, count), 
+   5.8. rtpproxy_stream2uas(prompt_name, count) 
+   5.9. rtpproxy_stop_stream2uac(), 
+   5.10. start_recording() 
+   5.11. rtpproxy_stop_stream2uas(prompt_name, count) 
+
+5.1.  set_rtp_proxy_set(setid)
+
+   Sets   the   Id   of  the  rtpproxy  set  to  be  used  for  the  next
+   unforce_rtp_proxy(),     rtpproxy_offer(),     rtpproxy_answer()    or
    rtpproxy_manage() command. The parameter can be an integer or a config
    variable holding an integer.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    BRANCH_ROUTE.
 
-   Example 1.9. set_rtp_proxy_set usage
+   Example 1.11. set_rtp_proxy_set usage
 ...
 set_rtp_proxy_set("2");
 rtpproxy_offer();
 ...
 
-5.2. rtpproxy_offer([flags [, ip_address]])
+5.2.  rtpproxy_offer([flags [, ip_address]])
 
    Rewrites SDP body to ensure that media is passed through an RTP proxy.
-   To be invoked on INVITE for the cases the SDPs are in INVITE and 200 OK
-   and on 200 OK when SDPs are in 200 OK and ACK.
+   To  be  invoked on INVITE for the cases the SDPs are in INVITE and 200
+   OK and on 200 OK when SDPs are in 200 OK and ACK.
 
    Meaning of the parameters is as follows:
      * flags - flags to turn on some features.
-          + 1 - append first Via branch to Call-ID when sending command to
-            rtpproxy. This can be used to create one media session per
-            branch on the rtpproxy. When sending a subsequent "delete"
-            command to the rtpproxy, you can then stop just the session
+          + 1  -  append first Via branch to Call-ID when sending command
+            to rtpproxy. This can be used to create one media session per
+            branch  on  the  rtpproxy. When sending a subsequent "delete"
+            command  to  the rtpproxy, you can then stop just the session
             for a specific branch when passing the flag '1' or '2' in the
-            "unforce_rtpproxy", or stop all sessions for a call when not
-            passing one of those two flags there. This is especially
-            useful if you have serially forked call scenarios where
-            rtpproxy gets an "update" command for a new branch, and then a
-            "delete" command for the previous branch, which would
-            otherwise delete the full call, breaking the subsequent
-            "lookup" for the new branch. This flag is only supported by
+            "unforce_rtpproxy",  or stop all sessions for a call when not
+            passing  one  of  those  two  flags there. This is especially
+            useful  if  you  have  serially  forked  call scenarios where
+            rtpproxy  gets an "update" command for a new branch, and then
+            a  "delete"  command  for  the  previous  branch, which would
+            otherwise  delete  the  full  call,  breaking  the subsequent
+            "lookup"  for  the new branch. This flag is only supported by
             the ngcp-mediaproxy-ng rtpproxy at the moment!
-          + 2 - append second Via branch to Call-ID when sending command
+          + 2  - append second Via branch to Call-ID when sending command
             to rtpproxy. See flag '1' for its meaning.
-          + 3 - behave like flag 1 is set for a request and like flag 2 is
-            set for a reply.
-          + a - flags that UA from which message is received doesn't
+          + 3  -  behave like flag 1 is set for a request and like flag 2
+            is set for a reply.
+          + a  -  flags  that  UA  from which message is received doesn't
             support symmetric RTP. (automatically sets the 'r' flag)
-          + b - append branch specific variable to Call-ID when sending
-            command to rtpproxy. This creates one rtpproxy session per
-            unique variable. Works similar to the 1, 2 and 3 parameter,
-            but is usefull when forking to multiple destinations on
-            different address families or network segments, requiring
-            different rtpproxy parameters. The variable value is taken
-            from the "extra_id_pv". When used, it must be used in every
-            call to rtpproxy_manage(), rtpproxy_offer(), rtpproxy_answer()
-            and rtpproxy_destroy() with the same contents of the PV. The b
-            parameter may not be used in conjunction with the 1, 2 or 3
-            parameter to use the Via branch in the Call-ID.
-          + l - force "lookup", that is, only rewrite SDP when
-            corresponding session already exists in the RTP proxy. By
+          + b  -  append branch specific variable to Call-ID when sending
+            command  to  rtpproxy.  This creates one rtpproxy session per
+            unique  variable.  Works similar to the 1, 2 and 3 parameter,
+            but  is  usefull  when  forking  to  multiple destinations on
+            different  address  families  or  network segments, requiring
+            different  rtpproxy  parameters.  The variable value is taken
+            from  the  "extra_id_pv". When used, it must be used in every
+            call       to       rtpproxy_manage(),      rtpproxy_offer(),
+            rtpproxy_answer()   and   rtpproxy_destroy()  with  the  same
+            contents  of  the  PV.  The  b  parameter  may not be used in
+            conjunction  with  the  1,  2  or  3 parameter to use the Via
+            branch in the Call-ID.
+          + l   -   force  "lookup",  that  is,  only  rewrite  SDP  when
+            corresponding  session  already  exists  in the RTP proxy. By
             default is on when the session is to be completed.
-          + i, e - these flags specify the direction of the SIP message.
-            These flags only make sense when rtpproxy is running in bridge
-            mode. 'i' means internal network (LAN), 'e' means external
-            network (WAN). 'i' corresponds to rtpproxy's first interface,
-            'e' corresponds to rtpproxy's second interface. You always
-            have to specify two flags to define the incoming network and
-            the outgoing network. For example, 'ie' should be used for SIP
-            message received from the local interface and sent out on the
-            external interface, and 'ei' vice versa. Other options are
-            'ii' and 'ee'. So, for example if a SIP requests is processed
-            with 'ie' flags, the corresponding response must be processed
-            with 'ie' flags.
-            Note: As rtpproxy in bridge mode s per default asymmetric, you
-            have to specify the 'w' flag for clients behind NAT! See also
-            above notes!
-          + x - this flag a shortcut for using the "ie" or "ei"-flags of
-            RTP-Proxy, in order to do automatic bridging between IPv4 on
-            the "internal network" and IPv6 on the "external network". The
-            distinction is done by the given IP in the SDP, e.g. a IPv4
-            Address will always call "ie" to the RTPProxy (IPv4(i) to
-            IPv6(e)) and an IPv6Address will always call "ei" to the
+          + i,  e - these flags specify the direction of the SIP message.
+            These  flags  only  make  sense  when  rtpproxy is running in
+            bridge  mode.  'i'  means  internal  network (LAN), 'e' means
+            external  network  (WAN). 'i' corresponds to rtpproxy's first
+            interface,  'e'  corresponds  to rtpproxy's second interface.
+            You  always  have to specify two flags to define the incoming
+            network and the outgoing network. For example, 'ie' should be
+            used  for  SIP  message received from the local interface and
+            sent  out  on  the  external  interface, and 'ei' vice versa.
+            Other  options  are  'ii'  and 'ee'. So, for example if a SIP
+            requests  is  processed  with  'ie'  flags, the corresponding
+            response must be processed with 'ie' flags.
+            Note:  As  rtpproxy  in bridge mode s per default asymmetric,
+            you  have to specify the 'w' flag for clients behind NAT! See
+            also above notes!
+          + x  - this flag a shortcut for using the "ie" or "ei"-flags of
+            RTP-Proxy,  in order to do automatic bridging between IPv4 on
+            the  "internal  network"  and IPv6 on the "external network".
+            The  distinction  is  done by the given IP in the SDP, e.g. a
+            IPv4  Address  will always call "ie" to the RTPProxy (IPv4(i)
+            to  IPv6(e))  and an IPv6Address will always call "ei" to the
             RTPProxy (IPv6(e) to IPv4(i)).
-            Note: Please note, that this will only work properly with
-            non-dual-stack user-agents or with dual-stack clients
-            according to RFC6157 (which suggest ICE for Dual-Stack
-            implementations). This short-cut will not work properly with
-            RFC4091 (ANAT) compatible clients, which suggests having
-            different m-lines with different IP-protocols grouped
+            Note:  Please  note,  that  this will only work properly with
+            non-dual-stack   user-agents   or   with  dual-stack  clients
+            according  to  RFC6157  (which  suggest  ICE  for  Dual-Stack
+            implementations).  This short-cut will not work properly with
+            RFC4091  (ANAT)  compatible  clients,  which  suggests having
+            different   m-lines   with   different  IP-protocols  grouped
             together.
-          + f - instructs rtpproxy to ignore marks inserted by another
-            rtpproxy in transit to indicate that the session is already
-            goes through another proxy. Allows creating a chain of
+          + f  -  instructs  rtpproxy to ignore marks inserted by another
+            rtpproxy  in  transit to indicate that the session is already
+            goes  through  another  proxy.  Allows  creating  a  chain of
             proxies.
-          + r - flags that IP address in SDP should be trusted. Without
-            this flag, rtpproxy ignores address in the SDP and uses source
-            address of the SIP message as media address which is passed to
-            the RTP proxy.
-          + o - flags that IP from the origin description (o=) should be
+          + r  -  flags that IP address in SDP should be trusted. Without
+            this  flag,  rtpproxy  ignores  address  in  the SDP and uses
+            source  address  of the SIP message as media address which is
+            passed to the RTP proxy.
+          + o  - flags that IP from the origin description (o=) should be
             also changed.
-          + c - flags to change the session-level SDP connection (c=) IP
+          + c  - flags to change the session-level SDP connection (c=) IP
             if media-description also includes connection information.
-          + w - flags that for the UA from which message is received,
+          + w  -  flags  that  for the UA from which message is received,
             support symmetric RTP must be forced.
-          + zNN - requests the RTPproxy to perform re-packetization of RTP
-            traffic coming from the UA which has sent the current message
-            to increase or decrease payload size per each RTP packet
-            forwarded if possible. The NN is the target payload size in
-            ms, for the most codecs its value should be in 10ms
-            increments, however for some codecs the increment could differ
-            (e.g. 30ms for GSM or 20ms for G.723). The RTPproxy would
-            select the closest value supported by the codec. This feature
-            could be used for significantly reducing bandwith overhead for
-            low bitrate codecs, for example with G.729 going from 10ms to
-            100ms saves two thirds of the network bandwith.
+          + zNN  -  requests  the RTPproxy to perform re-packetization of
+            RTP  traffic  coming  from  the UA which has sent the current
+            message  to  increase  or  decrease payload size per each RTP
+            packet  forwarded  if  possible. The NN is the target payload
+            size  in  ms, for the most codecs its value should be in 10ms
+            increments,  however  for  some  codecs  the  increment could
+            differ  (e.g.  30ms  for GSM or 20ms for G.723). The RTPproxy
+            would  select  the closest value supported by the codec. This
+            feature  could  be  used  for significantly reducing bandwith
+            overhead for low bitrate codecs, for example with G.729 going
+            from 10ms to 100ms saves two thirds of the network bandwith.
      * ip_address - new SDP IP address.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.10. rtpproxy_offer usage
+   Example 1.12. rtpproxy_offer usage
 route {
 ...
     if (is_method("INVITE")) {
-        if (has_sdp()) {
+        if (has_body("application/sdp")) {
             if (rtpproxy_offer())
                 t_on_reply("1");
         } else {
             t_on_reply("2");
         }
     }
-    if (is_method("ACK") && has_sdp())
+    if (is_method("ACK") && has_body("application/sdp"))
         rtpproxy_answer();
 ...
 }
@@ -484,7 +526,7 @@ route {
 onreply_route[1]
 {
 ...
-    if (has_sdp())
+    if (has_body("application/sdp"))
         rtpproxy_answer();
 ...
 }
@@ -492,28 +534,28 @@ onreply_route[1]
 onreply_route[2]
 {
 ...
-    if (has_sdp())
+    if (has_body("application/sdp"))
         rtpproxy_offer();
 ...
 }
 
-5.3. rtpproxy_answer([flags [, ip_address]])
+5.3.  rtpproxy_answer([flags [, ip_address]])
 
    Rewrites SDP body to ensure that media is passed through an RTP proxy.
-   To be invoked on 200 OK for the cases the SDPs are in INVITE and 200 OK
-   and on ACK when SDPs are in 200 OK and ACK.
+   To  be  invoked on 200 OK for the cases the SDPs are in INVITE and 200
+   OK and on ACK when SDPs are in 200 OK and ACK.
 
-   See rtpproxy_answer() function description above for the meaning of the
-   parameters.
+   See  rtpproxy_answer()  function  description above for the meaning of
+   the parameters.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.11. rtpproxy_answer usage
+   Example 1.13. rtpproxy_answer usage
 
    See rtpproxy_offer() function example above for example.
 
-5.4. rtpproxy_destroy([flags])
+5.4.  rtpproxy_destroy([flags])
 
    Tears down the RTPProxy session for the current call.
 
@@ -521,101 +563,101 @@ onreply_route[2]
 
    Meaning of the parameters is as follows:
      * flags - flags to turn on some features.
-          + 1 - append first Via branch to Call-ID when sending command to
-            rtpproxy. This can be used to create one media session per
-            branch on the rtpproxy. When sending a subsequent "delete"
-            command to the rtpproxy, you can then stop just the session
+          + 1  -  append first Via branch to Call-ID when sending command
+            to rtpproxy. This can be used to create one media session per
+            branch  on  the  rtpproxy. When sending a subsequent "delete"
+            command  to  the rtpproxy, you can then stop just the session
             for a specific branch when passing the flag '1' or '2' in the
-            "unforce_rtpproxy", or stop all sessions for a call when not
-            passing one of those two flags there. This is especially
-            useful if you have serially forked call scenarios where
-            rtpproxy gets an "update" command for a new branch, and then a
-            "delete" command for the previous branch, which would
-            otherwise delete the full call, breaking the subsequent
-            "lookup" for the new branch. This flag is only supported by
+            "unforce_rtpproxy",  or stop all sessions for a call when not
+            passing  one  of  those  two  flags there. This is especially
+            useful  if  you  have  serially  forked  call scenarios where
+            rtpproxy  gets an "update" command for a new branch, and then
+            a  "delete"  command  for  the  previous  branch, which would
+            otherwise  delete  the  full  call,  breaking  the subsequent
+            "lookup"  for  the new branch. This flag is only supported by
             the ngcp-mediaproxy-ng rtpproxy at the moment!
-          + 2 - append second Via branch to Call-ID when sending command
+          + 2  - append second Via branch to Call-ID when sending command
             to rtpproxy. See flag '1' for its meaning.
-          + b - append branch specific variable to Call-ID when sending
-            command to rtpproxy. See rtpproxy_offer() for details.
+          + b  -  append branch specific variable to Call-ID when sending
+            command   to  rtpproxy.  See  rtpproxy_offer()  for  details.
             <listitem>
             </listitem>
-            t - do not include To tag to "delete" command to rtpproxy thus
-            causing full call to be deleted. Useful for deleting unused
-            rtpproxy call when 200 OK is received on a branch, where
-            rtpproxy is not needed.
+            t  -  do  not  include To tag to "delete" command to rtpproxy
+            thus  causing  full  call  to be deleted. Useful for deleting
+            unused  rtpproxy  call  when  200 OK is received on a branch,
+            where rtpproxy is not needed.
 
-   Example 1.12. rtpproxy_destroy usage
+   Example 1.14. rtpproxy_destroy usage
 ...
 rtpproxy_destroy();
 ...
 
-5.5. unforce_rtp_proxy()
+5.5.  unforce_rtp_proxy()
 
    Same as rtpproxy_destroy().
 
-5.6. rtpproxy_manage([flags [, ip_address]])
+5.6.  rtpproxy_manage([flags [, ip_address]])
 
-   Manage the RTPProxy session - it combines the functionality of
-   rtpproxy_offer(), rtpproxy_answer() and unforce_rtpproxy(), detecting
+   Manage  the  RTPProxy  session  -  it  combines  the  functionality of
+   rtpproxy_offer(),  rtpproxy_answer() and unforce_rtpproxy(), detecting
    internally based on message type and method which one to execute.
 
-   It can take the same parameters as rtpproxy_offer(). The flags
-   parameter to rtpproxy_manage() can be a configuration variable
+   It  can  take  the  same  parameters  as  rtpproxy_offer().  The flags
+   parameter   to  rtpproxy_manage()  can  be  a  configuration  variable
    containing the flags as a string.
 
    Functionality:
      * If INVITE with SDP, then do rtpproxy_offer()
      * If INVITE with SDP, when the tm module is loaded, mark transaction
-       with internal flag FL_SDP_BODY to know that the 1xx and 2xx are for
-       rtpproxy_answer()
+       with  internal  flag  FL_SDP_BODY to know that the 1xx and 2xx are
+       for rtpproxy_answer()
      * If ACK with SDP, then do rtpproxy_answer()
-     * If BYE or CANCEL, or called within a FAILURE_ROUTE[], then do
+     * If  BYE  or  CANCEL,  or  called within a FAILURE_ROUTE[], then do
        unforce_rtpproxy()
      * If reply to INVITE with code >= 300 do unforce_rtpproxy()
-     * If reply with SDP to INVITE having code 1xx and 2xx, then do
-       rtpproxy_answer() if the request had SDP or tm is not loaded,
+     * If  reply  with  SDP  to  INVITE  having code 1xx and 2xx, then do
+       rtpproxy_answer()  if  the  request  had  SDP or tm is not loaded,
        otherwise do rtpproxy_offer()
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.13. rtpproxy_manage usage
+   Example 1.15. rtpproxy_manage usage
 ...
 rtpproxy_manage();
 ...
 
-5.7. rtpproxy_stream2uac(prompt_name, count),
+5.7.  rtpproxy_stream2uac(prompt_name, count),
 
-   Instruct the RTPproxy to stream prompt/announcement pre-encoded with
+   Instruct  the  RTPproxy to stream prompt/announcement pre-encoded with
    the makeann command from the RTPproxy distribution. The uac/uas suffix
-   selects who will hear the announcement relatively to the current
+   selects  who  will  hear  the  announcement  relatively to the current
    transaction - UAC or UAS. For example invoking the rtpproxy_stream2uac
-   in the request processing block on ACK transaction will play the prompt
-   to the UA that has generated original INVITE and ACK while
-   rtpproxy_stop_stream2uas on 183 in reply processing block will play the
-   prompt to the UA that has generated 183.
-
-   Apart from generating announcements, another possible application of
-   this function is implementing music on hold (MOH) functionality. When
-   count is -1, the streaming will be in loop indefinitely until the
+   in  the  request  processing  block  on  ACK transaction will play the
+   prompt  to  the  UA  that  has generated original INVITE and ACK while
+   rtpproxy_stop_stream2uas  on  183  in reply processing block will play
+   the prompt to the UA that has generated 183.
+
+   Apart  from  generating announcements, another possible application of
+   this  function is implementing music on hold (MOH) functionality. When
+   count  is  -1,  the  streaming  will be in loop indefinitely until the
    appropriate rtpproxy_stop_stream2xxx is issued.
 
-   In order to work correctly, these functions require that a session in
+   In  order to work correctly, these functions require that a session in
    the RTPproxy already exists. Also those functions don't alter the SDP,
-   so that they are not a substitute for calling rtpproxy_offer or
+   so  that  they  are  not  a  substitute  for calling rtpproxy_offer or
    rtpproxy_answer.
 
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE.
 
    Meaning of the parameters is as follows:
-     * prompt_name - name of the prompt to stream. Should be either
-       absolute pathname or pathname relative to the directory where
+     * prompt_name  -  name  of  the  prompt  to stream. Should be either
+       absolute  pathname  or  pathname  relative  to the directory where
        RTPproxy runs.
-     * count - number of times the prompt should be repeated. A value of
-       -1 means that it will be streaming in a loop indefinitely, until
+     * count  - number of times the prompt should be repeated. A value of
+       -1  means  that it will be streaming in a loop indefinitely, until
        the appropriate rtpproxy_stop_stream2xxx is issued.
 
-   Example 1.14. rtpproxy_stream2xxx usage
+   Example 1.16. rtpproxy_stream2xxx usage
 ...
     if (is_method("INVITE")) {
         rtpproxy_offer();
@@ -627,33 +669,33 @@ rtpproxy_manage();
     };
 ...
 
-5.8. rtpproxy_stream2uas(prompt_name, count)
+5.8.  rtpproxy_stream2uas(prompt_name, count)
 
    See function rtpproxy_stream2uac(prompt_name, count).
 
-5.9. rtpproxy_stop_stream2uac(),
+5.9.  rtpproxy_stop_stream2uac(),
 
-   Stop streaming of announcement/prompt/MOH started previously by the
-   respective rtpproxy_stream2xxx. The uac/uas suffix selects whose
+   Stop  streaming  of  announcement/prompt/MOH started previously by the
+   respective  rtpproxy_stream2xxx.  The  uac/uas  suffix  selects  whose
    announcement relatively to tha current transaction should be stopped -
    UAC or UAS.
 
    These functions can be used from REQUEST_ROUTE, ONREPLY_ROUTE.
 
-5.10. start_recording()
+5.10.  start_recording()
 
-   This function will send a signal to the RTP-Proxy to record the RTP
-   stream on the RTP-Proxy. This function is only supported by Sippy
+   This  function  will  send a signal to the RTP-Proxy to record the RTP
+   stream  on  the  RTP-Proxy.  This  function is only supported by Sippy
    RTPproxy at the moment!
 
    This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE.
 
-   Example 1.15. start_recording usage
+   Example 1.17. start_recording usage
 ...
 start_recording();
 ...
 
-5.11. rtpproxy_stop_stream2uas(prompt_name, count)
+5.11.  rtpproxy_stop_stream2uas(prompt_name, count)
 
    See function rtpproxy_stop_stream2uac(prompt_name, count).
 
@@ -664,11 +706,11 @@ start_recording();
 6.1. $rtpstat
 
    Returns the RTP-Statistics from the RTP-Proxy. The RTP-Statistics from
-   the RTP-Proxy are provided as a string and it does contain several
-   packet-counters. The statistics must be retrieved before the session is
-   deleted (before unforce_rtpproxy()).
+   the  RTP-Proxy  are  provided  as a string and it does contain several
+   packet-counters.  The  statistics must be retrieved before the session
+   is deleted (before unforce_rtpproxy()).
 
-   Example 1.16. $rtpstat-Usage
+   Example 1.18. $rtpstat-Usage
 ...
     append_hf("X-RTP-Statistics: $rtpstat\r\n");
 ...
@@ -680,30 +722,30 @@ start_recording();
 
 7.1. nh_enable_rtpp
 
-   Enables a rtp proxy if parameter value is greater than 0. Disables it
+   Enables  a rtp proxy if parameter value is greater than 0. Disables it
    if a zero value is given.
 
-   The first parameter is the rtp proxy url (exactly as defined in the
+   The  first  parameter  is the rtp proxy url (exactly as defined in the
    config file).
 
    The second parameter value must be a number in decimal.
 
-   NOTE: if a rtpproxy is defined multiple times (in the same or diferente
-   sete), all of its instances will be enables/disabled.
+   NOTE:  if  a  rtpproxy  is  defined  multiple  times  (in  the same or
+   diferente sete), all of its instances will be enables/disabled.
 
-   Example 1.17. nh_enable_rtpp usage
+   Example 1.19.  nh_enable_rtpp usage
 ...
 $ kamctl fifo nh_enable_rtpp udp:192.168.2.133:8081 0
 ...
 
 7.2. nh_show_rtpp
 
-   Displays all the rtp proxies and their information: set and status
+   Displays  all  the  rtp  proxies and their information: set and status
    (disabled or not, weight and recheck_ticks).
 
    No parameter.
 
-   Example 1.18. nh_show_rtpp usage
+   Example 1.20.  nh_show_rtpp usage
 ...
 $ kamctl fifo nh_show_rtpp
 ...
diff --git a/modules/rtpproxy/doc/rtpproxy_admin.xml b/modules/rtpproxy/doc/rtpproxy_admin.xml
index 18e89a5..7a60c17 100644
--- a/modules/rtpproxy/doc/rtpproxy_admin.xml
+++ b/modules/rtpproxy/doc/rtpproxy_admin.xml
@@ -98,8 +98,11 @@
 	<section>
 		<title><varname>rtpproxy_sock</varname> (string)</title>
 		<para>
-		Definition of socket(s) used to connect to (a set) RTPProxy. It may
-		specify a UNIX socket or an IPv4/IPv6 UDP socket.
+		Used to define the list of RTPPRoxy instances to connect to.
+		These can be UNIX sockets or IPv4/IPv6 UDP sockets.
+
+		Each modparam entry will insert sockets into a single set. If no set ID is given, the default set ID '0' will be used. To define multiple sets add the set number at the beginning of each parameter followed by '=='.
+		Sockets can be weighted by adding '=#' to a socket where # is an integer. A socket with a weight of 2 will be chosen twice as often as one with a weight of 1.
 		</para>
 		<para>
 		<emphasis>
@@ -112,9 +115,11 @@
 ...
 # single rtproxy
 modparam("rtpproxy", "rtpproxy_sock", "udp:localhost:12221")
+
 # multiple rtproxies for LB
 modparam("rtpproxy", "rtpproxy_sock",
 	"udp:localhost:12221 udp:localhost:12222")
+
 # multiple sets of multiple rtproxies
 modparam("rtpproxy", "rtpproxy_sock",
 	"1 == udp:localhost:12221 udp:localhost:12222")
@@ -230,7 +235,7 @@ modparam("rtpproxy", "nortpproxy_str", "a=sdpmangled:yes\r\n")
 		<title>Set <varname>timeout_socket</varname> parameter</title>
 		<programlisting format="linespecific">
 ...
-modparam("nathelper", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
+modparam("rtpproxy", "timeout_socket", "xmlrpc:http://127.0.0.1:8000/RPC2")
 ...
 </programlisting>
 		</example>
@@ -281,6 +286,41 @@ modparam("rtpproxy", "extra_id_pv", "$avp(extra_id)")
 </programlisting>
 		</example>
 	</section>
+	<section>
+		<title><varname>db_url</varname> (string)</title>
+		<para>
+			The database URL to load rtp_proxy sets from.
+			If this parameter is set, the module will attempt to load the rtpproxy sets from the specified database and will ignore any 'rtpproxy_sock' modparams.
+		</para>
+		<para>
+			Default is empty, a database will not be used.
+		</para>
+		<example>
+		<title>Set <varname>db_url</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy", "db_url", "mysql://user:passwb@localhost/database")
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>table_name</varname> (string)</title>
+		<para>
+			The name of the table containing the rtpproxy sets.
+		</para>
+		<para>
+			Default value is <quote>rtpproxy</quote>.
+		</para>
+		<example>
+		<title>Set <varname>table_name</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtpproxy", "table_name", "my_rtpp_sets")
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 
 	<section>
@@ -454,14 +494,14 @@ rtpproxy_offer();
 route {
 ...
     if (is_method("INVITE")) {
-        if (has_sdp()) {
+        if (has_body("application/sdp")) {
             if (rtpproxy_offer())
                 t_on_reply("1");
         } else {
             t_on_reply("2");
         }
     }
-    if (is_method("ACK") && has_sdp())
+    if (is_method("ACK") && has_body("application/sdp"))
         rtpproxy_answer();
 ...
 }
@@ -469,7 +509,7 @@ route {
 onreply_route[1]
 {
 ...
-    if (has_sdp())
+    if (has_body("application/sdp"))
         rtpproxy_answer();
 ...
 }
@@ -477,7 +517,7 @@ onreply_route[1]
 onreply_route[2]
 {
 ...
-    if (has_sdp())
+    if (has_body("application/sdp"))
         rtpproxy_offer();
 ...
 }
diff --git a/modules/rtpproxy/rtpproxy.c b/modules/rtpproxy/rtpproxy.c
index e25a3a3..ae9d291 100644
--- a/modules/rtpproxy/rtpproxy.c
+++ b/modules/rtpproxy/rtpproxy.c
@@ -241,6 +241,7 @@ MODULE_VERSION
 
 
 #define DEFAULT_RTPP_SET_ID		0
+static str DEFAULT_RTPP_SET_ID_STR = str_init("0");
 
 #define MI_SET_NATPING_STATE		"nh_enable_ping"
 #define MI_DEFAULT_NATPING_STATE	1
@@ -283,7 +284,8 @@ static int alter_mediaport(struct sip_msg *, str *, str *, str *, int);
 static int alter_rtcp(struct sip_msg *msg, str *body, str *oldport, str *newport);
 static char *gencookie();
 static int rtpp_test(struct rtpp_node*, int, int);
-static int unforce_rtp_proxy_f(struct sip_msg *, char *, char *);
+static int unforce_rtp_proxy1_f(struct sip_msg *, char *, char *);
+static int unforce_rtp_proxy(struct sip_msg *, char *);
 static int force_rtp_proxy(struct sip_msg *, char *, char *, int, int);
 static int start_recording_f(struct sip_msg *, char *, char *);
 static int rtpproxy_answer1_f(struct sip_msg *, char *, char *);
@@ -359,17 +361,17 @@ static cmd_export_t cmds[] = {
 	{"set_rtp_proxy_set",  (cmd_function)set_rtp_proxy_set_f,    1,
 		fixup_set_id, 0,
 		ANY_ROUTE},
-	{"unforce_rtp_proxy",  (cmd_function)unforce_rtp_proxy_f,    0,
+	{"unforce_rtp_proxy",  (cmd_function)unforce_rtp_proxy1_f,   0,
 		0, 0,
 		ANY_ROUTE},
-	{"rtpproxy_destroy",   (cmd_function)unforce_rtp_proxy_f,    0,
+	{"rtpproxy_destroy",   (cmd_function)unforce_rtp_proxy1_f,   0,
 		0, 0,
 		ANY_ROUTE},
-	{"unforce_rtp_proxy",  (cmd_function)unforce_rtp_proxy_f,    1,
-		0, 0,
+	{"unforce_rtp_proxy",  (cmd_function)unforce_rtp_proxy1_f,   1,
+		fixup_spve_null, 0,
 		ANY_ROUTE},
-	{"rtpproxy_destroy",   (cmd_function)unforce_rtp_proxy_f,    1,
-		0, 0,
+	{"rtpproxy_destroy",   (cmd_function)unforce_rtp_proxy1_f,   1,
+		fixup_spve_null, 0,
 		ANY_ROUTE},
 	{"start_recording",    (cmd_function)start_recording_f,      0,
 		0, 0,
@@ -378,19 +380,19 @@ static cmd_export_t cmds[] = {
 		0, 0,
 		ANY_ROUTE},
 	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer1_f,     1,
-		0, 0,
+		fixup_spve_null, 0,
 		ANY_ROUTE},
 	{"rtpproxy_offer",	(cmd_function)rtpproxy_offer2_f,     2,
-		0, 0,
+		fixup_spve_spve, 0,
 		ANY_ROUTE},
 	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer1_f,    0,
 		0, 0,
 		ANY_ROUTE},
 	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer1_f,    1,
-		0, 0,
+		fixup_spve_null, 0,
 		ANY_ROUTE},
 	{"rtpproxy_answer",	(cmd_function)rtpproxy_answer2_f,    2,
-		0, 0,
+		fixup_spve_spve, 0,
 		ANY_ROUTE},
 	{"rtpproxy_stream2uac",(cmd_function)rtpproxy_stream2uac2_f, 2,
 		fixup_var_str_int, 0,
@@ -433,6 +435,8 @@ static param_export_t params[] = {
 	{"ice_candidate_priority_avp", STR_PARAM,
 	 &ice_candidate_priority_avp_param},
 	{"extra_id_pv",           STR_PARAM, &extra_id_pv_param.s },
+	{"db_url",                STR_PARAM, &rtpp_db_url.s },
+	{"table_name",            STR_PARAM, &rtpp_table_name.s },
 	{0, 0, 0}
 };
 
@@ -501,13 +505,107 @@ static int rtpproxy_set_store(modparam_t type, void * val){
 	return 0;
 }
 
+struct rtpp_set *get_rtpp_set(str *const set_name)
+{
+	unsigned int this_set_id;
+	struct rtpp_set *rtpp_list;
+	if (rtpp_set_list == NULL)
+	{
+		LM_ERR("rtpp set list not configured\n");
+		return NULL;
+	}
+	/* Only integer set_names are valid at the moment */
+	if ((set_name->s == NULL) || (set_name->len == 0))
+	{
+		LM_ERR("Invalid set name '%.*s'\n", set_name->len, set_name->s);
+		return NULL;
+	}
+	if (str2int(set_name, &this_set_id) < 0)
+	{
+		LM_ERR("Invalid set name '%.*s' - must be integer\n", set_name->len, set_name->s);
+		return NULL;
+	}
+
+	rtpp_list = select_rtpp_set(this_set_id);
+
+	if(rtpp_list==NULL){	/*if a new id_set : add a new set of rtpp*/
+		rtpp_list = shm_malloc(sizeof(struct rtpp_set));
+		if(!rtpp_list){
+			LM_ERR("no shm memory left\n");
+			return NULL;
+		}
+		memset(rtpp_list, 0, sizeof(struct rtpp_set));
+		rtpp_list->id_set = this_set_id;
+		if (rtpp_set_list->rset_first == NULL)
+		{
+			rtpp_set_list->rset_first = rtpp_list;
+		} else {
+			rtpp_set_list->rset_last->rset_next = rtpp_list;
+		}
+		rtpp_set_list->rset_last = rtpp_list;
+		rtpp_set_count++;
+
+		if (this_set_id == DEFAULT_RTPP_SET_ID)
+		{
+			default_rtpp_set = rtpp_list;
+		}
+	}
+	return rtpp_list;
+}
+
+int insert_rtpp_node(struct rtpp_set *const rtpp_list, const str *const url, const int weight, const int disabled)
+{
+	struct rtpp_node *pnode;
+
+	if ((pnode = shm_malloc(sizeof(struct rtpp_node) + url->len + 1)) == NULL)
+	{
+		LM_ERR("out of shm memory\n");
+		return -1;
+	}
+	memset(pnode, 0, sizeof(struct rtpp_node) + url->len + 1);
+	pnode->idx = rtpp_no++;
+	pnode->rn_weight = weight;
+	pnode->rn_umode = 0;
+	pnode->rn_disabled = disabled;
+	/* Permanently disable if marked as disabled */
+	pnode->rn_recheck_ticks = disabled ? MI_MAX_RECHECK_TICKS : 0;
+	pnode->rn_url.s = (char*)(pnode + 1);
+	memcpy(pnode->rn_url.s, url->s, url->len);
+	pnode->rn_url.len = url->len;
+
+	LM_DBG("url is '%.*s'\n", pnode->rn_url.len, pnode->rn_url.s);
+
+	/* Find protocol and store address */
+	pnode->rn_address = pnode->rn_url.s;
+	if (strncasecmp(pnode->rn_address, "udp:", 4) == 0) {
+		pnode->rn_umode = 1;
+		pnode->rn_address += 4;
+	} else if (strncasecmp(pnode->rn_address, "udp6:", 5) == 0) {
+		pnode->rn_umode = 6;
+		pnode->rn_address += 5;
+	} else if (strncasecmp(pnode->rn_address, "unix:", 5) == 0) {
+		pnode->rn_umode = 0;
+		pnode->rn_address += 5;
+	}
+
+	if (rtpp_list->rn_first == NULL)
+	{
+		rtpp_list->rn_first = pnode;
+	} else {
+		rtpp_list->rn_last->rn_next = pnode;
+	}
+	rtpp_list->rn_last = pnode;
+	rtpp_list->rtpp_node_count++;
+
+	return 0;
+}
 
 static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, 
 										char * rtpproxy){
 	/* Make rtp proxies list. */
 	char *p, *p1, *p2, *plim;
-	struct rtpp_node *pnode;
 	int weight;
+	str url;
 
 	p = rtpproxy;
 	plim = p + strlen(p);
@@ -530,49 +628,10 @@ static int add_rtpproxy_socks(struct rtpp_set * rtpp_list,
 		} else {
 			p2 = p;
 		}
-		pnode = shm_malloc(sizeof(struct rtpp_node));
-		if (pnode == NULL) {
-			LM_ERR("no shm memory left\n");
-			return -1;
-		}
-		memset(pnode, 0, sizeof(*pnode));
-		pnode->idx = rtpp_no++;
-		pnode->rn_recheck_ticks = 0;
-		pnode->rn_weight = weight;
-		pnode->rn_umode = 0;
-		pnode->rn_disabled = 0;
-		pnode->rn_url.s = shm_malloc(p2 - p1 + 1);
-		if (pnode->rn_url.s == NULL) {
-			shm_free(pnode);
-			LM_ERR("no shm memory left\n");
-			return -1;
-		}
-		memmove(pnode->rn_url.s, p1, p2 - p1);
-		pnode->rn_url.s[p2 - p1] 	= 0;
-		pnode->rn_url.len 			= p2-p1;
-
-		LM_DBG("url is %s, len is %i\n", pnode->rn_url.s, pnode->rn_url.len);
-		/* Leave only address in rn_address */
-		pnode->rn_address = pnode->rn_url.s;
-		if (strncasecmp(pnode->rn_address, "udp:", 4) == 0) {
-			pnode->rn_umode = 1;
-			pnode->rn_address += 4;
-		} else if (strncasecmp(pnode->rn_address, "udp6:", 5) == 0) {
-			pnode->rn_umode = 6;
-			pnode->rn_address += 5;
-		} else if (strncasecmp(pnode->rn_address, "unix:", 5) == 0) {
-			pnode->rn_umode = 0;
-			pnode->rn_address += 5;
-		}
-
-		if (rtpp_list->rn_first == NULL) {
-			rtpp_list->rn_first = pnode;
-		} else {
-			rtpp_list->rn_last->rn_next = pnode;
-		}
 
-		rtpp_list->rn_last = pnode;
-		rtpp_list->rtpp_node_count++;
+		url.s = p1;
+		url.len = (p2-p1);
+		insert_rtpp_node(rtpp_list, &url, weight, 0);
 	}
 	return 0;
 }
@@ -585,9 +644,7 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies)
 {
 	char *p,*p2;
 	struct rtpp_set * rtpp_list;
-	unsigned int my_current_id;
 	str id_set;
-	int new_list;
 
 	/* empty definition? */
 	p= rtp_proxies;
@@ -612,7 +669,7 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies)
 		for(;isspace(*p2); *p2 = '\0',p2--);
 		id_set.s = p;	id_set.len = p2 - p+1;
 			
-		if(id_set.len <= 0 ||str2int(&id_set, &my_current_id)<0 ){
+		if(id_set.len <= 0){
 		LM_ERR("script error -invalid set_id value!\n");
 			return -1;
 		}
@@ -620,7 +677,7 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies)
 		rtp_proxies+=2;
 	}else{
 		rtp_proxies = p;
-		my_current_id = DEFAULT_RTPP_SET_ID;
+		id_set = DEFAULT_RTPP_SET_ID_STR;
 	}
 
 	for(;*rtp_proxies && isspace(*rtp_proxies);rtp_proxies++);
@@ -630,57 +687,18 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies)
 		return -1;;
 	}
 
-	/*search for the current_id*/
-	rtpp_list = rtpp_set_list ? rtpp_set_list->rset_first : 0;
-	while( rtpp_list != 0 && rtpp_list->id_set!=my_current_id)
-		rtpp_list = rtpp_list->rset_next;
-
-	if(rtpp_list==NULL){	/*if a new id_set : add a new set of rtpp*/
-		rtpp_list = shm_malloc(sizeof(struct rtpp_set));
-		if(!rtpp_list){
-			LM_ERR("no shm memory left\n");
-			return -1;
-		}
-		memset(rtpp_list, 0, sizeof(struct rtpp_set));
-		rtpp_list->id_set = my_current_id;
-		new_list = 1;
-	} else {
-		new_list = 0;
+	rtpp_list = get_rtpp_set(&id_set);
+	if (rtpp_list == NULL)
+	{
+		LM_ERR("Failed to get or create rtpp_list for '%.*s'\n", id_set.len, id_set.s);
+		return -1;
 	}
 
 	if(add_rtpproxy_socks(rtpp_list, rtp_proxies)!= 0){
-		/*if this list will not be inserted, clean it up*/
-		goto error;
-	}
-
-	if (new_list) {
-		if(!rtpp_set_list){/*initialize the list of set*/
-			rtpp_set_list = shm_malloc(sizeof(struct rtpp_set_head));
-			if(!rtpp_set_list){
-				LM_ERR("no shm memory left\n");
-				return -1;
-			}
-			memset(rtpp_set_list, 0, sizeof(struct rtpp_set_head));
-		}
-
-		/*update the list of set info*/
-		if(!rtpp_set_list->rset_first){
-			rtpp_set_list->rset_first = rtpp_list;
-		}else{
-			rtpp_set_list->rset_last->rset_next = rtpp_list;
-		}
-
-		rtpp_set_list->rset_last = rtpp_list;
-		rtpp_set_count++;
-
-		if(my_current_id == DEFAULT_RTPP_SET_ID){
-			default_rtpp_set = rtpp_list;
-		}
+		return -1;
 	}
 
 	return 0;
-error:
-	return -1;
 }
 
 
@@ -886,9 +904,14 @@ mod_init(void)
 		return -1;
 	}
 
-	/* any rtpproxy configured? */
-	if(rtpp_set_list)
-		default_rtpp_set = select_rtpp_set(DEFAULT_RTPP_SET_ID);
+	/* Configure the head of the rtpp_set_list */
+	rtpp_set_list = shm_malloc(sizeof(struct rtpp_set_head));
+	if (rtpp_set_list == NULL)
+	{
+		LM_ERR("no shm memory for rtpp_set_list\n");
+		return -1;
+	}
+	memset(rtpp_set_list, 0, sizeof(struct rtpp_set_head));
 
 	if (nortpproxy_str.s==NULL || nortpproxy_str.s[0]==0) {
 		nortpproxy_str.len = 0;
@@ -902,18 +925,31 @@ mod_init(void)
 			nortpproxy_str.s = NULL;
 	}
 
+	if (rtpp_db_url.s != NULL)
+	{
+		rtpp_db_url.len = strlen(rtpp_db_url.s);
+		init_rtpproxy_db();
+		if (rtpp_sets > 0)
+		{
+			LM_WARN("rtpproxy db url configured - ignoring modparam sets\n");
+		}
+	}
 	/* storing the list of rtp proxy sets in shared memory*/
 	for(i=0;i<rtpp_sets;i++){
-		if(rtpproxy_add_rtpproxy_set(rtpp_strings[i]) !=0){
+		LM_DBG("Adding RTP-Proxy set %d/%d: %s\n", i, rtpp_sets, rtpp_strings[i]);
+		if ((rtpp_db_url.s == NULL) &&
+		    (rtpproxy_add_rtpproxy_set(rtpp_strings[i]) != 0)) {
 			for(;i<rtpp_sets;i++)
 				if(rtpp_strings[i])
 					pkg_free(rtpp_strings[i]);
 			pkg_free(rtpp_strings);
+			LM_ERR("Failed to add RTP-Proxy from Config!\n");
 			return -1;
 		}
 		if(rtpp_strings[i])
 			pkg_free(rtpp_strings[i]);
 	}
+
 	if (timeout_socket_str.s==NULL || timeout_socket_str.s[0]==0) {
 		timeout_socket_str.len = 0;
 		timeout_socket_str.s = NULL;
@@ -1037,7 +1073,7 @@ child_init(int rank)
 			}
 			freeaddrinfo(res);
 rptest:
-			pnode->rn_disabled = rtpp_test(pnode, 0, 1);
+			pnode->rn_disabled = rtpp_test(pnode, pnode->rn_disabled, 1);
 		}
 	}
 
@@ -1061,9 +1097,6 @@ static void mod_destroy(void)
 
 		for(crt_rtpp = crt_list->rn_first; crt_rtpp != NULL;  ){
 
-			if(crt_rtpp->rn_url.s)
-				shm_free(crt_rtpp->rn_url.s);
-
 			last_rtpp = crt_rtpp;
 			crt_rtpp = last_rtpp->rn_next;
 			shm_free(last_rtpp);
@@ -1695,16 +1728,14 @@ static struct rtpp_set * select_rtpp_set(int id_set ){
 	struct rtpp_set * rtpp_list;
 	/*is it a valid set_id?*/
 	
-	if(!rtpp_set_list || !rtpp_set_list->rset_first){
-		LM_ERR("no rtp_proxy configured\n");
-		return 0;
+	if(!rtpp_set_list)
+	{
+		LM_ERR("rtpproxy set list not initialised\n");
+		return NULL;
 	}
 
-	for(rtpp_list=rtpp_set_list->rset_first; rtpp_list!=0 && 
+	for(rtpp_list=rtpp_set_list->rset_first; rtpp_list!=NULL && 
 		rtpp_list->id_set!=id_set; rtpp_list=rtpp_list->rset_next);
-	if(!rtpp_list){
-		LM_ERR(" script error-invalid id_set to be selected\n");
-	}
 
 	return rtpp_list;
 }
@@ -1800,7 +1831,21 @@ get_extra_id(struct sip_msg* msg, str *id_str) {
 
 
 static int
-unforce_rtp_proxy_f(struct sip_msg* msg, char* flags, char* str2)
+unforce_rtp_proxy1_f(struct sip_msg* msg, char* str1, char* str2)
+{
+	str flags;
+
+	if (str1)
+		get_str_fparam(&flags, msg, (fparam_t *) str1);
+	else
+		flags.s = NULL;
+
+	return unforce_rtp_proxy(msg, flags.s);
+}
+
+
+static int
+unforce_rtp_proxy(struct sip_msg* msg, char* flags)
 {
 	str callid, from_tag, to_tag, viabranch;
 	char *cp;
@@ -1813,6 +1858,7 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* flags, char* str2)
 	struct iovec v[1 + 4 + 3 + 2] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {NULL, 0}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}};
 	                                            /* 1 */   /* 2 */   /* 3 */    /* 4 */    /* 5 */    /* 6 */   /* 7 */    /* 8 */   /* 9 */
 
+
 	for (cp = flags; cp && *cp; cp++) {
 		switch (*cp) {
 			case '1':
@@ -1976,7 +2022,7 @@ rtpproxy_manage(struct sip_msg *msg, char *flags, char *ip)
 		return -1;
 
 	if(method==METHOD_CANCEL || method==METHOD_BYE)
-		return unforce_rtp_proxy_f(msg, flags, 0);
+		return unforce_rtp_proxy(msg, flags);
 
 	if(ip==NULL)
 	{
@@ -2005,13 +2051,13 @@ rtpproxy_manage(struct sip_msg *msg, char *flags, char *ip)
 					&& tmb.t_gett()!=T_UNDEFINED)
 				tmb.t_gett()->uas.request->msg_flags |= FL_SDP_BODY;
 			if(route_type==FAILURE_ROUTE)
-				return unforce_rtp_proxy_f(msg, flags, 0);
+				return unforce_rtp_proxy(msg, flags);
 			return force_rtp_proxy(msg, flags, (cp!=NULL)?newip:ip, 1,
 					(ip!=NULL)?1:0);
 		}
 	} else if(msg->first_line.type == SIP_REPLY) {
 		if(msg->first_line.u.reply.statuscode>=300)
-			return unforce_rtp_proxy_f(msg, flags, 0);
+			return unforce_rtp_proxy(msg, flags);
 		if(nosdp==0) {
 			if(method==METHOD_PRACK)
 				return force_rtp_proxy(msg, flags, (cp!=NULL)?newip:ip, 0,
@@ -2074,16 +2120,26 @@ rtpproxy_offer1_f(struct sip_msg *msg, char *str1, char *str2)
 {
         char *cp;
         char newip[IP_ADDR_MAX_STR_SIZE];
+	str flags;
 
         cp = ip_addr2a(&msg->rcv.dst_ip);
         strcpy(newip, cp);
-	return force_rtp_proxy(msg, str1, newip, 1, 0);
+
+	if (str1)
+		get_str_fparam(&flags, msg, (fparam_t *) str1);
+	else
+		flags.s = NULL;
+	return force_rtp_proxy(msg, flags.s, newip, 1, 0);
 }
 
 static int
 rtpproxy_offer2_f(struct sip_msg *msg, char *param1, char *param2)
 {
-	return force_rtp_proxy(msg, param1, param2, 1, 1);
+	str flags, new_ip;
+
+	get_str_fparam(&flags, msg, (fparam_t *) param1);
+	get_str_fparam(&new_ip, msg, (fparam_t *) param2);
+	return force_rtp_proxy(msg, flags.s, new_ip.s, 1, 1);
 }
 
 static int
@@ -2091,6 +2147,7 @@ rtpproxy_answer1_f(struct sip_msg *msg, char *str1, char *str2)
 {
         char *cp;
         char newip[IP_ADDR_MAX_STR_SIZE];
+	str flags;
 
 	if (msg->first_line.type == SIP_REQUEST)
 		if (msg->first_line.u.request.method_value != METHOD_ACK)
@@ -2098,18 +2155,27 @@ rtpproxy_answer1_f(struct sip_msg *msg, char *str1, char *str2)
 
         cp = ip_addr2a(&msg->rcv.dst_ip);
         strcpy(newip, cp);
-	return force_rtp_proxy(msg, str1, newip, 0, 0);
+
+	if (str1)
+		get_str_fparam(&flags, msg, (fparam_t *) str1);
+	else
+		flags.s = NULL;
+	return force_rtp_proxy(msg, flags.s, newip, 0, 0);
 }
 
 static int
 rtpproxy_answer2_f(struct sip_msg *msg, char *param1, char *param2)
 {
 
+	str flags, new_ip;
+
 	if (msg->first_line.type == SIP_REQUEST)
 		if (msg->first_line.u.request.method_value != METHOD_ACK)
 			return -1;
 
-	return force_rtp_proxy(msg, param1, param2, 0, 1);
+	get_str_fparam(&flags, msg, (fparam_t *) param1);
+	get_str_fparam(&new_ip, msg, (fparam_t *) param2);
+	return force_rtp_proxy(msg, flags.s, new_ip.s, 0, 1);
 }
 
 
diff --git a/modules/rtpproxy/rtpproxy.h b/modules/rtpproxy/rtpproxy.h
index ced1a0d..8672926 100644
--- a/modules/rtpproxy/rtpproxy.h
+++ b/modules/rtpproxy/rtpproxy.h
@@ -27,6 +27,7 @@
 #ifndef _RTPPROXY_H
 #define _RTPPROXY_H
 
+#include <sys/uio.h>
 #include "../../str.h"
 
 /* Handy macros */
@@ -68,4 +69,12 @@ struct rtpp_set_head{
 struct rtpp_node *select_rtpp_node(str, int);
 char *send_rtpp_command(struct rtpp_node *, struct iovec *, int);
 
+struct rtpp_set *get_rtpp_set(str *set_name);
+int insert_rtpp_node(struct rtpp_set *const rtpp_list, const str *const url, const int weight, const int disabled);
+
+int init_rtpproxy_db(void);
+
+extern str rtpp_db_url;
+extern str rtpp_table_name;
+
 #endif
diff --git a/modules/rtpproxy/rtpproxy_db.c b/modules/rtpproxy/rtpproxy_db.c
new file mode 100644
index 0000000..2d3e374
--- /dev/null
+++ b/modules/rtpproxy/rtpproxy_db.c
@@ -0,0 +1,169 @@
+/*
+ * rtpproxy module
+ *
+ * Copyright (c) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../../lib/srdb1/db.h"
+#include "../../lib/srdb1/db_res.h"
+
+#include "rtpproxy.h"
+
+#define RTPP_TABLE_VERSION 1
+
+static db_func_t rtpp_dbf;
+static db1_con_t *rtpp_db_handle = NULL;
+
+str rtpp_db_url = {NULL, 0};
+str rtpp_table_name = str_init("rtpproxy");
+str rtpp_set_name_col = str_init("set_name");
+str rtpp_url_col = str_init("url");
+str rtpp_weight_col = str_init("weight");
+str rtpp_flags_col = str_init("flags");
+
+static int rtpp_connect_db(void)
+{
+	if ((rtpp_db_url.s == NULL) || (rtpp_db_url.len == 0))
+		return -1;
+	if ((rtpp_db_handle = rtpp_dbf.init(&rtpp_db_url)) == NULL)
+	{
+		LM_ERR("Cannot initialize db connection\n");
+		return -1;
+	}
+	return 0;
+}
+
+static void rtpp_disconnect_db(void)
+{
+	if (rtpp_db_handle)
+	{
+		rtpp_dbf.close(rtpp_db_handle);
+		rtpp_db_handle = NULL;
+	}
+}
+
+static int rtpp_load_db(void)
+{
+	int i;
+	struct rtpp_set *rtpp_list = NULL;
+	db1_res_t *res = NULL;
+	db_val_t *values = NULL;
+	db_row_t *rows = NULL;
+	db_key_t query_cols[] = {&rtpp_set_name_col, &rtpp_url_col, &rtpp_weight_col, &rtpp_flags_col};
+
+	str set, url;
+	int weight, flags;
+	int n_rows = 0;
+	int n_cols = 4;
+
+	if (rtpp_db_handle == NULL)
+	{
+		LM_ERR("invalid db handle\n");
+		return -1;
+	}
+	if (rtpp_dbf.use_table(rtpp_db_handle, &rtpp_table_name) < 0)
+	{
+		LM_ERR("unable to use table '%.*s'\n", rtpp_table_name.len, rtpp_table_name.s);
+		return -1;
+	}
+	if (rtpp_dbf.query(rtpp_db_handle, 0, 0, 0, query_cols, 0, n_cols, 0, &res) < 0)
+	{
+		LM_ERR("error while running db query\n");
+		return -1;
+	}
+
+	n_rows = RES_ROW_N(res);
+	rows = RES_ROWS(res);
+	if (n_rows == 0)
+	{
+		LM_WARN("No rtpproxy instances in database\n");
+		return 0;
+	}
+	for (i=0; i<n_rows; i++)
+	{
+		values = ROW_VALUES(rows + i);
+
+		set.s = VAL_STR(values).s;
+		set.len = strlen(set.s);
+		url.s = VAL_STR(values+1).s;
+		url.len = strlen(url.s);
+		weight = VAL_INT(values+2);
+		flags = VAL_INT(values+3);
+
+		if ((rtpp_list = get_rtpp_set(&set)) == NULL)
+		{
+			LM_ERR("error getting rtpp_list for set '%.*s'\n", set.len, set.s);
+			continue;
+		}
+		if (insert_rtpp_node(rtpp_list, &url, weight, flags) < 0)
+		{
+			LM_ERR("error inserting '%.*s' into set '%.*s'\n", url.len, url.s, set.len, set.s);
+		}
+	}
+
+	rtpp_dbf.free_result(rtpp_db_handle, res);
+	return 0;
+}
+
+int init_rtpproxy_db(void)
+{
+	int ret;
+	int rtpp_table_version;
+	if (rtpp_db_url.s == NULL)
+		/* Database not configured */
+		return 0;
+
+	rtpp_db_url.len = strlen(rtpp_db_url.s);
+	rtpp_table_name.len = strlen(rtpp_table_name.s);
+
+	if (db_bind_mod(&rtpp_db_url, &rtpp_dbf) < 0)
+	{
+		LM_ERR("Unable to bind to db driver - %.*s\n", rtpp_db_url.len, rtpp_db_url.s);
+		return -1;
+	}
+	if (rtpp_connect_db() != 0)
+	{
+		LM_ERR("Unable to connect to db\n");
+		return -1;
+	}
+
+	rtpp_table_version = db_table_version(&rtpp_dbf, rtpp_db_handle, &rtpp_table_name);
+	if (rtpp_table_version < 0)
+	{
+		LM_ERR("failed to get rtpp table version\n");
+		ret = -1;
+		goto done;
+	}
+	switch (rtpp_table_version) {
+		case RTPP_TABLE_VERSION:
+			break;
+		default:
+			LM_ERR("invalid table version (found %d, require %d)\n",
+			  rtpp_table_version, RTPP_TABLE_VERSION);
+			ret = -1;
+			goto done;
+	}
+	ret = rtpp_load_db();
+
+done:
+	rtpp_disconnect_db();
+
+	return ret;
+}
diff --git a/modules/sca/README b/modules/sca/README
index 99fb1f3..7ca1b4c 100644
--- a/modules/sca/README
+++ b/modules/sca/README
@@ -256,7 +256,7 @@ modparam( "sca", "db_update_interval", 120 )
    4.1. sca_handle_subscribe()
    4.2. sca_call_info_update()
 
-4.1. sca_handle_subscribe()
+4.1.  sca_handle_subscribe()
 
    The function handling call-info and line-seize SUBSCRIBE requests. It
    stores or updates the subscriptions in shared memory, and sends NOTIFYs
@@ -284,7 +284,7 @@ if ( is_method( "SUBSCRIBE" )) {
 }
 ...
 
-4.2. sca_call_info_update()
+4.2.  sca_call_info_update()
 
    The sca_call_info_update function updates call state for SCA
    appearances. If a request or response packet contains a Call-Info
diff --git a/modules/sca/sca_call_info.h b/modules/sca/sca_call_info.h
index c47a47e..6a9f1ea 100644
--- a/modules/sca/sca_call_info.h
+++ b/modules/sca/sca_call_info.h
@@ -48,8 +48,9 @@ struct _sca_call_info {
 typedef struct _sca_call_info		sca_call_info;
 
 #define SCA_CALL_INFO_EMPTY( ci1 ) \
-	(!(ci1) || ((ci1)->index == SCA_CALL_INFO_APPEARANCE_INDEX_ANY && \
-			(ci1)->state == SCA_APPEARANCE_STATE_UNKNOWN))
+	((void*)(ci1) == NULL || \
+		((ci1)->index == SCA_CALL_INFO_APPEARANCE_INDEX_ANY && \
+		(ci1)->state == SCA_APPEARANCE_STATE_UNKNOWN))
 
 #define SCA_CALL_INFO_IS_SHARED_CALLER( ci1 ) \
 	(!SCA_CALL_INFO_EMPTY((ci1)) && \
diff --git a/modules/sca/sca_hash.c b/modules/sca/sca_hash.c
index 996acd9..a92b6c4 100644
--- a/modules/sca/sca_hash.c
+++ b/modules/sca/sca_hash.c
@@ -264,7 +264,7 @@ sca_hash_table_slot_kv_delete_unsafe( sca_hash_slot *slot, str *key )
 {
     sca_hash_entry	*e;
 
-    e = sca_hash_table_slot_kv_find_unsafe( slot, key );
+    e = sca_hash_table_slot_kv_find_entry_unsafe( slot, key );
     if ( e == NULL ) {
 	return( -1 );
     }
diff --git a/modules/sctp/Makefile b/modules/sctp/Makefile
new file mode 100644
index 0000000..a328f77
--- /dev/null
+++ b/modules/sctp/Makefile
@@ -0,0 +1,16 @@
+# $Id$
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=sctp.so
+LIBS=
+
+ifeq ($(OS), linux)
+LIBS+=-lsctp
+endif
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+include ../../Makefile.modules
diff --git a/modules/sctp/README b/modules/sctp/README
new file mode 100644
index 0000000..1fb71dc
--- /dev/null
+++ b/modules/sctp/README
@@ -0,0 +1,502 @@
+SCTP Module
+
+Daniel-Constantin Mierla
+
+   <miconda at gmail.com>
+
+Andrei Pelinescu-Onciul
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. sctp_socket_rcvbuf (int)
+              3.2. sctp_socket_sndbuf (int)
+              3.3. sctp_autoclose (int)
+              3.4. sctp_send_ttl (int)
+              3.5. sctp_send_retries (int)
+              3.6. sctp_assoc_tracking (int)
+              3.7. sctp_assoc_reuse (int)
+              3.8. sctp_max_assocs (int)
+              3.9. sctp_srto_initial (int)
+              3.10. sctp_srto_max (int)
+              3.11. sctp_srto_min (int)
+              3.12. sctp_asocmaxrxt (int)
+              3.13. sctp_init_max_attempts (int)
+              3.14. sctp_init_max_timeo (int)
+              3.15. sctp_hbinterval (int)
+              3.16. sctp_pathmaxrxt (int)
+              3.17. sctp_sack_delay (int)
+              3.18. sctp_sack_freq (int)
+              3.19. sctp_max_burst (int)
+
+        4. RPC Commands
+
+              4.1. sctp.info
+              4.2. sctp.options
+
+   List of Examples
+
+   1.1. Set sctp_socket_rcvbuf parameter
+   1.2. Set sctp_socket_sndbuf parameter
+   1.3. Set sctp_autoclose parameter
+   1.4. Set sctp_send_ttl parameter
+   1.5. Set sctp_send_retries parameter
+   1.6. Set sctp_assoc_tracking parameter
+   1.7. Set sctp_assoc_reuse parameter
+   1.8. Set sctp_max_assocs parameter
+   1.9. Set sctp_srto_initial parameter
+   1.10. Set sctp_srto_max parameter
+   1.11. Set sctp_srto_min parameter
+   1.12. Set sctp_asocmaxrxt parameter
+   1.13. Set sctp_init_max_attempts parameter
+   1.14. Set sctp_init_max_timeo parameter
+   1.15. Set sctp_hbinterval parameter
+   1.16. Set sctp_pathmaxrxt parameter
+   1.17. Set sctp_sack_delay parameter
+   1.18. Set sctp_sack_freq parameter
+   1.19. Set sctp_max_burst parameter
+   1.20. Use sctp.info with kamcmd
+   1.21. Use sctp.options with kamcmd
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. sctp_socket_rcvbuf (int)
+        3.2. sctp_socket_sndbuf (int)
+        3.3. sctp_autoclose (int)
+        3.4. sctp_send_ttl (int)
+        3.5. sctp_send_retries (int)
+        3.6. sctp_assoc_tracking (int)
+        3.7. sctp_assoc_reuse (int)
+        3.8. sctp_max_assocs (int)
+        3.9. sctp_srto_initial (int)
+        3.10. sctp_srto_max (int)
+        3.11. sctp_srto_min (int)
+        3.12. sctp_asocmaxrxt (int)
+        3.13. sctp_init_max_attempts (int)
+        3.14. sctp_init_max_timeo (int)
+        3.15. sctp_hbinterval (int)
+        3.16. sctp_pathmaxrxt (int)
+        3.17. sctp_sack_delay (int)
+        3.18. sctp_sack_freq (int)
+        3.19. sctp_max_burst (int)
+
+   4. RPC Commands
+
+        4.1. sctp.info
+        4.2. sctp.options
+
+1. Overview
+
+   This module provides SCTP transport layer for Kamailio. SCTP is an
+   acronym for Stream Control Transmission Protocol, read more about it
+   at: http://en.wikipedia.org/wiki/Stream_Control_Transmission_Protocol
+
+   The module itself implements the callbacks required by the core to
+   receive and send SIP messages over SCTP sockets.
+
+   The core Makefile variable SCTP must be set to 1 (which is by default
+   set to 1 in Makefile.defs) and sources compiled with -DUSE_SCTP
+   (automatically set when SCTP=1). In other words, if core Makefiles are
+   not changed and SCTP variable is not overwritten from command line,
+   then the SCTP support in core is enabled.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * libsctp - SCTP user space library available on Linux. To compile
+       the module, libsctp-dev is required as well.
+
+3. Parameters
+
+   3.1. sctp_socket_rcvbuf (int)
+   3.2. sctp_socket_sndbuf (int)
+   3.3. sctp_autoclose (int)
+   3.4. sctp_send_ttl (int)
+   3.5. sctp_send_retries (int)
+   3.6. sctp_assoc_tracking (int)
+   3.7. sctp_assoc_reuse (int)
+   3.8. sctp_max_assocs (int)
+   3.9. sctp_srto_initial (int)
+   3.10. sctp_srto_max (int)
+   3.11. sctp_srto_min (int)
+   3.12. sctp_asocmaxrxt (int)
+   3.13. sctp_init_max_attempts (int)
+   3.14. sctp_init_max_timeo (int)
+   3.15. sctp_hbinterval (int)
+   3.16. sctp_pathmaxrxt (int)
+   3.17. sctp_sack_delay (int)
+   3.18. sctp_sack_freq (int)
+   3.19. sctp_max_burst (int)
+
+3.1. sctp_socket_rcvbuf (int)
+
+   Size for the sctp socket receive buffer.
+
+   Default value is automatically set based on OS limits.
+
+   Example 1.1. Set sctp_socket_rcvbuf parameter
+...
+modparam("sctp", "sctp_socket_rcvbuf", 14096)
+...
+
+3.2. sctp_socket_sndbuf (int)
+
+   Size for the sctp socket send buffer.
+
+   Default value is automatically set based on OS limits.
+
+   Example 1.2. Set sctp_socket_sndbuf parameter
+...
+modparam("sctp", "sctp_socket_sndbuf", 14096)
+...
+
+3.3. sctp_autoclose (int)
+
+   Number of seconds before autoclosing an idle association. Can be
+   changed at runtime, but it will affect only new associations.
+
+   Default value is 180 (seconds).
+
+   Example 1.3. Set sctp_autoclose parameter
+...
+# kamcmd cfg.set_now_int sctp autoclose 120
+...
+modparam("sctp", "sctp_autoclose", 300)
+...
+
+3.4. sctp_send_ttl (int)
+
+   Number of milliseconds before an unsent message/chunk is dropped. Can
+   be changed at runtime.
+
+   Default value is 32000 (miliseconds - 32 seconds).
+
+   Example 1.4. Set sctp_send_ttl parameter
+...
+# kamcmd cfg.set_now_int sctp send_ttl 180000
+...
+modparam("sctp", "sctp_send_ttl", 10000)
+...
+
+3.5. sctp_send_retries (int)
+
+   How many times to attempt re-sending a message on a re-opened
+   association, if the sctp stack did give up sending it (it's not related
+   to sctp protocol level retransmission). Useful to improve reliability
+   with peers that reboot/restart or fail over to another machine.
+
+   WARNING: use with care and low values (e.g. 1-3) to avoid "multiplying"
+   traffic to unresponding hosts.
+
+   Can be changed at runtime.
+
+   Default value is 0.
+
+   Example 1.5. Set sctp_send_retries parameter
+...
+modparam("sctp", "sctp_send_retries", 1)
+...
+
+3.6. sctp_assoc_tracking (int)
+
+   Controls whether or not sctp associations are tracked inside Kamailio.
+   Turning it off would result in less memory being used and slightly
+   better performance, but it will also disable some other features that
+   depend on it (e.g. sctp_assoc_reuse).
+
+   Can be changed at runtime (sercmd sctp assoc_tracking 0), but changes
+   will be allowed only if all the other features that depend on it are
+   turned off (for example it can be turned off only if first
+   sctp_assoc_reuse was turned off).
+
+   Note: turning sctp_assoc_tracking on/off will delete all the tracking
+   information for all the currently tracked associations and might
+   introduce a small temporary delay in the sctp processing if lots of
+   associations were tracked.
+
+   Config options depending on sctp_assoc_tracking being on:
+   sctp_assoc_reuse.
+
+   Default value is 1 (enabled, 0 - disabled).
+
+   Example 1.6. Set sctp_assoc_tracking parameter
+...
+modparam("sctp", "sctp_assoc_tracking", 0)
+...
+
+3.7. sctp_assoc_reuse (int)
+
+   Controls sctp association reuse. For now only association reuse for
+   replies is affected by it. Default is on. Depends on
+   sctp_assoc_tracking being on.
+
+   Note that even if turned off, if the port in via corresponds to the
+   source port of the association the request was sent on or if rport is
+   turned on (force_rport() or via containing a rport option), the
+   association will be automatically reused by the sctp stack. Can be
+   changed at runtime (sctp assoc_reuse), but it can be turned on only if
+   sctp_assoc_tracking is on.
+
+   Default value is 1 (enabled, 0 - disabled).
+
+   Example 1.7. Set sctp_assoc_reuse parameter
+...
+modparam("sctp", "sctp_assoc_reuse", 0)
+...
+
+3.8. sctp_max_assocs (int)
+
+   Maximum number of allowed open sctp associations. -1 means maximum
+   allowed by the OS. Default: -1. Can be changed at runtime (e.g.: kamcmd
+   cfg.set_now_int sctp max_assocs 10 ). When the maximum associations
+   number is exceeded and a new associations is opened by a remote host,
+   the association will be immediately closed. However it is possible that
+   some sip packets get through (especially if they are sent early, as
+   part of the 4-way handshake).
+
+   When Kamailio tries to open a new association and the max_assocs is
+   exceeded the exact behaviour depends on whether or not
+   sctp_assoc_tracking is on. If on, the send triggering the active open
+   will gracefully fail, before actually opening the new association and
+   no packet will be sent. However if sctp_assoc_tracking is off, the
+   association will first be opened and then immediately closed. In
+   general this means that the initial sip packet will be sent (as part of
+   the 4-way handshake).
+
+   Default value is -1.
+
+   Example 1.8. Set sctp_max_assocs parameter
+...
+modparam("sctp", "sctp_max_assocs", 10)
+...
+
+3.9. sctp_srto_initial (int)
+
+   Initial value of the retransmission timeout (in miliseconds), used in
+   RTO calculations.
+
+   Can be changed at runtime (sctp srto_initial) but it will affect only
+   new associations.
+
+   Default value is OS specific.
+
+   Example 1.9. Set sctp_srto_initial parameter
+...
+modparam("sctp", "sctp_srto_initial", 1000)
+...
+
+3.10. sctp_srto_max (int)
+
+   Maximum value of the retransmission timeout (RTO) in milliseconds.
+
+   WARNING: values lower then the sctp sack_delay will cause lots of
+   retransmissions and connection instability (see sctp_srto_min for more
+   details).
+
+   Can be changed at runtime (sctp srto_max) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.10. Set sctp_srto_max parameter
+...
+modparam("sctp", "sctp_srto_max", 2000)
+...
+
+3.11. sctp_srto_min (int)
+
+   Minimum value of the retransmission timeout (RTO) in milliseconds.
+
+   WARNING: values lower then the sctp sack_delay of any peer might cause
+   retransmissions and possible interoperability problems. According to
+   the standard the sack_delay should be between 200 and 500 ms, so avoid
+   trying values lower then 500 ms unless you control all the possible
+   sctp peers and you do make sure their sack_delay is higher or their
+   sack_freq is 1.
+
+   Can be changed at runtime (sctp srto_min) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.11. Set sctp_srto_min parameter
+...
+modparam("sctp", "sctp_srto_min", 800)
+...
+
+3.12. sctp_asocmaxrxt (int)
+
+   Maximum retransmissions attempts per association. It should be set to
+   sctp_pathmaxrxt * no. of expected paths.
+
+   Can be changed at runtime (sctp asocmaxrxt) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.12. Set sctp_asocmaxrxt parameter
+...
+modparam("sctp", "sctp_asocmaxrxt", 5)
+...
+
+3.13. sctp_init_max_attempts (int)
+
+   Maximum INIT retransmission attempts.
+
+   Can be changed at runtime (sctp init_max_attempts).
+
+   Default value is OS specific.
+
+   Example 1.13. Set sctp_init_max_attempts parameter
+...
+modparam("sctp", "sctp_init_max_attempts", 3)
+...
+
+3.14. sctp_init_max_timeo (int)
+
+   Maximum INIT retransmission timeout (RTO max for INIT) in miliseconds.
+
+   Can be changed at runtime (sctp init_max_timeo).
+
+   Default value is OS specific.
+
+   Example 1.14. Set sctp_init_max_timeo parameter
+...
+modparam("sctp", "sctp_init_max_timeo", 1000)
+...
+
+3.15. sctp_hbinterval (int)
+
+   SCTP heartbeat interval. Setting it to -1 will disable the heartbeats.
+
+   Can be changed at runtime (sctp hbinterval) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.15. Set sctp_hbinterval parameter
+...
+modparam("sctp", "sctp_hbinterval", 2000)
+...
+
+3.16. sctp_pathmaxrxt (int)
+
+   Maximum retransmission attempts per path (see also sctp_asocmaxrxt).
+
+   Can be changed at runtime (sctp pathmaxrxt) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.16. Set sctp_pathmaxrxt parameter
+...
+modparam("sctp", "sctp_pathmaxrxt", 2)
+...
+
+3.17. sctp_sack_delay (int)
+
+   Delay until an ACK is generated after receiving a packet (in
+   miliseconds).
+
+   WARNING: a value higher then srto_min can cause a lot of
+   retransmissions (and strange problems). A value higher then srto_max
+   will result in very high connections instability. According to the
+   standard the sack_delay value should be between 200 and 500 ms.
+
+   Can be changed at runtime (sctp sack_delay) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.17. Set sctp_sack_delay parameter
+...
+modparam("sctp", "sctp_sack_delay", 400)
+...
+
+3.18. sctp_sack_freq (int)
+
+   Number of packets received before an ACK is sent (without waiting for
+   the sack_delay to expire). Default: OS specific.
+
+   Note: on linux with lksctp up to and including 1.0.9 is not possible to
+   set this value (having it in the config will produce a warning on
+   startup).
+
+   Can be changed at runtime (sctp sack_freq) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.18. Set sctp_sack_freq parameter
+...
+modparam("sctp", "sctp_sack_freq", 3)
+...
+
+3.19. sctp_max_burst (int)
+
+   Maximum burst of packets that can be emitted by an association.
+
+   Can be changed at runtime (sctp max_burst) but it will affect only new
+   associations.
+
+   Default value is OS specific.
+
+   Example 1.19. Set sctp_max_burst parameter
+...
+modparam("sctp", "sctp_max_burst", 3)
+...
+
+4. RPC Commands
+
+   4.1. sctp.info
+   4.2. sctp.options
+
+4.1. sctp.info
+
+   Print information about SCTP transport.
+
+   Example 1.20. Use sctp.info with kamcmd
+...
+kamcmd sctp.info
+...
+
+4.2. sctp.options
+
+   Print the options of SCTP sockets. It can take an optional parameter
+   that specifies the listen address of SCTP socket.
+
+   Example 1.21. Use sctp.options with kamcmd
+...
+kamcmd sctp.options
+...
diff --git a/modules/sctp/doc/Makefile b/modules/sctp/doc/Makefile
new file mode 100644
index 0000000..953e62d
--- /dev/null
+++ b/modules/sctp/doc/Makefile
@@ -0,0 +1,4 @@
+docs = sctp.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/sctp/doc/sctp.xml b/modules/sctp/doc/sctp.xml
new file mode 100644
index 0000000..4f03c2f
--- /dev/null
+++ b/modules/sctp/doc/sctp.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>SCTP Module</title>
+	<productname class="trade">kamailio.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>miconda at gmail.com</email>
+	    </author>
+        <author>
+        <firstname>Andrei</firstname>
+        <surname>Pelinescu-Onciul</surname>
+        <address>
+            <email>andrei at iptel.org</email>
+        </address>
+        </author>
+	</authorgroup>
+    </bookinfo>
+    <toc></toc>
+
+    <xi:include href="sctp_admin.xml"/>
+
+</book>
diff --git a/modules/sctp/doc/sctp_admin.xml b/modules/sctp/doc/sctp_admin.xml
new file mode 100644
index 0000000..3ede4ca
--- /dev/null
+++ b/modules/sctp/doc/sctp_admin.xml
@@ -0,0 +1,622 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		This module provides SCTP transport layer for &kamailio;. SCTP is an
+		acronym for Stream Control Transmission Protocol, read more about it
+		at: <ulink url="http://en.wikipedia.org/wiki/Stream_Control_Transmission_Protocol">
+			http://en.wikipedia.org/wiki/Stream_Control_Transmission_Protocol</ulink>
+	</para>
+	<para>
+		The module itself implements the callbacks required by the core to
+		receive and send SIP messages over SCTP sockets.
+	</para>
+	<para>
+		The core Makefile variable SCTP must be set to 1 (which is by default set
+		to 1 in Makefile.defs) and sources compiled with -DUSE_SCTP (automatically
+		set when SCTP=1). In other words, if core Makefiles are not changed and
+		SCTP variable is not overwritten from command line, then the SCTP 
+		support in core is enabled.
+	</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>libsctp</emphasis> - SCTP user space library available
+				on Linux. To compile the module, libsctp-dev is required as well.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+
+	<section>
+	<title>Parameters</title>
+	<section id="sctp.p.sctp_socket_rcvbuf">
+		<title><varname>sctp_socket_rcvbuf</varname> (int)</title>
+		<para>
+			 Size for the sctp socket receive buffer.
+		</para>
+		<para>
+		<emphasis>
+			Default value is automatically set based on OS limits.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_socket_rcvbuf</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_socket_rcvbuf", 14096)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_socket_sndbuf">
+		<title><varname>sctp_socket_sndbuf</varname> (int)</title>
+		<para>
+			 Size for the sctp socket send buffer.
+		</para>
+		<para>
+		<emphasis>
+			Default value is automatically set based on OS limits.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_socket_sndbuf</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_socket_sndbuf", 14096)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_autoclose">
+		<title><varname>sctp_autoclose</varname> (int)</title>
+		<para>
+			Number of seconds before autoclosing an idle association.
+			Can be changed at runtime, but it will affect only new associations.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 180 (seconds).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_autoclose</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+# kamcmd cfg.set_now_int sctp autoclose 120
+...
+modparam("sctp", "sctp_autoclose", 300)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_send_ttl">
+		<title><varname>sctp_send_ttl</varname> (int)</title>
+		<para>
+			Number of milliseconds before an unsent message/chunk is dropped.
+			Can be changed at runtime.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 32000 (miliseconds - 32 seconds).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_send_ttl</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+# kamcmd cfg.set_now_int sctp send_ttl 180000
+...
+modparam("sctp", "sctp_send_ttl", 10000)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_send_retries">
+		<title><varname>sctp_send_retries</varname> (int)</title>
+		<para>
+			How many times to attempt re-sending a message on a re-opened
+			association, if the sctp stack did give up sending it (it's not
+			related to sctp protocol level retransmission). Useful to improve
+			reliability with peers that reboot/restart or fail over to another
+			machine.
+		</para>
+		<para>
+			WARNING: use with care and low values (e.g. 1-3) to avoid
+			"multiplying" traffic to unresponding hosts.
+		</para>
+		<para>
+			Can be changed at runtime. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_send_retries</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_send_retries", 1)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_assoc_tracking">
+		<title><varname>sctp_assoc_tracking</varname> (int)</title>
+		<para>
+			Controls whether or not sctp associations are tracked inside
+			&kamailio;. Turning it off would result in less memory being used
+			and slightly better performance, but it will also disable some other
+			features that depend on it (e.g. sctp_assoc_reuse).
+		</para>
+		<para>
+			Can be changed at runtime (sercmd sctp assoc_tracking 0), but changes
+			will be allowed only if all the other features that depend on it are
+			turned off (for example it can be turned off only if first
+			sctp_assoc_reuse was turned off).
+		</para>
+		<para>
+			Note: turning sctp_assoc_tracking on/off will delete all the tracking
+			information for all the currently tracked associations and might
+			introduce a small temporary delay in the sctp processing if lots
+			of associations were tracked.
+		</para>
+		<para>
+			Config options depending on sctp_assoc_tracking being on:
+			sctp_assoc_reuse. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is 1 (enabled, 0 - disabled).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_assoc_tracking</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_assoc_tracking", 0)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_assoc_reuse">
+		<title><varname>sctp_assoc_reuse</varname> (int)</title>
+		<para>
+			Controls sctp association reuse. For now only association reuse
+			for replies is affected by it. Default is on. Depends on
+			sctp_assoc_tracking being on.
+		</para>
+		<para>
+			Note that even if turned off, if the port in via corresponds to
+			the source port of the association the request was sent on or if
+			rport is turned on (force_rport() or via containing a rport
+			option), the association will be automatically reused by the
+			sctp stack. Can be changed at runtime (sctp assoc_reuse), but it
+			can be turned on only if sctp_assoc_tracking is on. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is 1 (enabled, 0 - disabled).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_assoc_reuse</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_assoc_reuse", 0)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_max_assocs">
+		<title><varname>sctp_max_assocs</varname> (int)</title>
+		<para>
+			Maximum number of allowed open sctp associations. -1 means
+			maximum allowed by the OS. Default: -1. Can be changed at
+			runtime (e.g.: kamcmd cfg.set_now_int sctp max_assocs 10 ). When
+			the maximum associations number is exceeded and a new associations
+			is opened by a remote host, the association will be immediately
+			closed. However it is possible that some sip packets get through
+			(especially if they are sent early, as part of the 4-way handshake).
+		</para>
+		<para>
+			When &kamailio; tries to open a new association and the max_assocs
+			is exceeded the exact behaviour depends on whether or not
+			sctp_assoc_tracking is on. If on, the send triggering the active
+			open will gracefully fail, before actually opening the new
+			association and no packet will be sent. However if
+			sctp_assoc_tracking is off, the association will first be opened
+			and then immediately closed. In general this means that the initial
+			sip packet will be sent (as part of the 4-way handshake). 
+		</para>
+		<para>
+		<emphasis>
+			Default value is -1.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_max_assocs</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_max_assocs", 10)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_srto_initial">
+		<title><varname>sctp_srto_initial</varname> (int)</title>
+		<para>
+			Initial value of the retransmission timeout (in miliseconds),
+			used in RTO calculations.
+		</para>
+		<para>
+			Can be changed at runtime (sctp srto_initial) but it will affect
+			only new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_srto_initial</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_srto_initial", 1000)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_srto_max">
+		<title><varname>sctp_srto_max</varname> (int)</title>
+		<para>
+			Maximum value of the retransmission timeout (RTO) in milliseconds.
+		</para>
+		<para>
+			WARNING: values lower then the sctp sack_delay will cause lots
+			of retransmissions and connection instability (see sctp_srto_min
+			for more details).
+		</para>
+		<para>
+			Can be changed at runtime (sctp srto_max) but it will affect only
+			new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_srto_max</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_srto_max", 2000)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_srto_min">
+		<title><varname>sctp_srto_min</varname> (int)</title>
+		<para>
+			Minimum value of the retransmission timeout (RTO) in milliseconds.
+		</para>
+		<para>
+			WARNING: values lower then the sctp sack_delay of any peer might
+			cause retransmissions and possible interoperability problems.
+			According to the standard the sack_delay should be between 200
+			and 500 ms, so avoid trying values lower then 500 ms unless you
+			control all the possible sctp peers and you do make sure their
+			sack_delay is higher or their sack_freq is 1.
+		</para>
+		<para>
+			Can be changed at runtime (sctp srto_min) but it will affect only
+			new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_srto_min</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_srto_min", 800)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_asocmaxrxt">
+		<title><varname>sctp_asocmaxrxt</varname> (int)</title>
+		<para>
+			Maximum retransmissions attempts per association. It should be
+			set to sctp_pathmaxrxt * no. of expected paths.
+		</para>
+		<para>
+			Can be changed at runtime (sctp asocmaxrxt) but it will affect
+			only new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_asocmaxrxt</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_asocmaxrxt", 5)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_init_max_attempts">
+		<title><varname>sctp_init_max_attempts</varname> (int)</title>
+		<para>
+			Maximum INIT retransmission attempts.
+		</para>
+		<para>
+			Can be changed at runtime (sctp init_max_attempts). 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_init_max_attempts</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_init_max_attempts", 3)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_init_max_timeo">
+		<title><varname>sctp_init_max_timeo</varname> (int)</title>
+		<para>
+			Maximum INIT retransmission timeout (RTO max for INIT) in
+			miliseconds.
+		</para>
+		<para>
+			Can be changed at runtime (sctp init_max_timeo). 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_init_max_timeo</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_init_max_timeo", 1000)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_hbinterval">
+		<title><varname>sctp_hbinterval</varname> (int)</title>
+		<para>
+			SCTP heartbeat interval. Setting it to -1 will disable the
+			heartbeats.
+		</para>
+		<para>
+			Can be changed at runtime (sctp hbinterval) but it will affect only
+			new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_hbinterval</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_hbinterval", 2000)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_pathmaxrxt">
+		<title><varname>sctp_pathmaxrxt</varname> (int)</title>
+		<para>
+			Maximum retransmission attempts per path (see also
+			sctp_asocmaxrxt).
+		</para>
+		<para>
+			Can be changed at runtime (sctp pathmaxrxt) but it will affect
+			only new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_pathmaxrxt</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_pathmaxrxt", 2)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_sack_delay">
+		<title><varname>sctp_sack_delay</varname> (int)</title>
+		<para>
+			Delay until an ACK is generated after receiving a packet (in
+			miliseconds).
+		</para>
+		<para>
+			WARNING: a value higher then srto_min can cause a lot of
+			retransmissions (and strange problems). A value higher then
+			srto_max will result in very high connections instability.
+			According to the standard the sack_delay value should be between
+			200 and 500 ms.
+		</para>
+		<para>
+			Can be changed at runtime (sctp sack_delay) but it will affect
+			only new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_sack_delay</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_sack_delay", 400)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_sack_freq">
+		<title><varname>sctp_sack_freq</varname> (int)</title>
+		<para>
+			Number of packets received before an ACK is sent (without waiting
+			for the sack_delay to expire). Default: OS specific.
+		</para>
+		<para>
+			Note: on linux with lksctp up to and including 1.0.9 is not
+			possible to set this value (having it in the config will produce
+			a warning on startup).
+		</para>
+		<para>
+			Can be changed at runtime (sctp sack_freq) but it will affect only
+			new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_sack_freq</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_sack_freq", 3)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="sctp.p.sctp_max_burst">
+		<title><varname>sctp_max_burst</varname> (int)</title>
+		<para>
+			Maximum burst of packets that can be emitted by an association.
+		</para>
+		<para>
+			Can be changed at runtime (sctp max_burst) but it will affect only
+			new associations. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is OS specific.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>sctp_max_burst</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("sctp", "sctp_max_burst", 3)
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>RPC Commands</title>
+	<section id="sctp.r.sctp.info">
+		<title><varname>sctp.info</varname></title>
+		<para>
+			Print information about SCTP transport.
+		</para>
+		<example>
+		<title>Use <varname>sctp.info</varname> with kamcmd</title>
+		<programlisting format="linespecific">
+...
+kamcmd sctp.info
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sctp.r.sctp.">
+		<title><varname>sctp.options</varname></title>
+		<para>
+			Print the options of SCTP sockets. It can take an optional
+			parameter that specifies the listen address of SCTP socket.
+		</para>
+		<example>
+		<title>Use <varname>sctp.options</varname> with kamcmd</title>
+		<programlisting format="linespecific">
+...
+kamcmd sctp.options
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+</chapter>
+
diff --git a/modules/sctp/sctp_ev.h b/modules/sctp/sctp_ev.h
new file mode 100644
index 0000000..2f4aef8
--- /dev/null
+++ b/modules/sctp/sctp_ev.h
@@ -0,0 +1,97 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * sctp_ev.h - sctp events
+ */
+/*
+ * History:
+ * --------
+ *  2009-04-28  initial version (andrei)
+*/
+
+#ifndef __sctp_ev_h
+#define __sctp_ev_h
+
+#include <errno.h>
+#include <string.h>
+
+#ifndef USE_SCTP_EV
+
+#define SCTP_EV_ASSOC_CHANGE(lip, lport, src, reason, state)
+#define SCTP_EV_PEER_ADDR_CHANGE(lip, lport, src, reason, state, addr_su)
+#define SCTP_EV_REMOTE_ERROR(lip, lport, src, err)
+#define SCTP_EV_SEND_FAILED(lip, lport, src, err)
+#define SCTP_EV_SHUTDOWN_EVENT(lip, lport, src)
+#define SCTP_EV_SENDER_DRY_EVENT(lip, lport, src)
+
+#else /* USE_SCTP_EV */
+
+#include "../../ip_addr.h"
+
+
+/** an association has either been opened or closed.
+ * called for each SCTP_ASSOC_CHANGE event.
+ *
+ * @param err - if 0 it should be ignored (no corresp. libc error), if non-0
+ *                it will contain the errno.
+ * @param lip   - pointer to an ip_addr containing the local ip
+ *                   or 0 if dynamic (WARNING can be 0).
+ * @param lport - pointer to an ip_addr containing the local port or 0
+ *                   if unknown/dynamic.
+ * @param src   - pointer to a sockaddr_union containing the src.
+ * @param proto - protocol used
+ */
+#define SCTP_EV_ASSOC_CHANGE(lip, lport, src, reason, state) \
+	DBG("SCTP_ASSOC_CHANGE from %s on %s:%d: %s\n", \
+			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, reason)
+
+/** an address part of an assoc. changed state.
+ * called for the SCTP_PEER_ADDR_CHANGE event.*/
+#define SCTP_EV_PEER_ADDR_CHANGE(lip, lport, src, reason, state, addr_su) \
+	DBG("SCTP_PEER_ADDR_CHANGE from %s on %s:%d: %s\n", \
+			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, reason)
+
+/** remote operation error from the peer.
+ * called for the SCTP_REMOTE_ERROR event.*/
+#define SCTP_EV_REMOTE_ERROR(lip, lport, src, err) \
+	DBG("SCTP_REMOTE_ERROR from %s on %s:%d: %d\n", \
+			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, err)
+
+/** send failed.
+ * called for the SCTP_SEND_FAILED event.*/
+#define SCTP_EV_SEND_FAILED(lip, lport, src, err) \
+	DBG("SCTP_SEND_FAILED from %s on %s:%d: %d\n", \
+			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, err)
+
+/** the peer has sent a shutdown.
+ * called for the SCTP_SHUTDOWN_EVENT event.*/
+#define SCTP_EV_SHUTDOWN_EVENT(lip, lport, src) \
+	DBG("SCTP_SHUTDOWN_EVENT from %s on %s:%d\n", \
+			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport)
+
+/** kernel has finished sending all the queued data.
+ * called for the SCTP_SENDER_DRY_EVENT event.*/
+#define SCTP_EV_SENDER_DRY_EVENT(lip, lport, src) \
+	DBG("SCTP_SENDER_DRY_EVENT from %s on %s:%d\n", \
+			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport)
+
+#endif /* USE_SCTP_EV */
+
+#endif /*__sctp_ev_h*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/modules/sctp/sctp_mod.c b/modules/sctp/sctp_mod.c
new file mode 100644
index 0000000..1469e6d
--- /dev/null
+++ b/modules/sctp/sctp_mod.c
@@ -0,0 +1,145 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../shm_init.h"
+#include "../../sctp_core.h"
+
+#include "sctp_options.h"
+#include "sctp_server.h"
+#include "sctp_rpc.h"
+
+MODULE_VERSION
+
+static int mod_init(void);
+static int sctp_mod_pre_init(void);
+
+
+static cmd_export_t cmds[]={
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]={
+	{"sctp_socket_rcvbuf",     PARAM_INT, &sctp_default_cfg.so_rcvbuf},
+	{"sctp_socket_sndbuf",     PARAM_INT, &sctp_default_cfg.so_sndbuf},
+	{"sctp_autoclose",         PARAM_INT, &sctp_default_cfg.autoclose},
+	{"sctp_send_ttl",          PARAM_INT, &sctp_default_cfg.send_ttl},
+	{"sctp_send_retries",      PARAM_INT, &sctp_default_cfg.send_retries},
+	{"sctp_assoc_tracking",    PARAM_INT, &sctp_default_cfg.assoc_tracking},
+	{"sctp_assoc_reuse",       PARAM_INT, &sctp_default_cfg.assoc_reuse},
+	{"sctp_max_assocs",        PARAM_INT, &sctp_default_cfg.max_assocs},
+	{"sctp_srto_initial",      PARAM_INT, &sctp_default_cfg.srto_initial},
+	{"sctp_srto_max",          PARAM_INT, &sctp_default_cfg.srto_max},
+	{"sctp_srto_min",          PARAM_INT, &sctp_default_cfg.srto_min},
+	{"sctp_asocmaxrxt",        PARAM_INT, &sctp_default_cfg.asocmaxrxt},
+	{"sctp_init_max_attempts", PARAM_INT, &sctp_default_cfg.init_max_attempts},
+	{"sctp_init_max_timeo",    PARAM_INT, &sctp_default_cfg.init_max_timeo},
+	{"sctp_hbinterval",        PARAM_INT, &sctp_default_cfg.hbinterval},
+	{"sctp_pathmaxrxt",        PARAM_INT, &sctp_default_cfg.pathmaxrxt},
+	{"sctp_sack_delay",        PARAM_INT, &sctp_default_cfg.sack_delay},
+	{"sctp_sack_freq",         PARAM_INT, &sctp_default_cfg.sack_freq},
+	{"sctp_max_burst",         PARAM_INT, &sctp_default_cfg.max_burst},
+
+	{0, 0, 0}
+};
+
+struct module_exports exports = {
+	"sctp",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,
+	0,              /* exported MI functions */
+	0,              /* exported pseudo-variables */
+	0,              /* extra processes */
+	mod_init,       /* module initialization function */
+	0,              /* response function */
+	0,              /* destroy function */
+	0               /* per child init function */
+};
+
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+	if(!shm_initialized() && init_shm()<0)
+		return -1;
+
+#ifdef USE_SCTP
+	/* shm is used, be sure it is initialized */
+	if(sctp_mod_pre_init()<0)
+		return -1;
+	return 0;
+#else
+	LOG(L_CRIT, "sctp core support not enabled\n");
+	return -1;
+#endif
+}
+
+static int mod_init(void)
+{
+#ifdef USE_SCTP
+	char tmp[256];
+	if (sctp_check_compiled_sockopts(tmp, 256)!=0){
+		LM_WARN("sctp unsupported socket options: %s\n", tmp);
+	}
+
+	if (sctp_register_cfg()){
+		LOG(L_CRIT, "could not register the sctp configuration\n");
+		return -1;
+	}
+	if (sctp_register_rpc()){
+		LOG(L_CRIT, "could not register the sctp rpc commands\n");
+		return -1;
+	}
+	return 0;
+#else /* USE_SCTP */
+	LOG(L_CRIT, "sctp core support not enabled\n");
+	return -1;
+#endif /* USE_SCTP */
+}
+
+static int sctp_mod_pre_init(void)
+{
+	sctp_srapi_t api;
+
+	/* set defaults before the config mod params */
+	init_sctp_options();
+
+	memset(&api, 0, sizeof(sctp_srapi_t));
+	api.init                    = init_sctp;
+	api.destroy                 = destroy_sctp;
+	api.init_sock               = sctp_init_sock;
+	api.check_support           = sctp_check_support;
+	api.rcv_loop                = sctp_rcv_loop;
+	api.msg_send                = sctp_msg_send;
+
+	if(sctp_core_register_api(&api)<0) {
+		LM_ERR("cannot regiser sctp core api\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/modules/sctp/sctp_options.c b/modules/sctp/sctp_options.c
new file mode 100644
index 0000000..f74a59b
--- /dev/null
+++ b/modules/sctp/sctp_options.c
@@ -0,0 +1,748 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* 
+ * sctp options
+ */
+/*
+ * History:
+ * --------
+ *  2008-08-07  initial version (andrei)
+ *  2009-05-26  runtime cfg support (andrei)
+ */
+
+/*!
+ * \file
+ * \brief SIP-router core :: 
+ * \ingroup core
+ * Module: \ref core
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#ifdef USE_SCTP
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/sctp.h>
+#endif /* USE_SCTP */
+#include <errno.h>
+
+#include "sctp_options.h"
+
+#include "../../dprint.h"
+#include "../../cfg/cfg.h"
+#include "../../socket_info.h"
+
+#include "sctp_server.h"
+
+struct cfg_group_sctp sctp_default_cfg;
+
+
+
+#ifdef USE_SCTP
+
+#include "sctp_sockopts.h"
+
+static int fix_autoclose(void* cfg_h, str* gname, str* name, void** val);
+static void set_autoclose(str* gname, str* name);
+static int fix_assoc_tracking(void* cfg_h, str* gname, str* name, void** val);
+static int fix_assoc_reuse(void* cfg_h, str* gname, str* name, void** val);
+static int fix_srto_initial(void* cfg_h, str* gname, str* name, void** val);
+static void set_srto_initial(str* gname, str* name);
+static int fix_srto_max(void* cfg_h, str* gname, str* name, void** val);
+static void set_srto_max(str* gname, str* name);
+static int fix_srto_min(void* cfg_h, str* gname, str* name, void** val);
+static void set_srto_min(str* gname, str* name);
+static int fix_asocmaxrxt(void* cfg_h, str* gname, str* name, void** val);
+static void set_asocmaxrxt(str* gname, str* name);
+static int fix_sinit_max_init_timeo(void* cfg_h, str* gname, str* name,
+										void** val);
+static void set_sinit_max_init_timeo(str* gname, str* name);
+static int fix_sinit_max_attempts(void* cfg_h, str* gname, str* name,
+										void** val);
+static void set_sinit_max_attempts(str* gname, str* name);
+static int fix_hbinterval(void* cfg_h, str* gname, str* name, void** val);
+static void set_hbinterval(str* gname, str* name);
+static int fix_pathmaxrxt(void* cfg_h, str* gname, str* name, void** val);
+static void set_pathmaxrxt(str* gname, str* name);
+static int fix_sack_delay(void* cfg_h, str* gname, str* name, void** val);
+static void set_sack_delay(str* gname, str* name);
+static int fix_sack_freq(void* cfg_h, str* gname, str* name, void** val);
+static void set_sack_freq(str* gname, str* name);
+static int fix_max_burst(void* cfg_h, str* gname, str* name, void** val);
+static void set_max_burst(str* gname, str* name);
+
+/** cfg_group_sctp description (for the config framework). */
+static cfg_def_t sctp_cfg_def[] = {
+	/*   name        , type |input type| chg type, min, max, fixup, proc. cbk.
+	      description */
+	{ "socket_rcvbuf", CFG_VAR_INT| CFG_READONLY, 512, 102400, 0, 0,
+		"socket receive buffer size (read-only)" },
+	{ "socket_sndbuf", CFG_VAR_INT| CFG_READONLY, 512, 102400, 0, 0,
+		"socket send buffer size (read-only)" },
+	{ "autoclose", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 1, 1<<30,
+		fix_autoclose, set_autoclose,
+		"seconds before closing and idle connection (must be non-zero)" },
+	{ "send_ttl", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, 0, 0,
+		"milliseconds before aborting a send" },
+	{ "send_retries", CFG_VAR_INT| CFG_ATOMIC, 0, MAX_SCTP_SEND_RETRIES, 0, 0,
+		"re-send attempts on failure" },
+	{ "assoc_tracking", CFG_VAR_INT| CFG_ATOMIC, 0, 1, fix_assoc_tracking, 0,
+		"connection/association tracking (see also assoc_reuse)" },
+	{ "assoc_reuse", CFG_VAR_INT| CFG_ATOMIC, 0, 1, fix_assoc_reuse, 0,
+		"connection/association reuse (for now used only for replies)"
+		", depends on assoc_tracking being set"},
+	{ "max_assocs", CFG_VAR_INT| CFG_ATOMIC, 0, 0, 0, 0,
+		"maximum allowed open associations (-1 = disable, "
+			"as many as allowed by the OS)"},
+	{ "srto_initial", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
+		fix_srto_initial, set_srto_initial,
+		"initial value of the retr. timeout, used in RTO calculations,"
+			" in msecs" },
+	{ "srto_max", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
+		fix_srto_max, set_srto_max,
+		"maximum value of the retransmission timeout (RTO), in msecs" },
+	{ "srto_min", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
+		fix_srto_min, set_srto_min,
+		"minimum value of the retransmission timeout (RTO), in msecs" },
+	{ "asocmaxrxt", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
+		fix_asocmaxrxt, set_asocmaxrxt,
+		"maximum retransmission attempts per association" },
+	{ "init_max_attempts", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
+		fix_sinit_max_attempts, set_sinit_max_attempts,
+		"max INIT retransmission attempts" },
+	{ "init_max_timeo", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
+		fix_sinit_max_init_timeo, set_sinit_max_init_timeo,
+		"max INIT retransmission timeout (RTO max for INIT), in msecs" },
+	{ "hbinterval", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
+		fix_hbinterval, set_hbinterval, "heartbeat interval in msecs" },
+	{ "pathmaxrxt", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
+		fix_pathmaxrxt, set_pathmaxrxt,
+		"maximum retransmission attempts per path" },
+	{ "sack_delay", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
+		fix_sack_delay, set_sack_delay,
+		"time since the last received packet before sending a SACK, in msecs"},
+	{ "sack_freq", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
+		fix_sack_freq, set_sack_freq,
+		"number of received packets that trigger the sending of a SACK"},
+	{ "max_burst", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
+		fix_max_burst, set_max_burst,
+		"maximum burst of packets that can be emitted by an association"},
+	{0, 0, 0, 0, 0, 0, 0}
+};
+
+
+
+void* sctp_cfg; /* sctp config handle */
+
+#endif /* USE_SCTP */
+
+void init_sctp_options()
+{
+#ifdef USE_SCTP
+	sctp_get_os_defaults(&sctp_default_cfg);
+#if 0
+	sctp_default_cfg.so_rcvbuf=0; /* do nothing, use the kernel default */
+	sctp_default_cfg.so_sndbuf=0; /* do nothing, use the kernel default */
+#endif
+	sctp_default_cfg.autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
+	sctp_default_cfg.send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
+	sctp_default_cfg.send_retries=DEFAULT_SCTP_SEND_RETRIES;
+	sctp_default_cfg.max_assocs=-1; /* as much as possible by default */
+#ifdef SCTP_CONN_REUSE
+	sctp_default_cfg.assoc_tracking=1; /* on by default */
+	sctp_default_cfg.assoc_reuse=1; /* on by default */
+#else
+	sctp_default_cfg.assoc_tracking=0;
+	sctp_default_cfg.assoc_reuse=0;
+#endif /* SCTP_CONN_REUSE */
+#endif
+}
+
+
+
+#define W_OPT_NSCTP(option) \
+	if (sctp_default_cfg.option){\
+		WARN("sctp_options: " #option \
+			" cannot be enabled (sctp support not compiled-in)\n"); \
+			sctp_default_cfg.option=0; \
+	}
+
+
+
+void sctp_options_check()
+{
+#ifndef USE_SCTP
+	W_OPT_NSCTP(autoclose);
+	W_OPT_NSCTP(send_ttl);
+	W_OPT_NSCTP(send_retries);
+	W_OPT_NSCTP(assoc_tracking);
+	W_OPT_NSCTP(assoc_reuse);
+	W_OPT_NSCTP(max_assocs);
+#else /* USE_SCTP */
+	if (sctp_default_cfg.send_retries>MAX_SCTP_SEND_RETRIES) {
+		WARN("sctp: sctp_send_retries too high (%d), setting it to %d\n",
+				sctp_default_cfg.send_retries, MAX_SCTP_SEND_RETRIES);
+		sctp_default_cfg.send_retries=MAX_SCTP_SEND_RETRIES;
+	}
+#ifndef CONN_REUSE
+	if (sctp_default_cfg.assoc_tracking || sctp_default_cfg.assoc_reuse){
+		WARN("sctp_options: assoc_tracking and assoc_reuse support cannnot"
+				" be enabled (CONN_REUSE support not compiled-in)\n");
+		sctp_default_cfg.assoc_tracking=0;
+		sctp_default_cfg.assoc_reuse=0;
+	}
+#else /* CONN_REUSE */
+	if (sctp_default_cfg.assoc_reuse && sctp_default_cfg.assoc_tracking==0){
+		sctp_default_cfg.assoc_tracking=1;
+	}
+#endif /* CONN_REUSE */
+#endif /* USE_SCTP */
+}
+
+
+
+void sctp_options_get(struct cfg_group_sctp *s)
+{
+#ifdef USE_SCTP
+	*s=*(struct cfg_group_sctp*)sctp_cfg;
+#else
+	memset(s, 0, sizeof(*s));
+#endif /* USE_SCTP */
+}
+
+
+
+#ifdef USE_SCTP
+/** register sctp config into the configuration framework.
+ * @return 0 on success, -1 on error */
+int sctp_register_cfg()
+{
+	if (cfg_declare("sctp", sctp_cfg_def, &sctp_default_cfg, cfg_sizeof(sctp),
+				&sctp_cfg))
+		return -1;
+	if (sctp_cfg==0){
+		BUG("null sctp cfg");
+		return -1;
+	}
+	return 0;
+}
+
+
+
+#define SCTP_SET_SOCKOPT_DECLS \
+	int err; \
+	struct socket_info* si
+
+
+#define SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) \
+	err=0; \
+	for (si=sctp_listen; si; si=si->next){ \
+		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
+							sizeof((val)), (err_prefix))<0); \
+	}
+
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
+	SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) ; \
+	return -(err!=0)
+
+
+static int fix_autoclose(void*cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_AUTOCLOSE
+	return 0;
+#else
+	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_AUTOCLOSE */
+}
+
+
+static void set_autoclose(str* gname, str* name)
+{
+#ifdef SCTP_AUTOCLOSE
+	int optval;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	optval=cfg_get(sctp, sctp_cfg, autoclose);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_AUTOCLOSE, optval,
+								"cfg: setting SCTP_AUTOCLOSE");
+#else
+	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
+#endif /* SCTP_AUTOCLOSE */
+}
+
+
+
+static int fix_assoc_tracking(void* cfg_h, str* gname, str* name, void** val)
+{
+	int optval;
+	
+	optval=(int)(long)(*val);
+#ifndef SCTP_CONN_REUSE
+	if (optval!=0){
+		ERR("no SCTP_CONN_REUSE support, please recompile with it enabled\n");
+		return -1;
+	}
+#else /* SCTP_CONN_REUSE */
+	if (optval==0){
+		/* turn tracking off */
+		/* check if assoc_reuse is off */
+		if (cfg_get(sctp, cfg_h, assoc_reuse)!=0){
+			ERR("cannot turn sctp assoc_tracking off while assoc_reuse is"
+					" still on, please turn assoc_reuse off first\n");
+			return -1;
+		}
+		sctp_con_tracking_flush();
+	}else if (optval==1 && cfg_get(sctp, cfg_h, assoc_reuse)==0){
+		/* turning from off to on, make sure we flush the tracked list
+		   again, just incase the off flush was racing with a new connection*/
+		sctp_con_tracking_flush();
+	}
+#endif /* SCTP_CONN_REUSE */
+	return 0;
+}
+
+
+
+static int fix_assoc_reuse(void* cfg_h, str* gname, str* name, void** val)
+{
+	int optval;
+	
+	optval=(int)(long)(*val);
+#ifndef SCTP_CONN_REUSE
+	if (optval!=0){
+		ERR("no SCTP_CONN_REUSE support, please recompile with it enabled\n");
+		return -1;
+	}
+#else /* SCTP_CONN_REUSE */
+	if (optval==1 && cfg_get(sctp, cfg_h, assoc_tracking)==0){
+		/* conn reuse on, but assoc_tracking off => not possible */
+		ERR("cannot turn sctp assoc_reuse on while assoc_tracking is"
+					" off, please turn assoc_tracking on first\n");
+		return -1;
+	}
+#endif /* SCTP_CONN_REUSE */
+	return 0;
+}
+
+
+
+static int fix_srto_initial(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_initial);
+	}
+	return 0;
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
+}
+
+
+static void set_srto_initial(str* gname, str* name)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	int optval;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	optval=cfg_get(sctp, sctp_cfg, srto_initial);
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_initial=optval;
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+								"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+#endif /* SCTP_RTOINFO */
+}
+
+
+
+static int fix_srto_max(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_max);
+	}
+	return 0;
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
+}
+
+
+static void set_srto_max(str* gname, str* name)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_max=cfg_get(sctp, sctp_cfg, srto_max);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+								"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+#endif /* SCTP_RTOINFO */
+}
+
+
+
+static int fix_srto_min(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_RTOINFO
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_min);
+	}
+	return 0;
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_RTOINFO */
+}
+
+
+static void set_srto_min(str* gname, str* name)
+{
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
+	rto.srto_assoc_id=0; /* all */
+	rto.srto_min=cfg_get(sctp, sctp_cfg, srto_min);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_RTOINFO, rto,
+								"cfg: setting SCTP_RTOINFO");
+#else
+	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
+#endif /* SCTP_RTOINFO */
+}
+
+
+
+static int fix_asocmaxrxt(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_ASSOCINFO
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, asocmaxrxt);
+	}
+	return 0;
+#else
+	ERR("no SCTP_ASSOCINFO support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_ASSOCINFO */
+}
+
+
+static void set_asocmaxrxt(str* gname, str* name)
+{
+#ifdef SCTP_ASSOCINFO
+	struct sctp_assocparams ap;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&ap, 0, sizeof(ap)); /* zero everything we don't care about */
+	ap.sasoc_assoc_id=0; /* all */
+	ap.sasoc_asocmaxrxt= cfg_get(sctp, sctp_cfg, asocmaxrxt);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_ASSOCINFO, ap,
+								"cfg: setting SCTP_ASSOCINFO");
+#else
+	ERR("no SCTP_ASSOCINFO support, please upgrade your sctp library\n");
+#endif /* SCTP_ASSOCINFO */
+}
+
+
+
+static int fix_sinit_max_init_timeo(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_INITMSG
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, init_max_timeo);
+	}
+	return 0;
+#else
+	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_INITMSG */
+}
+
+
+static void set_sinit_max_init_timeo(str* gname, str* name)
+{
+#ifdef SCTP_INITMSG
+	struct sctp_initmsg im;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&im, 0, sizeof(im)); /* zero everything we don't care about */
+	im.sinit_max_init_timeo=cfg_get(sctp, sctp_cfg, init_max_timeo);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_INITMSG, im,
+								"cfg: setting SCTP_INITMSG");
+#else
+	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
+#endif /* SCTP_INITMSG */
+}
+
+
+
+static int fix_sinit_max_attempts(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_INITMSG
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, init_max_attempts);
+	}
+	return 0;
+#else
+	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_INITMSG */
+}
+
+
+static void set_sinit_max_attempts(str* gname, str* name)
+{
+#ifdef SCTP_INITMSG
+	struct sctp_initmsg im;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&im, 0, sizeof(im)); /* zero everything we don't care about */
+	im.sinit_max_attempts=cfg_get(sctp, sctp_cfg, init_max_attempts);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_INITMSG, im,
+								"cfg: setting SCTP_INITMSG");
+#else
+	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
+#endif /* SCTP_INITMSG */
+}
+
+
+
+static int fix_hbinterval(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_PEER_ADDR_PARAMS
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, hbinterval);
+	}
+	return 0;
+#else
+	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
+			" sctp library\n");
+	return -1;
+#endif /* SCTP_PEER_ADDR_PARAMS */
+}
+
+
+static void set_hbinterval(str* gname, str* name)
+{
+#ifdef SCTP_PEER_ADDR_PARAMS
+	struct sctp_paddrparams pp;
+	int optval;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	optval=cfg_get(sctp, sctp_cfg, hbinterval);
+	memset(&pp, 0, sizeof(pp)); /* zero everything we don't care about */
+	if (optval!=-1){
+		pp.spp_hbinterval=optval;
+		pp.spp_flags=SPP_HB_ENABLE;
+	}else{
+		pp.spp_flags=SPP_HB_DISABLE;
+	}
+	err=0;
+	for (si=sctp_listen; si; si=si->next){
+		/* set the AF, needed on older linux kernels even for INADDR_ANY */
+		pp.spp_address.ss_family=si->address.af;
+		err+=(sctp_setsockopt(si->socket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS,
+								(void*)(&pp), sizeof(pp),
+								"cfg: setting SCTP_PEER_ADDR_PARAMS")<0);
+	}
+#else
+	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
+			" sctp library\n");
+#endif /* SCTP_PEER_ADDR_PARAMS */
+}
+
+
+
+static int fix_pathmaxrxt(void* cfg_h, str* gname, str* name,
+									void** val)
+{
+#ifdef SCTP_PEER_ADDR_PARAMS
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, pathmaxrxt);
+	}
+	return 0;
+#else
+	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
+			" sctp library\n");
+	return -1;
+#endif /* SCTP_PEER_ADDR_PARAMS */
+}
+
+
+static void set_pathmaxrxt(str* gname, str* name)
+{
+#ifdef SCTP_PEER_ADDR_PARAMS
+	struct sctp_paddrparams pp;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&pp, 0, sizeof(pp)); /* zero everything we don't care about */
+	pp.spp_pathmaxrxt=cfg_get(sctp, sctp_cfg, pathmaxrxt);
+	err=0;
+	for (si=sctp_listen; si; si=si->next){
+		/* set the AF, needed on older linux kernels even for INADDR_ANY */
+		pp.spp_address.ss_family=si->address.af;
+		err+=(sctp_setsockopt(si->socket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS,
+								(void*)(&pp), sizeof(pp),
+								"cfg: setting SCTP_PEER_ADDR_PARAMS")<0);
+	}
+#else
+	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
+			" sctp library\n");
+#endif /* SCTP_PEER_ADDR_PARAMS */
+}
+
+
+
+static int fix_sack_delay(void* cfg_h, str* gname, str* name, void** val)
+{
+#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
+	}
+	return 0;
+#else
+	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_DELAYED_SACK | SCTP_DELAYED_ACK_TIME */
+}
+
+
+static void set_sack_delay(str* gname, str* name)
+{
+#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
+#ifdef SCTP_DELAYED_SACK
+	struct sctp_sack_info sack_info;
+#endif /* SCTP_DELAYED_SACK */
+#ifdef	SCTP_DELAYED_ACK_TIME
+	struct sctp_assoc_value sack_val; /* old version, sack delay only */
+#endif /* SCTP_DELAYED_ACK_TIME */
+	SCTP_SET_SOCKOPT_DECLS;
+	
+#ifdef SCTP_DELAYED_SACK
+	memset(&sack_info, 0, sizeof(sack_info)); /* zero everything we don't
+												 care about */
+	sack_info.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_SACK, sack_info, 0);
+	if (err==0){
+		return;
+	}else
+#endif /* SCTP_DELAYED_SACK */
+	{
+		/* setting SCTP_DELAYED_SACK failed or no lib support for 
+		   SCTP_DELAYED_SACK => try the old obsolete SCTP_DELAYED_ACK_TIME */
+#ifdef	SCTP_DELAYED_ACK_TIME
+		memset(&sack_val, 0, sizeof(sack_val)); /* zero everything we don't
+												   care about */
+		sack_val.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
+		SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
+									sack_val,
+									"cfg: setting SCTP_DELAYED_ACK_TIME");
+		if (err==0)
+			return;
+#else	/* SCTP_DELAYED_ACK_TIME */
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
+		   => error */
+		ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
+					strerror(errno), errno);
+#endif /* SCTP_DELAYED_ACK_TIME */
+	}
+#else
+	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
+#endif /* SCTP_DELAYED_SACK | SCTP_DELAYED_ACK_TIME */
+}
+
+
+
+static int fix_sack_freq(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_DELAYED_SACK
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_freq);
+	}
+	return 0;
+#else
+	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_DELAYED_SACK */
+}
+
+
+static void set_sack_freq(str* gname, str* name)
+{
+#ifdef SCTP_DELAYED_SACK
+	struct sctp_sack_info sa;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
+	sa.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_SACK, sa,
+								"cfg: setting SCTP_DELAYED_SACK");
+#else
+	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
+#endif /* SCTP_DELAYED_SACK */
+}
+
+
+
+static int fix_max_burst(void* cfg_h, str* gname, str* name, void** val)
+{
+#ifdef SCTP_MAX_BURST
+	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
+		*val=(void*)(long)cfg_get(sctp, cfg_h, max_burst);
+	}
+	return 0;
+#else
+	ERR("no SCTP_MAX_BURST support, please upgrade your sctp library\n");
+	return -1;
+#endif /* SCTP_MAX_BURST */
+}
+
+
+static void set_max_burst(str* gname, str* name)
+{
+#ifdef SCTP_MAX_BURST
+	struct sctp_assoc_value av;
+	SCTP_SET_SOCKOPT_DECLS;
+	
+	memset(&av, 0, sizeof(av)); /* zero everything we don't care about */
+	av.assoc_value=cfg_get(sctp, sctp_cfg, max_burst);
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_MAX_BURST, av,
+								"cfg: setting SCTP_MAX_BURST");
+#else
+	ERR("no SCTP_MAX_BURST support, please upgrade your sctp library\n");
+#endif /* SCTP_MAX_BURST */
+}
+
+#endif /* USE_SCTP */
diff --git a/sctp_options.h b/modules/sctp/sctp_options.h
similarity index 100%
rename from sctp_options.h
rename to modules/sctp/sctp_options.h
diff --git a/modules/sctp/sctp_rpc.c b/modules/sctp/sctp_rpc.c
new file mode 100644
index 0000000..15dbd07
--- /dev/null
+++ b/modules/sctp/sctp_rpc.c
@@ -0,0 +1,175 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../../rpc_lookup.h"
+#include "../../socket_info.h"
+#include "../../globals.h"
+#include "../../config.h"
+
+#ifdef USE_SCTP
+#include "sctp_options.h"
+#include "sctp_server.h"
+#endif
+
+
+static const char* core_sctp_options_doc[] = {
+	"Returns active sctp options. With one parameter"
+	" it returns the sctp options set in the kernel for a specific socket"
+	"(debugging), with 0 filled in for non-kernel related options."
+	" The parameter can be: \"default\" | \"first\" | address[:port] ."
+	" With no parameters it returns ser's idea of the current sctp options"
+	 " (intended non-debugging use).",
+	/* Documentation string */
+	0                                 /* Method signature(s) */
+};
+
+static void core_sctp_options(rpc_t* rpc, void* c)
+{
+#ifdef USE_SCTP
+	void *handle;
+	struct cfg_group_sctp t;
+	char* param;
+	struct socket_info* si;
+	char* host;
+	str hs;
+	int hlen;
+	int port;
+	int proto;
+
+	param=0;
+	if (!sctp_disable){
+		/* look for optional socket parameter */
+		if (rpc->scan(c, "*s", &param)>0){
+			si=0;
+			if (strcasecmp(param, "default")==0){
+				si=sendipv4_sctp?sendipv4_sctp:sendipv6_sctp;
+			}else if (strcasecmp(param, "first")==0){
+				si=sctp_listen;
+			}else{
+				if (parse_phostport(param, &host, &hlen, &port, &proto)!=0){
+					rpc->fault(c, 500, "bad param (use address, address:port,"
+										" default or first)");
+					return;
+				}
+				if (proto && proto!=PROTO_SCTP){
+					rpc->fault(c, 500, "bad protocol in param (only SCTP"
+										" allowed)");
+					return;
+				}
+				hs.s=host;
+				hs.len=hlen;
+				si=grep_sock_info(&hs, port, PROTO_SCTP);
+				if (si==0){
+					rpc->fault(c, 500, "not listening on sctp %s", param);
+					return;
+				}
+			}
+			if (si==0 || si->socket==-1){
+				rpc->fault(c, 500, "could not find a sctp socket");
+				return;
+			}
+			memset(&t, 0, sizeof(t));
+			if (sctp_get_cfg_from_sock(si->socket, &t)!=0){
+				rpc->fault(c, 500, "failed to get socket options");
+				return;
+			}
+		}else{
+			sctp_options_get(&t);
+		}
+		rpc->add(c, "{", &handle);
+		rpc->struct_add(handle, "ddddddddddddddddddd",
+			"sctp_socket_rcvbuf",	t.so_rcvbuf,
+			"sctp_socket_sndbuf",	t.so_sndbuf,
+			"sctp_autoclose",		t.autoclose,
+			"sctp_send_ttl",	t.send_ttl,
+			"sctp_send_retries",	t.send_retries,
+			"sctp_assoc_tracking",	t.assoc_tracking,
+			"sctp_assoc_reuse",	t.assoc_reuse,
+			"sctp_max_assocs", t.max_assocs,
+			"sctp_srto_initial",	t.srto_initial,
+			"sctp_srto_max",		t.srto_max,
+			"sctp_srto_min",		t.srto_min,
+			"sctp_asocmaxrxt",	t.asocmaxrxt,
+			"sctp_init_max_attempts",	t.init_max_attempts,
+			"sctp_init_max_timeo",t.init_max_timeo,
+			"sctp_hbinterval",	t.hbinterval,
+			"sctp_pathmaxrxt",	t.pathmaxrxt,
+			"sctp_sack_delay",	t.sack_delay,
+			"sctp_sack_freq",	t.sack_freq,
+			"sctp_max_burst",	t.max_burst
+		);
+	}else{
+		rpc->fault(c, 500, "sctp support disabled");
+	}
+#else
+	rpc->fault(c, 500, "sctp support not compiled");
+#endif
+}
+
+
+
+static const char* core_sctpinfo_doc[] = {
+	"Returns sctp related info.",    /* Documentation string */
+	0                               /* Method signature(s) */
+};
+
+static void core_sctpinfo(rpc_t* rpc, void* c)
+{
+#ifdef USE_SCTP
+	void *handle;
+	struct sctp_gen_info i;
+
+	if (!sctp_disable){
+		sctp_get_info(&i);
+		rpc->add(c, "{", &handle);
+		rpc->struct_add(handle, "ddd",
+			"opened_connections", i.sctp_connections_no,
+			"tracked_connections", i.sctp_tracked_no,
+			"total_connections", i.sctp_total_connections
+		);
+	}else{
+		rpc->fault(c, 500, "sctp support disabled");
+	}
+#else
+	rpc->fault(c, 500, "sctp support not compiled");
+#endif
+}
+
+
+/*
+ * RPC Methods exported by this module
+ */
+static rpc_export_t scp_rpc_methods[] = {
+	{"sctp.options",      core_sctp_options,      core_sctp_options_doc,
+		0},
+	{"sctp.info",         core_sctpinfo,          core_sctpinfo_doc,   0},
+
+	{0, 0, 0, 0}
+};
+
+
+int sctp_register_rpc(void)
+{
+	if (rpc_register_array(scp_rpc_methods)!=0)
+	{
+		LM_ERR("failed to register RPC commands\n");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/modules/sctp/sctp_rpc.h b/modules/sctp/sctp_rpc.h
new file mode 100644
index 0000000..54a8ebd
--- /dev/null
+++ b/modules/sctp/sctp_rpc.h
@@ -0,0 +1,24 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __sctp_rpc_h__
+#define __sctp_rpc_h__
+
+int sctp_register_rpc(void);
+
+#endif
diff --git a/modules/sctp/sctp_server.c b/modules/sctp/sctp_server.c
new file mode 100644
index 0000000..4f21b20
--- /dev/null
+++ b/modules/sctp/sctp_server.c
@@ -0,0 +1,2922 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* 
+ * sctp one to many 
+ */
+/*
+ * History:
+ * --------
+ *  2008-08-07  initial version (andrei)
+ *  2009-02-27  blacklist support (andrei)
+ *  2009-04-28  sctp stats & events macros (andrei)
+ */
+
+/*!
+ * \file
+ * \brief SIP-router core :: 
+ * \ingroup core
+ * Module: \ref core
+ */
+
+#ifdef USE_SCTP
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/sctp.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+#include "sctp_sockopts.h"
+#include "sctp_server.h"
+#include "sctp_options.h"
+
+#include "../../globals.h"
+#include "../../config.h"
+#include "../../dprint.h"
+#include "../../receive.h"
+#include "../../mem/mem.h"
+#include "../../ip_addr.h"
+#include "../../cfg/cfg_struct.h"
+#ifdef USE_DST_BLACKLIST
+#include "../../dst_blacklist.h"
+#endif /* USE_DST_BLACKLIST */
+#include "../../timer_ticks.h"
+#include "../../clist.h"
+#include "../../error.h"
+#include "../../timer.h"
+
+#include "sctp_stats.h"
+#include "sctp_ev.h"
+
+
+
+static atomic_t* sctp_conn_no;
+
+
+#define ABORT_REASON_MAX_ASSOCS \
+	"Maximum configured number of open associations exceeded"
+
+/* check if the underlying OS supports sctp
+   returns 0 if yes, -1 on error */
+int sctp_check_support()
+{
+	int s;
+	char buf[256];
+	
+	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+	if (s!=-1){
+		close(s);
+		if (sctp_check_compiled_sockopts(buf, sizeof(buf))!=0){
+			LOG(L_WARN, "WARNING: sctp: your ser version was compiled"
+						" without support for the following sctp options: %s"
+						", which might cause unforseen problems \n", buf);
+			LOG(L_WARN, "WARNING: sctp: please consider recompiling ser with"
+						" an upgraded sctp library version\n");
+		}
+		return 0;
+	}
+	return -1;
+}
+
+
+
+/* append a token to a buffer (uses space between tokens) */
+inline static void append_tok2buf(char* buf, int blen, char* tok)
+{
+	char* p;
+	char* end;
+	int len;
+	
+	if (buf && blen){
+		end=buf+blen;
+		p=memchr(buf, 0, blen);
+		if (p==0) goto error;
+		if (p!=buf && p<(end-1)){
+			*p=' ';
+			p++;
+		}
+		len=MIN_int(strlen(tok), end-1-p);
+		memcpy(p, tok, len);
+		p[len]=0;
+	}
+error:
+	return;
+}
+
+
+
+/* check if support fot all the needed sockopts  was compiled;
+   an ascii list of the unsuported options is returned in buf
+   returns 0 on success and  -number of unsuported options on failure
+   (<0 on failure)
+*/
+int sctp_check_compiled_sockopts(char* buf, int size)
+{
+	int err;
+
+	err=0;
+	if (buf && (size>0)) *buf=0; /* "" */
+#ifndef SCTP_FRAGMENT_INTERLEAVE
+	err++;
+	append_tok2buf(buf, size, "SCTP_FRAGMENT_INTERLEAVE");
+#endif
+#ifndef SCTP_PARTIAL_DELIVERY_POINT
+	err++;
+	append_tok2buf(buf, size, "SCTP_PARTIAL_DELIVERY_POINT");
+#endif
+#ifndef SCTP_NODELAY
+	err++;
+	append_tok2buf(buf, size, "SCTP_NODELAY");
+#endif
+#ifndef SCTP_DISABLE_FRAGMENTS
+	err++;
+	append_tok2buf(buf, size, "SCTP_DISABLE_FRAGMENTS");
+#endif
+#ifndef SCTP_AUTOCLOSE
+	err++;
+	append_tok2buf(buf, size, "SCTP_AUTOCLOSE");
+#endif
+#ifndef SCTP_EVENTS
+	err++;
+	append_tok2buf(buf, size, "SCTP_EVENTS");
+#endif
+	
+	return -err;
+}
+
+
+
+/* init all the sockaddr_union members of the socket_info struct
+   returns 0 on success and -1 on error */
+inline static int sctp_init_su(struct socket_info* sock_info)
+{
+	union sockaddr_union* addr;
+	struct addr_info* ai;
+	
+	addr=&sock_info->su;
+	if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
+		LOG(L_ERR, "ERROR: sctp_init_su: could not init sockaddr_union for"
+					"primary sctp address %.*s:%d\n",
+					sock_info->address_str.len, sock_info->address_str.s,
+					sock_info->port_no );
+		goto error;
+	}
+	for (ai=sock_info->addr_info_lst; ai; ai=ai->next)
+		if (init_su(&ai->su, &ai->address, sock_info->port_no)<0){
+			LOG(L_ERR, "ERROR: sctp_init_su: could not init"
+					"backup sctp sockaddr_union for %.*s:%d\n",
+					ai->address_str.len, ai->address_str.s,
+					sock_info->port_no );
+			goto error;
+		}
+	return 0;
+error:
+	return -1;
+}
+
+
+
+/** set a socket option (wrapper over setsockopt).
+  * @param err_prefix - if 0 no error message is printed on failure, if !=0
+  *                     it will be prepended to the error message.
+  * @return 0 on success, -1 on error */
+int sctp_setsockopt(int s, int level, int optname, 
+					void* optval, socklen_t optlen, char* err_prefix)
+{
+	if (setsockopt(s, level, optname, optval, optlen) ==-1){
+		if (err_prefix)
+			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
+		return -1;
+	}
+	return 0;
+}
+
+
+
+/** get a socket option (wrapper over getsockopt).
+  * @param err_prefix - if 0 no error message is printed on failure, if !=0
+  *                     it will be prepended to the error message.
+  * @return 0 on success, -1 on error */
+int sctp_getsockopt(int s, int level, int optname, 
+					void* optval, socklen_t* optlen, char* err_prefix)
+{
+	if (getsockopt(s, level, optname, optval, optlen) ==-1){
+		if (err_prefix)
+			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
+		return -1;
+	}
+	return 0;
+}
+
+
+
+/** get the os defaults for cfg options with os correspondents.
+ *  @param cfg - filled with the os defaults
+ *  @return -1 on error, 0 on success
+ */
+int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
+{
+	int s;
+	int ret;
+	
+	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+	if (s==-1)
+		return -1;
+	ret=sctp_get_cfg_from_sock(s, cfg);
+	close(s);
+	return ret;
+}
+
+
+
+/** get the os cfg options from a specific socket.
+ *  @param s - intialized sctp socket
+ *  @param cfg - filled with the os defaults
+ *  @return -1 on error, 0 on success
+ */
+int sctp_get_cfg_from_sock(int s, struct cfg_group_sctp* cfg)
+{
+	int optval;
+	socklen_t optlen;
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+#endif /* SCTP_RTOINFO */
+#ifdef SCTP_ASSOCINFO
+	struct sctp_assocparams ap;
+#endif /* SCTP_ASSOCINFO */
+#ifdef SCTP_INITMSG
+	struct sctp_initmsg im;
+#endif /* SCTP_INITMSG */
+#ifdef SCTP_PEER_ADDR_PARAMS
+	struct sctp_paddrparams pp;
+#endif /* SCTP_PEER_ADDR_PARAMS */
+#ifdef	SCTP_DELAYED_SACK
+	struct sctp_sack_info sack_info;
+#endif	/* SCTP_DELAYED_SACK */
+#ifdef	SCTP_DELAYED_ACK_TIME
+	struct sctp_assoc_value sack_val; /* old version */
+#endif /* SCTP_DELAYED_ACK_TIME */
+#ifdef SCTP_MAX_BURST
+	struct sctp_assoc_value av;
+#endif /* SCTP_MAX_BURST */
+	
+	/* SO_RCVBUF */
+	optlen=sizeof(int);
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
+							&optlen, "SO_RCVBUF")==0){
+		/* success => hack to set the "default" values*/
+		#ifdef __OS_linux
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
+		#endif
+		cfg->so_rcvbuf=optval;
+	}
+	/* SO_SNDBUF */
+	optlen=sizeof(int);
+	if (sctp_getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&optval,
+							&optlen, "SO_SNDBUF")==0){
+		/* success => hack to set the "default" values*/
+		#ifdef __OS_linux
+			optval/=2; /* in linux getsockopt() returns 2*set_value */
+		#endif
+		cfg->so_sndbuf=optval;
+	}
+	/* SCTP_AUTOCLOSE */
+#ifdef SCTP_AUTOCLOSE
+	optlen=sizeof(int);
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE, (void*)&optval,
+							&optlen, "SCTP_AUTOCLOSE")==0){
+		cfg->autoclose=optval;
+	}
+#endif /* SCTP_AUTOCLOSE */
+	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
+#ifdef SCTP_RTOINFO
+	optlen=sizeof(rto);
+	rto.srto_assoc_id=0;
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
+							&optlen, "SCTP_RTOINFO")==0){
+		/* success => hack to set the "default" values*/
+		cfg->srto_initial=rto.srto_initial;
+		cfg->srto_min=rto.srto_min;
+		cfg->srto_max=rto.srto_max;
+	}
+#endif /* SCTP_RTOINFO */
+#ifdef SCTP_ASSOCINFO
+	optlen=sizeof(ap);
+	ap.sasoc_assoc_id=0;
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_ASSOCINFO, (void*)&ap,
+							&optlen, "SCTP_ASSOCINFO")==0){
+		/* success => hack to set the "default" values*/
+		cfg->asocmaxrxt=ap.sasoc_asocmaxrxt;
+	}
+#endif /* SCTP_ASSOCINFO */
+#ifdef SCTP_INITMSG
+	optlen=sizeof(im);
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, (void*)&im,
+							&optlen, "SCTP_INITMSG")==0){
+		/* success => hack to set the "default" values*/
+		cfg->init_max_attempts=im.sinit_max_attempts;
+		cfg->init_max_timeo=im.sinit_max_init_timeo;
+	}
+#endif /* SCTP_INITMSG */
+#ifdef SCTP_PEER_ADDR_PARAMS
+	optlen=sizeof(pp);
+	memset(&pp, 0, sizeof(pp)); /* get defaults */
+	/* set the AF, needed on older linux kernels even for INADDR_ANY */
+	pp.spp_address.ss_family=AF_INET;
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, (void*)&pp,
+							&optlen, "SCTP_PEER_ADDR_PARAMS")==0){
+		/* success => hack to set the "default" values*/
+		cfg->hbinterval=pp.spp_hbinterval;
+		cfg->pathmaxrxt=pp.spp_pathmaxrxt;
+	}
+#endif /* SCTP_PEER_ADDR_PARAMS */
+#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
+#ifdef SCTP_DELAYED_SACK
+	optlen=sizeof(sack_info);
+	memset(&sack_info, 0, sizeof(sack_info));
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sack_info,
+							&optlen, 0)==0){
+		/* success => hack to set the "default" values*/
+		cfg->sack_delay=sack_info.sack_delay;
+		cfg->sack_freq=sack_info.sack_freq;
+	}else
+#endif /* SCTP_DELAYED_SACK */
+	{
+#ifdef	SCTP_DELAYED_ACK_TIME
+		optlen=sizeof(sack_val);
+		memset(&sack_val, 0, sizeof(sack_val));
+		/* if no SCTP_DELAYED_SACK supported by the sctp lib, or setting it
+		   failed (not supported by the kernel) try using the obsolete
+		   SCTP_DELAYED_ACK_TIME method */
+		if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
+								(void*)&sack_val, &optlen, 
+								"SCTP_DELAYED_ACK_TIME")==0){
+			/* success => hack to set the "default" values*/
+			cfg->sack_delay=sack_val.assoc_value;
+			cfg->sack_freq=0; /* unknown */
+		}
+#else	/* SCTP_DELAYED_ACK_TIME */
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
+		   => error */
+		ERR("cfg: SCTP_DELAYED_SACK: %s [%d]\n", strerror(errno), errno);
+#endif /* SCTP_DELAYED_ACK_TIME */
+	}
+#endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
+#ifdef SCTP_MAX_BURST
+	optlen=sizeof(av);
+	av.assoc_id=0;
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_MAX_BURST, (void*)&av,
+							&optlen, "SCTP_MAX_BURST")==0){
+		/* success => hack to set the "default" values*/
+		cfg->max_burst=av.assoc_value;
+	}
+#endif /* SCTP_MAX_BURST */
+	
+	return 0;
+}
+
+
+
+/* set common (for one to many and one to one) sctp socket options
+   tries to ignore non-critical errors (it will only log them), for
+   improved portability (for example older linux kernel version support
+   only a limited number of sctp socket options)
+   returns 0 on success, -1 on error
+   WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */
+static int sctp_init_sock_opt_common(int s, int af)
+{
+	int optval;
+	int pd_point;
+	int saved_errno;
+	socklen_t optlen;
+	int sctp_err;
+#ifdef SCTP_RTOINFO
+	struct sctp_rtoinfo rto;
+#endif /* SCTP_RTOINFO */
+#ifdef SCTP_ASSOCINFO
+	struct sctp_assocparams ap;
+#endif /* SCTP_ASSOCINFO */
+#ifdef SCTP_INITMSG
+	struct sctp_initmsg im;
+#endif /* SCTP_INITMSG */
+#ifdef SCTP_PEER_ADDR_PARAMS
+	struct sctp_paddrparams pp;
+#endif /* SCTP_PEER_ADDR_PARAMS */
+#ifdef SCTP_DELAYED_SACK
+	struct sctp_sack_info sack_info;
+#endif	/* SCTP_DELAYED_SACK */
+#ifdef	SCTP_DELAYED_ACK_TIME
+	struct sctp_assoc_value sack_val;
+#endif /* defined SCTP_DELAYED_ACK_TIME */
+#ifdef SCTP_MAX_BURST
+	struct sctp_assoc_value av;
+#endif /* SCTP_MAX_BURST */
+	
+#ifdef __OS_linux
+	union {
+		struct sctp_event_subscribe s;
+		char padding[sizeof(struct sctp_event_subscribe)+sizeof(__u8)];
+	} es;
+#else
+	struct sctp_event_subscribe es;
+#endif
+	struct sctp_event_subscribe* ev_s;
+	
+	sctp_err=0;
+#ifdef __OS_linux
+	ev_s=&es.s;
+#else
+	ev_s=&es;
+#endif
+	/* set tos */
+	optval = tos;
+	if(af==AF_INET){
+		if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,
+					sizeof(optval)) ==-1){
+			LM_WARN("sctp_init_sock_opt_common: setsockopt tos: %s\n",
+					strerror(errno));
+			/* continue since this is not critical */
+		}
+	} else if(af==AF_INET6){
+		if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS,
+					(void*)&optval, sizeof(optval)) ==-1) {
+			LM_WARN("sctp_init_sock_opt_common: setsockopt v6 tos: %s\n",
+					strerror(errno));
+			/* continue since this is not critical */
+		}
+	}
+	
+	/* set receive buffer: SO_RCVBUF*/
+	if (cfg_get(sctp, sctp_cfg, so_rcvbuf)){
+		optval=cfg_get(sctp, sctp_cfg, so_rcvbuf);
+		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
+					(void*)&optval, sizeof(optval)) ==-1){
+			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt:"
+						" SO_RCVBUF (%d): %s\n", optval, strerror(errno));
+			/* continue, non-critical */
+		}
+	}
+	
+	/* set send buffer: SO_SNDBUF */
+	if (cfg_get(sctp, sctp_cfg, so_sndbuf)){
+		optval=cfg_get(sctp, sctp_cfg, so_sndbuf);
+		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+					(void*)&optval, sizeof(optval)) ==-1){
+			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt:"
+						" SO_SNDBUF (%d): %s\n", optval, strerror(errno));
+			/* continue, non-critical */
+		}
+	}
+	
+	/* set reuseaddr */
+	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+						(void*)&optval, sizeof(optval))==-1){
+			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt:"
+						" SO_REUSEADDR (%d): %s\n", optval, strerror(errno));
+			/* continue, non-critical */
+	}
+
+	
+	/* disable fragments interleave (SCTP_FRAGMENT_INTERLEAVE) --
+	 * we don't want partial delivery, so fragment interleave must be off too
+	 */
+#ifdef SCTP_FRAGMENT_INTERLEAVE
+	optval=0;
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE ,
+					(void*)&optval, sizeof(optval)) ==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
+					"SCTP_FRAGMENT_INTERLEAVE: %s\n", strerror(errno));
+		sctp_err++;
+		/* try to continue */
+	}
+#else
+#warning no sctp lib support for SCTP_FRAGMENT_INTERLEAVE, consider upgrading
+#endif /* SCTP_FRAGMENT_INTERLEAVE */
+	
+	/* turn off partial delivery: on linux setting SCTP_PARTIAL_DELIVERY_POINT
+	 * to 0 or a very large number seems to be enough, however the portable
+	 * way to do it is to set it to the socket receive buffer size
+	 * (this is the maximum value allowed in the sctp api draft) */
+#ifdef SCTP_PARTIAL_DELIVERY_POINT
+	optlen=sizeof(optval);
+	if (getsockopt(s, SOL_SOCKET, SO_RCVBUF,
+					(void*)&optval, &optlen) ==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: getsockopt: "
+						"SO_RCVBUF: %s\n", strerror(errno));
+		/* try to continue */
+		optval=0;
+	}
+#ifdef __OS_linux
+	optval/=2; /* in linux getsockopt() returns twice the set value */
+#endif
+	pd_point=optval;
+	saved_errno=0;
+	while(pd_point &&
+			setsockopt(s, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
+					(void*)&pd_point, sizeof(pd_point)) ==-1){
+		if (!saved_errno)
+			saved_errno=errno;
+		pd_point--;
+	}
+	
+	if (pd_point!=optval){
+		if (pd_point==0){
+			/* all attempts failed */
+			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
+						"SCTP_PARTIAL_DELIVERY_POINT (%d): %s\n",
+						optval, strerror(errno));
+			sctp_err++;
+			/* try to continue */
+		}else{
+			/* success but to a lower value (might not be disabled) */
+			LOG(L_WARN, "setsockopt SCTP_PARTIAL_DELIVERY_POINT set to %d, but"
+				" the socket rcvbuf is %d (higher values fail with"
+				" \"%s\" [%d])\n",
+				pd_point, optval, strerror(saved_errno), saved_errno);
+		}
+	}
+#else
+#warning no sctp lib support for SCTP_PARTIAL_DELIVERY_POINT, consider upgrading
+#endif /* SCTP_PARTIAL_DELIVERY_POINT */
+	
+	/* nagle / no delay */
+#ifdef SCTP_NODELAY
+	optval=1;
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY,
+					(void*)&optval, sizeof(optval)) ==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
+						"SCTP_NODELAY: %s\n", strerror(errno));
+		sctp_err++;
+		/* non critical, try to continue */
+	}
+#else
+#warning no sctp lib support for SCTP_NODELAY, consider upgrading
+#endif /* SCTP_NODELAY */
+	
+	/* enable message fragmentation (SCTP_DISABLE_FRAGMENTS)  (on send) */
+#ifdef SCTP_DISABLE_FRAGMENTS
+	optval=0;
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
+					(void*)&optval, sizeof(optval)) ==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
+						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
+		sctp_err++;
+		/* non critical, try to continue */
+	}
+#else
+#warning no sctp lib support for SCTP_DISABLE_FRAGMENTS, consider upgrading
+#endif /* SCTP_DISABLE_FRAGMENTS */
+	
+	/* set autoclose */
+#ifdef SCTP_AUTOCLOSE
+	optval=cfg_get(sctp, sctp_cfg, autoclose);
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE,
+					(void*)&optval, sizeof(optval)) ==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
+						"SCTP_AUTOCLOSE: %s (critical)\n", strerror(errno));
+		/* critical: w/o autoclose we could have sctp connection living
+		   forever (if the remote side doesn't close them) */
+		sctp_err++;
+		goto error;
+	}
+#else
+#error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
+#endif /* SCTP_AUTOCLOSE */
+	/* set rtoinfo options: srto_initial, srto_min, srto_max */
+#ifdef SCTP_RTOINFO
+	memset(&rto, 0, sizeof(rto));
+	rto.srto_initial=cfg_get(sctp, sctp_cfg, srto_initial);
+	rto.srto_min=cfg_get(sctp, sctp_cfg, srto_min);
+	rto.srto_max=cfg_get(sctp, sctp_cfg, srto_max);
+	if (rto.srto_initial || rto.srto_min || rto.srto_max){
+		/* if at least one is non-null => we have to set it */
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
+							sizeof(rto), "setsockopt: SCTP_RTOINFO")!=0){
+			sctp_err++;
+			/* non critical, try to continue */
+		}
+	}
+#else
+#warning no sctp lib support for SCTP_RTOINFO, consider upgrading
+#endif /* SCTP_RTOINFO */
+	/* set associnfo options: assocmaxrxt */
+#ifdef SCTP_ASSOCINFO
+	memset(&ap, 0, sizeof(ap));
+	ap.sasoc_asocmaxrxt=cfg_get(sctp, sctp_cfg, asocmaxrxt);
+	if (ap.sasoc_asocmaxrxt){
+		/* if at least one is non-null => we have to set it */
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_ASSOCINFO, (void*)&ap,
+							sizeof(ap), "setsockopt: SCTP_ASSOCINFO")!=0){
+			sctp_err++;
+			/* non critical, try to continue */
+		}
+	}
+#else
+#warning no sctp lib support for SCTP_ASSOCINFO, consider upgrading
+#endif /* SCTP_ASOCINFO */
+	/* set initmsg options: init_max_attempts & init_max_init_timeo */
+#ifdef SCTP_INITMSG
+	memset(&im, 0, sizeof(im));
+	im.sinit_max_attempts=cfg_get(sctp, sctp_cfg, init_max_attempts);
+	im.sinit_max_init_timeo=cfg_get(sctp, sctp_cfg, init_max_timeo);
+	if (im.sinit_max_attempts || im.sinit_max_init_timeo){
+		/* if at least one is non-null => we have to set it */
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, (void*)&im,
+							sizeof(im), "setsockopt: SCTP_INITMSG")!=0){
+			sctp_err++;
+			/* non critical, try to continue */
+		}
+	}
+#else
+#warning no sctp lib support for SCTP_INITMSG, consider upgrading
+#endif /* SCTP_INITMSG */
+	/* set sctp peer addr options: hbinterval & pathmaxrxt */
+#ifdef SCTP_PEER_ADDR_PARAMS
+	memset(&pp, 0, sizeof(pp));
+	pp.spp_address.ss_family=af;
+	pp.spp_hbinterval=cfg_get(sctp, sctp_cfg, hbinterval);
+	pp.spp_pathmaxrxt=cfg_get(sctp, sctp_cfg, pathmaxrxt);
+	if (pp.spp_hbinterval || pp.spp_pathmaxrxt){
+		if (pp.spp_hbinterval > 0)
+			pp.spp_flags=SPP_HB_ENABLE;
+		else if (pp.spp_hbinterval==-1){
+			pp.spp_flags=SPP_HB_DISABLE;
+			pp.spp_hbinterval=0;
+		}
+#ifdef __OS_linux
+		if (pp.spp_pathmaxrxt){
+			/* hack to work on linux, pathmaxrxt is set only if
+			   SPP_PMTUD_ENABLE */
+			pp.spp_flags|=SPP_PMTUD_ENABLE;
+		}
+#endif /*__OS_linux */
+		/* if at least one is non-null => we have to set it */
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, (void*)&pp,
+						sizeof(pp), "setsockopt: SCTP_PEER_ADDR_PARAMS")!=0){
+			sctp_err++;
+			/* non critical, try to continue */
+		}
+	}
+#else
+#warning no sctp lib support for SCTP_PEER_ADDR_PARAMS, consider upgrading
+#endif /* SCTP_PEER_ADDR_PARAMS */
+	/* set delayed ack options: sack_delay & sack_freq */
+#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
+#ifdef SCTP_DELAYED_SACK
+	memset(&sack_info, 0, sizeof(sack_info));
+	sack_info.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
+	sack_info.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
+	if ((sack_info.sack_delay || sack_info.sack_freq) &&
+		(sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK,
+							(void*)&sack_info, sizeof(sack_info), 0)!=0)) {
+		/* if setting SCTP_DELAYED_SACK failed, try the old obsolete
+		   SCTP_DELAYED_ACK_TIME */
+#endif /* SCTP_DELAYED_SACK */
+#ifdef SCTP_DELAYED_ACK_TIME
+		memset(&sack_val, 0, sizeof(sack_val));
+		sack_val.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
+		if (sack_val.assoc_value){
+			if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
+									(void*)&sack_val, sizeof(sack_val),
+									"setsockopt: SCTP_DELAYED_ACK_TIME")!=0){
+				sctp_err++;
+				/* non critical, try to continue */
+			}
+		}
+#else /* SCTP_DELAYED_ACK_TIME */
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
+		   => error */
+		if (sack_info.sack_delay){
+			sctp_err++;
+			ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
+						strerror(errno), errno);
+		}
+#endif /* SCTP_DELAYED_ACK_TIME */
+		if (cfg_get(sctp, sctp_cfg, sack_freq)){
+#ifdef SCTP_DELAYED_SACK
+			sctp_err++;
+			WARN("could not set sctp sack_freq, please upgrade your kernel\n");
+#else /* SCTP_DELAYED_SACK */
+			WARN("could not set sctp sack_freq, please upgrade your sctp"
+					" library\n");
+#endif /* SCTP_DELAYED_SACK */
+			((struct cfg_group_sctp*)sctp_cfg)->sack_freq=0;
+		}
+#ifdef SCTP_DELAYED_SACK
+	}
+#endif /* SCTP_DELAYED_SACK */
+	
+#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
+#warning no sctp lib support for SCTP_DELAYED_SACK, consider upgrading
+#endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
+	/* set max burst option */
+#ifdef SCTP_MAX_BURST
+	memset(&av, 0, sizeof(av));
+	av.assoc_value=cfg_get(sctp, sctp_cfg, max_burst);
+	if (av.assoc_value){
+		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_MAX_BURST, (void*)&av,
+							sizeof(av), "setsockopt: SCTP_MAX_BURST")!=0){
+			sctp_err++;
+			/* non critical, try to continue */
+		}
+	}
+#else
+#warning no sctp lib support for SCTP_MAX_BURST, consider upgrading
+#endif /* SCTP_MAX_BURST */
+	
+	memset(&es, 0, sizeof(es));
+	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
+	 *  information in sctp_sndrcvinfo */
+	ev_s->sctp_data_io_event=1;
+	/* enable association event notifications */
+	ev_s->sctp_association_event=1; /* SCTP_ASSOC_CHANGE */
+	ev_s->sctp_address_event=1;  /* enable address events notifications */
+	ev_s->sctp_send_failure_event=1; /* SCTP_SEND_FAILED */
+	ev_s->sctp_peer_error_event=1;   /* SCTP_REMOTE_ERROR */
+	ev_s->sctp_shutdown_event=1;     /* SCTP_SHUTDOWN_EVENT */
+	ev_s->sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */
+	/* ev_s->sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/
+	/* ev_s->sctp_authentication_event=1; -- not supported on linux 2.6.25 */
+	
+	/* enable the SCTP_EVENTS */
+#ifdef SCTP_EVENTS
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s))==-1){
+		/* on linux the checks for the struct sctp_event_subscribe size
+		   are too strict, making certain lksctp/kernel combination
+		   unworkable => since we don't use the extra information
+		   (sctp_authentication_event) added in newer version, we can
+		   try with different sizes) */
+#ifdef __OS_linux
+		/* 1. lksctp 1.0.9 with kernel < 2.6.26 -> kernel expects 
+		      the structure without the authentication event member */
+		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s)-1)==0)
+			goto ev_success;
+		/* 2. lksctp < 1.0.9? with kernel >= 2.6.26: the sctp.h structure
+		   does not have the authentication member, but the newer kernels 
+		   check only for optlen > sizeof(...) => we should never reach
+		   this point. */
+		/* 3. just to be foolproof if we reached this point, try
+		    with a bigger size before giving up  (out of desperation) */
+		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(es))==0)
+			goto ev_success;
+
+#endif
+		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
+				"SCTP_EVENTS: %s\n", strerror(errno));
+		sctp_err++;
+		goto error; /* critical */
+	}
+#ifdef __OS_linux
+ev_success:
+#endif
+#else
+#error no sctp lib support for SCTP_EVENTS, consider upgrading
+#endif /* SCTP_EVENTS */
+	
+	if (sctp_err){
+		LOG(L_ERR, "ERROR: sctp: setting some sctp sockopts failed, "
+					"consider upgrading your kernel\n");
+	}
+	return 0;
+error:
+	return -1;
+}
+
+
+
+/* bind all addresses from sock (sockaddr_unions)
+   returns 0 on success, .1 on error */
+static int sctp_bind_sock(struct socket_info* sock_info)
+{
+	struct addr_info* ai;
+	union sockaddr_union* addr;
+	
+	addr=&sock_info->su;
+	/* bind the addresses*/
+	if (bind(sock_info->socket,  &addr->s, sockaddru_len(*addr))==-1){
+		LOG(L_ERR, "ERROR: sctp_bind_sock: bind(%x, %p, %d) on %s: %s\n",
+				sock_info->socket, &addr->s, 
+				(unsigned)sockaddru_len(*addr),
+				sock_info->address_str.s,
+				strerror(errno));
+		if (addr->s.sa_family==AF_INET6)
+			LOG(L_ERR, "ERROR: sctp_bind_sock: might be caused by using a "
+							"link local address, try site local or global\n");
+		goto error;
+	}
+	for (ai=sock_info->addr_info_lst; ai; ai=ai->next)
+		if (sctp_bindx(sock_info->socket, &ai->su.s, 1, SCTP_BINDX_ADD_ADDR)
+					==-1){
+			LOG(L_ERR, "ERROR: sctp_bind_sock: sctp_bindx(%x, %.*s:%d, 1, ...)"
+						" on %s:%d : [%d] %s (trying to continue)\n",
+						sock_info->socket,
+						ai->address_str.len, ai->address_str.s, 
+						sock_info->port_no,
+						sock_info->address_str.s, sock_info->port_no,
+						errno, strerror(errno));
+			if (ai->su.s.sa_family==AF_INET6)
+				LOG(L_ERR, "ERROR: sctp_bind_sock: might be caused by using a "
+							"link local address, try site local or global\n");
+			/* try to continue, a secondary address bind failure is not 
+			 * critical */
+		}
+	return 0;
+error:
+	return -1;
+}
+
+
+
+/* init, bind & start listening on the corresp. sctp socket
+   returns 0 on success, -1 on error */
+int sctp_init_sock(struct socket_info* sock_info)
+{
+	union sockaddr_union* addr;
+	
+	sock_info->proto=PROTO_SCTP;
+	addr=&sock_info->su;
+	if (sctp_init_su(sock_info)!=0)
+		goto error;
+	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET, 
+								IPPROTO_SCTP);
+	if (sock_info->socket==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock: socket: %s\n", strerror(errno));
+		goto error;
+	}
+	INFO("sctp: socket %d initialized (%p)\n", sock_info->socket, sock_info);
+	/* make socket non-blocking */
+#if 0
+	/* recvmsg must block so use blocking sockets
+	 * and send with MSG_DONTWAIT */
+	optval=fcntl(sock_info->socket, F_GETFL);
+	if (optval==-1){
+		LOG(L_ERR, "ERROR: init_sctp: fnctl failed: (%d) %s\n",
+				errno, strerror(errno));
+		goto error;
+	}
+	if (fcntl(sock_info->socket, F_SETFL, optval|O_NONBLOCK)==-1){
+		LOG(L_ERR, "ERROR: init_sctp: fcntl: set non-blocking failed:"
+				" (%d) %s\n", errno, strerror(errno));
+		goto error;
+	}
+#endif
+
+	/* set sock opts */
+	if (sctp_init_sock_opt_common(sock_info->socket, sock_info->address.af)!=0)
+		goto error;
+	/* SCTP_EVENTS for send dried out -> present in the draft not yet
+	 * present in linux (might help to detect when we could send again to
+	 * some peer, kind of poor's man poll on write, based on received
+	 * SCTP_SENDER_DRY_EVENTs */
+	
+	if (sctp_bind_sock(sock_info)<0)
+		goto error;
+	if (listen(sock_info->socket, 1)<0){
+		LOG(L_ERR, "ERROR: sctp_init_sock: listen(%x, 1) on %s: %s\n",
+					sock_info->socket, sock_info->address_str.s,
+					strerror(errno));
+		goto error;
+	}
+	return 0;
+error:
+	return -1;
+}
+
+
+#define USE_SCTP_OO
+
+#ifdef USE_SCTP_OO
+
+/* init, bind & start listening on the corresp. sctp socket, using
+   sctp one-to-one mode
+   returns 0 on success, -1 on error */
+int sctp_init_sock_oo(struct socket_info* sock_info)
+{
+	union sockaddr_union* addr;
+	int optval;
+	
+	sock_info->proto=PROTO_SCTP;
+	addr=&sock_info->su;
+	if (sctp_init_su(sock_info)!=0)
+		goto error;
+	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 
+								IPPROTO_SCTP);
+	if (sock_info->socket==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_oo: socket: %s\n", strerror(errno));
+		goto error;
+	}
+	INFO("sctp:oo socket %d initialized (%p)\n", sock_info->socket, sock_info);
+	/* make socket non-blocking */
+	optval=fcntl(sock_info->socket, F_GETFL);
+	if (optval==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_oo: fnctl failed: (%d) %s\n",
+				errno, strerror(errno));
+		goto error;
+	}
+	if (fcntl(sock_info->socket, F_SETFL, optval|O_NONBLOCK)==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_oo: fcntl: set non-blocking failed:"
+				" (%d) %s\n", errno, strerror(errno));
+		goto error;
+	}
+	
+	/* set sock opts */
+	if (sctp_init_sock_opt_common(sock_info->socket, sock_info->address.af)!=0)
+		goto error;
+	
+#ifdef SCTP_REUSE_PORT
+	/* set reuse port */
+	optval=1;
+	if (setsockopt(sock_info->socket, IPPROTO_SCTP, SCTP_REUSE_PORT ,
+					(void*)&optval, sizeof(optval)) ==-1){
+		LOG(L_ERR, "ERROR: sctp_init_sock_oo: setsockopt: "
+					"SCTP_REUSE_PORT: %s\n", strerror(errno));
+		goto error;
+	}
+#endif /* SCTP_REUSE_PORT */
+	
+	if (sctp_bind_sock(sock_info)<0)
+		goto error;
+	if (listen(sock_info->socket, 1)<0){
+		LOG(L_ERR, "ERROR: sctp_init_sock_oo: listen(%x, 1) on %s: %s\n",
+					sock_info->socket, sock_info->address_str.s,
+					strerror(errno));
+		goto error;
+	}
+	return 0;
+error:
+	return -1;
+}
+
+#endif /* USE_SCTP_OO */
+
+
+#ifdef SCTP_CONN_REUSE
+
+/* we  need SCTP_ADDR_HASH for being able to make inquires related to existing
+   sctp association to a particular address  (optional) */
+/*#define SCTP_ADDR_HASH*/
+
+#define SCTP_ID_HASH_SIZE 1024 /* must be 2^k */
+#define SCTP_ASSOC_HASH_SIZE 1024 /* must be 2^k */
+#define SCTP_ADDR_HASH_SIZE 1024 /* must be 2^k */
+
+/* lock method */
+#ifdef GEN_LOCK_T_UNLIMITED
+#define SCTP_HASH_LOCK_PER_BUCKET
+#elif defined GEN_LOCK_SET_T_UNLIMITED
+#define SCTP_HASH_LOCK_SET
+#else
+#define SCTP_HASH_ONE_LOCK
+#endif
+
+
+#ifdef SCTP_HASH_LOCK_PER_BUCKET
+/* lock included in the hash bucket */
+#define LOCK_SCTP_ID_H(h)		lock_get(&sctp_con_id_hash[(h)].lock)
+#define UNLOCK_SCTP_ID_H(h)		lock_release(&sctp_con_id_hash[(h)].lock)
+#define LOCK_SCTP_ASSOC_H(h)	lock_get(&sctp_con_assoc_hash[(h)].lock)
+#define UNLOCK_SCTP_ASSOC_H(h)	lock_release(&sctp_con_assoc_hash[(h)].lock)
+#define LOCK_SCTP_ADDR_H(h)		lock_get(&sctp_con_addr_hash[(h)].lock)
+#define UNLOCK_SCTP_ADDR_H(h)	lock_release(&sctp_con_addr_hash[(h)].lock)
+#elif defined SCTP_HASH_LOCK_SET
+static gen_lock_set_t* sctp_con_id_h_lock_set=0;
+static gen_lock_set_t* sctp_con_assoc_h_lock_set=0;
+static gen_lock_set_t* sctp_con_addr_h_lock_set=0;
+#define LOCK_SCTP_ID_H(h)		lock_set_get(sctp_con_id_h_lock_set, (h))
+#define UNLOCK_SCTP_ID_H(h)		lock_set_release(sctp_con_id_h_lock_set, (h))
+#define LOCK_SCTP_ASSOC_H(h)	lock_set_get(sctp_con_assoc_h_lock_set, (h))
+#define UNLOCK_SCTP_ASSOC_H(h)	\
+	lock_set_release(sctp_con_assoc_h_lock_set, (h))
+#define LOCK_SCTP_ADDR_H(h)	lock_set_get(sctp_con_addr_h_lock_set, (h))
+#define UNLOCK_SCTP_ADDR_H(h)	lock_set_release(sctp_con_addr_h_lock_set, (h))
+#else /* use only one lock */
+static gen_lock_t* sctp_con_id_h_lock=0;
+static gen_lock_t* sctp_con_assoc_h_lock=0;
+static gen_lock_t* sctp_con_addr_h_lock=0;
+#define LOCK_SCTP_ID_H(h)		lock_get(sctp_con_id_h_lock)
+#define UNLOCK_SCTP_ID_H(h)		lock_release(sctp_con_id_hlock)
+#define LOCK_SCTP_ASSOC_H(h)	lock_get(sctp_con_assoc_h_lock)
+#define UNLOCK_SCTP_ASSOC_H(h)	lock_release(sctp_con_assoc_h_lock)
+#define LOCK_SCTP_ADDR_H(h)	lock_get(sctp_con_addr_h_lock)
+#define UNLOCK_SCTP_ADDR_H(h)	lock_release(sctp_con_addr_h_lock)
+#endif /* SCTP_HASH_LOCK_PER_BUCKET */
+
+
+/* sctp connection flags */
+#define SCTP_CON_UP_SEEN   1
+#define SCTP_CON_RCV_SEEN  2
+#define SCTP_CON_DOWN_SEEN 4
+
+struct sctp_connection{
+	unsigned int id;       /**< ser unique global id */
+	unsigned int assoc_id; /**< sctp assoc id (can be reused for new assocs)*/
+	struct socket_info* si; /**< local socket used */
+	unsigned flags; /**< internal flags UP_SEEN, RCV_SEEN, DOWN_SEEN */
+	ticks_t start;
+	ticks_t expire; 
+	union sockaddr_union remote; /**< remote ip & port */
+};
+
+struct sctp_lst_connector{
+	/* id hash */
+	struct sctp_con_elem* next_id;
+	struct sctp_con_elem* prev_id;
+	/* assoc hash */
+	struct sctp_con_elem* next_assoc;
+	struct sctp_con_elem* prev_assoc;
+#ifdef SCTP_ADDR_HASH
+	/* addr hash */
+	struct sctp_con_elem* next_addr;
+	struct sctp_con_elem* prev_addr;
+#endif /* SCTP_ADDR_HASH */
+};
+
+struct sctp_con_elem{
+	struct sctp_lst_connector l; /* must be first */
+	atomic_t refcnt;
+	/* data */
+	struct sctp_connection con;
+};
+
+struct sctp_con_id_hash_head{
+	struct sctp_lst_connector l; /* must be first */
+#ifdef SCTP_HASH_LOCK_PER_BUCKET
+	gen_lock_t lock;
+#endif /* SCTP_HASH_LOCK_PER_BUCKET */
+};
+
+struct sctp_con_assoc_hash_head{
+	struct sctp_lst_connector l; /* must be first */
+#ifdef SCTP_HASH_LOCK_PER_BUCKET
+	gen_lock_t lock;
+#endif /* SCTP_HASH_LOCK_PER_BUCKET */
+};
+
+#ifdef SCTP_ADDR_HASH
+struct sctp_con_addr_hash_head{
+	struct sctp_lst_connector l; /* must be first */
+#ifdef SCTP_HASH_LOCK_PER_BUCKET
+	gen_lock_t lock;
+#endif /* SCTP_HASH_LOCK_PER_BUCKET */
+};
+#endif /* SCTP_ADDR_HASH */
+
+static struct sctp_con_id_hash_head*     sctp_con_id_hash;
+static struct sctp_con_assoc_hash_head*  sctp_con_assoc_hash;
+#ifdef SCTP_ADDR_HASH
+static struct sctp_con_addr_hash_head*  sctp_con_addr_hash;
+#endif /* SCTP_ADDR_HASH */
+
+static atomic_t* sctp_id;
+static atomic_t* sctp_conn_tracked;
+
+
+#define get_sctp_con_id_hash(id) ((id) % SCTP_ID_HASH_SIZE)
+#define get_sctp_con_assoc_hash(assoc_id)  ((assoc_id) % SCTP_ASSOC_HASH_SIZE)
+#ifdef SCTP_ADDR_HASH
+static inline unsigned get_sctp_con_addr_hash(union sockaddr_union* remote,
+											struct socket_info* si)
+{
+	struct ip_addr ip;
+	unsigned short port;
+	unsigned h;
+	
+	su2ip_addr(&ip, remote);
+	port=su_getport(remote);
+	if (likely(ip.len==4))
+		h=ip.u.addr32[0]^port;
+	else if (ip.len==16)
+		h=ip.u.addr32[0]^ip.u.addr32[1]^ip.u.addr32[2]^ ip.u.addr32[3]^port;
+	else
+		h=0; /* error */
+	/* make sure the first bits are influenced by all 32
+	 * (the first log2(SCTP_ADDR_HASH_SIZE) bits should be a mix of all
+	 *  32)*/
+	h ^= h>>17;
+	h ^= h>>7;
+	return h & (SCTP_ADDR_HASH_SIZE-1);
+}
+#endif /* SCTP_ADDR_HASH */
+
+
+
+/** destroy sctp conn hashes. */
+void destroy_sctp_con_tracking()
+{
+	int r;
+	
+#ifdef SCTP_HASH_LOCK_PER_BUCKET
+	if (sctp_con_id_hash)
+		for(r=0; r<SCTP_ID_HASH_SIZE; r++)
+			lock_destroy(&sctp_con_id_hash[r].lock);
+	if (sctp_con_assoc_hash)
+		for(r=0; r<SCTP_ASSOC_HASH_SIZE; r++)
+			lock_destroy(&sctp_con_assoc_hash[r].lock);
+#	ifdef SCTP_ADDR_HASH
+	if (sctp_con_addr_hash)
+		for(r=0; r<SCTP_ADDR_HASH_SIZE; r++)
+			lock_destroy(&sctp_con_addr_hash[r].lock);
+#	endif /* SCTP_ADDR_HASH */
+#elif defined SCTP_HASH_LOCK_SET
+	if (sctp_con_id_h_lock_set){
+		lock_set_destroy(sctp_con_id_h_lock_set);
+		lock_set_dealloc(sctp_con_id_h_lock_set);
+		sctp_con_id_h_lock_set=0;
+	}
+	if (sctp_con_assoc_h_lock_set){
+		lock_set_destroy(sctp_con_assoc_h_lock_set);
+		lock_set_dealloc(sctp_con_assoc_h_lock_set);
+		sctp_con_assoc_h_lock_set=0;
+	}
+#	ifdef SCTP_ADDR_HASH
+	if (sctp_con_addr_h_lock_set){
+		lock_set_destroy(sctp_con_addr_h_lock_set);
+		lock_set_dealloc(sctp_con_addr_h_lock_set);
+		sctp_con_addr_h_lock_set=0;
+	}
+#	endif /* SCTP_ADDR_HASH */
+#else /* SCTP_HASH_ONE_LOCK */
+	if (sctp_con_id_h_lock){
+		lock_destroy(sctp_con_id_h_lock);
+		lock_dealloc(sctp_con_id_h_lock);
+		sctp_con_id_h_lock=0;
+	}
+	if (sctp_con_assoc_h_lock){
+		lock_destroy(sctp_con_assoc_h_lock);
+		lock_dealloc(sctp_con_assoc_h_lock);
+		sctp_con_assoc_h_lock=0;
+	}
+#	ifdef SCTP_ADDR_HASH
+	if (sctp_con_addr_h_lock){
+		lock_destroy(sctp_con_addr_h_lock);
+		lock_dealloc(sctp_con_addr_h_lock);
+		sctp_con_addr_h_lock=0;
+	}
+#	endif /* SCTP_ADDR_HASH */
+#endif /* SCTP_HASH_LOCK_PER_BUCKET/SCTP_HASH_LOCK_SET/one lock */
+	if (sctp_con_id_hash){
+		shm_free(sctp_con_id_hash);
+		sctp_con_id_hash=0;
+	}
+	if (sctp_con_assoc_hash){
+		shm_free(sctp_con_assoc_hash);
+		sctp_con_assoc_hash=0;
+	}
+#ifdef SCTP_ADDR_HASH
+	if (sctp_con_addr_hash){
+		shm_free(sctp_con_addr_hash);
+		sctp_con_addr_hash=0;
+	}
+#endif /* SCTP_ADDR_HASH */
+	if (sctp_id){
+		shm_free(sctp_id);
+		sctp_id=0;
+	}
+	if (sctp_conn_tracked){
+		shm_free(sctp_conn_tracked);
+		sctp_conn_tracked=0;
+	}
+}
+
+
+
+/** intializaze sctp_conn hashes.
+  * @return 0 on success, <0 on error
+  */
+int init_sctp_con_tracking()
+{
+	int r, ret;
+	
+	sctp_con_id_hash=shm_malloc(SCTP_ID_HASH_SIZE*sizeof(*sctp_con_id_hash));
+	sctp_con_assoc_hash=shm_malloc(SCTP_ASSOC_HASH_SIZE*
+									sizeof(*sctp_con_assoc_hash));
+#ifdef SCTP_ADDR_HASH
+	sctp_con_addr_hash=shm_malloc(SCTP_ADDR_HASH_SIZE*
+									sizeof(*sctp_con_addr_hash));
+#endif /* SCTP_ADDR_HASH */
+	sctp_id=shm_malloc(sizeof(*sctp_id));
+	sctp_conn_tracked=shm_malloc(sizeof(*sctp_conn_tracked));
+	if (sctp_con_id_hash==0 || sctp_con_assoc_hash==0 ||
+#ifdef SCTP_ADDR_HASH
+			sctp_con_addr_hash==0 ||
+#endif /* SCTP_ADDR_HASH */
+			sctp_id==0 || sctp_conn_tracked==0){
+		ERR("sctp init: memory allocation error\n");
+		ret=E_OUT_OF_MEM;
+		goto error;
+	}
+	atomic_set(sctp_id, 0);
+	atomic_set(sctp_conn_tracked, 0);
+	for (r=0; r<SCTP_ID_HASH_SIZE; r++)
+		clist_init(&sctp_con_id_hash[r], l.next_id, l.prev_id);
+	for (r=0; r<SCTP_ASSOC_HASH_SIZE; r++)
+		clist_init(&sctp_con_assoc_hash[r], l.next_assoc, l.prev_assoc);
+#ifdef SCTP_ADDR_HASH
+	for (r=0; r<SCTP_ADDR_HASH_SIZE; r++)
+		clist_init(&sctp_con_addr_hash[r], l.next_addr, l.prev_addr);
+#endif /* SCTP_ADDR_HASH */
+#ifdef SCTP_HASH_LOCK_PER_BUCKET
+	for (r=0; r<SCTP_ID_HASH_SIZE; r++){
+		if (lock_init(&sctp_con_id_hash[r].lock)==0){
+			ret=-1;
+			ERR("sctp init: failed to initialize locks\n");
+			goto error;
+		}
+	}
+	for (r=0; r<SCTP_ASSOC_HASH_SIZE; r++){
+		if (lock_init(&sctp_con_assoc_hash[r].lock)==0){
+			ret=-1;
+			ERR("sctp init: failed to initialize locks\n");
+			goto error;
+		}
+	}
+#	ifdef SCTP_ADDR_HASH
+	for (r=0; r<SCTP_ADDR_HASH_SIZE; r++){
+		if (lock_init(&sctp_con_addr_hash[r].lock)==0){
+			ret=-1;
+			ERR("sctp init: failed to initialize locks\n");
+			goto error;
+		}
+	}
+#	endif /* SCTP_ADDR_HASH */
+#elif defined SCTP_HASH_LOCK_SET
+	sctp_con_id_h_lock_set=lock_set_alloc(SCTP_ID_HASH_SIZE);
+	sctp_con_assoc_h_lock_set=lock_set_alloc(SCTP_ASSOC_HASH_SIZE);
+#	ifdef SCTP_ADDR_HASH
+	sctp_con_addr_h_lock_set=lock_set_alloc(SCTP_ADDR_HASH_SIZE);
+#	endif /* SCTP_ADDR_HASH */
+	if (sctp_con_id_h_lock_set==0 || sctp_con_assoc_h_lock_set==0
+#	ifdef SCTP_ADDR_HASH
+			|| sctp_con_addr_h_lock_set==0
+#	endif /* SCTP_ADDR_HASH */
+			){
+		ret=E_OUT_OF_MEM;
+		ERR("sctp_init: failed to alloc lock sets\n");
+		goto error;
+	}
+	if (lock_set_init(sctp_con_id_h_lock_set)==0){
+		lock_set_dealloc(sctp_con_id_h_lock_set);
+		sctp_con_id_h_lock_set=0;
+		ret=-1;
+		ERR("sctp init: failed to initialize lock set\n");
+		goto error;
+	}
+	if (lock_set_init(sctp_con_assoc_h_lock_set)==0){
+		lock_set_dealloc(sctp_con_assoc_h_lock_set);
+		sctp_con_assoc_h_lock_set=0;
+		ret=-1;
+		ERR("sctp init: failed to initialize lock set\n");
+		goto error;
+	}
+#	ifdef SCTP_ADDR_HASH
+	if (lock_set_init(sctp_con_addr_h_lock_set)==0){
+		lock_set_dealloc(sctp_con_addr_h_lock_set);
+		sctp_con_addr_h_lock_set=0;
+		ret=-1;
+		ERR("sctp init: failed to initialize lock set\n");
+		goto error;
+	}
+#	endif /* SCTP_ADDR_HASH */
+#else /* SCTP_HASH_ONE_LOCK */
+	sctp_con_id_h_lock=lock_alloc();
+	sctp_con_assoc_h_lock=lock_alloc();
+#	ifdef SCTP_ADDR_HASH
+	sctp_con_addr_h_lock=lock_alloc();
+#	endif /* SCTP_ADDR_HASH */
+	if (sctp_con_id_h_lock==0 || sctp_con_assoc_h_lock==0
+#	ifdef SCTP_ADDR_HASH
+			|| sctp_con_addr_h_lock==0
+#	endif /* SCTP_ADDR_HASH */
+			){
+		ret=E_OUT_OF_MEM;
+		ERR("sctp init: failed to alloc locks\n");
+		goto error;
+	}
+	if (lock_init(sctp_con_id_h_lock)==0){
+		lock_dealloc(sctp_con_id_h_lock);
+		sctp_con_id_h_lock=0;
+		ret=-1;
+		ERR("sctp init: failed to initialize lock\n");
+		goto error;
+	}
+	if (lock_init(sctp_con_assoc_h_lock)==0){
+		lock_dealloc(sctp_con_assoc_h_lock);
+		sctp_con_assoc_h_lock=0;
+		ret=-1;
+		ERR("sctp init: failed to initialize lock\n");
+		goto error;
+	}
+#	ifdef SCTP_ADDR_HASH
+	if (lock_init(sctp_con_addr_h_lock)==0){
+		lock_dealloc(sctp_con_addr_h_lock);
+		sctp_con_addr_h_lock=0;
+		ret=-1;
+		ERR("sctp init: failed to initialize lock\n");
+		goto error;
+	}
+#	endif /* SCTP_ADDR_HASH */
+#endif /* SCTP_HASH_LOCK_PER_BUCKET/SCTP_HASH_LOCK_SET/one lock */
+	return 0;
+error:
+	destroy_sctp_con_tracking();
+	return ret;
+}
+
+
+
+#if 0
+/** adds "e" to the hashes, safe locking version.*/
+static void sctp_con_add(struct sctp_con_elem* e)
+{
+	unsigned hash;
+	DBG("sctp_con_add(%p) ( ser id %d, assoc_id %d)\n",
+			e, e->con.id, e->con.assoc_id);
+	
+	e->l.next_id=e->l.prev_id=0;
+	e->l.next_assoc=e->l.prev_assoc=0;
+#ifdef SCTP_ADDR_HASH
+	e->l.next_addr=e->l.prev_addr=0;
+	e->refcnt.val+=3; /* account for the 3 lists */
+#else /* SCTP_ADDR_HASH */
+	e->refcnt.val+=2; /* account for the 2 lists */
+#endif /* SCTP_ADDR_HASH */
+	hash=get_sctp_con_id_hash(e->con.id);
+	DBG("adding to con id hash %d\n", hash);
+	LOCK_SCTP_ID_H(hash);
+		clist_insert(&sctp_con_id_hash[hash], e, l.next_id, l.prev_id);
+	UNLOCK_SCTP_ID_H(hash);
+	hash=get_sctp_con_assoc_hash(e->con.assoc_id);
+	DBG("adding to assoc_id hash %d\n", hash);
+	LOCK_SCTP_ASSOC_H(hash);
+		clist_insert(&sctp_con_assoc_hash[hash], e,
+						l.next_assoc, l.prev_assoc);
+	UNLOCK_SCTP_ASSOC_H(hash);
+#ifdef SCTP_ADDR_HASH
+	hash=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
+	DBG("adding to addr hash %d\n", hash);
+	LOCK_SCTP_ADDR_H(hash);
+		clist_insert(&sctp_con_addr_hash[hash], e,
+						l.next_addr, l.prev_addr);
+	UNLOCK_SCTP_ADDR_H(hash);
+#endif /* SCTP_ADDR_HASH */
+	atomic_inc(sctp_conn_tracked);
+}
+#endif
+
+
+
+/** helper internal del elem function, the id hash must be locked.
+  * WARNING: the id hash(h) _must_ be locked (LOCK_SCTP_ID_H(h)).
+  * @param h - id hash
+  * @param e - sctp_con_elem to delete (from all the hashes)
+  * @return 0 if the id hash was unlocked, 1 if it's still locked */
+inline static int _sctp_con_del_id_locked(unsigned h, struct sctp_con_elem* e)
+{
+	unsigned assoc_id_h;
+	int deref; /* delayed de-reference counter */
+	int locked;
+#ifdef SCTP_ADDR_HASH
+	unsigned addr_h;
+#endif /* SCTP_ADDR_HASH */
+	
+	locked=1;
+	clist_rm(e, l.next_id, l.prev_id);
+	e->l.next_id=e->l.prev_id=0; /* mark it as id unhashed */
+	/* delay atomic dereference, so that we'll perform only one
+	   atomic op. even for multiple derefs. It also has the
+	   nice side-effect that the entry will be guaranteed to be
+	   referenced until we perform the delayed deref. at the end,
+	   so we don't need to keep some lock to prevent somebody from
+	   deleting the entry from under us */
+	deref=1; /* removed from one list =>  deref once */
+	/* remove it from the assoc hash if needed */
+	if (likely(e->l.next_assoc)){
+		UNLOCK_SCTP_ID_H(h);
+		locked=0; /* no longer id-locked */
+		/* we haven't dec. refcnt, so it's still safe to use e */
+		assoc_id_h=get_sctp_con_assoc_hash(e->con.assoc_id);
+		LOCK_SCTP_ASSOC_H(assoc_id_h);
+			/* make sure nobody removed it in the meantime */
+			if (likely(e->l.next_assoc)){
+				clist_rm(e, l.next_assoc, l.prev_assoc);
+				e->l.next_assoc=e->l.prev_assoc=0; /* mark it as removed */
+				deref++; /* rm'ed from the assoc list => inc. delayed deref. */
+			}
+		UNLOCK_SCTP_ASSOC_H(assoc_id_h);
+	}
+#ifdef SCTP_ADDR_HASH
+	/* remove it from the addr. hash if needed */
+	if (likely(e->l.next_addr)){
+		if (unlikely(locked)){
+			UNLOCK_SCTP_ID_H(h);
+			locked=0; /* no longer id-locked */
+		}
+		addr_h=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
+		LOCK_SCTP_ADDR_H(addr_h);
+			/* make sure nobody removed it in the meantime */
+			if (likely(e->l.next_addr)){
+				clist_rm(e, l.next_addr, l.prev_addr);
+				e->l.next_addr=e->l.prev_addr=0; /* mark it as removed */
+				deref++; /* rm'ed from the addr list => inc. delayed deref. */
+			}
+		UNLOCK_SCTP_ADDR_H(addr_h);
+	}
+#endif /* SCTP_ADDR_HASH */
+	
+	/* performed delayed de-reference */
+	if (atomic_add(&e->refcnt, -deref)==0){
+		atomic_dec(sctp_conn_tracked);
+		shm_free(e);
+	}
+	else
+		DBG("del assoc post-deref (kept): ser id %d, assoc_id %d,"
+			" post-refcnt %d, deref %d, post-tracked %d\n",
+			e->con.id, e->con.assoc_id, atomic_get(&e->refcnt), deref,
+			atomic_get(sctp_conn_tracked));
+	return locked;
+}
+
+
+
+/** helper internal del elem function, the assoc hash must be locked.
+  * WARNING: the assoc hash(h) _must_ be locked (LOCK_SCTP_ASSOC_H(h)).
+  * @param h - assoc hash
+  * @param e - sctp_con_elem to delete (from all the hashes)
+  * @return 0 if the assoc hash was unlocked, 1 if it's still locked */
+inline static int _sctp_con_del_assoc_locked(unsigned h,
+												struct sctp_con_elem* e)
+{
+	unsigned id_hash;
+	int deref; /* delayed de-reference counter */
+	int locked;
+#ifdef SCTP_ADDR_HASH
+	unsigned addr_h;
+#endif /* SCTP_ADDR_HASH */
+	
+	locked=1;
+	clist_rm(e, l.next_assoc, l.prev_assoc);
+	e->l.next_assoc=e->l.prev_assoc=0; /* mark it as assoc unhashed */
+	/* delay atomic dereference, so that we'll perform only one
+	   atomic op. even for multiple derefs. It also has the
+	   nice side-effect that the entry will be guaranteed to be
+	   referenced until we perform the delayed deref. at the end,
+	   so we don't need to keep some lock to prevent somebody from
+	   deleting the entry from under us */
+	deref=1; /* removed from one list =>  deref once */
+	/* remove it from the id hash if needed */
+	if (likely(e->l.next_id)){
+		UNLOCK_SCTP_ASSOC_H(h);
+		locked=0; /* no longer assoc-hash-locked */
+		/* we have a ref. to it so it's still safe to use e */
+		id_hash=get_sctp_con_id_hash(e->con.id);
+		LOCK_SCTP_ID_H(id_hash);
+			/* make sure nobody removed it in the meantime */
+			if (likely(e->l.next_id)){
+				clist_rm(e, l.next_id, l.prev_id);
+				e->l.next_id=e->l.prev_id=0; /* mark it as removed */
+				deref++; /* rm'ed from the id list => inc. delayed deref. */
+			}
+		UNLOCK_SCTP_ID_H(id_hash);
+	}
+#ifdef SCTP_ADDR_HASH
+	/* remove it from the addr. hash if needed */
+	if (likely(e->l.next_addr)){
+		if (unlikely(locked)){
+			UNLOCK_SCTP_ASSOC_H(h);
+			locked=0; /* no longer id-locked */
+		}
+		addr_h=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
+		LOCK_SCTP_ADDR_H(addr_h);
+			/* make sure nobody removed it in the meantime */
+			if (likely(e->l.next_addr)){
+				clist_rm(e, l.next_addr, l.prev_addr);
+				e->l.next_addr=e->l.prev_addr=0; /* mark it as removed */
+				deref++; /* rm'ed from the addr list => inc. delayed deref. */
+			}
+		UNLOCK_SCTP_ADDR_H(addr_h);
+	}
+#endif /* SCTP_ADDR_HASH */
+	if (atomic_add(&e->refcnt, -deref)==0){
+		atomic_dec(sctp_conn_tracked);
+		shm_free(e);
+	}
+	else
+		DBG("del assoc post-deref (kept): ser id %d, assoc_id %d,"
+				" post-refcnt %d, deref %d, post-tracked %d\n",
+				e->con.id, e->con.assoc_id, atomic_get(&e->refcnt), deref,
+				atomic_get(sctp_conn_tracked));
+	return locked;
+}
+
+
+
+#ifdef SCTP_ADDR_HASH
+/** helper internal del elem function, the addr hash must be locked.
+  * WARNING: the addr hash(h) _must_ be locked (LOCK_SCTP_ADDR_H(h)).
+  * @param h - addr hash
+  * @param e - sctp_con_elem to delete (from all the hashes)
+  * @return 0 if the addr hash was unlocked, 1 if it's still locked */
+inline static int _sctp_con_del_addr_locked(unsigned h,
+												struct sctp_con_elem* e)
+{
+	unsigned id_hash;
+	unsigned assoc_id_h;
+	int deref; /* delayed de-reference counter */
+	int locked;
+	
+	locked=1;
+	clist_rm(e, l.next_addr, l.prev_addr);
+	e->l.next_addr=e->l.prev_addr=0; /* mark it as addr unhashed */
+	/* delay atomic dereference, so that we'll perform only one
+	   atomic op. even for multiple derefs. It also has the
+	   nice side-effect that the entry will be guaranteed to be
+	   referenced until we perform the delayed deref. at the end,
+	   so we don't need to keep some lock to prevent somebody from
+	   deleting the entry from under us */
+	deref=1; /* removed from one list =>  deref once */
+	/* remove it from the id hash if needed */
+	if (likely(e->l.next_id)){
+		UNLOCK_SCTP_ADDR_H(h);
+		locked=0; /* no longer addr-hash-locked */
+		/* we have a ref. to it so it's still safe to use e */
+		id_hash=get_sctp_con_id_hash(e->con.id);
+		LOCK_SCTP_ID_H(id_hash);
+			/* make sure nobody removed it in the meantime */
+			if (likely(e->l.next_id)){
+				clist_rm(e, l.next_id, l.prev_id);
+				e->l.next_id=e->l.prev_id=0; /* mark it as removed */
+				deref++; /* rm'ed from the id list => inc. delayed deref. */
+			}
+		UNLOCK_SCTP_ID_H(id_hash);
+	}
+	/* remove it from the assoc hash if needed */
+	if (likely(e->l.next_assoc)){
+		if (locked){
+			UNLOCK_SCTP_ADDR_H(h);
+			locked=0; /* no longer addr-hash-locked */
+		}
+		/* we haven't dec. refcnt, so it's still safe to use e */
+		assoc_id_h=get_sctp_con_assoc_hash(e->con.assoc_id);
+		LOCK_SCTP_ASSOC_H(assoc_id_h);
+			/* make sure nobody removed it in the meantime */
+			if (likely(e->l.next_assoc)){
+				clist_rm(e, l.next_assoc, l.prev_assoc);
+				e->l.next_assoc=e->l.prev_assoc=0; /* mark it as removed */
+				deref++; /* rm'ed from the assoc list => inc. delayed deref. */
+			}
+		UNLOCK_SCTP_ASSOC_H(assoc_id_h);
+	}
+	if (atomic_add(&e->refcnt, -deref)==0){
+		atomic_dec(sctp_conn_tracked);
+		shm_free(e);
+	}
+	else
+		DBG("del assoc post-deref (kept): ser id %d, assoc_id %d,"
+				" post-refcnt %d, deref %d, post-tracked %d\n",
+				e->con.id, e->con.assoc_id, atomic_get(&e->refcnt), deref,
+				atomic_get(sctp_conn_tracked));
+	return locked;
+}
+#endif /* SCTP_ADDR_HASH */
+
+
+
+/** delete all tracked associations entries.
+ */
+void sctp_con_tracking_flush()
+{
+	unsigned h;
+	struct sctp_con_elem* e;
+	struct sctp_con_elem* tmp;
+	
+	for (h=0; h<SCTP_ID_HASH_SIZE; h++){
+again:
+		LOCK_SCTP_ID_H(h);
+			clist_foreach_safe(&sctp_con_id_hash[h], e, tmp, l.next_id) {
+				if (_sctp_con_del_id_locked(h, e)==0){
+					/* unlocked, need to lock again and restart the list */
+					goto again;
+				}
+			}
+		UNLOCK_SCTP_ID_H(h);
+	}
+}
+
+
+
+/** using id, get the corresponding sctp assoc & socket. 
+ *  @param id - ser unique assoc id
+ *  @param si  - result parameter, filled with the socket info on success
+ *  @param remote - result parameter, filled with the address and port
+ *  @param del - if 1 delete the entry,
+ *  @return assoc_id (!=0) on success & sets si, 0 on not found
+ * si and remote will not be touched on failure.
+ *
+ */
+int sctp_con_get_assoc(unsigned int id, struct socket_info** si, 
+								union sockaddr_union *remote, int del)
+{
+	unsigned h;
+	ticks_t now; 
+	struct sctp_con_elem* e;
+	struct sctp_con_elem* tmp;
+	int ret;
+	
+	ret=0;
+	now=get_ticks_raw();
+	h=get_sctp_con_id_hash(id);
+#if 0
+again:
+#endif
+	LOCK_SCTP_ID_H(h);
+		clist_foreach_safe(&sctp_con_id_hash[h], e, tmp, l.next_id){
+			if(e->con.id==id){
+				ret=e->con.assoc_id;
+				*si=e->con.si;
+				*remote=e->con.remote;
+				if (del){
+					if (_sctp_con_del_id_locked(h, e)==0)
+						goto skip_unlock;
+				}else
+					e->con.expire=now +
+								S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
+				break;
+			}
+#if 0
+			else if (TICKS_LT(e->con.expire, now)){
+				WARN("sctp con: found expired assoc %d, id %d (%d s ago)\n",
+						e->con.assoc_id, e->con.id,
+						TICKS_TO_S(now-e->con.expire));
+				if (_sctp_con_del_id_locked(h, e)==0)
+					goto again; /* if unlocked need to restart the list */
+			}
+#endif
+		}
+	UNLOCK_SCTP_ID_H(h);
+skip_unlock:
+	return ret;
+}
+
+
+
+/** using the assoc_id, remote addr. & socket, get the corresp. internal id.
+ *  @param assoc_id - sctp assoc id
+ *  @param si  - socket on which the packet was received
+ *  @param del - if 1 delete the entry,
+ *  @return assoc_id (!=0) on success, 0 on not found
+ */
+int sctp_con_get_id(unsigned int assoc_id, union sockaddr_union* remote,
+					struct socket_info* si, int del)
+{
+	unsigned h;
+	ticks_t now; 
+	struct sctp_con_elem* e;
+	struct sctp_con_elem* tmp;
+	int ret;
+	
+	ret=0;
+	now=get_ticks_raw();
+	h=get_sctp_con_assoc_hash(assoc_id);
+#if 0
+again:
+#endif
+	LOCK_SCTP_ASSOC_H(h);
+		clist_foreach_safe(&sctp_con_assoc_hash[h], e, tmp, l.next_assoc){
+			if(e->con.assoc_id==assoc_id && e->con.si==si &&
+					su_cmp(remote, &e->con.remote)){
+				ret=e->con.id;
+				if (del){
+					if (_sctp_con_del_assoc_locked(h, e)==0)
+						goto skip_unlock;
+				}else
+					e->con.expire=now +
+								S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
+				break;
+			}
+#if 0
+			else if (TICKS_LT(e->con.expire, now)){
+				WARN("sctp con: found expired assoc %d, id %d (%d s ago)\n",
+						e->con.assoc_id, e->con.id,
+						TICKS_TO_S(now-e->con.expire));
+				if (_sctp_con_del_assoc_locked(h, e)==0)
+					goto again; /* if unlocked need to restart the list */
+			}
+#endif
+		}
+	UNLOCK_SCTP_ASSOC_H(h);
+skip_unlock:
+	return ret;
+}
+
+
+
+#ifdef SCTP_ADDR_HASH
+/** using the dest. & source socket, get the corresponding id and assoc_id 
+ *  @param remote   - peer address & port
+ *  @param si       - local source socket
+ *  @param assoc_id - result, filled with the sctp assoc_id
+ *  @param del - if 1 delete the entry,
+ *  @return ser id (!=0) on success, 0 on not found
+ */
+int sctp_con_addr_get_id_assoc(union sockaddr_union* remote,
+								struct socket_info* si,
+								int* assoc_id, int del)
+{
+	unsigned h;
+	ticks_t now; 
+	struct sctp_con_elem* e;
+	struct sctp_con_elem* tmp;
+	int ret;
+	
+	ret=0;
+	*assoc_id=0;
+	now=get_ticks_raw();
+	h=get_sctp_con_addr_hash(remote, si);
+again:
+	LOCK_SCTP_ADDR_H(h);
+		clist_foreach_safe(&sctp_con_addr_hash[h], e, tmp, l.next_addr){
+			if(su_cmp(remote, &e->con.remote) && e->con.si==si){
+				ret=e->con.id;
+				*assoc_id=e->con.assoc_id;
+				if (del){
+					if (_sctp_con_del_addr_locked(h, e)==0)
+						goto skip_unlock;
+				}else
+					e->con.expire=now +
+								S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
+				break;
+			}
+#if 0
+			else if (TICKS_LT(e->con.expire, now)){
+				WARN("sctp con: found expired assoc %d, id %d (%d s ago)\n",
+						e->con.assoc_id, e->con.id,
+						TICKS_TO_S(now-e->con.expire));
+				if (_sctp_con_del_addr_locked(h, e)==0)
+					goto again; /* if unlocked need to restart the list */
+			}
+#endif
+		}
+	UNLOCK_SCTP_ADDR_H(h);
+skip_unlock:
+	return ret;
+}
+#endif /* SCTP_ADDR_HASH */
+
+
+
+/** del con tracking for (assod_id, si).
+ * @return 0 on success, -1 on error (not found)
+ */
+#define sctp_con_del_assoc(assoc_id, si) \
+	(-(sctp_con_get_id((assoc_id), (si), 1)==0))
+
+
+
+/** create a new sctp con elem.
+  * @param id - ser connection id
+  * @param assoc_id - sctp assoc id
+  * @param si - corresp. socket
+  * @param remote - remote side
+  * @return pointer to shm allocated sctp_con_elem on success, 0 on error
+  */
+struct sctp_con_elem* sctp_con_new(unsigned id, unsigned assoc_id, 
+									struct socket_info* si,
+									union sockaddr_union* remote)
+{
+	struct sctp_con_elem* e;
+	
+	e=shm_malloc(sizeof(*e));
+	if (unlikely(e==0))
+		goto error;
+	e->l.next_id=e->l.prev_id=0;
+	e->l.next_assoc=e->l.prev_assoc=0;
+	atomic_set(&e->refcnt, 0);
+	e->con.id=id;
+	e->con.assoc_id=assoc_id;
+	e->con.si=si;
+	e->con.flags=0;
+	if (likely(remote))
+		e->con.remote=*remote;
+	else
+		memset(&e->con.remote, 0, sizeof(e->con.remote));
+	e->con.start=get_ticks_raw();
+	e->con.expire=e->con.start +
+				S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
+	return e;
+error:
+	return 0;
+}
+
+
+
+/** handles every ev on sctp assoc_id.
+  * @return ser id on success (!=0) or 0 on not found/error
+  */
+static int sctp_con_track(int assoc_id, struct socket_info* si,
+							union sockaddr_union* remote, int ev)
+{
+	int id;
+	unsigned hash;
+	unsigned assoc_hash;
+	struct sctp_con_elem* e;
+	struct sctp_con_elem* tmp;
+	
+	id=0;
+	DBG("sctp_con_track(%d, %p, %d) \n", assoc_id, si, ev);
+	
+	/* search for (assoc_id, si) */
+	assoc_hash=get_sctp_con_assoc_hash(assoc_id);
+	LOCK_SCTP_ASSOC_H(assoc_hash);
+		clist_foreach_safe(&sctp_con_assoc_hash[assoc_hash], e, tmp,
+								l.next_assoc){
+			/* we need to use the remote side address, because at least
+			   on linux assoc_id are immediately reused (even if sctp
+			   autoclose is off) and so it's possible that the association
+			   id we saved is already closed and assigned to another
+			   association by the time we search for it) */
+			if(e->con.assoc_id==assoc_id && e->con.si==si &&
+					su_cmp(remote, &e->con.remote)){
+				if (ev==SCTP_CON_DOWN_SEEN){
+					if (e->con.flags & SCTP_CON_UP_SEEN){
+						/* DOWN after UP => delete */
+						id=e->con.id;
+						/* do delete */
+						if (_sctp_con_del_assoc_locked(assoc_hash, e)==0)
+							goto found; /* skip unlock */
+					}else{
+						/* DOWN after DOWN => error
+						   DOWN after RCV w/ no UP -> not possible
+						    since we never create a tracking entry on RCV
+							only */
+						BUG("unexpected flags: %x for assoc_id %d, id %d"
+								", sctp con %p\n", e->con.flags, assoc_id,
+								e->con.id, e);
+						/* do delete */
+						if (_sctp_con_del_assoc_locked(assoc_hash, e)==0)
+							goto found; /* skip unlock */
+					}
+				}else if (ev==SCTP_CON_RCV_SEEN){
+					/* RCV after UP or DOWN => just mark RCV as seen */
+					id=e->con.id;
+					e->con.flags |= SCTP_CON_RCV_SEEN;
+				}else{
+					/* SCTP_CON_UP */
+					if (e->con.flags & SCTP_CON_DOWN_SEEN){
+						/* UP after DOWN => delete */
+						id=e->con.id;
+						/* do delete */
+						if (_sctp_con_del_assoc_locked(assoc_hash, e)==0)
+							goto found; /* skip unlock */
+					}else{
+						/* UP after UP or after RCVD => BUG */
+						BUG("connection with same assoc_id (%d) already"
+								" present, flags %x\n",
+								assoc_id, e->con.flags);
+					}
+				}
+				UNLOCK_SCTP_ASSOC_H(assoc_hash);
+				goto found;
+			}
+		}
+		/* not found */
+		if (unlikely(ev!=SCTP_CON_RCV_SEEN)){
+			/* UP or DOWN and no tracking entry => create new tracking entry
+			   for both of them (because we can have a re-ordered DOWN before
+			   the UP) */
+again:
+				id=atomic_add(sctp_id, 1);
+				if (unlikely(id==0)){
+					/* overflow  and 0 is not a valid id */
+					goto again;
+				}
+				e=sctp_con_new(id, assoc_id, si, remote);
+				if (likely(e)){
+					e->con.flags=ev;
+					e->l.next_id=e->l.prev_id=0;
+					e->l.next_assoc=e->l.prev_assoc=0;
+#ifdef SCTP_ADDR_HASH
+					e->l.next_addr=e->l.prev_addr=0;
+					e->refcnt.val+=3; /* account for the 3 lists */
+#else /* SCTP_ADDR_HASH */
+					e->refcnt.val+=2; /* account for the 2 lists */
+#endif /* SCTP_ADDR_HASH */
+					/* already locked */
+					clist_insert(&sctp_con_assoc_hash[assoc_hash], e,
+									l.next_assoc, l.prev_assoc);
+					hash=get_sctp_con_id_hash(e->con.id);
+					LOCK_SCTP_ID_H(hash);
+						clist_insert(&sctp_con_id_hash[hash], e,
+									l.next_id, l.prev_id);
+					UNLOCK_SCTP_ID_H(hash);
+#ifdef SCTP_ADDR_HASH
+					hash=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
+					LOCK_SCTP_ADDR_H(hash);
+						clist_insert(&sctp_con_addr_hash[hash], e,
+									l.next_addr, l.prev_addr);
+					UNLOCK_SCTP_ADDR_H(hash);
+#endif /* SCTP_ADDR_HASH */
+					atomic_inc(sctp_conn_tracked);
+				}
+		} /* else not found and RCV -> ignore
+			 We cannot create a new entry because we don't know when to
+			 delete it (we can have UP DOWN RCV which would result in a
+			 tracking entry living forever). This means that if we receive
+			 a msg. on an assoc. before it's UP notification we won't know
+			 the id for connection reuse, but since happens very rarely it's
+			 an acceptable tradeoff */
+	UNLOCK_SCTP_ASSOC_H(assoc_hash);
+	if (unlikely(e==0)){
+		ERR("memory allocation failure\n");
+		goto error;
+	}
+found:
+	return id;
+error:
+	return 0;
+}
+
+
+
+#else /* SCTP_CONN_REUSE */
+void sctp_con_tracking_flush() {}
+#endif /* SCTP_CONN_REUSE */
+
+
+int init_sctp()
+{
+	int ret;
+	
+	ret=0;
+	if (INIT_SCTP_STATS()!=0){
+		ERR("sctp init: failed to intialize sctp stats\n");
+		goto error;
+	}
+	/* sctp options must be initialized before  calling this function */
+	sctp_conn_no=shm_malloc(sizeof(*sctp_conn_tracked));
+	if ( sctp_conn_no==0){
+		ERR("sctp init: memory allocation error\n");
+		ret=E_OUT_OF_MEM;
+		goto error;
+	}
+	atomic_set(sctp_conn_no, 0);
+#ifdef SCTP_CONN_REUSE
+	return init_sctp_con_tracking();
+#endif
+error:
+	return ret;
+}
+
+
+
+void destroy_sctp()
+{
+	if (sctp_conn_no){
+		shm_free(sctp_conn_no);
+		sctp_conn_no=0;
+	}
+#ifdef SCTP_CONN_REUSE
+	destroy_sctp_con_tracking();
+#endif
+	DESTROY_SCTP_STATS();
+}
+
+
+
+static int sctp_msg_send_ext(struct dest_info* dst, char* buf, unsigned len,
+						struct sctp_sndrcvinfo* sndrcv_info);
+#define SCTP_SEND_FIRST_ASSOCID 1  /* sctp_raw_send flag */
+static int sctp_raw_send(int socket, char* buf, unsigned len,
+						union sockaddr_union* to,
+						struct sctp_sndrcvinfo* sndrcv_info,
+						int flags);
+
+
+
+/* debugging: return a string name for SCTP_ASSOC_CHANGE state */
+static char* sctp_assoc_change_state2s(short int state)
+{
+	char* s;
+	
+	switch(state){
+		case SCTP_COMM_UP:
+			s="SCTP_COMM_UP";
+			break;
+		case SCTP_COMM_LOST:
+			s="SCTP_COMM_LOST";
+			break;
+		case SCTP_RESTART:
+			s="SCTP_RESTART";
+			break;
+		case SCTP_SHUTDOWN_COMP:
+			s="SCTP_SHUTDOWN_COMP";
+			break;
+		case SCTP_CANT_STR_ASSOC:
+			s="SCTP_CANT_STR_ASSOC";
+			break;
+		default:
+			s="UNKNOWN";
+			break;
+	};
+	return s;
+}
+
+
+
+/* debugging: return a string name for a SCTP_PEER_ADDR_CHANGE state */
+static char* sctp_paddr_change_state2s(unsigned int state)
+{
+	char* s;
+	
+	switch (state){
+		case SCTP_ADDR_AVAILABLE:
+			s="SCTP_ADDR_AVAILABLE";
+			break;
+		case SCTP_ADDR_UNREACHABLE:
+			s="SCTP_ADDR_UNREACHABLE";
+			break;
+		case SCTP_ADDR_REMOVED:
+			s="SCTP_ADDR_REMOVED";
+			break;
+		case SCTP_ADDR_ADDED:
+			s="SCTP_ADDR_ADDED";
+			break;
+		case SCTP_ADDR_MADE_PRIM:
+			s="SCTP_ADDR_MADE_PRIM";
+			break;
+	/* not supported by lksctp 1.0.6 
+		case SCTP_ADDR_CONFIRMED:
+			s="SCTP_ADDR_CONFIRMED";
+			break;
+	*/
+		default:
+			s="UNKNOWN";
+			break;
+	}
+	return s;
+}
+
+
+
+/* handle SCTP_SEND_FAILED notifications: if packet marked for retries
+ * retry the send (with 0 assoc_id)
+ * returns 0 on success, -1 on failure
+ */
+static int sctp_handle_send_failed(struct socket_info* si,
+									union sockaddr_union* su,
+									char* buf, unsigned len)
+{
+	union sctp_notification* snp;
+	struct sctp_sndrcvinfo sinfo;
+	struct dest_info dst;
+	char* data;
+	unsigned data_len;
+	int retries;
+	int ret;
+#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
+	int send_ttl;
+#endif
+	
+	ret=-1;
+	SCTP_STATS_SEND_FAILED();
+	snp=(union sctp_notification*) buf;
+	retries=snp->sn_send_failed.ssf_info.sinfo_context;
+	
+	/* don't retry on explicit remote error
+	 * (unfortunately we can't be more picky than this, we get no 
+	 * indication in the SEND_FAILED notification for other error
+	 * reasons (e.g. ABORT received, INIT timeout a.s.o)
+	 */
+	if (retries && (snp->sn_send_failed.ssf_error==0)) {
+		DBG("sctp: RETRY-ing (%d)\n", retries);
+		SCTP_STATS_SEND_FORCE_RETRY();
+		retries--;
+		data=(char*)snp->sn_send_failed.ssf_data;
+		data_len=snp->sn_send_failed.ssf_length - 
+					sizeof(struct sctp_send_failed);
+		
+		memset(&sinfo, 0, sizeof(sinfo));
+		sinfo.sinfo_flags=SCTP_UNORDERED;
+#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
+		if ((send_ttl=cfg_get(sctp, sctp_cfg, send_ttl))){
+			sinfo.sinfo_pr_policy=SCTP_PR_SCTP_TTL;
+			sinfo.sinfo_pr_value=send_ttl;
+		}else
+			sinfo.info_pr_policy=SCTP_PR_SCTP_NONE;
+#else
+		sinfo.sinfo_timetolive=cfg_get(sctp, sctp_cfg, send_ttl);
+#endif
+		sinfo.sinfo_context=retries;
+		
+		dst.to=*su;
+		dst.send_sock=si;
+		dst.id=0;
+		dst.proto=PROTO_SCTP;
+#ifdef USE_COMP
+		dst.comp=COMP_NONE;
+#endif
+		
+		ret=sctp_msg_send_ext(&dst, data, data_len, &sinfo);
+	}
+#ifdef USE_DST_BLACKLIST
+	 else if (cfg_get(sctp, sctp_cfg, send_retries)) {
+		/* blacklist only if send_retries is on, if off we blacklist
+		   from SCTP_ASSOC_CHANGE: SCTP_COMM_LOST/SCTP_CANT_STR_ASSOC
+		   which is better (because we can tell connect errors from send
+		   errors and we blacklist a failed dst only once) */
+		dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
+	}
+#endif /* USE_DST_BLACKLIST */
+	
+	return (ret>0)?0:ret;
+}
+
+
+
+/* handle SCTP_ASOC_CHANGE notifications: map ser global sctp ids
+ * to kernel asoc_ids. The global ids are needed because the kernel ones
+ * might get reused after a close and so they are not unique for ser's
+ * lifetime. We need a unique id to match replies to the association on
+ * which we received the corresponding request (so that we can send them
+ * back on the same asoc & socket if still opened).
+ * returns 0 on success, -1 on failure
+ */
+static int sctp_handle_assoc_change(struct socket_info* si,
+									union sockaddr_union* su,
+									union sctp_notification* snp
+									)
+{
+	int ret;
+	int state;
+	int assoc_id;
+	struct sctp_sndrcvinfo sinfo;
+	struct ip_addr ip; /* used only on error, for debugging */
+	
+	state=snp->sn_assoc_change.sac_state;
+	assoc_id=snp->sn_assoc_change.sac_assoc_id;
+	
+	ret=-1;
+	switch(state){
+		case SCTP_COMM_UP:
+			SCTP_STATS_ESTABLISHED();
+			atomic_inc(sctp_conn_no);
+#ifdef SCTP_CONN_REUSE
+			/* new connection, track it */
+			if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking)))
+					sctp_con_track(assoc_id, si, su, SCTP_CON_UP_SEEN);
+#if 0
+again:
+			id=atomic_add(sctp_id, 1);
+			if (unlikely(id==0)){
+				/* overflow  and 0 is not a valid id */
+				goto again;
+			}
+			e=sctp_con_new(id, assoc_id, si, su);
+			if (unlikely(e==0)){
+				ERR("memory allocation failure\n");
+			}else{
+				sctp_con_add(e);
+				ret=0;
+			}
+#endif
+#endif /* SCTP_CONN_REUSE */
+			if (unlikely((unsigned)atomic_get(sctp_conn_no) >
+							(unsigned)cfg_get(sctp, sctp_cfg, max_assocs))){
+				/* maximum assoc exceeded => we'll have to immediately 
+				   close it */
+				memset(&sinfo, 0, sizeof(sinfo));
+				sinfo.sinfo_flags=SCTP_UNORDERED | SCTP_ABORT;
+				sinfo.sinfo_assoc_id=assoc_id;
+				ret=sctp_raw_send(si->socket, ABORT_REASON_MAX_ASSOCS,
+											sizeof(ABORT_REASON_MAX_ASSOCS)-1,
+											su, &sinfo, 0);
+				if (ret<0){
+					su2ip_addr(&ip, su);
+					WARN("failed to ABORT new sctp association %d (%s:%d):"
+							" %s (%d)\n", assoc_id, ip_addr2a(&ip),
+							su_getport(su), strerror(errno), errno);
+				}else{
+					SCTP_STATS_LOCAL_REJECT();
+				}
+			}
+			break;
+		case SCTP_COMM_LOST:
+			SCTP_STATS_COMM_LOST();
+#ifdef USE_DST_BLACKLIST
+			/* blacklist only if send_retries is turned off (if on we don't
+			   know here if we did retry or we are at the first error) */
+			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
+						dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
+#endif /* USE_DST_BLACKLIST */
+			/* no break */
+			goto comm_lost_cont;	/* do not increment counters for
+									   SCTP_SHUTDOWN_COMP */
+		case SCTP_SHUTDOWN_COMP:
+			SCTP_STATS_ASSOC_SHUTDOWN();
+comm_lost_cont:
+			atomic_dec(sctp_conn_no);
+#ifdef SCTP_CONN_REUSE
+			/* connection down*/
+			if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking)))
+				sctp_con_track(assoc_id, si, su, SCTP_CON_DOWN_SEEN);
+#if 0
+			if (unlikely(sctp_con_del_assoc(assoc_id, si)!=0))
+				WARN("sctp con: tried to remove inexistent connection\n");
+			else
+				ret=0;
+#endif
+#endif /* SCTP_CONN_REUSE */
+			break;
+		case SCTP_RESTART:
+			/* do nothing on restart */
+			break;
+		case SCTP_CANT_STR_ASSOC:
+			SCTP_STATS_CONNECT_FAILED();
+			/* do nothing when failing to start an assoc
+			  (in this case we never see SCTP_COMM_UP so we never 
+			  track the assoc) */
+#ifdef USE_DST_BLACKLIST
+			/* blacklist only if send_retries is turned off (if on we don't 
+			   know here if we did retry or we are at the first error) */
+			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
+					dst_blacklist_su(BLST_ERR_CONNECT, PROTO_SCTP, su, 0, 0);
+#endif /* USE_DST_BLACKLIST */
+			break;
+		default:
+			break;
+	}
+	return ret;
+}
+
+
+
+static int sctp_handle_notification(struct socket_info* si,
+									union sockaddr_union* su,
+									char* buf, unsigned len)
+{
+	union sctp_notification* snp;
+	char su_buf[SU2A_MAX_STR_SIZE];
+	
+	#define SNOT DBG
+	#define ERR_LEN_TOO_SMALL(length, val, bind_addr, from_su, text) \
+		if (unlikely((length)<(val))){\
+			SNOT("ERROR: sctp notification from %s on %.*s:%d: " \
+						text " too short (%d bytes instead of %d bytes)\n", \
+						su2a((from_su), sizeof(*(from_su))), \
+						(bind_addr)->name.len, (bind_addr)->name.s, \
+						(bind_addr)->port_no, (int)(length), (int)(val)); \
+			goto error; \
+		}
+
+	if (len < sizeof(snp->sn_header)){
+		LOG(L_ERR, "ERROR: sctp_handle_notification: invalid length %d "
+					"on %.*s:%d, from %s\n",
+					len, si->name.len, si->name.s, si->port_no,
+					su2a(su, sizeof(*su)));
+		goto error;
+	}
+	snp=(union sctp_notification*) buf;
+	switch(snp->sn_header.sn_type){
+		case SCTP_REMOTE_ERROR:
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_remote_error), si, su,
+								"SCTP_REMOTE_ERROR");
+			SCTP_EV_REMOTE_ERROR(&si->address, si->port_no, su, 
+									ntohs(snp->sn_remote_error.sre_error) );
+			SNOT("sctp notification from %s on %.*s:%d: SCTP_REMOTE_ERROR:"
+					" %d, len %d\n, assoc_id %d",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no,
+					ntohs(snp->sn_remote_error.sre_error),
+					ntohs(snp->sn_remote_error.sre_length),
+					snp->sn_remote_error.sre_assoc_id
+				);
+			break;
+		case SCTP_SEND_FAILED:
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_send_failed), si, su,
+								"SCTP_SEND_FAILED");
+			SCTP_EV_SEND_FAILED(&si->address, si->port_no, su, 
+									snp->sn_send_failed.ssf_error);
+			SNOT("sctp notification from %s on %.*s:%d: SCTP_SEND_FAILED:"
+					" error %d, assoc_id %d, flags %x\n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no, snp->sn_send_failed.ssf_error,
+					snp->sn_send_failed.ssf_assoc_id,
+					snp->sn_send_failed.ssf_flags);
+			sctp_handle_send_failed(si, su, buf, len);
+			break;
+		case SCTP_PEER_ADDR_CHANGE:
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_paddr_change), si, su,
+								"SCTP_PEER_ADDR_CHANGE");
+			SCTP_EV_PEER_ADDR_CHANGE(&si->address, si->port_no, su, 
+					sctp_paddr_change_state2s(snp->sn_paddr_change.spc_state),
+					snp->sn_paddr_change.spc_state,
+					&snp->sn_paddr_change.spc_aaddr);
+			strcpy(su_buf, su2a((union sockaddr_union*)
+									&snp->sn_paddr_change.spc_aaddr, 
+									sizeof(snp->sn_paddr_change.spc_aaddr)));
+			SNOT("sctp notification from %s on %.*s:%d: SCTP_PEER_ADDR_CHANGE"
+					": %s: %s: assoc_id %d \n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no, su_buf,
+					sctp_paddr_change_state2s(snp->sn_paddr_change.spc_state),
+					snp->sn_paddr_change.spc_assoc_id
+					);
+			break;
+		case SCTP_SHUTDOWN_EVENT:
+			SCTP_STATS_REMOTE_SHUTDOWN();
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_shutdown_event), si, su,
+								"SCTP_SHUTDOWN_EVENT");
+			SCTP_EV_SHUTDOWN_EVENT(&si->address, si->port_no, su);
+			SNOT("sctp notification from %s on %.*s:%d: SCTP_SHUTDOWN_EVENT:"
+					" assoc_id %d\n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no, snp->sn_shutdown_event.sse_assoc_id);
+			break;
+		case SCTP_ASSOC_CHANGE:
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_assoc_change), si, su,
+								"SCTP_ASSOC_CHANGE");
+			SCTP_EV_ASSOC_CHANGE(&si->address, si->port_no, su, 
+					sctp_assoc_change_state2s(snp->sn_assoc_change.sac_state),
+					snp->sn_assoc_change.sac_state);
+			SNOT("sctp notification from %s on %.*s:%d: SCTP_ASSOC_CHANGE"
+					": %s: assoc_id %d, ostreams %d, istreams %d\n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no,
+					sctp_assoc_change_state2s(snp->sn_assoc_change.sac_state),
+					snp->sn_assoc_change.sac_assoc_id,
+					snp->sn_assoc_change.sac_outbound_streams,
+					snp->sn_assoc_change.sac_inbound_streams
+					);
+			sctp_handle_assoc_change(si, su, snp);
+			break;
+#ifdef SCTP_ADAPTION_INDICATION
+		case SCTP_ADAPTION_INDICATION:
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_adaption_event), si, su,
+								"SCTP_ADAPTION_INDICATION");
+			SNOT("sctp notification from %s on %.*s:%d: "
+					"SCTP_ADAPTION_INDICATION \n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no);
+			break;
+#endif /* SCTP_ADAPTION_INDICATION */
+		case SCTP_PARTIAL_DELIVERY_EVENT:
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_pdapi_event), si, su,
+								"SCTP_PARTIAL_DELIVERY_EVENT");
+			ERR("sctp notification from %s on %.*s:%d: "
+					"SCTP_PARTIAL_DELIVERY_EVENT not supported: %d %s,"
+					"assoc_id %d\n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no, snp->sn_pdapi_event.pdapi_indication,
+					(snp->sn_pdapi_event.pdapi_indication==
+					 	SCTP_PARTIAL_DELIVERY_ABORTED)? " PD ABORTED":"",
+					snp->sn_pdapi_event.pdapi_assoc_id);
+			break;
+#ifdef SCTP_SENDER_DRY_EVENT /* new, not yet supported */
+		case SCTP_SENDER_DRY_EVENT:
+			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_sender_dry_event),
+								si, su, "SCTP_SENDER_DRY_EVENT");
+			SCTP_EV_REMOTE_ERROR(&si->address, si->port_no, su);
+			SNOT("sctp notification from %s on %.*s:%d: "
+					"SCTP_SENDER_DRY_EVENT on %d\n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no, snp->sn_sender_dry_event.sender_dry_assoc_id);
+			break;
+#endif /* SCTP_SENDER_DRY_EVENT */
+		default:
+			SNOT("sctp notification from %s on %.*s:%d: UNKNOWN (%d)\n",
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
+					si->port_no, snp->sn_header.sn_type);
+	}
+	return 0;
+error:
+	return -1;
+	#undef ERR_LEN_TOO_SMALL
+}
+
+
+
+int sctp_rcv_loop()
+{
+	unsigned len;
+	static char buf [BUF_SIZE+1];
+	char *tmp;
+	struct receive_info ri;
+	struct sctp_sndrcvinfo* sinfo;
+	struct msghdr msg;
+	struct iovec iov[1];
+	struct cmsghdr* cmsg;
+	/* use a larger buffer then needed in case some other ancillary info
+	 * is enabled */
+	char cbuf[CMSG_SPACE(sizeof(*sinfo))+CMSG_SPACE(1024)];
+
+	
+	ri.bind_address=bind_address; /* this will not change */
+	ri.dst_port=bind_address->port_no;
+	ri.dst_ip=bind_address->address;
+	ri.proto=PROTO_SCTP;
+	ri.proto_reserved2=0;
+	
+	iov[0].iov_base=buf;
+	iov[0].iov_len=BUF_SIZE;
+	msg.msg_iov=iov;
+	msg.msg_iovlen=1;
+	msg.msg_flags=0;
+	
+
+	/* initialize the config framework */
+	if (cfg_child_init()) goto error;
+	
+	for(;;){
+		msg.msg_name=&ri.src_su.s;
+		msg.msg_namelen=sockaddru_len(bind_address->su);
+		msg.msg_control=cbuf;
+		msg.msg_controllen=sizeof(cbuf);
+		sinfo=0;
+
+		len=recvmsg(bind_address->socket, &msg, 0);
+		if (len==-1){
+			if (errno==EAGAIN){
+				DBG("sctp_rcv_loop: EAGAIN on sctp socket\n");
+				continue;
+			}
+			LOG(L_ERR, "ERROR: sctp_rcv_loop: sctp_recvmsg on %d (%p):"
+						"[%d] %s\n", bind_address->socket, bind_address,
+						errno, strerror(errno));
+			if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
+				continue; /* goto skip;*/
+			else goto error;
+		}
+		/* update the local config */
+		cfg_update();
+		
+		if (unlikely(msg.msg_flags & MSG_NOTIFICATION)){
+			/* intercept useful notifications */
+			sctp_handle_notification(bind_address, &ri.src_su, buf, len);
+			continue;
+		}else if (unlikely(!(msg.msg_flags & MSG_EOR))){
+			LOG(L_ERR, "ERROR: sctp_rcv_loop: partial delivery not"
+						"supported\n");
+			continue;
+		}
+		
+		su2ip_addr(&ri.src_ip, &ri.src_su);
+		ri.src_port=su_getport(&ri.src_su);
+		
+		/* get ancillary data */
+		for (cmsg=CMSG_FIRSTHDR(&msg); cmsg; cmsg=CMSG_NXTHDR(&msg, cmsg)){
+#ifdef SCTP_EXT
+			if (likely((cmsg->cmsg_level==IPPROTO_SCTP) &&
+						((cmsg->cmsg_type==SCTP_SNDRCV)
+						 || (cmsg->cmsg_type==SCTP_EXTRCV)
+						) && (cmsg->cmsg_len>=CMSG_LEN(sizeof(*sinfo)))) )
+#else  /* !SCTP_EXT -- same as above but w/o SCTP_EXTRCV */
+			if (likely((cmsg->cmsg_level==IPPROTO_SCTP) &&
+						((cmsg->cmsg_type==SCTP_SNDRCV)
+						) && (cmsg->cmsg_len>=CMSG_LEN(sizeof(*sinfo)))) )
+#endif /*SCTP_EXT */
+			{
+				sinfo=(struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
+				DBG("sctp recv: message from %s:%d stream %d  ppid %x"
+						" flags %x%s tsn %u" " cumtsn %u assoc_id %d\n",
+						ip_addr2a(&ri.src_ip), ri.src_port,
+						sinfo->sinfo_stream, sinfo->sinfo_ppid,
+						sinfo->sinfo_flags,
+						(sinfo->sinfo_flags&SCTP_UNORDERED)?
+							" (SCTP_UNORDERED)":"",
+						sinfo->sinfo_tsn, sinfo->sinfo_cumtsn, 
+						sinfo->sinfo_assoc_id);
+				break;
+			}
+		}
+		/* we  0-term the messages for debugging */
+		buf[len]=0; /* no need to save the previous char */
+
+		/* sanity checks */
+		if (len<MIN_SCTP_PACKET) {
+			tmp=ip_addr2a(&ri.src_ip);
+			DBG("sctp_rcv_loop: probing packet received from %s:%d\n",
+					tmp, ri.src_port);
+			continue;
+		}
+		if (ri.src_port==0){
+			tmp=ip_addr2a(&ri.src_ip);
+			LOG(L_INFO, "sctp_rcv_loop: dropping 0 port packet from %s:0\n",
+						tmp);
+			continue;
+		}
+#ifdef USE_COMP
+		ri.comp=COMP_NONE;
+#endif
+#ifdef SCTP_CONN_REUSE
+		if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking) && sinfo)){
+			ri.proto_reserved1 = sctp_con_track(sinfo->sinfo_assoc_id,
+												ri.bind_address, 
+												&ri.src_su,
+												SCTP_CON_RCV_SEEN);
+			/* debugging */
+			if (unlikely(ri.proto_reserved1==0))
+				DBG("no tracked assoc. found for assoc_id %d, from %s\n",
+						sinfo->sinfo_assoc_id, 
+						su2a(&ri.src_su, sizeof(ri.src_su)));
+#if 0
+			ri.proto_reserved1=
+				sctp_con_get_id(sinfo->sinfo_assoc_id, ri.bind_address, 0);
+#endif
+		}else
+			ri.proto_reserved1=0;
+#else /* SCTP_CONN_REUSE */
+		ri.proto_received1=0;
+#endif /* SCTP_CONN_REUSE */
+		receive_msg(buf, len, &ri);
+	}
+error:
+	return -1;
+}
+
+
+
+/** low level sctp non-blocking send.
+ * @param socket - sctp socket to send on.
+ * @param buf   - data.
+ * @param len   - lenght of the data.
+ * @param to    - destination in ser sockaddr_union format.
+ * @param sndrcv_info - sctp_sndrcvinfo structure pointer, pre-filled.
+ * @param flags - can have one of the following values (or'ed):
+ *                SCTP_SEND_FIRST_ASSOCID - try to send first to assoc_id
+ *                and only if that fails use "to".
+ * @return the numbers of bytes sent on success (>=0) and -1 on error.
+ * On error errno is set too.
+ */
+static int sctp_raw_send(int socket, char* buf, unsigned len,
+						union sockaddr_union* to,
+						struct sctp_sndrcvinfo* sndrcv_info,
+						int flags)
+{
+	int n;
+	int tolen;
+	int try_assoc_id;
+#if 0
+	struct ip_addr ip; /* used only on error, for debugging */
+#endif
+	struct msghdr msg;
+	struct iovec iov[1];
+	struct sctp_sndrcvinfo* sinfo;
+	struct cmsghdr* cmsg;
+	/* make sure msg_control will point to properly aligned data */
+	union {
+		struct cmsghdr cm;
+		char cbuf[CMSG_SPACE(sizeof(*sinfo))];
+	}ctrl_un;
+	
+	iov[0].iov_base=buf;
+	iov[0].iov_len=len;
+	msg.msg_iov=iov;
+	msg.msg_iovlen=1;
+	msg.msg_flags=0; /* not used on send (use instead sinfo_flags) */
+	msg.msg_control=ctrl_un.cbuf;
+	msg.msg_controllen=sizeof(ctrl_un.cbuf);
+	cmsg=CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level=IPPROTO_SCTP;
+	cmsg->cmsg_type=SCTP_SNDRCV;
+	cmsg->cmsg_len=CMSG_LEN(sizeof(*sinfo));
+	sinfo=(struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
+	*sinfo=*sndrcv_info;
+	/* some systems need msg_controllen set to the actual size and not
+	 * something bigger (e.g. openbsd) */
+	msg.msg_controllen=cmsg->cmsg_len;
+	try_assoc_id= ((flags & SCTP_SEND_FIRST_ASSOCID) && sinfo->sinfo_assoc_id);
+	/* if assoc_id is set it means we want to send on association assoc_id
+	   and only if it's not opened any longer use the addresses */
+	if (try_assoc_id){
+		/* on linux msg->name has priority over assoc_id. To try first assoc_id
+		 * and then "to", one has to call first sendmsg() with msg->name==0 and
+		 * sinfo->assoc_id set. If it returns EPIPE => association is no longer
+		 * open => call again sendmsg() this time with msg->name!=0.
+		 * on freebsd assoc_id has priority over msg->name and moreover the
+		 * send falls back automatically to the address if the assoc_id is
+		 * closed, so a single call to sendmsg(msg->name, sinfo->assoc_id ) is
+		 * enough.  If one tries calling with msg->name==0 and the association
+		 * is no longer open send will return ENOENT.
+		 * on solaris it seems one must always use a dst address (assoc_id
+		 * will be ignored).
+		 */
+#ifdef __OS_linux
+		msg.msg_name=0;
+		msg.msg_namelen=0;
+#elif defined __OS_freebsd
+		tolen=sockaddru_len(*to);
+		msg.msg_name=&to->s;
+		msg.msg_namelen=tolen;
+#else /* __OS_* */
+		/* fallback for solaris and others, sent back to
+		  the address recorded (not exactly what we want, but there's
+		  no way to fallback to "to") */
+		tolen=sockaddru_len(*to);
+		msg.msg_name=&to->s;
+		msg.msg_namelen=tolen;
+#endif /* __OS_* */
+	}else{
+		tolen=sockaddru_len(*to);
+		msg.msg_name=&to->s;
+		msg.msg_namelen=tolen;
+	}
+	
+again:
+	n=sendmsg(socket, &msg, MSG_DONTWAIT);
+	if (n==-1){
+#ifdef __OS_linux
+		if ((errno==EPIPE) && try_assoc_id){
+			/* try again, this time with null assoc_id and non-null msg.name */
+			DBG("sctp raw sendmsg: assoc already closed (EPIPE), retrying with"
+					" assoc_id=0\n");
+			tolen=sockaddru_len(*to);
+			msg.msg_name=&to->s;
+			msg.msg_namelen=tolen;
+			sinfo->sinfo_assoc_id=0;
+			try_assoc_id=0;
+			goto again;
+		}
+#elif defined __OS_freebsd
+		if ((errno==ENOENT)){
+			/* it didn't work, no retrying */
+			WARN("unexpected sendmsg() failure (ENOENT),"
+					" assoc_id %d\n", sinfo->sinfo_assoc_id);
+		}
+#else /* __OS_* */
+		if ((errno==ENOENT || errno==EPIPE) && try_assoc_id){
+			/* in case the sctp stack prioritises assoc_id over msg->name,
+			   try again with 0 assoc_id and msg->name set to "to" */
+			WARN("unexpected ENOENT or EPIPE (assoc_id %d),"
+					"trying automatic recovery... (please report along with"
+					"your OS version)\n", sinfo->sinfo_assoc_id);
+			tolen=sockaddru_len(*to);
+			msg.msg_name=&to->s;
+			msg.msg_namelen=tolen;
+			sinfo->sinfo_assoc_id=0;
+			try_assoc_id=0;
+			goto again;
+		}
+#endif /* __OS_* */
+#if 0
+		if (errno==EINTR) goto again;
+		su2ip_addr(&ip, to);
+		LOG(L_ERR, "ERROR: sctp_raw_send: sendmsg(sock,%p,%d,0,%s:%d,...):"
+				" %s(%d)\n", buf, len, ip_addr2a(&ip), su_getport(to),
+				strerror(errno), errno);
+		if (errno==EINVAL) {
+			LOG(L_CRIT,"CRITICAL: invalid sendmsg parameters\n"
+			"one possible reason is the server is bound to localhost and\n"
+			"attempts to send to the net\n");
+		}else if (errno==EAGAIN || errno==EWOULDBLOCK){
+			SCTP_STATS_SENDQ_FULL();
+			LOG(L_ERR, "ERROR: sctp_msg_send: failed to send, send buffers"
+						" full\n");
+		}
+#endif
+	}
+	return n;
+}
+
+
+
+/* send buf:len over sctp to dst using sndrcv_info (uses send_sock,
+ * to and id from dest_info)
+ * returns the numbers of bytes sent on success (>=0) and -1 on error
+ */
+static int sctp_msg_send_ext(struct dest_info* dst, char* buf, unsigned len,
+						struct sctp_sndrcvinfo* sndrcv_info)
+{
+	int n;
+	int tolen;
+	struct ip_addr ip; /* used only on error, for debugging */
+	struct msghdr msg;
+	struct iovec iov[1];
+	struct socket_info* si;
+	struct sctp_sndrcvinfo* sinfo;
+	struct cmsghdr* cmsg;
+	/* make sure msg_control will point to properly aligned data */
+	union {
+		struct cmsghdr cm;
+		char cbuf[CMSG_SPACE(sizeof(*sinfo))];
+	}ctrl_un;
+#ifdef SCTP_CONN_REUSE
+	int assoc_id;
+	union sockaddr_union to;
+#ifdef SCTP_ADDR_HASH
+	int tmp_id, tmp_assoc_id;
+#endif /* SCTP_ADDR_HASH */
+#endif /* SCTP_CONN_REUSE */
+	
+	iov[0].iov_base=buf;
+	iov[0].iov_len=len;
+	msg.msg_iov=iov;
+	msg.msg_iovlen=1;
+	msg.msg_flags=0; /* not used on send (use instead sinfo_flags) */
+	msg.msg_control=ctrl_un.cbuf;
+	msg.msg_controllen=sizeof(ctrl_un.cbuf);
+	cmsg=CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level=IPPROTO_SCTP;
+	cmsg->cmsg_type=SCTP_SNDRCV;
+	cmsg->cmsg_len=CMSG_LEN(sizeof(*sinfo));
+	sinfo=(struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
+	*sinfo=*sndrcv_info;
+	/* some systems need msg_controllen set to the actual size and not
+	 * something bigger (e.g. openbsd) */
+	msg.msg_controllen=cmsg->cmsg_len;
+	si=dst->send_sock;
+#ifdef SCTP_CONN_REUSE
+	/* if dst->id is set it means we want to send on association with
+	   ser id dst->id if still opened and only if closed use dst->to */
+	assoc_id=0;
+	if ((dst->id) && cfg_get(sctp, sctp_cfg, assoc_reuse) &&
+			cfg_get(sctp, sctp_cfg, assoc_tracking) &&
+			(assoc_id=sctp_con_get_assoc(dst->id, &si, &to, 0))){
+		DBG("sctp: sending on sctp assoc_id %d (ser id %d)\n",
+				assoc_id, dst->id);
+		sinfo->sinfo_assoc_id=assoc_id;
+		/* on linux msg->name has priority over assoc_id. To try first assoc_id
+		 * and then dst, one has to call first sendmsg() with msg->name==0 and
+		 * sinfo->assoc_id set. If it returns EPIPE => association is no longer
+		 * open => call again sendmsg() this time with msg->name!=0.
+		 * on freebsd assoc_id has priority over msg->name and moreover the
+		 * send falls back automatically to the address if the assoc_id is
+		 * closed, so a single call to sendmsg(msg->name, sinfo->assoc_id ) is
+		 * enough.  If one tries calling with msg->name==0 and the association
+		 * is no longer open send will return ENOENT.
+		 * on solaris it seems one must always use a dst address (assoc_id
+		 * will be ignored).
+		 */
+#ifdef __OS_linux
+		DBG("sctp: linux: trying with 0 msg_name\n");
+		msg.msg_name=0;
+		msg.msg_namelen=0;
+#elif defined __OS_freebsd
+		tolen=sockaddru_len(dst->to);
+		msg.msg_name=&dst->to.s;
+		msg.msg_namelen=tolen;
+#else /* __OS_* */
+		/* fallback for solaris and others, sent back to
+		  the address recorded (not exactly what we want, but there's 
+		  no way to fallback to dst->to) */
+		tolen=sockaddru_len(dst->to);
+		msg.msg_name=&dst->to.s;
+		msg.msg_namelen=tolen;
+#endif /* __OS_* */
+	}else{
+#ifdef SCTP_ADDR_HASH
+		/* update timeout for the assoc identified  by (dst->to, dst->si) */
+		if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking))){
+			tmp_id=sctp_con_addr_get_id_assoc(&dst->to, dst->send_sock,
+												&tmp_assoc_id, 0);
+			DBG("sctp send: timeout updated ser id %d, sctp assoc_id %d\n",
+					tmp_id, tmp_assoc_id);
+			if (tmp_id==0 /* not tracked/found */ &&
+					(unsigned)atomic_get(sctp_conn_tracked) >=
+						(unsigned)cfg_get(sctp, sctp_cfg, max_assocs)){
+				ERR("maximum number of sctp associations exceeded\n");
+				goto error;
+			}
+		}
+#endif /* SCTP_ADDR_HASH */
+		tolen=sockaddru_len(dst->to);
+		msg.msg_name=&dst->to.s;
+		msg.msg_namelen=tolen;
+	}
+#else /* SCTP_CONN_REUSE */
+	tolen=sockaddru_len(dst->to);
+	msg.msg_name=&dst->to.s;
+	msg.msg_namelen=tolen;
+#endif /* SCTP_CONN_REUSE */
+
+again:
+	n=sendmsg(si->socket, &msg, MSG_DONTWAIT);
+	if (n==-1){
+#ifdef SCTP_CONN_REUSE
+#ifdef __OS_linux
+		if ((errno==EPIPE) && assoc_id){
+			/* try again, this time with null assoc_id and non-null msg.name */
+			DBG("sctp sendmsg: assoc already closed (EPIPE), retrying with"
+					" assoc_id=0\n");
+			tolen=sockaddru_len(dst->to);
+			msg.msg_name=&dst->to.s;
+			msg.msg_namelen=tolen;
+			sinfo->sinfo_assoc_id=0;
+			goto again;
+		}
+#elif defined __OS_freebsd
+		if ((errno==ENOENT)){
+			/* it didn't work, no retrying */
+			WARN("sctp sendmsg: unexpected sendmsg() failure (ENOENT),"
+					" assoc_id %d\n", assoc_id);
+		}
+#else /* __OS_* */
+		if ((errno==ENOENT || errno==EPIPE) && assoc_id){
+			/* in case the sctp stack prioritises assoc_id over msg->name,
+			   try again with 0 assoc_id and msg->name set to dst->to */
+			WARN("sctp sendmsg: unexpected ENOENT or EPIPE (assoc_id %d),"
+					"trying automatic recovery... (please report along with"
+					"your OS version)\n", assoc_id);
+			tolen=sockaddru_len(dst->to);
+			msg.msg_name=&dst->to.s;
+			msg.msg_namelen=tolen;
+			sinfo->sinfo_assoc_id=0;
+			goto again;
+		}
+#endif /* __OS_* */
+#endif /* SCTP_CONN_REUSE */
+		su2ip_addr(&ip, &dst->to);
+		LOG(L_ERR, "ERROR: sctp_msg_send: sendmsg(sock,%p,%d,0,%s:%d,...):"
+				" %s(%d)\n", buf, len, ip_addr2a(&ip), su_getport(&dst->to),
+				strerror(errno), errno);
+		if (errno==EINTR) goto again;
+		if (errno==EINVAL) {
+			LOG(L_CRIT,"CRITICAL: invalid sendmsg parameters\n"
+			"one possible reason is the server is bound to localhost and\n"
+			"attempts to send to the net\n");
+		}else if (errno==EAGAIN || errno==EWOULDBLOCK){
+			SCTP_STATS_SENDQ_FULL();
+			LOG(L_ERR, "ERROR: sctp_msg_send: failed to send, send buffers"
+						" full\n");
+		}
+	}
+	return n;
+#ifdef SCTP_CONN_REUSE
+#ifdef SCTP_ADDR_HASH
+error:
+	return -1;
+#endif /* SCTP_ADDR_HASH */
+#endif /* SCTP_CONN_REUSE */
+}
+
+
+
+/* wrapper around sctp_msg_send_ext():
+ * send buf:len over udp to dst (uses only the to, send_sock and id members
+ * from dst)
+ * returns the numbers of bytes sent on success (>=0) and -1 on error
+ */
+int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len)
+{
+	struct sctp_sndrcvinfo sinfo;
+#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
+	int send_ttl;
+#endif
+	
+	memset(&sinfo, 0, sizeof(sinfo));
+	sinfo.sinfo_flags=SCTP_UNORDERED;
+#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
+	if ((send_ttl=cfg_get(sctp, sctp_cfg, send_ttl))){
+		sinfo.sinfo_pr_policy=SCTP_PR_SCTP_TTL;
+		sinfo.sinfo_pr_value=send_ttl;
+	}else
+		sinfo->sinfo_pr_policy=SCTP_PR_SCTP_NONE;
+#else
+		sinfo.sinfo_timetolive=cfg_get(sctp, sctp_cfg, send_ttl);
+#endif
+	sinfo.sinfo_context=cfg_get(sctp, sctp_cfg, send_retries);
+	return sctp_msg_send_ext(dst, buf, len, &sinfo);
+}
+
+
+
+/** generic sctp info (basic stats).*/
+void sctp_get_info(struct sctp_gen_info* i)
+{
+	if (i){
+		i->sctp_connections_no=atomic_get(sctp_conn_no);
+#ifdef SCTP_CONN_REUSE
+		if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking)))
+			i->sctp_tracked_no=atomic_get(sctp_conn_tracked);
+		else
+			i->sctp_tracked_no=-1;
+#else /* SCTP_CONN_REUSE */
+		i->sctp_tracked_no=-1;
+#endif /* SCTP_CONN_REUSE */
+		i->sctp_total_connections=atomic_get(sctp_id);
+	}
+}
+
+
+#endif /* USE_SCTP */
diff --git a/modules/sctp/sctp_server.h b/modules/sctp/sctp_server.h
new file mode 100644
index 0000000..29fb8a0
--- /dev/null
+++ b/modules/sctp/sctp_server.h
@@ -0,0 +1,55 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* 
+ * sctp one to many 
+ */
+/*
+ * History:
+ * --------
+ *  2008-08-07  initial version (andrei)
+ */
+
+#ifndef _sctp_server_h
+#define _sctp_server_h
+
+#include "../../ip_addr.h"
+
+struct sctp_gen_info{
+	int sctp_connections_no;
+	int sctp_tracked_no;
+	int sctp_total_connections;
+};
+
+int init_sctp(void);
+void destroy_sctp(void);
+int sctp_check_compiled_sockopts(char* buf, int size);
+int sctp_check_support(void);
+int sctp_init_sock(struct socket_info* sock_info);
+int sctp_rcv_loop(void);
+int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len);
+
+/* generic sctp information (stats a.s.o) */
+void sctp_get_info(struct sctp_gen_info* sinf);
+
+void destroy_sctp(void);
+
+int sctp_setsockopt(int s, int level, int optname,
+					void* optval, socklen_t optlen, char* err_prefix);
+
+void sctp_con_tracking_flush(void);
+#endif /* _sctp_server_h */
diff --git a/sctp_sockopts.h b/modules/sctp/sctp_sockopts.h
similarity index 100%
rename from sctp_sockopts.h
rename to modules/sctp/sctp_sockopts.h
diff --git a/modules/sctp/sctp_stats.c b/modules/sctp/sctp_stats.c
new file mode 100644
index 0000000..b533d29
--- /dev/null
+++ b/modules/sctp/sctp_stats.c
@@ -0,0 +1,124 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/** sctp statistics.
+ * @file sctp_stats.c
+ * @ingroup:  core (sctp)
+ */
+/*
+ * History:
+ * --------
+ *  2010-08-09  initial version (andrei)
+*/
+
+#ifdef USE_SCTP
+
+#include "sctp_stats.h"
+
+#ifdef USE_SCTP_STATS
+
+#include "../../counters.h"
+
+#include "sctp_server.h"
+
+struct sctp_counters_h sctp_cnts_h;
+
+
+enum sctp_info_req { SCTP_INFO_NONE, SCTP_INFO_CONN_NO, SCTP_INFO_TRACKED_NO };
+static counter_val_t sctp_info(counter_handle_t h, void* what);
+
+
+
+/* sctp counters definitions */
+counter_def_t sctp_cnt_defs[] =  {
+	{&sctp_cnts_h.established, "established", 0, 0, 0,
+		"incremented each time a new association is established."},
+	{&sctp_cnts_h.connect_failed, "connect_failed", 0, 0, 0,
+		"incremented each time a new outgoing connection fails."},
+	{&sctp_cnts_h.local_reject, "local_reject", 0, 0, 0,
+		"number of rejected incoming connections."},
+	{&sctp_cnts_h.remote_shutdown, "remote_shutdown", 0, 0, 0,
+		"incremented each time an association is closed by the peer."},
+	{&sctp_cnts_h.assoc_shutdown, "assoc_shutdown", 0, 0, 0,
+		"incremented each time an association is shutdown."},
+	{&sctp_cnts_h.comm_lost, "comm_lost", 0, 0, 0,
+		"incremented each time an established connection is close due to"
+			"some error."},
+	{&sctp_cnts_h.sendq_full, "sendq_full", 0, 0, 0,
+		"number of failed send attempt due to exceeded buffering capacity"
+	    " (full kernel buffers)."},
+	{&sctp_cnts_h.send_failed, "send_failed", 0, 0, 0,
+		"number of failed send attempt for any reason except full buffers."},
+	{&sctp_cnts_h.send_force_retry, "send_force_retry", 0, 0, 0,
+		"incremented each time a failed send is force-retried"
+			"(possible only if sctp_send_retries ! = 0"},
+	{0, "current_opened_connections", 0,
+		sctp_info, (void*)(long)SCTP_INFO_CONN_NO,
+		"number of currently opened associations."},
+	{0, "current_tracked_connections", 0,
+		sctp_info, (void*)(long)SCTP_INFO_TRACKED_NO,
+		"number of currently tracked associations."},
+	{0, 0, 0, 0, 0, 0 }
+};
+
+
+
+/** helper function for some stats (which are kept internally inside sctp).
+ */
+static counter_val_t sctp_info(counter_handle_t h, void* what)
+{
+	enum sctp_info_req w;
+	struct sctp_gen_info i;
+
+	if (sctp_disable)
+		return 0;
+	w = (int)(long)what;
+	sctp_get_info(&i);
+	switch(w) {
+		case SCTP_INFO_CONN_NO:
+			return i.sctp_connections_no;
+		case SCTP_INFO_TRACKED_NO:
+			return i.sctp_tracked_no;
+		case SCTP_INFO_NONE:
+			break;
+	};
+	return 0;
+}
+
+/** intialize sctp statistics.
+ *  Must be called before forking.
+ * @return < 0 on errror, 0 on success.
+ */
+int sctp_stats_init()
+{
+	if (counter_register_array("sctp", sctp_cnt_defs) < 0)
+		goto error;
+	return 0;
+error:
+	return -1;
+}
+
+
+void sctp_stats_destroy()
+{
+	/* do nothing */
+}
+
+#endif /* USE_SCTP_STATS */
+#endif /* USE_SCTP */
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/modules/sctp/sctp_stats.h b/modules/sctp/sctp_stats.h
new file mode 100644
index 0000000..5b0c578
--- /dev/null
+++ b/modules/sctp/sctp_stats.h
@@ -0,0 +1,139 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * sctp_stats.h - sctp statistics macros
+ */
+/*
+ * History:
+ * --------
+ *  2009-04-28  initial version (andrei)
+*/
+
+#ifndef __sctp_stats_h
+#define __sctp_stats_h
+
+
+/* enable sctp stats by default */
+#ifndef NO_SCTP_STATS
+#define USE_SCTP_STATS
+#endif
+
+#ifndef USE_SCTP_STATS
+
+#define INIT_SCTP_STATS() 0 /* success */
+#define DESTROY_SCTP_STATS()
+
+#define SCTP_STATS_ESTABLISHED()
+#define SCTP_STATS_CONNECT_FAILED()
+#define SCTP_STATS_LOCAL_REJECT()
+#define SCTP_STATS_REMOTE_SHUTDOWN()
+#define SCTP_STATS_ASSOC_SHUTDOWN()
+#define SCTP_STATS_COMM_LOST()
+#define SCTP_STATS_SENDQ_FULL()
+#define SCTP_STATS_SEND_FAILED()
+#define SCTP_STATS_SEND_FORCE_RETRY()
+
+#else /* USE_SCTP_STATS */
+
+#include "../../counters.h"
+
+struct sctp_counters_h {
+	counter_handle_t established;
+	counter_handle_t connect_failed;
+	counter_handle_t local_reject;
+	counter_handle_t remote_shutdown;
+	counter_handle_t assoc_shutdown;
+	counter_handle_t comm_lost;
+	counter_handle_t sendq_full;
+	counter_handle_t send_failed;
+	counter_handle_t send_force_retry;
+};
+
+extern struct sctp_counters_h sctp_cnts_h;
+
+int sctp_stats_init();
+void sctp_stats_destroy();
+
+#define INIT_SCTP_STATS() sctp_stats_init() /* success */
+
+#define DESTROY_SCTP_STATS() sctp_stats_destroy()
+
+
+/** called each time a new sctp assoc. is established.
+ * sctp notification: SCTP_COMM_UP.
+ */
+#define SCTP_STATS_ESTABLISHED() \
+	counter_inc(sctp_cnts_h.established)
+
+/** called each time a new outgoing connection/assoc open fails.
+ *  sctp notification: SCTP_CANT_STR_ASSOC
+ */
+#define SCTP_STATS_CONNECT_FAILED() \
+	counter_inc(sctp_cnts_h.connect_failed)
+
+/** called each time a new incoming connection is rejected.  */
+#define SCTP_STATS_LOCAL_REJECT() \
+	counter_inc(sctp_cnts_h.local_reject)
+
+
+/** called each time a connection is closed by the peer.
+  * sctp notification: SCTP_SHUTDOWN_EVENT
+  */
+#define SCTP_STATS_REMOTE_SHUTDOWN() \
+	counter_inc(sctp_cnts_h.remote_shutdown)
+
+
+/** called each time a connection is shutdown.
+  * sctp notification: SCTP_SHUTDOWN_COMP
+  */
+#define SCTP_STATS_ASSOC_SHUTDOWN() \
+	counter_inc(sctp_cnts_h.assoc_shutdown)
+
+
+/** called each time an established connection is closed due to some error.
+  * sctp notification: SCTP_COMM_LOST
+  */
+#define SCTP_STATS_COMM_LOST() \
+	counter_inc(sctp_cnts_h.comm_lost)
+
+
+/** called each time a send fails due to the buffering capacity being exceeded.
+  * (send fails due to full kernel buffers)
+  */
+#define SCTP_STATS_SENDQ_FULL() \
+	counter_inc(sctp_cnts_h.sendq_full)
+
+
+/** called each time a send fails.
+  * (send fails for any reason except buffers full)
+  * sctp notification: SCTP_SEND_FAILED
+  */
+#define SCTP_STATS_SEND_FAILED() \
+	counter_inc(sctp_cnts_h.send_failed)
+
+/** called each time a failed send is force-retried.
+  * (possible only if sctp_send_retries is != 0)
+  */
+#define SCTP_STATS_SEND_FORCE_RETRY() \
+	counter_inc(sctp_cnts_h.send_force_retry)
+
+#endif /* USE_SCTP_STATS */
+
+#endif /*__sctp_stats_h*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/modules/sdpops/README b/modules/sdpops/README
index 8f9cc87..7c9f9f8 100644
--- a/modules/sdpops/README
+++ b/modules/sdpops/README
@@ -10,7 +10,7 @@ Daniel-Constantin Mierla
 
    <miconda at gmail.com>
 
-   Copyright � 2011 asipto.com
+   Copyright © 2011 asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -33,11 +33,14 @@ Daniel-Constantin Mierla
               4.5. sdp_keep_codecs_by_name(list [, mtype])
               4.6. sdp_with_media(type)
               4.7. sdp_remove_media(type)
-              4.8. sdp_with_codecs_by_id(list)
-              4.9. sdp_with_codecs_by_name(list)
-              4.10. sdp_print(level)
-              4.11. sdp_get(avpvar)
-              4.12. sdp_content()
+              4.8. sdp_with_transport(type)
+              4.9. sdp_remove_transport(type)
+              4.10. sdp_with_codecs_by_id(list)
+              4.11. sdp_with_codecs_by_name(list)
+              4.12. sdp_print(level)
+              4.13. sdp_get(avpvar)
+              4.14. sdp_content()
+              4.15. sdp_get_line_startswith(avpvar, string)
 
    List of Examples
 
@@ -48,11 +51,14 @@ Daniel-Constantin Mierla
    1.5. sdp_keep_codecs_by_name usage
    1.6. sdp_with_media usage
    1.7. sdp_remove_media usage
-   1.8. sdp_with_codecs_by_id usage
-   1.9. sdp_with_codecs_by_name usage
-   1.10. sdp_print usage
-   1.11. sdp_get usage
-   1.12. sdp_content usage
+   1.8. sdp_with_transport usage
+   1.9. sdp_remove_transport usage
+   1.10. sdp_with_codecs_by_id usage
+   1.11. sdp_with_codecs_by_name usage
+   1.12. sdp_print usage
+   1.13. sdp_get usage
+   1.14. sdp_content usage
+   1.15. sdp_get_line_startswith usage
 
 Chapter 1. Admin Guide
 
@@ -74,11 +80,14 @@ Chapter 1. Admin Guide
         4.5. sdp_keep_codecs_by_name(list [, mtype])
         4.6. sdp_with_media(type)
         4.7. sdp_remove_media(type)
-        4.8. sdp_with_codecs_by_id(list)
-        4.9. sdp_with_codecs_by_name(list)
-        4.10. sdp_print(level)
-        4.11. sdp_get(avpvar)
-        4.12. sdp_content()
+        4.8. sdp_with_transport(type)
+        4.9. sdp_remove_transport(type)
+        4.10. sdp_with_codecs_by_id(list)
+        4.11. sdp_with_codecs_by_name(list)
+        4.12. sdp_print(level)
+        4.13. sdp_get(avpvar)
+        4.14. sdp_content()
+        4.15. sdp_get_line_startswith(avpvar, string)
 
 1. Overview
 
@@ -119,13 +128,16 @@ Chapter 1. Admin Guide
    4.5. sdp_keep_codecs_by_name(list [, mtype])
    4.6. sdp_with_media(type)
    4.7. sdp_remove_media(type)
-   4.8. sdp_with_codecs_by_id(list)
-   4.9. sdp_with_codecs_by_name(list)
-   4.10. sdp_print(level)
-   4.11. sdp_get(avpvar)
-   4.12. sdp_content()
+   4.8. sdp_with_transport(type)
+   4.9. sdp_remove_transport(type)
+   4.10. sdp_with_codecs_by_id(list)
+   4.11. sdp_with_codecs_by_name(list)
+   4.12. sdp_print(level)
+   4.13. sdp_get(avpvar)
+   4.14. sdp_content()
+   4.15. sdp_get_line_startswith(avpvar, string)
 
-4.1. sdp_remove_codecs_by_id(list)
+4.1.  sdp_remove_codecs_by_id(list)
 
    Remove the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one item or
@@ -142,7 +154,7 @@ sdp_remove_codecs_by_id("0");
 sdp_remove_codecs_by_id("0,8,3");
 ...
 
-4.2. sdp_remove_codecs_by_name(list)
+4.2.  sdp_remove_codecs_by_name(list)
 
    Remove the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one item or
@@ -159,7 +171,7 @@ sdp_remove_codecs_by_name("PCMU");
 sdp_remove_codecs_by_name("PCMU,PCMA,GSM");
 ...
 
-4.3. sdp_remove_line_by_prefix(string)
+4.3.  sdp_remove_line_by_prefix(string)
 
    Remove all SDP attribute lines beginning with 'string' in all media
    streams.
@@ -178,7 +190,7 @@ if ($si == "2001:DB8::8:800:200C:417A"
 
 ...
 
-4.4. sdp_keep_codecs_by_id(list [, mtype])
+4.4.  sdp_keep_codecs_by_id(list [, mtype])
 
    Keep only the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one item or
@@ -198,7 +210,7 @@ sdp_keep_codecs_by_id("0");
 sdp_keep_codecs_by_id("0,8,3", "audio");
 ...
 
-4.5. sdp_keep_codecs_by_name(list [, mtype])
+4.5.  sdp_keep_codecs_by_name(list [, mtype])
 
    Keep only the codecs provided in the parameter 'list' from all media
    streams found in SDP payload. The parameter 'list' must be one or a
@@ -218,7 +230,7 @@ sdp_keep_codecs_by_name("PCMU");
 sdp_keep_codecs_by_name("PCMU,PCMA,GSM");
 ...
 
-4.6. sdp_with_media(type)
+4.6.  sdp_with_media(type)
 
    Return true of the SDP has 'media=type ...' line. Useful to check the
    content of the RTP sessions, such as 'audio' or 'video'. The parameter
@@ -235,7 +247,7 @@ if(sdp_with_media("video"))
 }
 ...
 
-4.7. sdp_remove_media(type)
+4.7.  sdp_remove_media(type)
 
    Remove the streams that match on 'm=type ...' line. The parameter can
    be static string or variable holding the media type.
@@ -248,7 +260,38 @@ if(sdp_with_media("video"))
 sdp_remove_media("video");
 ...
 
-4.8. sdp_with_codecs_by_id(list)
+4.8.  sdp_with_transport(type)
+
+   Return true of the SDP has 'media=media port type ...' line. Useful to
+   check the transport of the RTP sessions, such as 'RTP/AVP', 'RTP/SAVP'
+   or 'RTP/SAVPF'. The parameter can be static string or variable holding
+   the transport type.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.8. sdp_with_transport usage
+...
+# check for RTP/SAVP stream
+if(sdp_with_transport("RTP/SAVP"))
+{
+    # the session has a SRTP/SAVP stream
+}
+...
+
+4.9.  sdp_remove_transport(type)
+
+   Remove the streams that match on 'm=media port type ...' line. The
+   parameter can be static string or variable holding the transport type.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.9. sdp_remove_transport usage
+...
+# remove stream with transport RTP/AVP
+sdp_remove_transport("RTP/AVP");
+...
+
+4.10.  sdp_with_codecs_by_id(list)
 
    Returns true if any of the codecs provided in the parameter 'list' from
    all media streams is found in SDP payload. The parameter 'list' must be
@@ -257,7 +300,7 @@ sdp_remove_media("video");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.8. sdp_with_codecs_by_id usage
+   Example 1.10. sdp_with_codecs_by_id usage
 ...
 # test for PCMU
 if(sdp_with_codecs_by_id("0")) { ... }
@@ -265,7 +308,7 @@ if(sdp_with_codecs_by_id("0")) { ... }
 if(sdp_with_codecs_by_id("0,8,3")) { ... }
 ...
 
-4.9. sdp_with_codecs_by_name(list)
+4.11.  sdp_with_codecs_by_name(list)
 
    Returns true if any of the codecs provided in the parameter 'list' from
    all media streams is found in SDP payload. The parameter 'list' must be
@@ -274,7 +317,7 @@ if(sdp_with_codecs_by_id("0,8,3")) { ... }
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.9. sdp_with_codecs_by_name usage
+   Example 1.11. sdp_with_codecs_by_name usage
 ...
 # test for PCMU
 if(sdp_with_codecs_by_name("PCMU")) { ... }
@@ -282,40 +325,55 @@ if(sdp_with_codecs_by_name("PCMU")) { ... }
 if(sdp_with_codecs_by_name("PCMU,PCMA,GSM")) { ... }
 ...
 
-4.10. sdp_print(level)
+4.12.  sdp_print(level)
 
    Print the SDP internal structure to log 'level'. The parameter can be
    static integer or variable holding the integer value of the log level.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.10. sdp_print usage
+   Example 1.12. sdp_print usage
 ...
 # print the SDP
 sdp_print("1");
 ...
 
-4.11. sdp_get(avpvar)
+4.13.  sdp_get(avpvar)
 
    Store the SDP part of message body in an AVP. Return 1 if SDP is found,
    -1 on error and -2 if there is no SDP part in the message body.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.11. sdp_get usage
+   Example 1.13. sdp_get usage
 ...
 sdp_get("$avp(sdp)");
 ...
 
-4.12. sdp_content()
+4.14.  sdp_content()
 
    Return true if the SIP message has SDP body or a SDP part in body.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.12. sdp_content usage
+   Example 1.14. sdp_content usage
 ...
 if(sdp_content()) {
     ...
 }
 ...
+
+4.15.  sdp_get_line_startswith(avpvar, string)
+
+   Store the search part of SDP body message with line beginning with
+   'string' in an AVP. Return 1 if 'string' is found in SDP, -1 on error
+   and -2 if there is no SDP part in the message body.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.15. sdp_get_line_startswith usage
+...
+if(sdp_get_line_startswith("$avp(mline)", "m=")) {
+        xlog("m-line: $avp(mline)\n");
+}
+...
diff --git a/modules/sdpops/doc/sdpops_admin.xml b/modules/sdpops/doc/sdpops_admin.xml
index 831669e..dfa7fd1 100644
--- a/modules/sdpops/doc/sdpops_admin.xml
+++ b/modules/sdpops/doc/sdpops_admin.xml
@@ -253,6 +253,52 @@ sdp_remove_media("video");
 	</section>
 	<section>
 	    <title>
+		<function moreinfo="none">sdp_with_transport(type)</function>
+	    </title>
+	    <para>
+		Return true of the SDP has 'media=media port type ...' line. Useful to check
+		the transport of the RTP sessions, such as 'RTP/AVP', 'RTP/SAVP' or 'RTP/SAVPF'. The
+		parameter can be static string or variable holding the transport type.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_with_transport</function> usage</title>
+		<programlisting format="linespecific">
+...
+# check for RTP/SAVP stream
+if(sdp_with_transport("RTP/SAVP"))
+{
+    # the session has a SRTP/SAVP stream
+}
+...
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_remove_transport(type)</function>
+	    </title>
+	    <para>
+		Remove the streams that match on 'm=media port type ...' line. The
+		parameter can be static string or variable holding the transport type.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_remove_transport</function> usage</title>
+		<programlisting format="linespecific">
+...
+# remove stream with transport RTP/AVP
+sdp_remove_transport("RTP/AVP");
+...
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title>
 		<function moreinfo="none">sdp_with_codecs_by_id(list)</function>
 	    </title>
 	    <para>
@@ -366,6 +412,28 @@ if(sdp_content()) {
 </programlisting>
 	    </example>
 	</section>
+	<section>
+		<title>
+			<function moreinfo="none">sdp_get_line_startswith(avpvar, string)</function>
+		</title>
+		<para>
+			Store the search part of SDP body message with line beginning with 'string' in an AVP. 
+			Return 1 if 'string' is found in SDP, -1 on error and -2 if there is no SDP part in the message body.
+		</para>
+		<para>
+			This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+			<title><function>sdp_get_line_startswith</function> usage</title>
+			<programlisting format="linespecific">
+...
+if(sdp_get_line_startswith("$avp(mline)", "m=")) {
+	xlog("m-line: $avp(mline)\n");
+}
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 </chapter>
 
diff --git a/modules/sdpops/sdpops_mod.c b/modules/sdpops/sdpops_mod.c
index 72ad265..a506fc6 100644
--- a/modules/sdpops/sdpops_mod.c
+++ b/modules/sdpops/sdpops_mod.c
@@ -30,6 +30,7 @@
 #include "../../dprint.h"
 #include "../../mod_fix.h"
 #include "../../pvar.h"
+#include "../../usr_avp.h"
 #include "../../parser/sdp/sdp.h"
 #include "../../parser/sdp/sdp_helpr_funcs.h"
 #include "../../trim.h"
@@ -46,12 +47,16 @@ static int w_sdp_remove_codecs_by_name(sip_msg_t* msg, char* codecs, char *bar);
 static int w_sdp_keep_codecs_by_id(sip_msg_t* msg, char* codecs, char *bar);
 static int w_sdp_keep_codecs_by_name(sip_msg_t* msg, char* codecs, char *bar);
 static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar);
+static int w_sdp_with_transport(sip_msg_t* msg, char* transport, char *bar);
 static int w_sdp_with_codecs_by_id(sip_msg_t* msg, char* codec, char *bar);
 static int w_sdp_with_codecs_by_name(sip_msg_t* msg, char* codec, char *bar);
 static int w_sdp_remove_media(sip_msg_t* msg, char* media, char *bar);
+static int w_sdp_remove_transport(sip_msg_t* msg, char* transport, char *bar);
 static int w_sdp_print(sip_msg_t* msg, char* level, char *bar);
 static int w_sdp_get(sip_msg_t* msg, char *bar);
 static int w_sdp_content(sip_msg_t* msg, char* foo, char *bar);
+static int w_sdp_get_line_startswith(sip_msg_t* msg, char *foo, char *bar);
+
 
 static int mod_init(void);
 
@@ -74,6 +79,10 @@ static cmd_export_t cmds[] = {
 		1, fixup_spve_null,  0, ANY_ROUTE},
 	{"sdp_remove_media",             (cmd_function)w_sdp_remove_media,
 		1, fixup_spve_null,  0, ANY_ROUTE},
+	{"sdp_with_transport",         (cmd_function)w_sdp_with_transport,
+		1, fixup_spve_null,  0, ANY_ROUTE},
+	{"sdp_remove_transport",       (cmd_function)w_sdp_remove_transport,
+		1, fixup_spve_null,  0, ANY_ROUTE},
 	{"sdp_with_codecs_by_id",      (cmd_function)w_sdp_with_codecs_by_id,
 		1, fixup_spve_null,  0, ANY_ROUTE},
 	{"sdp_with_codecs_by_name",    (cmd_function)w_sdp_with_codecs_by_name,
@@ -84,6 +93,8 @@ static cmd_export_t cmds[] = {
 		1, 0,  0, ANY_ROUTE},
 	{"sdp_content",                (cmd_function)w_sdp_content,
 		0, 0,  0, ANY_ROUTE},
+	{"sdp_get_line_startswith", (cmd_function)w_sdp_get_line_startswith,
+		2, 0,  0, ANY_ROUTE},
 	{"bind_sdpops",                (cmd_function)bind_sdpops,
 		1, 0, 0, 0},
 	{0, 0, 0, 0, 0, 0}
@@ -888,6 +899,174 @@ static int w_sdp_remove_media(sip_msg_t* msg, char* media, char *bar)
 	return 1;
 }
 
+/** 
+ * @brief check 'media' matches the value of any 'm=media port value ...' lines
+ * @return -1 - error; 0 - not found; 1 - found
+ */
+static int sdp_with_transport(sip_msg_t *msg, str *transport)
+{
+	int sdp_session_num;
+	int sdp_stream_num;
+	sdp_session_cell_t* sdp_session;
+	sdp_stream_cell_t* sdp_stream;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	LM_DBG("attempting to search for transport type: [%.*s]\n",
+			transport->len, transport->s);
+
+	sdp_session_num = 0;
+	for(;;)
+	{
+		sdp_session = get_sdp_session(msg, sdp_session_num);
+		if(!sdp_session) break;
+		sdp_stream_num = 0;
+		for(;;)
+		{
+			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
+			if(!sdp_stream) break;
+
+			LM_DBG("stream %d of %d - transport [%.*s]\n",
+				sdp_stream_num, sdp_session_num,
+				sdp_stream->transport.len, sdp_stream->transport.s);
+			if(transport->len==sdp_stream->transport.len
+					&& strncasecmp(sdp_stream->transport.s, transport->s,
+							transport->len)==0)
+				return 1;
+			sdp_stream_num++;
+		}
+		sdp_session_num++;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+static int w_sdp_with_transport(sip_msg_t* msg, char* transport, char *bar)
+{
+	str ltransport = {0, 0};
+
+	if(transport==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)transport, &ltransport)!=0)
+	{
+		LM_ERR("unable to get the transport value\n");
+		return -1;
+	}
+
+	if(sdp_with_transport(msg, &ltransport)<=0)
+		return -1;
+	return 1;
+}
+
+/**
+ * @brief remove streams matching the m=media port 'transport'
+ * @return -1 - error; 0 - not found; >=1 - found
+ */
+static int sdp_remove_transport(sip_msg_t *msg, str *transport)
+{
+	sdp_info_t *sdp = NULL;
+	int sdp_session_num;
+	int sdp_stream_num;
+	sdp_session_cell_t* sdp_session;
+	sdp_stream_cell_t* sdp_stream;
+	sdp_stream_cell_t* nxt_stream;
+	int ret = 0;
+	char *dstart = NULL;
+	int dlen = 0;
+	struct lump *anchor;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	LM_DBG("attempting to search for transport type: [%.*s]\n",
+			transport->len, transport->s);
+
+	sdp = (sdp_info_t*)msg->body;
+
+	sdp_session_num = 0;
+	for(;;)
+	{
+		sdp_session = get_sdp_session(msg, sdp_session_num);
+		if(!sdp_session) break;
+		sdp_stream_num = 0;
+		for(;;)
+		{
+			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
+			if(!sdp_stream) break;
+
+			LM_DBG("stream %d of %d - transport [%.*s]\n",
+				sdp_stream_num, sdp_session_num,
+				sdp_stream->transport.len, sdp_stream->transport.s);
+			if(transport->len==sdp_stream->transport.len
+					&& strncasecmp(sdp_stream->transport.s, transport->s,
+							transport->len)==0)
+			{
+				/* found - remove */
+				LM_DBG("removing transport stream: %.*s", transport->len, transport->s);
+				nxt_stream = get_sdp_stream(msg, sdp_session_num,
+								sdp_stream_num+1);
+				/* skip back 'm=' */
+				dstart = sdp_stream->media.s - 2;
+				if(!nxt_stream) {
+					/* delete to end of sdp */
+					dlen = (int)(sdp->text.s + sdp->text.len - dstart);
+				} else {
+					/* delete to start of next stream */
+					dlen = (int)(nxt_stream->media.s - 2 - dstart);
+				}
+				anchor = del_lump(msg, dstart - msg->buf, dlen, 0);
+				if (anchor == NULL) {
+					LM_ERR("failed to remove transport type [%.*s]\n",
+						 transport->len, transport->s);
+					return -1;
+				}
+
+				ret++;
+			}
+			sdp_stream_num++;
+		}
+		sdp_session_num++;
+	}
+
+	return ret;
+}
+
+
+/**
+ *
+ */
+static int w_sdp_remove_transport(sip_msg_t* msg, char* transport, char *bar)
+{
+	str ltransport = {0, 0};
+
+	if(transport==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)transport, &ltransport)!=0)
+	{
+		LM_ERR("unable to get the transport value\n");
+		return -1;
+	}
+
+	if(sdp_remove_transport(msg, &ltransport)<=0)
+		return -1;
+	return 1;
+}
 
 /**
  *
@@ -1127,6 +1306,123 @@ static int w_sdp_content(sip_msg_t* msg, char* foo, char *bar)
 /**
  *
  */
+static int w_sdp_get_line_startswith(sip_msg_t *msg, char *avp, char *s_line)
+{
+	sdp_info_t *sdp = NULL;
+	str body = {NULL, 0};
+	str line = {NULL, 0};
+	char* p = NULL;
+	str s;
+	str sline;
+        int_str avp_val;
+        int_str avp_name;
+        pv_spec_t *avp_spec = NULL;
+        static unsigned short avp_type = 0;
+	int sdp_missing=1;
+
+	if (s_line == NULL || strlen(s_line) <= 0)
+	{
+		LM_ERR("Search string is null or empty\n");
+		    return -1;
+	}
+	sline.s = s_line;
+	sline.len = strlen(s_line);
+
+	sdp_missing = parse_sdp(msg);
+
+	if(sdp_missing < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	sdp = (sdp_info_t *)msg->body;
+
+        if (sdp_missing || sdp == NULL)
+	{
+                LM_DBG("No SDP\n");
+                return -2;
+	}
+
+	body.s = sdp->raw_sdp.s;
+	body.len = sdp->raw_sdp.len;
+
+	if (body.s==NULL) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+
+	body.len = msg->len - (body.s - msg->buf);
+	if (body.len==0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	if (avp == NULL || strlen(avp) <= 0)
+	{
+		LM_ERR("avp variable is null or empty\n");
+		    return -1;
+	}
+
+	s.s = avp;
+	s.len = strlen(s.s);
+
+	if (pv_locate_name(&s) != s.len)
+        {
+                LM_ERR("invalid parameter\n");
+                return -1;
+        }
+
+        if (((avp_spec = pv_cache_get(&s)) == NULL)
+                        || avp_spec->type!=PVT_AVP) {
+                LM_ERR("malformed or non AVP %s AVP definition\n", avp);
+                return -1;
+        }
+
+        if(pv_get_avp_name(0, &avp_spec->pvp, &avp_name, &avp_type)!=0)
+        {
+                LM_ERR("[%s]- invalid AVP definition\n", avp);
+                return -1;
+        }
+
+	p = find_sdp_line(body.s, body.s+body.len, sline.s[0]);
+	while (p != NULL)
+	{
+		if (sdp_locate_line(msg, p, &line) != 0)
+		{
+			LM_ERR("sdp_locate_line fail\n");
+			return -1;
+		}
+
+		if (strncmp(line.s, sline.s, sline.len) == 0)
+		{
+            		avp_val.s.s = line.s;
+            		avp_val.s.len = line.len;
+
+			// remove ending \r\n if exists
+			if (avp_val.s.s[line.len-2] == '\r' && avp_val.s.s[line.len-1] == '\n')
+			{
+			    avp_val.s.s[line.len-2] = '\0';
+			    avp_val.s.len -= 2;
+			}
+
+    			if (add_avp(AVP_VAL_STR | avp_type, avp_name, avp_val) != 0)
+    			{
+        		    LM_ERR("Failed to add SDP line avp");
+        		    return -1;
+    			}
+
+			return 1;
+		}
+
+		p = find_sdp_line(line.s + line.len, body.s + body.len, sline.s[0]);
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
 int bind_sdpops(struct sdpops_binds *sob){
 	if (sob == NULL) {
 		LM_WARN("bind_sdpops: Cannot load sdpops API into a NULL pointer\n");
diff --git a/modules/seas/README b/modules/seas/README
index 25a0a19..abffbd8 100644
--- a/modules/seas/README
+++ b/modules/seas/README
@@ -11,7 +11,7 @@ Elias Baixas
      www.voztele.com
      <elias.baixas at voztele.com>
 
-   Copyright � 2006 VozTelecom Sistemas
+   Copyright © 2006 VozTelecom Sistemas
      __________________________________________________________________
 
    Table of Contents
@@ -348,7 +348,7 @@ t_reply("500","App Server not connected");
    Server, which is in charge of making it reach back to the user. The
    Application Server implements the network protocol, it takes care of
    everything needed for a proper communication between user and server,
-   so the servlet doesn't have to care about these things. The servlet
+   so the servlet doesn’t have to care about these things. The servlet
    uses a set of resources from the Application Server, such as Session
    management, service routing or chaining, and request/response header
    composition.
@@ -462,7 +462,7 @@ ServletException, IOException
    SipServlet UML diagram
 
    The Servlet programming language is JAVA, which offers a wide spectrum
-   of programming API's dealing with all kinds of techniques, tools and
+   of programming API’s dealing with all kinds of techniques, tools and
    resources, which also are available seamlessly from the Servlet
    context.
 
@@ -488,7 +488,7 @@ ServletException, IOException
    Convergence of SIP and HTTP protocols into the same Application Server
    offers, amongst others, the following key advantages:
 
-   -It doesn't require to have 2 different servers (Http and Sip) so it
+   -It doesn’t require to have 2 different servers (Http and Sip) so it
    relieves from maintenance problems, and eases user and configuration
    provisioning.
 
@@ -521,7 +521,7 @@ ServletException, IOException
    -Click-to-dial: users could initiate SIP sessions only by clicking a
    link on a web page, without the need of the Web-Browser being SIP-aware
    nor needing even a SIP phone: the server could handle all the logic so
-   the user who clicked could receive a call from the server's SIP
+   the user who clicked could receive a call from the server’s SIP
    network.
 
 2.2. Configuring WeSIP to work with SEAS
@@ -1016,10 +1016,10 @@ Chapter 2. Developer Guide
    members: name, version, transport, host, proto, port, port_str, params,
    comment, received, rport, etc. each of these members gives quick access
    to each of the parts of the header. For example, a via header like
-   this: "Via: SIP/2.0/UDP 192.168.1.64:5070;branch=z9hG4bK-c02c60cc"
-   would have the member proto pointing to the "U" of "UDP", and a length
-   of 3, the host member would be pointing to "192.168.1.64" and have a
-   length of 12, the branch member would be pointing to "z9hG4bK-c02c60cc"
+   this: “Via: SIP/2.0/UDP 192.168.1.64:5070;branch=z9hG4bK-c02c60cc”
+   would have the member proto pointing to the “U” of “UDP”, and a length
+   of 3, the host member would be pointing to “192.168.1.64” and have a
+   length of 12, the branch member would be pointing to “z9hG4bK-c02c60cc”
    and a length of 16, and so on.
 
    This structure is the result of the parsing. All this meta-information
@@ -1161,7 +1161,7 @@ Chapter 2. Developer Guide
    two past the end of the URI, so that the length of the last header can
    be computed.
 
-   The reason to have the "other parameters" and headers flags at the
+   The reason to have the “other parameters” and headers flags at the
    beginning (just after the strictly URI stuff), is that it will be
    necessary to know the length of the parameters section and the headers
    section. The parameters can appear in an arbitrary order, they won't be
@@ -1206,7 +1206,7 @@ Chapter 2. Developer Guide
 2.2.5. Codification of Accept and Content-Type headers
 
    These two kinds of headers carry mime type and subtype definitions in
-   the form "type/subtype" (ie. text/xml, application/sdp or whatever).
+   the form “type/subtype” (ie. text/xml, application/sdp or whatever).
    For internal handling of this headers, SER codifies the known types and
    subtypes into a single 32 bit integer, with the highest two bytes
    giving the mime type, and the lowest two bytes giving the subtype.
@@ -1374,7 +1374,7 @@ Chapter 2. Developer Guide
 
    }
 
-   this would let in the "results" array all the indexes in the headers
+   this would let in the “results” array all the indexes in the headers
    table that refer to a Route header. Then, the Route codification for
    each of the headers could be reached thanks to the two-byte unsigned
    integer that follows each of the header identifiers.
@@ -1423,7 +1423,7 @@ Chapter 2. Developer Guide
    RequestIn events: they start with the Action length in bytes, then
    follows a byte giving the type of action, then follows the Hash Index
    and the Label associated with the transaction that is being replied,
-   and finally the SIP Message in raw format. It doesn't use the SEAS
+   and finally the SIP Message in raw format. It doesn’t use the SEAS
    codification described above, because SER can easily parse the JAIN
    provided Response to process it and send it out, so the pre-parsing is
    not needed in that direction.
@@ -1431,7 +1431,7 @@ Chapter 2. Developer Guide
    In order to generate Client Transactions, that is, sending SIP Requests
    out, JAIN utilizes another kind of action called Seas Request Action.
    In this case, when JAIN generates the Request to be sent out, it
-   doesn't have any means to know the transaction identifier (hash index
+   doesn’t have any means to know the transaction identifier (hash index
    and label) that will be assigned to it by SER, so a new mechanism has
    bee implemented to correlate JAIN requests to SER transactions.
    Basically, JAIN-SIP assigns a unique identifier (an integer) that is
diff --git a/modules/seas/seas_action.c b/modules/seas/seas_action.c
index d1267d5..c5c534d 100644
--- a/modules/seas/seas_action.c
+++ b/modules/seas/seas_action.c
@@ -1093,8 +1093,9 @@ int ac_uac_req(as_p the_as,unsigned char processor_id,unsigned int flags,char *a
       this is the same as (TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT) in Kamailio
    */
 
-   memset(&uac_r,0, sizeof(uac_req_t));
-   set_uac_req(&uac_r, &(my_msg->first_line.u.request.method), &headers, &body, my_dlg,TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT, uac_cb, (void*)the_param);
+   set_uac_req(&uac_r, &(my_msg->first_line.u.request.method), &headers,
+		   &body, my_dlg,TMCB_DONT_ACK|TMCB_LOCAL_RESPONSE_OUT, uac_cb,
+		   (void*)the_param);
 
    ret=seas_f.tmb.t_request_within(&uac_r);
 
diff --git a/modules/sipcapture/README b/modules/sipcapture/README
index a7cec5a..edf544d 100644
--- a/modules/sipcapture/README
+++ b/modules/sipcapture/README
@@ -66,7 +66,7 @@ Alexandr Dubovikov
    1.8. Set raw_ipip_capture_on parameter
    1.9. Set raw_moni_capture_on parameter
    1.10. Set raw_socket_listen parameter
-   1.11. Set raw_socket_listen parameter
+   1.11. Set raw_interface parameter
    1.12. Set raw_sock_children parameter
    1.13. Set promiscous_on parameter
    1.14. Set raw_moni_bpf_on parameter
@@ -301,7 +301,7 @@ modparam("sipcapture", "raw_socket_listen", "10.0.0.1:5060")
 
    Default value is "".
 
-   Example 1.11. Set raw_socket_listen parameter
+   Example 1.11. Set raw_interface parameter
 ...
 modparam("sipcapture", "raw_interface", "eth0")
 ...
diff --git a/modules/sipcapture/doc/sipcapture_admin.xml b/modules/sipcapture/doc/sipcapture_admin.xml
index 052ce00..c172c5a 100644
--- a/modules/sipcapture/doc/sipcapture_admin.xml
+++ b/modules/sipcapture/doc/sipcapture_admin.xml
@@ -82,7 +82,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="sipcapture.p.db_url">
 		<title><varname>db_url</varname> (str)</title>
 		<para>
 		Database URL.
@@ -101,7 +101,7 @@ modparam("sipcapture", "db_url", "mysql://user:passwd@host/dbname")
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="sipcapture.p.table_name">
 		<title><varname>table_name</varname> (str)</title>
 		<para>
 		Name of the table's name used to store the SIP messages. Can contain multiple tables, separated by "|".
@@ -122,7 +122,7 @@ modparam("sipcapture", "table_name", "homer_capture1|homer_capture2");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="sipcapture.p.mt_mode">
 		<title><varname>mt_mode</varname> (str)</title>
 		<para>
 		Name of the mode used for storing data in multiple tables. Modes can be "rand" (random), "round_robin" (use a round_robin algorithm) or "hash" (use hashing to determine the table to store). These modes are only triggered if there is more than one table specified in table_name parameter, separated by "|". 
@@ -141,7 +141,7 @@ modparam("sipcapture", "mt_mode", "hash")
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="sipcapture.p.hash_source">
 		<title><varname>hash_source</varname> (str)</title>
 		<para>
 		The field of the SIP message used for hashing, when mt_mode is set to "hash". The value can be "call_id", "to_user" or "from_user".
@@ -160,7 +160,7 @@ modparam("sipcapture", "hash_source", "to_user")
 </programlisting>
 		</example>
 	</section>
-        <section>
+	<section id="sipcapture.p.db_insert_mode">
                 <title><varname>db_insert_mode</varname> (integer)</title>
                 <para>
                 If set to 1, use INSERT DELAYED to store sip message into capture table
@@ -177,7 +177,7 @@ modparam("sipcapture", "db_insert_mode", 1)
 </programlisting>
                 </example>
         </section>
-	<section>
+	<section id="sipcapture.p.capture_on">
 		<title><varname>capture_on</varname> (integer)</title>
 		<para>
 		Parameter to enable/disable capture globaly (on(1)/off(0))
@@ -196,7 +196,27 @@ modparam("sipcapture", "capture_on", 1)
 </programlisting>
 		</example>
 	</section>
-        <section>
+
+	<section id="sipcapture.p.capture_mode">
+                <title><varname>capture_mode</varname> (integer)</title>
+                <para>
+				This parameter can be used for defining a capture mode which can be used in
+				the sip_capture calls as a parameter. A capture mode has a name and some parameters.
+				It must be defined in the format: name=>param1=val1;param2=val2;...
+				The parameters are db_url, table_name, mt_mode and hash_source (optional).
+				Multiple capture modes can be defined by using this parameter multiple times.
+				After this, the capture modes can be used like:
+				sip_capture ("", "CAPTURE_MODE");
+				</para>
+                <example>
+                <title>capture_mode example</title>
+                <programlisting format="linespecific">
+modparam("sipcapture", "capture_mode", "mode1=>db_url=mysql://user:passwd@host/dbname1;table_name=homer_capture1|homer_capture2;mt_mode=hash;hash_source=call_id;")
+modparam("sipcapture", "capture_mode", "mode2=>db_url=mysql://user:passwd@host/dbname2;table_name=homer_capture3|homer_capture4;mt_mode=rand;")
+</programlisting>
+                </example>
+        </section>
+	<section id="sipcapture.p.hep_capture_on">
                 <title><varname>hep_capture_on</varname> (integer)</title>
                 <para>
                 Parameter to enable/disable capture of HEP (on(1)/off(0))
@@ -215,7 +235,7 @@ modparam("sipcapture", "hep_capture_on", 1)
 </programlisting>
                 </example>
         </section>
-        <section>
+	<section id="sipcapture.p.raw_ipip_capture_on">
                 <title><varname>raw_ipip_capture_on</varname> (integer)</title>
                 <para>
                 Parameter to enable/disable IPIP capturing (on(1)/off(0))
@@ -234,7 +254,7 @@ modparam("sipcapture", "raw_ipip_capture_on", 1)
 </programlisting>
                 </example>
         </section>
-        <section>
+	<section id="sipcapture.p.raw_moni_capture_on">
                 <title><varname>raw_moni_capture_on</varname> (integer)</title>
                 <para>
                 Parameter to enable/disable monitoring/mirroring port capturing (on(1)/off(0))
@@ -255,7 +275,7 @@ modparam("sipcapture", "raw_moni_capture_on", 1)
 		</programlisting>
                 </example>
         </section>
-	<section>
+	<section id="sipcapture.p.raw_socket_listen">
                 <title><varname>raw_socket_listen</varname> (string)</title>
                 <para>
                 Parameter indicate an listen IP address of RAW socket for IPIP capturing. 
@@ -290,7 +310,7 @@ modparam("sipcapture", "raw_socket_listen", "10.0.0.1:5060")
 </programlisting>
                 </example>
         </section>
-       <section>
+	<section id="sipcapture.p.raw_interface">
                 <title><varname>raw_interface</varname> (string)</title>
 		<para>
 		Name of the interface to bind on the raw socket.
@@ -301,7 +321,7 @@ modparam("sipcapture", "raw_socket_listen", "10.0.0.1:5060")
                 </emphasis>
                 </para>
                 <example>
-                <title>Set <varname>raw_socket_listen</varname> parameter</title>
+                <title>Set <varname>raw_interface</varname> parameter</title>
                 <programlisting format="linespecific">
 ...
 modparam("sipcapture", "raw_interface", "eth0")
@@ -309,7 +329,7 @@ modparam("sipcapture", "raw_interface", "eth0")
 </programlisting>
                 </example>
         </section>
-        <section>
+	<section id="sipcapture.p.raw_sock_children">
                 <title><varname>raw_sock_children</varname> (integer)</title>
                 <para>
 		Parameter define how many children that must be created to listen the raw socket.
@@ -328,7 +348,7 @@ modparam("sipcapture", "raw_sock_children", 6)
 </programlisting>
                 </example>
         </section>
-        <section>
+	<section id="sipcapture.p.promiscuous_on">
                 <title><varname>promiscuous_on</varname> (integer)</title>
                 <para>
                 Parameter to enable/disable promiscuous mode on the raw socket.
@@ -348,7 +368,7 @@ modparam("sipcapture", "promiscuous_on", 1)
 </programlisting>
                 </example>
         </section>
-        <section>
+	<section id="sipcapture.p.raw_moni_bpf_on">
                 <title><varname>raw_moni_bpf_on</varname> (integer)</title>
                 <para>
                 Activate Linux Socket Filter (LSF based on BPF) on the mirroring interface. 
@@ -369,7 +389,7 @@ modparam("sipcapture", "raw_moni_bpf_on", 1)
 </programlisting>
                 </example>
         </section>        
-	<section>
+	<section id="sipcapture.p.capture_node">
 		<title><varname>capture_node</varname> (str)</title>
 		<para>
 		Name of the capture node.
@@ -391,7 +411,7 @@ modparam("sipcapture", "capture_node", "homer03")
 </section>	
     <section>
 	<title>MI Commands</title>
-	<section>
+	<section id="sipcapture.m.sip_capture">
 		<title>
 		<function moreinfo="none">sip_capture</function>
 		</title>
@@ -428,7 +448,7 @@ modparam("sipcapture", "capture_node", "homer03")
 	</section><!-- MI commands -->
     	<section>
 	<title>RPC Commands</title>
-	<section>
+	<section id="sipcapture.r.sipcapture.status">
 		<title>
 		<function moreinfo="none">sipcapture.status param</function>
 		</title>
diff --git a/modules/sipcapture/hep.c b/modules/sipcapture/hep.c
index a5162c7..8460d12 100644
--- a/modules/sipcapture/hep.c
+++ b/modules/sipcapture/hep.c
@@ -97,9 +97,7 @@ int hepv2_received(char *buf, unsigned int len, struct receive_info *ri){
 	struct hep_timehdr* heptime_tmp = NULL;
         memset(heptime, 0, sizeof(struct hep_timehdr));
 
-#ifdef USE_IPV6
         struct hep_ip6hdr *hepip6h = NULL;
-#endif /* USE_IPV6 */
 
 	hep_offset = 0; 
 	
@@ -117,11 +115,9 @@ int hepv2_received(char *buf, unsigned int len, struct receive_info *ri){
         	case AF_INET:
                 	hl += sizeof(struct hep_iphdr);
                         break;
-#ifdef USE_IPV6
 		case AF_INET6:
                 	hl += sizeof(struct hep_ip6hdr);
                         break;
-#endif /* USE_IPV6 */
 		default:
                         LOG(L_ERR, "ERROR: sipcapture:hep_msg_received:  unsupported family [%d]\n", heph->hp_f);
                         return -1;
@@ -151,13 +147,11 @@ int hepv2_received(char *buf, unsigned int len, struct receive_info *ri){
                 	hep_offset+=sizeof(struct hep_iphdr);
                         hepiph = (struct hep_iphdr*) hep_ip;
                         break;
-#ifdef USE_IPV6
 
 		case AF_INET6:
                 	hep_offset+=sizeof(struct hep_ip6hdr);
                         hepip6h = (struct hep_ip6hdr*) hep_ip;
                         break;
-#endif /* USE_IPV6 */
 
 	}
 
@@ -189,7 +183,6 @@ int hepv2_received(char *buf, unsigned int len, struct receive_info *ri){
                         memcpy(&dst_ip.u.addr, &hepiph->hp_dst, 4);
                         memcpy(&src_ip.u.addr, &hepiph->hp_src, 4);
                         break;
-#ifdef USE_IPV6
 
 		case AF_INET6:
                 	dst_ip.af = src_ip.af = AF_INET6;
@@ -198,7 +191,6 @@ int hepv2_received(char *buf, unsigned int len, struct receive_info *ri){
                         memcpy(&src_ip.u.addr, &hepip6h->hp6_src, 16);
                         break;
 
-#endif /* USE_IPV6 */
 	}
 
         ri->src_ip = src_ip;
@@ -228,7 +220,7 @@ int hepv2_received(char *buf, unsigned int len, struct receive_info *ri){
  */
 int hepv3_received(char *buf, unsigned int len, struct receive_info *ri)
 {
-	if(parsing_hepv3_message(buf, len)) {
+	if(!parsing_hepv3_message(buf, len)) {
 		LM_ERR("couldn't parse hepv3 message\n");
         	return -2;
         }
@@ -338,7 +330,6 @@ int parsing_hepv3_message(char *buf, unsigned int len) {
                                         totelem++;
 
                                         break;
-#ifdef USE_IPV6                                                     
                                 case 5:
                                         hg->hep_src_ip6  = (hep_chunk_ip6_t *) (tmp);
                                         i+=chunk_length;
@@ -355,7 +346,6 @@ int parsing_hepv3_message(char *buf, unsigned int len) {
 				        memcpy(dst_ip.u.addr, &hg->hep_dst_ip6->data, 16);
 				        totelem++;
                                         break;
-#endif                                             
         
                                 case 7:
                                         hg->src_port  = (hep_chunk_uint16_t *) (tmp);
@@ -396,7 +386,7 @@ int parsing_hepv3_message(char *buf, unsigned int len) {
                                         hg->capt_id  = (hep_chunk_uint32_t *) (tmp);
                                         i+=chunk_length;
                                         heptime->captid = ntohs(hg->capt_id->data);
-                                        LM_ERR("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: [%i] vs [%i]\n", heptime->captid, ntohl(hg->capt_id->data));
+                                        //LM_ERR("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: [%i] vs [%i]\n", heptime->captid, ntohl(hg->capt_id->data));
                                         totelem++;
                                         break;
 
diff --git a/modules/sipcapture/hep.h b/modules/sipcapture/hep.h
index ea0046e..307beda 100644
--- a/modules/sipcapture/hep.h
+++ b/modules/sipcapture/hep.h
@@ -63,12 +63,10 @@ struct hep_timehdr{
    u_int16_t captid;          /* Capture ID node */
 };
 
-#ifdef USE_IPV6
 struct hep_ip6hdr {
         struct in6_addr hp6_src;        /* source address */
         struct in6_addr hp6_dst;        /* destination address */
 };
-#endif
 
 /* HEPv3 types */
 
@@ -115,12 +113,10 @@ struct hep_chunk_ip4 {
 
 typedef struct hep_chunk_ip4 hep_chunk_ip4_t;
 
-#ifdef USE_IPV6
 struct hep_chunk_ip6 {
        hep_chunk_t chunk;
        struct in6_addr data;
 } __attribute__((packed));
-#endif
 
 typedef struct hep_chunk_ip6 hep_chunk_ip6_t;
 
@@ -152,10 +148,8 @@ struct hep_generic_recv {
         hep_chunk_uint32_t *time_usec;
         hep_chunk_ip4_t    *hep_src_ip4;
         hep_chunk_ip4_t	    *hep_dst_ip4;
-#ifdef USE_IPV6
         hep_chunk_ip6_t    *hep_src_ip6;
         hep_chunk_ip6_t    *hep_dst_ip6;
-#endif
         hep_chunk_uint8_t  *proto_t;
         hep_chunk_uint32_t *capt_id;
         hep_chunk_uint16_t *keep_tm;
diff --git a/modules/sipcapture/sipcapture.c b/modules/sipcapture/sipcapture.c
index 515150d..932ba4d 100644
--- a/modules/sipcapture/sipcapture.c
+++ b/modules/sipcapture/sipcapture.c
@@ -68,13 +68,13 @@
 #include "../../parser/parse_from.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/digest/digest.h"
-#include "../../lib/kcore/parse_pai.h"
-#include "../../lib/kcore/parse_ppi.h"
+#include "../../parser/parse_ppi_pai.h"
 #include "../../pvar.h"
 #include "../../str.h"
 #include "../../onsend.h"
 #include "../../resolve.h"
 #include "../../receive.h"
+#include "../../mod_fix.h"
 #include "sipcapture.h"
 #include "hash_mode.h"
 #include "hep.h"
@@ -95,12 +95,43 @@ MODULE_VERSION
 
 #define NR_KEYS 36
 
+/*multiple table mode*/
+enum e_mt_mode{
+	mode_random = 1,
+	mode_hash,
+	mode_round_robin,
+	mode_error
+};
+
+
+typedef struct _capture_mode_data {
+	unsigned int id;
+	str name;
+	str db_url;
+	db1_con_t *db_con;
+	db_func_t db_funcs;
+	str * table_names;
+	unsigned int no_tables;
+	enum e_mt_mode mtmode;
+	enum hash_source hash_source;
+	unsigned int rr_idx;
+	stat_var* sipcapture_req;
+	stat_var* sipcapture_rpl;
+	struct _capture_mode_data * next;
+}_capture_mode_data_t;
+
+_capture_mode_data_t * capture_modes_root = NULL;
+_capture_mode_data_t * capture_def = NULL;
+
 /* module function prototypes */
 static int mod_init(void);
 static int sipcapture_init_rpc(void);
 static int child_init(int rank);
 static void destroy(void);
-static int sip_capture(struct sip_msg *msg, char *s1, char *s2);
+static int sipcapture_fixup(void** param, int param_no);
+static int sip_capture(struct sip_msg *msg, str *dtable,  _capture_mode_data_t *cm_data);
+
+static int w_sip_capture(struct sip_msg* _m, char* _table, _capture_mode_data_t * _cm_data, char* s2);
 int init_rawsock_children(void);
 int extract_host_port(void);
 int raw_capture_socket(struct ip_addr* ip, str* iface, int port_start, int port_end, int proto);
@@ -153,6 +184,7 @@ static str node_column 		= str_init("node");
 static str msg_column 		= str_init("msg");   
 static str capture_node 	= str_init("homer01");     	
 static str star_contact		= str_init("*");
+static str callid_aleg_header   = str_init("X-CID");
 
 int raw_sock_desc = -1; /* raw socket used for ip packets */
 unsigned int raw_sock_children = 1;
@@ -186,25 +218,19 @@ static struct sock_filter BPF_code[] = { { 0x28, 0, 0, 0x0000000c }, { 0x15, 0,
 };
 #endif
 
-db1_con_t *db_con = NULL; 		/*!< database connection */
-db_func_t db_funcs;      		/*!< Database functions */
+//db1_con_t *db_con = NULL; 		/*!< database connection */
+//db_func_t db_funcs;      		/*!< Database functions */
+
+//str* table_names = NULL;
 
-str* table_names = NULL;
-char* table_name_cpy = NULL;
 unsigned int no_tables = 0;
 
-/*multiple table mode*/
-enum e_mt_mode{
-	mode_random = 1,
-	mode_hash,
-	mode_round_robin,
-	mode_error
-};
+
 
 enum e_mt_mode mtmode = mode_random ;
 enum hash_source source = hs_error;
 
-unsigned int rr_idx = 0;
+//unsigned int rr_idx = 0;
 
 struct hep_timehdr* heptime;
 
@@ -213,11 +239,15 @@ struct hep_timehdr* heptime;
  * Exported functions
  */
 static cmd_export_t cmds[] = {
-	{"sip_capture", (cmd_function)sip_capture, 0, 0, 0, ANY_ROUTE},
+	{"sip_capture", (cmd_function)w_sip_capture, 0, 0, 0, ANY_ROUTE},
+	{"sip_capture", (cmd_function)w_sip_capture, 1, sipcapture_fixup, 0, ANY_ROUTE },	                         
+	{"sip_capture", (cmd_function)w_sip_capture, 2, sipcapture_fixup, 0, ANY_ROUTE },
 	{0, 0, 0, 0, 0, 0}
 };
 
 
+int capture_mode_param(modparam_t type, void *val);
+
 /*! \brief
  * Exported parameters
  */
@@ -274,9 +304,13 @@ static param_export_t params[] = {
 	{"raw_interface",     		STR_PARAM, &raw_interface.s   },
         {"promiscious_on",  		INT_PARAM, &promisc_on   },		
         {"raw_moni_bpf_on",  		INT_PARAM, &bpf_on   },		
-	{0, 0, 0}
+        {"callid_aleg_header",          STR_PARAM, &callid_aleg_header.s},
+        {"capture_mode",		STR_PARAM|USE_FUNC_PARAM, (void *)capture_mode_param},
+		{0, 0, 0}
 };
 
+
+
 /*! \brief
  * MI commands
  */
@@ -287,7 +321,7 @@ static mi_export_t mi_cmds[] = {
 
 
 #ifdef STATISTICS
-stat_var* sipcapture_req;
+/*stat_var* sipcapture_req;
 stat_var* sipcapture_rpl;
 
 stat_export_t sipcapture_stats[] = {
@@ -295,6 +329,8 @@ stat_export_t sipcapture_stats[] = {
 	{"captured_replies"  ,  0,  &sipcapture_rpl  },
 	{0,0,0}
 };
+*/
+stat_export_t *sipcapture_stats = NULL;
 #endif
 
 /*! \brief module exports */
@@ -304,7 +340,8 @@ struct module_exports exports = {
 	cmds,       /*!< Exported functions */
 	params,     /*!< Exported parameters */
 #ifdef STATISTICS
-	sipcapture_stats,  /*!< exported statistics */
+//	sipcapture_stats,  /*!< exported statistics */
+	0,
 #else
 	0,          /*!< exported statistics */
 #endif
@@ -318,13 +355,22 @@ struct module_exports exports = {
 };
 
 
-static int mt_init(void) {
+
+/* returns number of tables if successful
+ * <0 if failed
+ */
+int parse_table_names (str table_name, str ** table_names){
 
 	char *p = NULL;
-	int i = 0;
+	unsigned int no_tables;
+	char * table_name_cpy;
+	unsigned int i;
 
 	/*parse and save table names*/
 	no_tables = 1;
+	i = 0;
+
+	str * names;
 
 	table_name_cpy = (char *) pkg_malloc(sizeof(char) * table_name.len + 1 );
 	if (table_name_cpy == NULL){
@@ -345,8 +391,8 @@ static int mt_init(void) {
 		p++;
 	}
 
-	table_names = (str*)pkg_malloc(sizeof(str) * no_tables);
-	if(table_names == NULL) {
+	names = (str*)pkg_malloc(sizeof(str) * no_tables);
+	if(names == NULL) {
 		LM_ERR("no more pkg memory left\n");
 		return -1;
 	}
@@ -354,55 +400,284 @@ static int mt_init(void) {
 	while (p != NULL)
 	{
 		LM_INFO ("INFO: table name:%s\n",p);
-		table_names[i].s =  p;
-		table_names[i].len = strlen (p);
+		names[i].len = strlen (p);
+		names[i].s =  (char *)pkg_malloc(sizeof(char) *names[i].len);
+		memcpy(names[i].s, p, names[i].len);
 		i++;
 		p = strtok (NULL, "| \t");
 	}
 
-	if (strcmp (mt_mode.s, "rand") ==0)
-	{
-		mtmode = mode_random;
+	pkg_free(table_name_cpy);
+
+	*table_names = names;
+
+	return no_tables;
+
+}
+
+/* checks for some missing fields*/
+int check_capture_mode ( _capture_mode_data_t * n) {
+
+
+	if (!n->db_url.s || !n->db_url.len){
+		LM_ERR("db_url not set\n");
+		goto error;
 	}
-	else if (strcmp (mt_mode.s, "round_robin") ==0)
-	{
-		mtmode = mode_round_robin;
+
+	if (!n->mtmode ){
+		LM_ERR("mt_mode not set\n");
+		goto error;
 	}
-	else if (strcmp (mt_mode.s, "hash") == 0)
-	{
-		mtmode = mode_hash;
+	else if (!n->no_tables || !n->table_names){
+		LM_ERR("table names not set\n");
+		goto error;
 	}
-	else {
-		LM_ERR("ERROR: sipcapture: mod_init: multiple tables mode unrecognized\n");
+	return 0;
+
+	error:
+	LM_ERR("parsing capture_mode: not all needed parameters are set. Please check again\n");
+	return -1;
+}
+
+int capture_mode_set_params (_capture_mode_data_t * n, str * params){
+
+
+	param_t * params_list = NULL;
+	param_hooks_t phooks;
+	param_t *pit=NULL;
+	db_func_t db_funcs;
+
+	str s;
+	LM_DBG("to tokenize: [%.*s]\n", params->len, params->s);
+	if ( n == NULL || params == NULL)
 		return -1;
-		
+	s = *params;
+
+	if (parse_params(&s, CLASS_ANY, &phooks, &params_list)<0)
+		return -1;
+	for (pit = params_list; pit; pit=pit->next)
+	{
+		LM_DBG("parameter is [%.*s]\n",pit->name.len, pit->name.s );
+		LM_DBG("parameter value is [%.*s]\n", pit->body.len, pit->body.s);
+		if (pit->name.len == 6 && strncmp (pit->name.s, "db_url", pit->name.len)==0){
+
+			n->db_url.len =pit->body.len;
+			n->db_url.s = (char*)pkg_malloc(sizeof(char) * n->db_url.len);
+			if (!n->db_url.s){
+				LM_ERR("no more pkg memory\n");
+				goto error;
+			}
+			memcpy(n->db_url.s, pit->body.s,n->db_url.len );
+
+			if (db_bind_mod(&n->db_url, &db_funcs)){
+
+				LM_ERR("parsing capture_mode: could not bind db funcs for url:[%.*s]\n", n->db_url.len, n->db_url.s);
+				goto error;
+			}
+			n->db_funcs = db_funcs;
+
+			if (!DB_CAPABILITY(n->db_funcs, DB_CAP_INSERT))
+			{
+				LM_ERR("parsing capture_mode: database modules does not provide all functions needed"
+						" by module\n");
+					goto error;
+			}
+
+		}
+
+		else if (pit->name.len == 10 && strncmp (pit->name.s, "table_name", pit->name.len)==0){
+			if ((n->no_tables = parse_table_names(pit->body, &n->table_names))<0){
+				LM_ERR("parsing capture_mode: table name parsing failed\n");
+				goto error;
+			}
+
+		}
+		else if (pit->name.len == 7 && strncmp (pit->name.s, "mt_mode", pit->name.len)==0){
+
+			if (pit->body.len == 4 && strncmp(pit->body.s, "rand",pit->body.len ) ==0)
+			{
+				n->mtmode  = mode_random;
+			}
+			else if (pit->body.len == 11 && strncmp(pit->body.s, "round_robin",pit->body.len ) ==0)
+			{
+				n->mtmode = mode_round_robin;
+			}
+			else if (pit->body.len == 4 && strncmp(pit->body.s, "hash", pit->body.len) ==0)
+			{
+				n->mtmode = mode_hash;
+			}
+			else {
+				LM_ERR("parsing capture_mode: capture mode not recognized: [%.*s]\n", pit->body.len, pit->body.s);
+				goto error;
+
+			}
+		}
+		else if (pit->name.len == 11 && strncmp (pit->name.s, "hash_source", pit->name.len)==0){
+			if ( (n->hash_source = get_hash_source (pit->body.s))  == hs_error)
+			{
+				LM_ERR("parsing capture_mode: hash source unrecognized: [%.*s]\n", pit->body.len, pit->body.s);
+				goto error;
+			}
+		}
+
+
+	}
+	if (n->mtmode == mode_hash && ( n->hash_source == 0 || n->hash_source == hs_error )){
+		LM_WARN("Hash mode set, but no hash source provided for [%.*s]. Will consider hashing by call id.\n", n->name.len, n->name.s);
+		n->hash_source = hs_call_id;
+	}
+
+	if ( check_capture_mode(n)){
+		goto error;
+	}
+
+	return 0;
+
+error:
+	if (n->db_url.s){
+		pkg_free(n->db_url.s);
 	}
+	return -1;
+
+
+
+
+
+}
+
+void * capture_mode_init(str *name, str * params) {
+
+	_capture_mode_data_t * n = NULL;
+	unsigned int id;
+
+	if (!name || name->len == 0){
+		LM_ERR("capture_mode name is empty\n");
+		goto error;
+	}
+	if (!params || params->len == 0){
+		LM_ERR("capture_mode params are empty\n");
+		goto error;
+	}
+	id = core_case_hash(name, 0, 0);
+	n = (_capture_mode_data_t *) pkg_malloc(sizeof(_capture_mode_data_t));
+	if (!n){
+		LM_ERR("no more pkg memory\n");
+		goto error;
+	}
+	memset (n, 0,sizeof(_capture_mode_data_t) );
+	n->id = id;
+	n->name.len = name->len;
+	n->name.s = (char *)pkg_malloc(sizeof(char) * n->name.len);
+	if (!n->name.s){
+		LM_ERR("no more pkg memory\n");
+		goto error;
+	}
+	memcpy(n->name.s, name->s, n->name.len);
+	n->table_names = (str *)pkg_malloc(sizeof(str));
+	if (!n->table_names){
+		LM_ERR("no more pkg memory\n");
+		goto error;
+	}
+
+
+
+	if (capture_mode_set_params (n, params)<0){
+		LM_ERR("capture mode parsing failed\n");
+		goto error;
+	}
+
+	n->next = capture_modes_root;
+	capture_modes_root = n;
+	return n;
+
+error:
+	if (n->name.s){
+		pkg_free(n->name.s);
+	}
+	if (n->table_names){
+		pkg_free(n->table_names);
+	}
+	if (n){
+		pkg_free(n);
+	}
+	return 0;
+
+}
+
+/*parse name=>param1=>val1;param2=>val2;..*/
+int capture_mode_param(modparam_t type, void *val){
+
 
+	str name;
+	str in;
+	str tok;
+	char * p;
 
-	if ( mtmode == mode_hash && (source = get_hash_source (hash_source.s) ) == hs_error)
+	in.s = val;
+	in.len = strlen(in.s);
+	p = in.s;
+
+	while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+		p++;
+	if(p>in.s+in.len || *p=='\0')
+		goto error;
+	name.s = p;
+	while(p < in.s + in.len)
 	{
-		LM_ERR("ERROR: sipcapture: mod_init: hash source unrecognized\n");
-		return -1;
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
+			break;
+		p++;
 	}
 
-	srand(time(NULL));
+	if(p>in.s+in.len || *p=='\0')
+		goto error;
+	name.len = p - name.s;
+	if(*p!='=')
+	{
+		while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+			p++;
+		if(p>in.s+in.len || *p=='\0' || *p!='=')
+			goto error;
+	}
+	p++;
+	if(*p!='>')
+		goto error;
+	p++;
+	while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+		p++;
+	tok.s = p;
+	tok.len = in.len + (int)(in.s - p);
 
+	LM_DBG("capture_mode name: [%.*s] data: [%.*s]\n", name.len, name.s, tok.len, tok.s);
+	if (!capture_mode_init(&name, &tok)){
+		return -1;
+	}
 	return 0;
 
+	error:
+		LM_ERR("invalid parameter [%.*s] at [%d]\n", in.len, in.s,
+				(int)(p-in.s));
+		return -1;
 }
 
+
+
+
+
+
 /*! \brief Initialize sipcapture module */
 static int mod_init(void) {
 
+
 	struct ip_addr *ip = NULL;
+	char * def_params = NULL;
 
 #ifdef STATISTICS
-	/* register statistics */
-	if (register_module_stats(exports.name, sipcapture_stats)!=0)
-	{
-		LM_ERR("failed to register core statistics\n");
-		return -1;
-	}
+	int cnt = 0;
+	int i = 0;
+	char * stat_name = NULL;
+	_capture_mode_data_t * c = NULL;
+	int def;
 #endif
 
 	if(register_mi_mod(exports.name, mi_cmds)!=0)
@@ -456,35 +731,85 @@ static int mod_init(void) {
 	node_column.len = strlen(node_column.s);  
 	msg_column.len = strlen(msg_column.s);   
 	capture_node.len = strlen(capture_node.s);     	
+	callid_aleg_header.len = strlen(callid_aleg_header.s);
 	
 	if(raw_socket_listen.s) 
 		raw_socket_listen.len = strlen(raw_socket_listen.s);     	
 	if(raw_interface.s)
 		raw_interface.len = strlen(raw_interface.s);     	
 
-	/* Find a database module */
-	if (db_bind_mod(&db_url, &db_funcs))
-	{
-		LM_ERR("unable to bind database module\n");
+
+	/*Check the table name - if table_name is empty and no capture modes are defined, then error*/
+	if(!table_name.len && capture_modes_root == NULL) {
+		LM_ERR("ERROR: sipcapture: mod_init: table_name is not defined or empty\n");
 		return -1;
 	}
-	if (!DB_CAPABILITY(db_funcs, DB_CAP_INSERT))
-	{
-		LM_ERR("database modules does not provide all functions needed"
-				" by module\n");
-		return -1;
+
+
+	/*create a default capture mode using the default parameters*/
+	def_params = (char *) pkg_malloc(snprintf(NULL, 0, "db_url=%s;table_name=%s;mt_mode=%s;hash_source=%s",db_url.s, table_name.s, mt_mode.s,hash_source.s) + 1);
+	sprintf(def_params, "db_url=%s;table_name=%s;mt_mode=%s;hash_source=%s",db_url.s, table_name.s, mt_mode.s,hash_source.s);
+
+	str def_name,  def_par;
+	def_name.s= strdup("default");
+	def_name.len = 7;
+	def_par.s = def_params;
+	def_par.len = strlen (def_params);
+
+	LM_DBG("def_params is: %s\n", def_params);
+
+
+	if ((capture_def =capture_mode_init(&def_name, &def_par)) == NULL){
+		LM_WARN("Default capture mode configuration failed. Suppose sip_capture calls will use other defined capture modes.\n");
 	}
 
-	/*Check the table name*/
-	if(!table_name.len) {	
-		LM_ERR("ERROR: sipcapture: mod_init: table_name is not defined or empty\n");
-		return -1;
+	pkg_free(def_params);
+
+
+#ifdef STATISTICS
+
+	c = capture_modes_root;
+	while (c){
+		cnt++;
+		c=c->next;
 	}
+	/*requests and replies for each mode + 1 zero-filled stat_export */
+	stat_export_t *stats = (stat_export_t *) shm_malloc(sizeof(stat_export_t) * cnt * 2 + 1 );
+
+	c = capture_modes_root;
+
+	while (c){
+		/*for the default capture_mode, don't add it's name to the stat name*/
+		def = (capture_def && c == capture_def)?1:0;
+		stat_name = (char *)shm_malloc(sizeof (char) * snprintf(NULL, 0 , (def)?"captured_requests":"captured_requests[%.*s]", c->name.len, c->name.s) + 1);
+		sprintf(stat_name, (def)?"captured_requests":"captured_requests[%.*s]", c->name.len, c->name.s);
+		stats[i].name = stat_name;
+		stats[i].flags = 0;
+		stats[i].stat_pointer = &c->sipcapture_req;
+		i++;
+		stat_name = (char *)shm_malloc(sizeof (char) * snprintf(NULL, 0 , (def)?"captured_replies":"captured_replies[%.*s]", c->name.len, c->name.s) + 1);
+		sprintf(stat_name, (def)?"captured_replies":"captured_replies[%.*s]", c->name.len, c->name.s);
+		stats[i].name = stat_name;
+		stats[i].flags = 0;
+		stats[i].stat_pointer = &c->sipcapture_rpl;
+		i++;
+		c=c->next;
+	}
+	stats[i].name = 0;
+	stats[i].flags = 0;
+	stats[i].stat_pointer = 0;
+
+	sipcapture_stats = stats;
 
-	if (mt_init () <0)
+	/* register statistics */
+	if (register_module_stats(exports.name, sipcapture_stats)!=0)
 	{
+		LM_ERR("failed to register core statistics\n");
 		return -1;
 	}
+#endif
+
+	srand(time(NULL));
 
 
 	if(db_insert_mode) {
@@ -518,9 +843,7 @@ static int mod_init(void) {
 		register_procs(raw_sock_children);
 		                		
 		if(extract_host_port() && (((ip=str2ip(&raw_socket_listen)) == NULL)
-#ifdef  USE_IPV6
 		               && ((ip=str2ip6(&raw_socket_listen)) == NULL)
-#endif
 		         )) 
 		{		
 			LM_ERR("sipcapture mod_init: bad RAW IP: %.*s\n", raw_socket_listen.len, raw_socket_listen.s); 
@@ -580,6 +903,57 @@ error:
 #endif
 }
 
+static int sipcapture_fixup(void** param, int param_no)
+{
+
+		_capture_mode_data_t *con;
+
+		str val;
+		unsigned int id;
+
+        if (param_no == 1 ) {
+                return fixup_var_pve_str_12(param, 1);
+        }
+        if (param_no == 2 ){
+
+			val.s = (char *)*param;
+			val.len = strlen((char *)*param);
+
+
+			con = capture_modes_root;
+			id = core_case_hash (&val, 0 , 0);
+			while (con){
+				if (id == con->id && con->name.len == val.len
+						&& strncmp(con->name.s, val.s, val.len) == 0){
+					*param = (void *)con;
+					LM_DBG("found capture mode :[%.*s]\n",con->name.len, con->name.s);
+					return 0;
+				}
+				con = con->next;
+			}
+
+			LM_ERR("no capture mode found\n");
+			return -1;
+
+        }
+        
+        return 0;
+} 
+   
+static int w_sip_capture(struct sip_msg* _m, char* _table, _capture_mode_data_t * cm_data, char* s2)
+{
+        str table = {0};
+        
+        if(_table!=NULL && (get_str_fparam(&table, _m, (fparam_t*)_table) < 0))
+        {
+                LM_ERR("invalid table parameter [%s] [%s]\n", _table, table.s);
+                return -1;
+        }
+
+        return sip_capture(_m, (table.len>0)?&table:NULL, cm_data );
+}
+
+
 int extract_host_port(void)
 {
 	if(raw_socket_listen.len) {
@@ -606,6 +980,9 @@ int extract_host_port(void)
 
 static int child_init(int rank)
 {
+
+	_capture_mode_data_t * c;
+
 	if (rank == PROC_MAIN && (ipip_capture_on || moni_capture_on)) {
                 if (init_rawsock_children() < 0) return -1;
         }
@@ -613,23 +990,34 @@ static int child_init(int rank)
 	if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
 		return 0; /* do nothing for the main process */
 
-	db_con = db_funcs.init(&db_url);
-	if (!db_con)
-	{
-		LM_ERR("unable to connect to database. Please check configuration.\n");
-		return -1;
+
+	c = capture_modes_root;
+
+	while (c){
+		if (!c->db_url.s || !c->db_url.len ){
+			LM_ERR("DB URL not set for capture mode:[%.*s]", c->name.len, c->name.s);
+			return -1;
+		}
+		c->db_con = c->db_funcs.init(&c->db_url);
+		if (!c->db_con)
+		{
+			LM_ERR("unable to connect to database [%.*s] from capture_mode param.\n", c->db_url.len, c->db_url.s);
+			return -1;
+		}
+	    if (c->mtmode ==mode_round_robin && rank > 0)
+	    {
+			c->rr_idx = rank % c->no_tables;
+	    }
+		c = c->next;
 	}
-	
+
+
 	heptime = (struct hep_timehdr*)pkg_malloc(sizeof(struct hep_timehdr));
         if(heptime==NULL) {
                 LM_ERR("no more pkg memory left\n");
                 return -1;
         }
 
-    if (mtmode ==mode_round_robin && rank > 0)
-    {
-		rr_idx = rank % no_tables;
-    }
 
 	return 0;
 }
@@ -660,8 +1048,32 @@ int init_rawsock_children(void)
 
 static void destroy(void)
 {
-	if (db_con!=NULL)
-		db_funcs.close(db_con);
+	//if (capture_def->db_con!=NULL)
+	//	capture_def->db_funcs.close(capture_def->db_con);
+
+	/*free content from the linked list*/
+	_capture_mode_data_t * c;
+
+	c = capture_modes_root;
+
+	while (c){
+		if (c->name.s){
+			pkg_free(c->name.s);
+		}
+		if (c->db_url.s){
+			pkg_free(c->name.s);
+		}
+		if (c->db_con){
+			c->db_funcs.close(c->db_con);
+		}
+		if (c->table_names){
+			pkg_free(c->table_names);
+		}
+
+		pkg_free(c);
+		c = c->next;
+	}
+
 	if (capture_on_flag)
 		shm_free(capture_on_flag);
 		
@@ -681,12 +1093,10 @@ static void destroy(void)
 		close(raw_sock_desc);
 	}
 
-	if (table_name_cpy){
-		pkg_free(table_name_cpy);
-	}
-	if (table_names){
-		pkg_free(table_names);
-	}
+
+//	if (table_names){
+//		pkg_free(table_names);
+//	}
 }
 
 static int sip_capture_prepare(sip_msg_t *msg)
@@ -694,19 +1104,27 @@ static int sip_capture_prepare(sip_msg_t *msg)
         /* We need parse all headers */
         if (parse_headers(msg, HDR_CALLID_F|HDR_EOH_F, 0) != 0) {
                 LM_ERR("cannot parse headers\n");
-                return -1;
+                return 0;
         }
 
         return 0;
 }
 
-static int sip_capture_store(struct _sipcapture_object *sco)
+static int sip_capture_store(struct _sipcapture_object *sco, str *dtable, _capture_mode_data_t * cm_data)
 {
 	db_key_t db_keys[NR_KEYS];
 	db_val_t db_vals[NR_KEYS];
 
 	str tmp;
 	int ii = 0;
+	str *table = NULL;
+	_capture_mode_data_t *c = NULL;
+
+	c = (cm_data)? cm_data:capture_def;
+	if (!c){
+		LM_ERR("no connection mode available to store data\n");
+		return -1;
+	}
 
 	if(sco==NULL)
 	{
@@ -912,34 +1330,47 @@ static int sip_capture_store(struct _sipcapture_object *sco)
 
 	db_vals[35].val.blob_val = tmp;
 
-	if (no_tables > 0 ){
-		if ( mtmode == mode_hash ){
-			ii = hash_func ( sco, source , no_tables);
+	if (dtable){
+		table = dtable;
+	}
+
+	else if (c->no_tables > 0 ){
+
+		if ( c->mtmode == mode_hash ){
+			ii = hash_func ( sco, c->hash_source , c->no_tables);
+			if (ii < 0){
+				LM_ERR("hashing failed\n");
+				return -1;
+			}
 			LM_DBG ("hash idx is:%d\n", ii);
 		}
-		else if (mtmode == mode_random )
+		else if (c->mtmode == mode_random )
 		{
-			ii = rand() % no_tables;
+			ii = rand() % c->no_tables;
 			LM_DBG("rand idx is:%d\n", ii);
 		}
-		else if (mtmode == mode_round_robin)
+		else if (c->mtmode == mode_round_robin)
 		{
-			ii = rr_idx;
-			rr_idx = (rr_idx +1) % no_tables;
+			ii = c->rr_idx;
+			c->rr_idx = (c->rr_idx +1) % c->no_tables;
 			LM_DBG("round robin idx is:%d\n", ii);
 		}
+		table = &c->table_names[ii];
 	}
-	LM_DBG("insert into homer table: [%.*s]\n", table_names[ii].len, table_names[ii].s);
-	db_funcs.use_table(db_con, &table_names[ii]);
+
+
+	/* check dynamic table */
+	LM_DBG("insert into homer table: [%.*s]\n", table->len, table->s);
+	c->db_funcs.use_table(c->db_con, table);
 
 	LM_DBG("storing info...\n");
 	
-	if(db_insert_mode==1 && db_funcs.insert_delayed!=NULL) {
-                if (db_funcs.insert_delayed(db_con, db_keys, db_vals, NR_KEYS) < 0) {
+	if(db_insert_mode==1 && c->db_funcs.insert_delayed!=NULL) {
+                if (c->db_funcs.insert_delayed(c->db_con, db_keys, db_vals, NR_KEYS) < 0) {
                 	LM_ERR("failed to insert delayed into database\n");
                         goto error;
                 }
-        } else if (db_funcs.insert(db_con, db_keys, db_vals, NR_KEYS) < 0) {
+        } else if (c->db_funcs.insert(c->db_con, db_keys, db_vals, NR_KEYS) < 0) {
 		LM_ERR("failed to insert into database\n");
                 goto error;               
 	}
@@ -954,10 +1385,10 @@ error:
 	return -1;
 }
 
-static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
+static int sip_capture(struct sip_msg *msg, str *_table, _capture_mode_data_t * cm_data)
 {
 	struct _sipcapture_object sco;
-	struct sip_uri from, to, pai, contact;
+	struct sip_uri from, to, contact;
 	struct hdr_field *hook1 = NULL;	 
 	hdr_field_t *tmphdr[4];       
 	contact_body_t*  cb=0;	        	        
@@ -1006,7 +1437,7 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
 		EMPTY_STR(sco.ruri_user);		
 	}
 	else {		
-		LM_ERR("unknow type [%i]\n", msg->first_line.type);	
+		LM_ERR("unknown type [%i]\n", msg->first_line.type);
 		EMPTY_STR(sco.method);
 		EMPTY_STR(sco.reply_reason);
 		EMPTY_STR(sco.ruri);
@@ -1062,32 +1493,35 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
         	EMPTY_STR(sco.to_user);
         	EMPTY_STR(sco.to_tag);
         }
-	
+
 	/* Call-id */
 	if(msg->callid) sco.callid = msg->callid->body;
 	else { EMPTY_STR(sco.callid); }
-	
+
 	/* P-Asserted-Id */
-	if(msg->pai && (parse_pai_header(msg) == 0)) {
-
-	     if (parse_uri(get_pai(msg)->uri.s, get_pai(msg)->uri.len, &pai)<0){
-             	LM_DBG("DEBUG: do_action: bad pai: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
-             }
-             else {
-	        LM_DBG("PARSE PAI: (%.*s)\n",get_pai(msg)->uri.len, get_pai(msg)->uri.s);
-	        sco.pid_user = pai.user;                          
-             }
-	}	
-	else if(msg->ppi && (parse_ppi_header(msg) == 0)) {
-		
-	     if (parse_uri(get_ppi(msg)->uri.s, get_ppi(msg)->uri.len, &pai)<0){
-             	LM_DBG("DEBUG: do_action: bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
-             }
-             else {
-	        sco.pid_user = pai.user;
-             }
-        }
-        else { EMPTY_STR(sco.pid_user); }
+	if((parse_pai_header(msg) == 0) && (msg->pai) && (msg->pai->parsed)) {
+		to_body_t *pai = get_pai(msg)->id; /* This returns the first entry */
+		if ((pai->parsed_uri.user.s == NULL) &&
+			(parse_uri(pai->uri.s, pai->uri.len, &pai->parsed_uri) < 0)){
+			LM_DBG("DEBUG: do_action: bad pai: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
+		}
+		else {
+			LM_DBG("PARSE PAI: (%.*s)\n", pai->uri.len, pai->uri.s);
+			sco.pid_user = pai->parsed_uri.user;
+		}
+	}
+	else if((parse_ppi_header(msg) == 0) && (msg->ppi) && (msg->ppi->parsed)) {
+		to_body_t *ppi = get_ppi(msg)->id; /* This returns the first entry */
+		if ((ppi->parsed_uri.user.s == NULL) &&
+			(parse_uri(ppi->uri.s, ppi->uri.len, &ppi->parsed_uri) < 0)){
+			LM_DBG("DEBUG: do_action: bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s);
+		}
+		else {
+			LM_DBG("PARSE PPI: (%.*s)\n", ppi->uri.len, ppi->uri.s);
+			sco.pid_user = ppi->parsed_uri.user;
+		}
+	}
+	else { EMPTY_STR(sco.pid_user); }
 	
 	/* Auth headers */
         if(msg->proxy_auth != NULL) hook1 = msg->proxy_auth;
@@ -1127,9 +1561,8 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
 	    }
         }
 
-	/* get header x-cid: */
-	/* callid_aleg X-CID */
-	if((tmphdr[0] = get_hdr_by_name(msg,"X-CID", 5)) != NULL) {
+	/* callid_aleg - default is X-CID but configurable via modul params */
+        if((tmphdr[0] = get_hdr_by_name(msg, callid_aleg_header.s, callid_aleg_header.len)) != NULL) {	
 		sco.callid_aleg = tmphdr[0]->body;
         }
 	else { EMPTY_STR(sco.callid_aleg);}
@@ -1254,13 +1687,13 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2)
         
 #ifdef STATISTICS
 	if(msg->first_line.type==SIP_REPLY) {
-		sco.stat = sipcapture_rpl;
+		sco.stat = (cm_data)?cm_data->sipcapture_rpl:capture_def->sipcapture_rpl;
 	} else {
-		sco.stat = sipcapture_req;
+		sco.stat = (cm_data)?cm_data->sipcapture_req:capture_def->sipcapture_req;
 	}
 #endif
 	//LM_DBG("DONE");
-	return sip_capture_store(&sco);
+	return sip_capture_store(&sco, _table, cm_data);
 }
 
 #define capture_is_off(_msg) \
diff --git a/modules/sipt/Makefile b/modules/sipt/Makefile
new file mode 100644
index 0000000..d3342fe
--- /dev/null
+++ b/modules/sipt/Makefile
@@ -0,0 +1,18 @@
+# $Id: $
+#
+# sipt module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=sipt.so
+LIBS=
+
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+
+include ../../Makefile.modules
+
diff --git a/modules/sipt/README b/modules/sipt/README
new file mode 100644
index 0000000..36801f6
--- /dev/null
+++ b/modules/sipt/README
@@ -0,0 +1,246 @@
+sipt Module
+
+Torrey Searle
+
+   Voxbone SA
+   <torrey at voxbone.com>
+
+   Copyright © 2013 Voxbone SA
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+        3. Functions
+
+              3.1. sipt_destination(destination, hops, nai)
+              3.2. sipt_set_calling(origin, nai, presentation, screening)
+
+        4. Exported pseudo-variables
+
+              4.1. $sipt_presentation
+              4.2. $sipt_screening
+              4.3. $sipt_hop_counter
+              4.4. $sipt_cpc
+              4.5. $sipt_calling_party_nai
+              4.6. $sipt_called_party_nai
+
+   List of Tables
+
+   1.1. Address Presentation Restricted Indicator Values
+   1.2. Screening Indicator Values
+   1.3. Calling Nature of Address Values
+   1.4. Called Nature of Address Values
+
+   List of Examples
+
+   1.1. sipt_destination(destination, hops, nai) usage
+   1.2. sipt_set_calling(origin, nai, presentation, screening) usage
+   1.3. sipt_presentation pseudo-variable usage
+   1.4. sipt_screening pseudo-variable usage
+   1.5. sipt_hop_counter pseudo-variable usage
+   1.6. sipt_cpc pseudo-variable usage
+   1.7. sipt_calling_party_nai pseudo-variable usage
+   1.8. sipt_called_party_nai pseudo-variable usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+   3. Functions
+
+        3.1. sipt_destination(destination, hops, nai)
+        3.2. sipt_set_calling(origin, nai, presentation, screening)
+
+   4. Exported pseudo-variables
+
+        4.1. $sipt_presentation
+        4.2. $sipt_screening
+        4.3. $sipt_hop_counter
+        4.4. $sipt_cpc
+        4.5. $sipt_calling_party_nai
+        4.6. $sipt_called_party_nai
+
+1. Overview
+
+   Module for updating ISUP encapuslated in SIP (SIP-T/SIP-I)
+
+   The sipt module can be used to update various ss7 headers contained
+   inside a message.
+
+2. Dependencies
+
+   The module depends on the following modules (in the other words the
+   listed modules must be loaded before this module):
+     * none
+
+3. Functions
+
+   3.1. sipt_destination(destination, hops, nai)
+   3.2. sipt_set_calling(origin, nai, presentation, screening)
+
+3.1. sipt_destination(destination, hops, nai)
+
+   updates the IAM in the body if it exists, setting the called party
+   number to “destination” with the nature address specified in “nai” and
+   decrementing the hop counter value if present. If the hop counter
+   header is missing it will be added with the value of “hops”.
+
+   Example 1.1. sipt_destination(destination, hops, nai) usage
+...
+# update the destination number to our current request uri,
+# setting nature of address to international
+$rU = "19495551234";
+sipt_destination($rU, 31, 4);
+...
+
+3.2. sipt_set_calling(origin, nai, presentation, screening)
+
+   updates the IAM in the body if it exists, setting (or adding) the
+   calling party number to “origin” with the nature address specified in
+   “nai” and setting the presentation and screening values to
+   “presentation” and “screening”.
+
+   Example 1.2. sipt_set_calling(origin, nai, presentation, screening)
+   usage
+...
+# update the calling party to the value in the from header
+sipt_set_calling($fU, 4, 0, 3);
+...
+
+4. Exported pseudo-variables
+
+   4.1. $sipt_presentation
+   4.2. $sipt_screening
+   4.3. $sipt_hop_counter
+   4.4. $sipt_cpc
+   4.5. $sipt_calling_party_nai
+   4.6. $sipt_called_party_nai
+
+4.1. $sipt_presentation
+
+   Returns the value of the Address presentation restricted indicator
+   contained in the Calling Party Number header of the IAM message if it
+   exists. Returns -1 if there isn't a Calling Party Number header.
+
+   Table 1.1. Address Presentation Restricted Indicator Values
+   0 presentation allowed
+   1 presentation restricted
+   2 address not avail (national use)
+   3 spare
+
+   Example 1.3. sipt_presentation pseudo-variable usage
+...
+# add privacy header if restriction is requested
+if($sipt_presentation == 1)
+{
+        append_hf("Privacy: id\r\n");
+        $fn = "Anonymous";
+}
+
+...
+
+4.2. $sipt_screening
+
+   Returns the value of the Screening Indicator contained in the Calling
+   Party Number header of the IAM message if it exists. Returns -1 if
+   there isn't a Calling Party Number header.
+
+   Table 1.2. Screening Indicator Values
+   0 Reserved (user provided, not verified)
+   1 User Provided, Verified and Passed
+   2 Reserved (user provided, verified and failed)
+   3 Network provided
+
+   Example 1.4. sipt_screening pseudo-variable usage
+...
+
+# remove P-Asserted-Identity header if the screening isn't verified
+# or network provided
+$avp(s:screening) = $sipt_screening;
+if($avp(s:screening) != 1 && $avp(s:screening) != 3)
+{
+        remove_hf("P-Asserted-Id");
+}
+
+...
+
+4.3. $sipt_hop_counter
+
+   Returns the value of the Hop Counter for the IAM message if it exists.
+   Returns -1 if there isn't a hop counter.
+
+   Example 1.5. sipt_hop_counter pseudo-variable usage
+...
+# get the hop counter and update the Max-Forwards header if it exists
+$avp(s:hop) = $sipt_hop_counter;
+if($avp(s:hop) > 0)
+{
+        remove_hf("Max-Forwards");
+        append_hf("Max-Forwards: $avp(s:hop)\r\n");
+}
+
+...
+
+4.4. $sipt_cpc
+
+   Returns the value of the Calling Party Category for the IAM message.
+   Returns -1 if there is a parsing error.
+
+   Example 1.6. sipt_cpc pseudo-variable usage
+...
+# get the Cpc code and set put it in a custom sip header
+append_hf("X-CPC: $sipt_cpc\r\n");
+
+...
+
+4.5. $sipt_calling_party_nai
+
+   Returns the value of the Nature of Address Indicator of the Calling
+   Party for the IAM message. Returns -1 if there is a parsing error or if
+   the Calling Party Number is not present.
+
+   Table 1.3. Calling Nature of Address Values
+   0 Spare
+   1 Subscriber Number (national use)
+   2 Unknown (national use)
+   3 National (significant) number (national use)
+   4 International use
+
+   Example 1.7. sipt_calling_party_nai pseudo-variable usage
+...
+# get the Calling Nai and add country code if national
+if($sipt_calling_party_nai == 3)
+{
+        $fU = "32" + "$fU";
+}
+
+...
+
+4.6. $sipt_called_party_nai
+
+   Returns the value of the Nature of Address Indicator of the Called
+   Party for the IAM message. Returns -1 if there is a parsing error.
+
+   Table 1.4. Called Nature of Address Values
+   0 Spare
+   1 Subscriber Number (national use)
+   2 Unknown (national use)
+   3 National (significant) number
+   4 International use
+   5 Network-specific number (national use)
+
+   Example 1.8. sipt_called_party_nai pseudo-variable usage
+...
+# get the Called Nai and add country code if national
+if($sipt_called_party_nai == 3)
+{
+        $rU = "32" + "$rU";
+}
+
+...
diff --git a/modules/sipt/doc/Makefile b/modules/sipt/doc/Makefile
new file mode 100644
index 0000000..102dc57
--- /dev/null
+++ b/modules/sipt/doc/Makefile
@@ -0,0 +1,4 @@
+docs = sipt.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/sipt/doc/sipt.xml b/modules/sipt/doc/sipt.xml
new file mode 100644
index 0000000..75ea181
--- /dev/null
+++ b/modules/sipt/doc/sipt.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>sipt Module</title>
+	<authorgroup>
+		<author>
+		<firstname>Torrey</firstname>
+		<surname>Searle</surname>
+		<affiliation><orgname>Voxbone SA</orgname></affiliation>
+		<email>torrey at voxbone.com</email>
+		</author>
+	</authorgroup>
+	<copyright>
+		<year>2013</year>
+		<holder>Voxbone SA</holder>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+
+	<xi:include href="sipt_admin.xml"/>
+
+</book>
diff --git a/modules/sipt/doc/sipt_admin.xml b/modules/sipt/doc/sipt_admin.xml
new file mode 100644
index 0000000..9c33e8c
--- /dev/null
+++ b/modules/sipt/doc/sipt_admin.xml
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- sipt Module User's Guide -->
+
+<chapter>
+    
+    <title>&adminguide;</title>
+
+    <section>
+	<title>Overview</title>
+	<para>Module for updating ISUP encapuslated in SIP (SIP-T/SIP-I)</para>
+	<para>
+	The sipt module can be used to update various ss7 headers contained inside
+	a message. 
+	</para>
+	</section>
+	<section>
+	<title>Dependencies</title>
+	<para>
+	    The module depends on the following modules (in the other words the
+		listed modules must be loaded before this module):
+	    <itemizedlist>
+		<listitem>
+		    <para><emphasis>none</emphasis></para>
+		</listitem>
+	    </itemizedlist>
+	</para>
+    </section>
+
+    <section>
+	<title>Functions</title>
+	<section id="sipt.f.sipt_destination">
+		<title><function moreinfo="none">sipt_destination(destination, hops, nai)</function></title>
+		<para>
+			updates the IAM in the body if it exists, setting the called party number to <quote>destination</quote>
+			with the nature address specified in <quote>nai</quote> and decrementing the hop counter value if present.
+			If the hop counter header is missing it will be added with the value of <quote>hops</quote>.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_destination(destination, hops, nai)</function> usage</title>
+			<programlisting format="linespecific">
+...
+# update the destination number to our current request uri, 
+# setting nature of address to international
+$rU = "19495551234";
+sipt_destination($rU, 31, 4);
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.f.sipt_set_calling">
+		<title><function moreinfo="none">sipt_set_calling(origin, nai, presentation, screening)</function></title>
+		<para>
+			updates the IAM in the body if it exists, setting (or adding) the calling party number to <quote>origin</quote>
+			with the nature address specified in <quote>nai</quote> and setting the presentation and screening values to 
+			 <quote>presentation</quote> and <quote>screening</quote>.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_set_calling(origin, nai, presentation, screening)</function> usage</title>
+			<programlisting format="linespecific">
+...
+# update the calling party to the value in the from header
+sipt_set_calling($fU, 4, 0, 3);
+...
+</programlisting>
+		</example>
+	</section>
+</section>
+<section>
+        <title>Exported pseudo-variables</title>
+	<section id="sipt.v.sipt_presentation">
+		<title><varname>$sipt_presentation</varname></title>
+		<para>
+			Returns the value of the Address presentation restricted indicator contained in the
+			Calling Party Number header of the IAM message if it exists.
+			Returns -1 if there isn't a Calling Party Number header.
+		</para>
+		<table>
+			<title>Address Presentation Restricted Indicator Values</title>
+			<tgroup cols="2">
+				<tbody>
+					<row><entry>0</entry><entry>presentation allowed</entry></row>
+					<row><entry>1</entry><entry>presentation restricted</entry></row>
+					<row><entry>2</entry><entry>address not avail (national use)</entry></row>
+					<row><entry>3</entry><entry>spare</entry></row>
+				</tbody>
+			</tgroup>
+		</table>
+		<example>
+			<title><function moreinfo="none">sipt_presentation pseudo-variable</function> usage</title>
+			<programlisting format="linespecific">
+...
+# add privacy header if restriction is requested 
+if($sipt_presentation == 1)
+{
+	append_hf("Privacy: id\r\n");
+	$fn = "Anonymous";
+}
+
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.v.sipt_screening">
+		<title><varname>$sipt_screening</varname></title>
+		<para>
+			Returns the value of the Screening Indicator contained in the
+			Calling Party Number header of the IAM message if it exists.
+			Returns -1 if there isn't a Calling Party Number header.
+		</para>
+		<table>
+			<title>Screening Indicator Values</title>
+			<tgroup cols="2">
+				<tbody>
+					<row><entry>0</entry><entry>Reserved (user provided, not verified)</entry></row>
+					<row><entry>1</entry><entry>User Provided, Verified and Passed</entry></row>
+					<row><entry>2</entry><entry>Reserved (user provided, verified and failed)</entry></row>
+					<row><entry>3</entry><entry>Network provided</entry></row>
+				</tbody>
+			</tgroup>
+		</table>
+		<example>
+			<title><function moreinfo="none">sipt_screening pseudo-variable</function> usage</title>
+			<programlisting format="linespecific">
+...
+
+# remove P-Asserted-Identity header if the screening isn't verified 
+# or network provided
+$avp(s:screening) = $sipt_screening;
+if($avp(s:screening) != 1 && $avp(s:screening) != 3)
+{
+	remove_hf("P-Asserted-Id");
+}
+
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.v.sipt_hop_counter">
+		<title><varname>$sipt_hop_counter</varname></title>
+		<para>
+			Returns the value of the Hop Counter for the IAM message if it exists.
+			Returns -1 if there isn't a hop counter.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_hop_counter pseudo-variable</function> usage</title>
+			<programlisting format="linespecific">
+...
+# get the hop counter and update the Max-Forwards header if it exists
+$avp(s:hop) = $sipt_hop_counter;
+if($avp(s:hop) > 0)
+{
+	remove_hf("Max-Forwards");
+	append_hf("Max-Forwards: $avp(s:hop)\r\n");
+}
+
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.v.sipt_cpc">
+		<title><varname>$sipt_cpc</varname></title>
+		<para>
+			Returns the value of the Calling Party Category for the IAM message.
+			Returns -1 if there is a parsing error.
+		</para>
+		<example>
+			<title><function moreinfo="none">sipt_cpc pseudo-variable</function> usage</title>
+			<programlisting format="linespecific">
+...
+# get the Cpc code and set put it in a custom sip header
+append_hf("X-CPC: $sipt_cpc\r\n");
+
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.v.sipt_calling_party_nai">
+		<title><varname>$sipt_calling_party_nai</varname></title>
+		<para>
+			Returns the value of the Nature of Address Indicator
+			of the Calling Party for the IAM message.
+			Returns -1 if there is a parsing error or if
+			the Calling Party Number is not present.
+		</para>
+		<table>
+			<title>Calling Nature of Address Values</title>
+			<tgroup cols="2">
+				<tbody>
+					<row><entry>0</entry><entry>Spare</entry></row>
+					<row><entry>1</entry><entry>Subscriber Number (national use)</entry></row>
+					<row><entry>2</entry><entry>Unknown (national use)</entry></row>
+					<row><entry>3</entry><entry>National (significant) number (national use)</entry></row>
+					<row><entry>4</entry><entry>International use</entry></row>
+				</tbody>
+			</tgroup>
+		</table>
+		<example>
+			<title><function moreinfo="none">sipt_calling_party_nai pseudo-variable</function> usage</title>
+			<programlisting format="linespecific">
+...
+# get the Calling Nai and add country code if national
+if($sipt_calling_party_nai == 3)
+{
+	$fU = "32" + "$fU";
+}
+
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="sipt.v.sipt_called_party_nai">
+		<title><varname>$sipt_called_party_nai</varname></title>
+		<para>
+			Returns the value of the Nature of Address Indicator
+			of the Called Party for the IAM message.
+			Returns -1 if there is a parsing error.
+		</para>
+		<table>
+			<title>Called Nature of Address Values</title>
+			<tgroup cols="2">
+				<tbody>
+					<row><entry>0</entry><entry>Spare</entry></row>
+					<row><entry>1</entry><entry>Subscriber Number (national use)</entry></row>
+					<row><entry>2</entry><entry>Unknown (national use)</entry></row>
+					<row><entry>3</entry><entry>National (significant) number</entry></row>
+					<row><entry>4</entry><entry>International use</entry></row>
+					<row><entry>5</entry><entry>Network-specific number (national use)</entry></row>
+				</tbody>
+			</tgroup>
+		</table>
+		<example>
+			<title><function moreinfo="none">sipt_called_party_nai pseudo-variable</function> usage</title>
+			<programlisting format="linespecific">
+...
+# get the Called Nai and add country code if national
+if($sipt_called_party_nai == 3)
+{
+	$rU = "32" + "$rU";
+}
+
+...
+</programlisting>
+		</example>
+	</section>
+
+</section>
+</chapter>
+
diff --git a/modules/sipt/sdp_mangle.c b/modules/sipt/sdp_mangle.c
new file mode 100644
index 0000000..598ee27
--- /dev/null
+++ b/modules/sipt/sdp_mangle.c
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+#include "sdp_mangle.h"
+
+int replace_body_segment(struct sdp_mangler * mangler, int offset, int len, unsigned char * new_data, int new_len)
+{
+	
+	struct lump * l;
+	char *s;
+
+	l = del_lump(mangler->msg, mangler->body_offset + offset, len, 0);
+
+	if(l == NULL)
+	{
+		return -1;
+	}
+
+ 	s = pkg_malloc(new_len);
+	memcpy(s, new_data, new_len);
+
+	if(insert_new_lump_after(l, s, new_len, 0) == 0)
+	{
+		pkg_free(s);
+		return -2;
+	}
+
+	return 0;
+}
+
+int add_body_segment(struct sdp_mangler * mangler, int offset, unsigned char * new_data, int new_len)
+{
+	
+	struct lump * l;
+	char *s;
+	int exists;
+	l = anchor_lump2(mangler->msg, mangler->body_offset + offset, 0, 0, &exists);
+	if(l == NULL)
+	{
+		return -1;
+	}
+
+ 	s = pkg_malloc(new_len);
+	memcpy(s, new_data, new_len);
+	if(insert_new_lump_after(l, s, new_len, 0) == 0)
+	{
+		pkg_free(s);
+		return -2;
+	}
+
+	return 0;
+}
+
diff --git a/modules/sipt/sdp_mangle.h b/modules/sipt/sdp_mangle.h
new file mode 100644
index 0000000..592e3da
--- /dev/null
+++ b/modules/sipt/sdp_mangle.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+#include "../../data_lump.h"
+#include "../../parser/msg_parser.h"	/* struct sip_msg */
+
+#ifndef _SIPT_SDP_MANGLE_
+#define _SIPT_SDP_MANGLE_
+
+
+struct sdp_mangler
+{
+	struct sip_msg *msg;
+	int body_offset;
+};
+
+
+int replace_body_segment(struct sdp_mangler * mangler, int offset, int len, unsigned char * new_data, int new_len);
+int add_body_segment(struct sdp_mangler * mangler, int offset, unsigned char * new_data, int new_len);
+
+#endif
diff --git a/modules/sipt/sipt.c b/modules/sipt/sipt.c
new file mode 100644
index 0000000..f1d534b
--- /dev/null
+++ b/modules/sipt/sipt.c
@@ -0,0 +1,384 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+
+#include "../../sr_module.h"
+#include "../../parser/parse_param.h"
+#include "../../data_lump.h"
+#include "../../mem/mem.h"
+#include "../../mod_fix.h"
+#include "../../parser/parse_content.h"
+#include "../../parser/parse_body.h"
+#include "../../parser/parser_f.h"
+#include "../../trim.h"
+#include "ss7.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+MODULE_VERSION
+
+static int sipt_destination(struct sip_msg *msg, char *_destination, char *_hops, char * _nai);
+static int sipt_set_calling(struct sip_msg *msg, char *_origin, char *_nai, char *_pres, char * _screen);
+static int sipt_get_hop_counter(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int sipt_get_cpc(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int sipt_get_calling_party_nai(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int sipt_get_presentation(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int sipt_get_screening(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+static int sipt_get_called_party_nai(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+
+static int mod_init(void);
+static void mod_destroy(void);
+
+
+
+static int fixup_str_str_str(void** param, int param_no)
+{
+	if(param_no == 1 || param_no == 2 || param_no == 3 || param_no == 4)
+	{
+		return fixup_str_null(param, 1);
+	}
+	return E_CFG;
+}
+
+static int fixup_free_str_str_str(void** param, int param_no)
+{
+	if(param_no == 1 || param_no == 2 || param_no == 3 || param_no == 4)
+	{
+		return fixup_free_str_null(param, 1);
+	}
+	return E_CFG;
+}
+
+
+static cmd_export_t cmds[]={
+	{"sipt_destination", /* action name as in scripts */
+		(cmd_function)sipt_destination,  /* C function name */
+		3,          /* number of parameters */
+		fixup_str_str_str, fixup_free_str_str_str,         /* */
+		/* can be applied to original requests */
+		REQUEST_ROUTE|BRANCH_ROUTE}, 
+	{"sipt_set_calling", /* action name as in scripts */
+		(cmd_function)sipt_set_calling,  /* C function name */
+		4,          /* number of parameters */
+		fixup_str_str_str, fixup_free_str_str_str,         /* */
+		/* can be applied to original requests */
+		REQUEST_ROUTE|BRANCH_ROUTE}, 
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]={ 
+	{0,0,0} 
+};
+
+static mi_export_t mi_cmds[] = {
+	{ 0, 0, 0, 0, 0}
+};
+
+static pv_export_t mod_items[] = {
+        { {"sipt_presentation",  sizeof("sipt_presentation")-1}, PVT_OTHER,  sipt_get_presentation,    0,
+                0, 0, 0, 0 },
+        { {"sipt_screening",  sizeof("sipt_screening")-1}, PVT_OTHER,  sipt_get_screening,    0,
+                0, 0, 0, 0 },
+        { {"sipt_hop_counter",  sizeof("sipt_hop_counter")-1}, PVT_OTHER,  sipt_get_hop_counter,    0,
+                0, 0, 0, 0 },
+        { {"sipt_cpc",  sizeof("sipt_cpc")-1}, PVT_OTHER,  sipt_get_cpc,    0,
+                0, 0, 0, 0 },
+        { {"sipt_calling_party_nai",  sizeof("sipt_calling_party_nai")-1}, PVT_OTHER,  sipt_get_calling_party_nai,    0,
+                0, 0, 0, 0 },
+        { {"sipt_called_party_nai",  sizeof("sipt_called_party_nai")-1}, PVT_OTHER,  sipt_get_called_party_nai,    0,
+                0, 0, 0, 0 },
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+struct module_exports exports = {
+	"sipt",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,        /* exported functions */
+	params,      /* exported parameters */
+	0,           /* exported statistics */
+	mi_cmds,     /* exported MI functions */
+	mod_items,   /* exported pseudo-variables */
+	0,           /* extra processes */
+	mod_init,    /* module initialization function */
+	0,           /* response function*/
+	mod_destroy, /* destroy function */
+	0            /* per-child init function */
+};
+
+static int sipt_get_hop_counter(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+	
+	pv_get_sintval(msg, param, res, isup_get_hop_counter((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_get_cpc(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+	
+	pv_get_sintval(msg, param, res, isup_get_cpc((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_get_calling_party_nai(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+	
+	pv_get_sintval(msg, param, res, isup_get_calling_party_nai((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_get_presentation(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+	
+	pv_get_sintval(msg, param, res, isup_get_presentation((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_get_screening(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+	LM_DBG("about to get screening\n");
+	
+	pv_get_sintval(msg, param, res, isup_get_screening((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_get_called_party_nai(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+	
+	pv_get_sintval(msg, param, res, isup_get_called_party_nai((unsigned char*)body.s, body.len));
+	return 0;
+}
+
+static int sipt_destination(struct sip_msg *msg, char *_destination, char *_hops, char * _nai)
+{
+	str * str_hops = (str*)_hops;
+	unsigned int hops = 0;
+	str2int(str_hops, &hops);
+	str * nai = (str*)_nai;
+	unsigned int int_nai = 0;
+	str2int(nai, &int_nai);
+	str * destination = (str*)_destination;
+	struct sdp_mangler mangle;
+
+	// update forwarded iam
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+	str sdp;
+	sdp.s = get_body_part(msg, TYPE_APPLICATION, SUBTYPE_SDP, &sdp.len);
+	
+	unsigned char newbuf[1024];
+	memset(newbuf, 0, 1024);
+	if (body.s==0) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+	if (body.len==0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+
+	mangle.msg = msg;
+	mangle.body_offset = (int)(body.s - msg->buf);
+
+
+	char * digits = calloc(1,destination->len+2);
+	memcpy(digits, destination->s, destination->len);
+	digits[destination->len] = '#';
+
+	int res = isup_update_destination(&mangle, digits, hops, int_nai, (unsigned char*)body.s, body.len);
+	free(digits);
+	if(res < 0)
+	{
+		LM_DBG("error updating IAM\n");
+		return -1;
+	}
+
+	return 1;
+}
+
+static int sipt_set_calling(struct sip_msg *msg, char *_origin, char *_nai, char * _pres, char *_screen)
+{
+	unsigned int pres = 0;
+	str * str_pres = (str*)_pres;
+	str2int(str_pres, &pres);
+	unsigned int screen = 0;
+	str * str_screen = (str*)_screen;
+	str2int(str_screen, &screen);
+	str * nai = (str*)_nai;
+	unsigned int int_nai = 0;
+	str2int(nai, &int_nai);
+	str * origin = (str*)_origin;
+	struct sdp_mangler mangle;
+
+	// update forwarded iam
+	str body;
+	body.s = get_body_part(msg, TYPE_APPLICATION,SUBTYPE_ISUP,&body.len);
+
+	if(body.s == NULL)
+	{
+		LM_ERR("No ISUP Message Found");
+		return -1;
+	}
+
+	if (body.s==0) {
+		LM_ERR("failed to get the message body\n");
+		return -1;
+	}
+	body.len = msg->len -(int)(body.s-msg->buf);
+	if (body.len==0) {
+		LM_DBG("message body has zero length\n");
+		return -1;
+	}
+
+	if(body.s[0] != ISUP_IAM)
+	{
+		LM_DBG("message not an IAM\n");
+		return -1;
+	}
+
+
+	mangle.msg = msg;
+	mangle.body_offset = (int)(body.s - msg->buf);
+
+	char * digits = calloc(1,origin->len+1);
+	memcpy(digits, origin->s, origin->len);
+
+	int res = isup_update_calling(&mangle, digits, int_nai, pres, screen, (unsigned char*)body.s, body.len);
+	free(digits);
+	if(res < 0)
+	{
+		LM_DBG("error updating IAM\n");
+		return -1;
+	}
+
+	return 1;
+}
+
+
+static int mod_init(void)
+{
+	return 0;
+}
+
+
+static void mod_destroy(void)
+{
+}
diff --git a/modules/sipt/ss7.h b/modules/sipt/ss7.h
new file mode 100644
index 0000000..24127fc
--- /dev/null
+++ b/modules/sipt/ss7.h
@@ -0,0 +1,188 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ * 
+ * Parsing code derrived from libss7 Copyright (C) Digium
+ *
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+#include "sdp_mangle.h"
+
+#ifndef _SIPT_SS7_H_
+#define _SIPT_SS7_H_
+
+/* ISUP messages */
+#define ISUP_IAM	0x01
+#define ISUP_SAM	0x02
+#define ISUP_INR	0x03
+#define ISUP_INF	0x04
+#define ISUP_COT	0x05
+#define ISUP_ACM	0x06
+#define ISUP_CON	0x07
+#define ISUP_FOT	0x08
+#define ISUP_ANM	0x09
+#define ISUP_REL	0x0c
+#define ISUP_SUS	0x0d
+#define ISUP_RES	0x0e
+#define ISUP_RLC	0x10
+#define ISUP_CCR	0x11
+#define ISUP_RSC	0x12
+#define ISUP_BLO	0x13
+#define ISUP_UBL	0x14
+#define ISUP_BLA	0x15
+#define ISUP_UBA	0x16
+#define ISUP_GRS	0x17
+#define ISUP_CGB	0x18
+#define ISUP_CGU	0x19
+#define ISUP_CGBA	0x1a
+#define ISUP_CGUA	0x1b
+#define ISUP_CMR	0x1c
+#define ISUP_CMC	0x1d
+#define ISUP_CMRJ	0x1e
+#define ISUP_FAR	0x1f
+#define ISUP_FAA	0x20
+#define ISUP_FRJ	0x21
+#define ISUP_FAD	0x22
+#define ISUP_FAI	0x23
+#define ISUP_LPA	0x24
+#define ISUP_CSVR	0x25
+#define ISUP_CSVS	0x26
+#define ISUP_DRS	0x27
+#define ISUP_PAM	0x28
+#define ISUP_GRA	0x29
+#define ISUP_CQM	0x2a
+#define ISUP_CQR	0x2b
+#define ISUP_CPG	0x2c
+#define ISUP_USR	0x2d
+#define ISUP_UCIC	0x2e
+#define ISUP_CFN	0x2f
+#define ISUP_OLM	0x30
+#define ISUP_CRG	0x31
+#define ISUP_FAC	0x33
+#define ISUP_CRA	0xe9
+#define ISUP_CRM	0xea
+#define ISUP_CVR	0xeb
+#define ISUP_CVT	0xec
+#define ISUP_EXM	0xed
+
+/* ISUP Parameters */
+#define ISUP_PARM_NATURE_OF_CONNECTION_IND 0x06
+#define ISUP_PARM_FORWARD_CALL_IND 0x07
+#define ISUP_PARM_CALLING_PARTY_CAT 0x09
+#define ISUP_PARM_USER_SERVICE_INFO 0x1d
+#define ISUP_PARM_TRANSMISSION_MEDIUM_REQS 0x02
+#define ISUP_PARM_CALLED_PARTY_NUM 0x04
+#define ISUP_PARM_ACCESS_TRANS 0x03
+#define ISUP_PARM_BUSINESS_GRP 0xc6
+#define ISUP_PARM_CALL_REF 0x01
+#define ISUP_PARM_CALLING_PARTY_NUM 0x0a
+#define ISUP_PARM_CARRIER_ID 0xc5
+#define ISUP_PARM_SELECTION_INFO 0xee
+#define ISUP_PARM_CHARGE_NUMBER 0xeb
+#define ISUP_PARM_CIRCUIT_ASSIGNMENT_MAP 0x25
+#define ISUP_PARM_OPT_BACKWARD_CALL_IND 0x29
+#define ISUP_PARM_CONNECTION_REQ 0x0d
+#define ISUP_PARM_CONTINUITY_IND 0x10
+#define ISUP_PARM_CUG_INTERLOCK_CODE 0x1a
+#define ISUP_PARM_EGRESS_SERV 0xc3
+#define ISUP_PARM_GENERIC_ADDR 0xc0
+#define ISUP_PARM_GENERIC_DIGITS 0xc1
+#define ISUP_PARM_GENERIC_NAME 0xc7
+#define ISUP_PARM_GENERIC_NOTIFICATION_IND 0x2c
+#define ISUP_PARM_BACKWARD_CALL_IND 0x11
+#define ISUP_PARM_CAUSE 0x12
+#define ISUP_PARM_CIRCUIT_GROUP_SUPERVISION_IND 0x15
+#define ISUP_PARM_RANGE_AND_STATUS 0x16
+#define ISUP_PARM_PROPAGATION_DELAY 0x31
+#define ISUP_PARM_EVENT_INFO 0x24
+#define ISUP_PARM_HOP_COUNTER 0x3d
+#define ISUP_PARM_OPT_FORWARD_CALL_INDICATOR 0x08
+#define ISUP_PARM_LOCATION_NUMBER 0x3f
+#define ISUP_PARM_ORIG_LINE_INFO 0xea
+#define ISUP_PARM_REDIRECTION_NUMBER 0x0c
+#define ISUP_PARM_REDIRECTION_INFO 0x13
+#define ISUP_PARM_ORIGINAL_CALLED_NUM 0x28
+#define ISUP_PARM_JIP 0xc4
+#define ISUP_PARM_ECHO_CONTROL_INFO 0x37
+#define ISUP_PARM_PARAMETER_COMPAT_INFO 0x39
+#define ISUP_PARM_CIRCUIT_STATE_IND 0x26
+#define ISUP_PARM_TRANSIT_NETWORK_SELECTION 0x23
+#define ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION 0xe4
+#define ISUP_PARM_FACILITY_IND 0x18
+#define ISUP_PARM_REDIRECTING_NUMBER 0x0b 
+#define ISUP_PARM_ACCESS_DELIVERY_INFO 0x2e
+#define ISUP_PARM_REDIRECT_COUNTER 0x77
+#define ISUP_PARM_SUSRES_IND 0x22
+#define ISUP_PARM_INF_IND 0x0f
+#define ISUP_PARM_INR_IND 0x0e
+#define ISUP_PARM_SUBSEQUENT_NUMBER 0x05
+#define ISUP_CONNECTED_NUMBER 0x21
+#define ISUP_PARM_DIVERSION_INFORMATION 0x36
+#define ISUP_PARM_UUI 0x20
+
+/* Address Presentation */
+#define SS7_PRESENTATION_ALLOWED                       0x00
+#define SS7_PRESENTATION_RESTRICTED                    0x01
+#define SS7_PRESENTATION_ADDR_NOT_AVAILABLE            0x02
+
+/* Screening */
+#define SS7_SCREENING_USER_PROVIDED_NOT_VERIFIED       0x00
+#define SS7_SCREENING_USER_PROVIDED                    0x01
+#define SS7_SCREENING_NETWORK_PROVIDED_FAILED          0x02
+#define SS7_SCREENING_NETWORK_PROVIDED                 0x03
+
+
+
+#ifndef bool
+#define bool unsigned char
+#endif
+
+
+/* ISUP Parameter Pseudo-type */
+struct isup_parm_opt {
+	unsigned char type;
+	unsigned char len;
+	unsigned char data[0];
+};
+
+
+struct isup_iam_fixed {
+	unsigned char type;
+	unsigned char nature_of_connection;
+	unsigned char forward_call_indicators[2];
+	unsigned char calling_party_category;
+	unsigned char transmission_medium_req;
+	unsigned char fixed_pointer;
+	unsigned char optional_pointer;
+	unsigned char called_party_number[0];
+};
+
+int isup_get_hop_counter(unsigned char *buf, int len);
+int isup_get_cpc(unsigned char *buf, int len);
+int isup_get_calling_party_nai(unsigned char *buf, int len);
+int isup_get_called_party_nai(unsigned char *buf, int len);
+int isup_get_screening(unsigned char *buf, int len);
+int isup_get_presentation(unsigned char *buf, int len);
+int isup_update_destination(struct sdp_mangler * mangle, char * dest, int hops, int nai, unsigned char *buf, int len);
+int isup_update_calling(struct sdp_mangler * mangle, char * origin, int nai, int presentation, int screening, unsigned char * buf, int len);
+
+
+#endif
diff --git a/modules/sipt/ss7_parser.c b/modules/sipt/ss7_parser.c
new file mode 100644
index 0000000..c8fc239
--- /dev/null
+++ b/modules/sipt/ss7_parser.c
@@ -0,0 +1,441 @@
+/*
+ *
+ * Copyright (C) 2013 Voxbone SA
+ * 
+ * Parsing code derrived from libss7 Copyright (C) Digium
+ *
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ */
+
+#include "ss7.h"
+#include <string.h>
+#include <stddef.h>
+
+static char char2digit(char localchar)
+{
+	switch (localchar) {
+		case '0':
+			return 0;
+		case '1':
+			return 1;
+		case '2':
+			return 2;
+		case '3':
+			return 3;
+		case '4':
+			return 4;
+		case '5':
+			return 5;
+		case '6':
+			return 6;
+		case '7':
+			return 7;
+		case '8':
+			return 8;
+		case '9':
+			return 9;
+		case 'A':
+			return 0xa;
+		case 'B':
+			return 0xb;
+		case 'C':
+			return 0xc;
+		case 'D':
+			return 0xd;
+		case '*':
+			return 0xe;
+		case '#':
+		case 'F':
+			return 0xf;
+		default:
+			return 0;
+	}
+}
+
+static void isup_put_number(unsigned char *dest, char *src, int *len, int *oddeven)
+{
+	int i = 0;
+	int numlen = strlen(src);
+
+	if (numlen % 2) {
+		*oddeven = 1;
+		*len = numlen/2 + 1;
+	} else {
+		*oddeven = 0;
+		*len = numlen/2;
+	}
+	
+
+	while (i < numlen) {
+		if (!(i % 2))
+			dest[i/2] = char2digit(src[i]) & 0xf;
+		else
+		{
+			dest[i/2] |= (char2digit(src[i]) << 4) & 0xf0;
+		}
+		i++;
+	}
+}
+
+static int encode_called_party(char * number, unsigned char * flags, int nai, unsigned char * buf, int len)
+{
+	int numlen, oddeven;
+	buf[0] = flags[0]&0x7F;
+	buf[1] = flags[1];
+
+	isup_put_number(&buf[2], number, &numlen, &oddeven);
+
+	if(oddeven)
+	{
+		buf[0] |= 0x80;
+	}
+	
+	if(nai)
+	{
+		buf[0] &= 0x80;
+		buf[0] = (unsigned char)(nai&0x7F);
+	}
+
+	return numlen + 2;
+}
+
+static int encode_calling_party(char * number, int nai, int presentation, int screening, unsigned char * buf, int len) 
+{
+        int oddeven, datalen;
+
+        if (!number[0] && presentation != SS7_PRESENTATION_ADDR_NOT_AVAILABLE)
+                return 0;
+
+        if (number[0] && presentation != SS7_PRESENTATION_ADDR_NOT_AVAILABLE)
+	{
+                isup_put_number(&buf[2], number, &datalen, &oddeven);
+	}
+        else 
+	{
+                datalen = 0;
+                oddeven = 0;
+                nai = 0;
+        }
+
+        buf[0] = (oddeven << 7) | nai;      /* Nature of Address Indicator */
+         /* Assume E.164 ISDN numbering plan, calling number complete */
+        buf[1] = ((presentation == SS7_PRESENTATION_ADDR_NOT_AVAILABLE) ? 0 : (1 << 4)) |
+                ((presentation & 0x3) << 2) |
+                (screening & 0x3);
+
+        return datalen + 2;
+}
+
+// returns start of specified optional header of IAM, otherwise return -1
+static int get_optional_header(unsigned char header, unsigned char *buf, int len)
+{
+	struct isup_iam_fixed * message = (struct isup_iam_fixed*)buf;
+	int offset = 0;
+	int res;
+
+	// not an iam? do nothing
+	if(message->type != ISUP_IAM)
+	{
+		return -1;
+	}
+
+	len -= offsetof(struct isup_iam_fixed, optional_pointer);
+	offset += offsetof(struct isup_iam_fixed, optional_pointer);
+
+	if (len < 1)
+		return -1;
+
+	offset += message->optional_pointer;
+	len -= message->optional_pointer;
+
+	if (len < 1 )
+		return -1;
+
+	/* Optional paramter parsing code */
+	if (message->optional_pointer) {
+		while ((len > 0) && (buf[offset] != 0)) {
+			struct isup_parm_opt *optparm = (struct isup_parm_opt *)(buf + offset);
+
+			res = optparm->len+2;
+			if(optparm->type == header)
+			{
+				return offset;
+			}
+
+			len -= res;
+			offset += res;
+		}
+	}
+	return -1;
+}
+
+int isup_get_hop_counter(unsigned char *buf, int len)
+{
+	int  offset = get_optional_header(ISUP_PARM_HOP_COUNTER, buf, len);
+
+	if(offset != -1 && len-offset-2 > 0)
+	{
+		return buf[offset+2] & 0x1F;
+	}
+	return -1;
+}
+
+int isup_get_cpc(unsigned char *buf, int len)
+{
+	struct isup_iam_fixed * message = (struct isup_iam_fixed*)buf;
+
+	// not an iam? do nothing
+	if(message->type != ISUP_IAM)
+	{
+		return -1;
+	}
+
+	/* Message Type = 1 */
+	len -= offsetof(struct isup_iam_fixed, calling_party_category);
+
+	if (len < 1)
+		return -1;
+
+	return (int)message->calling_party_category;
+}
+
+
+int isup_get_calling_party_nai(unsigned char *buf, int len)
+{
+	int  offset = get_optional_header(ISUP_PARM_CALLING_PARTY_NUM, buf, len);
+
+	if(offset != -1 && len-offset-2 > 0)
+	{
+		return buf[offset+2] & 0x7F;
+	}
+	return -1;
+}
+
+int isup_get_screening(unsigned char *buf, int len)
+{
+	int  offset = get_optional_header(ISUP_PARM_CALLING_PARTY_NUM, buf, len);
+
+	if(offset != -1 && len-offset-3 > 0)
+	{
+		return buf[offset+3] & 0x03;
+	}
+	return -1;
+}
+
+int isup_get_presentation(unsigned char *buf, int len)
+{
+	int  offset = get_optional_header(ISUP_PARM_CALLING_PARTY_NUM, buf, len);
+
+	if(offset != -1 && len-offset-3 > 0)
+	{
+		return (buf[offset+3]>>2) & 0x03;
+	}
+	return -1;
+}
+
+int isup_get_called_party_nai(unsigned char *buf, int len)
+{
+	struct isup_iam_fixed * message = (struct isup_iam_fixed*)buf;
+
+	// not an iam? do nothing
+	if(message->type != ISUP_IAM)
+	{
+		return -1;
+	}
+
+	/* Message Type = 1 */
+	len -= offsetof(struct isup_iam_fixed, called_party_number);
+
+	if (len < 1)
+		return -1;
+	return message->called_party_number[1]&0x7F;
+}
+
+int isup_update_destination(struct sdp_mangler * mangle, char * dest, int hops, int nai, unsigned char *buf, int len)
+{
+	int offset = 0;
+	int res, res2;
+	struct isup_iam_fixed * orig_message = (struct isup_iam_fixed*)buf;
+	unsigned char tmp_buf[255];
+
+
+	// not an iam? do nothing
+	if(orig_message->type != ISUP_IAM)
+	{
+		return 1;
+	}
+
+	// bounds checking
+	if(hops > 31)
+	{
+		hops = 31;
+	}
+
+
+
+	/* Copy the fixed parms */
+	len -= 6;
+	offset += 6;
+
+	if (len < 1)
+		return -1;
+
+	/* IAM has one Fixed variable param, Called party number, we need to modify this */
+
+	// pointer to fixed part (2)
+	offset++;
+
+	//pointer to optional part (to update later)
+	offset++;
+	len--;
+
+
+	// modify the mandatory fixed header
+	res2 = encode_called_party(dest, buf+offset+1, nai, tmp_buf+1, 255-1);
+	tmp_buf[0] = (char)res2;
+	res = buf[offset]+1;
+	
+	replace_body_segment(mangle, offset,res,tmp_buf, res2+1);
+
+	offset += res;
+	len -= res;
+	
+	if (len < 1 )
+		return -1;
+
+
+	/* Optional paramter parsing code */
+	if (orig_message->optional_pointer) {
+
+		bool has_hops = 0;
+		
+		while ((len > 0) && (buf[offset] != 0)) {
+			struct isup_parm_opt *optparm = (struct isup_parm_opt *)(buf + offset);
+
+
+			res = optparm->len+2;
+			switch(optparm->type)
+			{
+				case ISUP_PARM_HOP_COUNTER:
+					tmp_buf[0] = ISUP_PARM_HOP_COUNTER;
+					tmp_buf[1] = 1;
+					tmp_buf[2] = ((optparm->data[0]&0x1F)-1)&0x1F;
+					replace_body_segment(mangle, offset, res, tmp_buf, 3);
+					has_hops = 1;
+					break;
+				default:
+					break;
+			}
+
+			len -= res;
+			offset += res;
+		}
+
+		// add missing headers
+		if(!has_hops && len >= 0)
+		{
+			tmp_buf[0] = ISUP_PARM_HOP_COUNTER;
+			tmp_buf[1] = 1;
+			tmp_buf[2] = hops & 0x1F;
+			has_hops = 1;
+			add_body_segment(mangle, offset,tmp_buf,3);
+		}
+	}
+
+	return offset;
+}
+
+int isup_update_calling(struct sdp_mangler * mangle, char * origin, int nai, int presentation, int screening, unsigned char * buf, int len)
+{
+	int offset = 0;
+	int res;
+	struct isup_iam_fixed * orig_message = (struct isup_iam_fixed*)buf;
+
+	// not an iam? do nothing
+	if(orig_message->type != ISUP_IAM)
+	{
+		return 1;
+	}
+
+	/* Copy the fixed parms */
+	len -= offsetof(struct isup_iam_fixed, called_party_number);
+	offset += offsetof(struct isup_iam_fixed, called_party_number);
+
+	if (len < 1)
+		return -1;
+
+
+	/* IAM has one Fixed variable param, Called party number, we need to modify this */
+
+
+	// add the new mandatory fixed header
+	res = buf[offset];
+	offset += res+1;
+	len -= res+1;
+	
+	if (len < 1 )
+		return -1;
+
+
+	/* Optional paramter parsing code */
+	if (orig_message->optional_pointer) {
+
+		bool has_calling = 0;
+		
+		while ((len > 0) && (buf[offset] != 0)) {
+			int res2 = 0;
+			struct isup_parm_opt *optparm = (struct isup_parm_opt *)(buf + offset);
+			unsigned char new_party[255];
+
+
+			res = optparm->len+2;
+			switch(optparm->type)
+			{
+				case ISUP_PARM_CALLING_PARTY_NUM:
+					res2 = encode_calling_party(origin, nai, presentation, screening, &new_party[1], 255-1);
+					new_party[0] = (char)res2;
+					replace_body_segment(mangle, offset+1,(int)buf[offset+1],new_party, res2+1);
+
+					has_calling = 1;
+					break;
+				default:
+					break;
+			}
+
+			len -= res;
+			offset += res;
+		}
+
+
+		// add missing headers
+		if(!has_calling && len >= 0)
+		{
+			unsigned char new_party[255];
+			new_party[0] = ISUP_PARM_CALLING_PARTY_NUM;
+			res = encode_calling_party(origin, nai, presentation, screening, new_party+2, 255-2);
+			new_party[1] = (char)res;
+
+			add_body_segment(mangle, offset,new_party, res+2);
+		}
+
+	}
+
+	return offset;
+}
diff --git a/modules/siptrace/README b/modules/siptrace/README
index 7502008..bb8bb67 100644
--- a/modules/siptrace/README
+++ b/modules/siptrace/README
@@ -408,7 +408,7 @@ modparam("siptrace", "trace_delayed", 1)
 
    4.1. sip_trace()
 
-4.1. sip_trace()
+4.1.  sip_trace()
 
    Store current processed SIP message in database. It is stored in the
    form prior applying chages made to it.
@@ -425,7 +425,7 @@ sip_trace();
 
    5.1. sip_trace
 
-5.1. sip_trace
+5.1.  sip_trace
 
    Name: sip_trace
 
@@ -446,7 +446,7 @@ sip_trace();
 
    6.1. siptrace.status param
 
-6.1. siptrace.status param
+6.1.  siptrace.status param
 
    Name: siptrace.status
 
diff --git a/modules/siptrace/siptrace.c b/modules/siptrace/siptrace.c
index c333e76..40618db 100644
--- a/modules/siptrace/siptrace.c
+++ b/modules/siptrace/siptrace.c
@@ -1517,9 +1517,7 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 	struct timeval tvb;
 	struct timezone tz;
 	                 
-#if USE_IPV6
 	struct hep_ip6hdr hep_ip6header;
-#endif
 
 	if(body->s==NULL || body->len <= 0)
 		return -1;
@@ -1533,11 +1531,7 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 
 	/* message length */
 	len = body->len 
-#if USE_IPV6
 		+ sizeof(struct hep_ip6hdr)
-#else
-		+ sizeof(struct hep_iphdr)          
-#endif
 		+ sizeof(struct hep_hdr) + sizeof(struct hep_timehdr);;
 
 
@@ -1595,7 +1589,6 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 
 		len = sizeof(struct hep_iphdr);
 	}
-#ifdef USE_IPV6
 	else if (from_su.s.sa_family==AF_INET6){
 		/* prepare the hep6 headers */
 
@@ -1609,7 +1602,6 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 
 		len = sizeof(struct hep_ip6hdr);
 	}
-#endif /* USE_IPV6 */
 	else {
 		LOG(L_ERR, "ERROR: trace_send_hep_duplicate: Unsupported protocol family\n");
 		goto error;;
@@ -1638,12 +1630,10 @@ static int trace_send_hep_duplicate(str *body, str *from, str *to)
 		memcpy((void*)buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr));
 		buflen += sizeof(struct hep_iphdr);
 	}
-#if USE_IPV6
 	else {
 		memcpy((void*)buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr));
 		buflen += sizeof(struct hep_ip6hdr);
 	}
-#endif /* USE_IPV6 */
 
 	if(hep_version == 2) {
 
@@ -1700,6 +1690,8 @@ static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int
 	if(strncmp(pipport, "udp:",4) == 0) *proto = IPPROTO_UDP;
 	else if(strncmp(pipport, "tcp:",4) == 0) *proto = IPPROTO_TCP;
 	else if(strncmp(pipport, "tls:",4) == 0) *proto = IPPROTO_IDP; /* fake proto type */
+	else if(strncmp(pipport, "ws:",3) == 0) *proto = IPPROTO_IDP; /* fake proto type */
+	else if(strncmp(pipport, "wss:",4) == 0) *proto = IPPROTO_IDP; /* fake proto type */
 #ifdef USE_SCTP
 	else if(strncmp(pipport, "sctp:",5) == 0) cutlen = 5, *proto = IPPROTO_SCTP;
 #endif
@@ -1761,9 +1753,7 @@ static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int
 
 	/* check if it's an ip address */
 	if (((ip=str2ip(&host_uri))!=0)
-#ifdef  USE_IPV6
 			|| ((ip=str2ip6(&host_uri))!=0)
-#endif
 	   ) {
 		ip_addr2su(tmp_su, ip, ntohs(port_no));
 		return 0;	
diff --git a/modules/siputils/README b/modules/siputils/README
index 5367d23..978d0c4 100644
--- a/modules/siputils/README
+++ b/modules/siputils/README
@@ -84,15 +84,16 @@ Gabriel Vasile
               4.14. decode_contact_header()
               4.15. cmp_uri(str1, str2)
               4.16. cmp_aor(str1, str2)
-              4.17. is_rpid_user_e164()
-              4.18. append_rpid_hf()
-              4.19. append_rpid_hf(prefix, suffix)
-              4.20. is_rpid_user_e164()
-              4.21. set_uri_user(uri, user)
-              4.22. set_uri_host(uri, host)
-              4.23. is_request()
-              4.24. is_reply()
-              4.25. is_gruu([uri])
+              4.17. append_rpid_hf()
+              4.18. append_rpid_hf(prefix, suffix)
+              4.19. is_rpid_user_e164()
+              4.20. set_uri_user(uri, user)
+              4.21. set_uri_host(uri, host)
+              4.22. is_request()
+              4.23. is_reply()
+              4.24. is_gruu([uri])
+              4.25. is_supported(option)
+              4.26. is_first_hop()
 
    List of Examples
 
@@ -121,15 +122,16 @@ Gabriel Vasile
    1.23. decode_contact_header usage
    1.24. cmp_uri usage
    1.25. cmp_aor usage
-   1.26. is_rpid_user_e164 usage
-   1.27. append_rpid_hf usage
-   1.28. append_rpid_hf(prefix, suffix) usage
-   1.29. is_rpid_user_e164 usage
-   1.30. set_uri_user usage
-   1.31. set_uri_host usage
-   1.32. is_request usage
-   1.33. is_reply usage
-   1.34. is_gruu() usage
+   1.26. append_rpid_hf usage
+   1.27. append_rpid_hf(prefix, suffix) usage
+   1.28. is_rpid_user_e164 usage
+   1.29. set_uri_user usage
+   1.30. set_uri_host usage
+   1.31. is_request usage
+   1.32. is_reply usage
+   1.33. is_gruu() usage
+   1.34. is_supported() usage
+   1.35. is_first_hop() usage
 
 Chapter 1. Admin Guide
 
@@ -171,15 +173,16 @@ Chapter 1. Admin Guide
         4.14. decode_contact_header()
         4.15. cmp_uri(str1, str2)
         4.16. cmp_aor(str1, str2)
-        4.17. is_rpid_user_e164()
-        4.18. append_rpid_hf()
-        4.19. append_rpid_hf(prefix, suffix)
-        4.20. is_rpid_user_e164()
-        4.21. set_uri_user(uri, user)
-        4.22. set_uri_host(uri, host)
-        4.23. is_request()
-        4.24. is_reply()
-        4.25. is_gruu([uri])
+        4.17. append_rpid_hf()
+        4.18. append_rpid_hf(prefix, suffix)
+        4.19. is_rpid_user_e164()
+        4.20. set_uri_user(uri, user)
+        4.21. set_uri_host(uri, host)
+        4.22. is_request()
+        4.23. is_reply()
+        4.24. is_gruu([uri])
+        4.25. is_supported(option)
+        4.26. is_first_hop()
 
 1. Overview
 
@@ -371,15 +374,16 @@ modparam("auth", "rpid_avp", "$avp(myrpid)")
    4.14. decode_contact_header()
    4.15. cmp_uri(str1, str2)
    4.16. cmp_aor(str1, str2)
-   4.17. is_rpid_user_e164()
-   4.18. append_rpid_hf()
-   4.19. append_rpid_hf(prefix, suffix)
-   4.20. is_rpid_user_e164()
-   4.21. set_uri_user(uri, user)
-   4.22. set_uri_host(uri, host)
-   4.23. is_request()
-   4.24. is_reply()
-   4.25. is_gruu([uri])
+   4.17. append_rpid_hf()
+   4.18. append_rpid_hf(prefix, suffix)
+   4.19. is_rpid_user_e164()
+   4.20. set_uri_user(uri, user)
+   4.21. set_uri_host(uri, host)
+   4.22. is_request()
+   4.23. is_reply()
+   4.24. is_gruu([uri])
+   4.25. is_supported(option)
+   4.26. is_first_hop()
 
 4.1. ring_insert_callid()
 
@@ -680,24 +684,7 @@ if(cmp_aor("$rU at KaMaIlIo.org", "sip:kamailio@$fd"))
 }
 ...
 
-4.17. is_rpid_user_e164()
-
-   The function checks if the SIP URI received from the database or radius
-   server and will potentially be used in Remote-Party-ID header field
-   contains an E164 number (+followed by up to 15 decimal digits) in its
-   user part. Check fails, if no such SIP URI exists (i.e. radius server
-   or database didn't provide this information).
-
-   This function can be used from REQUEST_ROUTE.
-
-   Example 1.26. is_rpid_user_e164 usage
-...
-if (is_rpid_user_e164()) {
-    # do something here
-};
-...
-
-4.18. append_rpid_hf()
+4.17. append_rpid_hf()
 
    Appends to the message a Remote-Party-ID header that contains header
    'Remote-Party-ID: ' followed by the saved value of the SIP URI received
@@ -708,14 +695,14 @@ if (is_rpid_user_e164()) {
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
 
-   Example 1.27. append_rpid_hf usage
+   Example 1.26. append_rpid_hf usage
 ...
 append_rpid_hf();  # Append Remote-Party-ID header field
 ...
 
-4.19. append_rpid_hf(prefix, suffix)
+4.18. append_rpid_hf(prefix, suffix)
 
-   This function is the same as Section 4.18, " append_rpid_hf()". The
+   This function is the same as Section 4.17, " append_rpid_hf()". The
    only difference is that it accepts two parameters--prefix and suffix to
    be added to Remote-Party-ID header field. This function ignores
    rpid_prefix and rpid_suffix parameters, instead of that allows to set
@@ -732,13 +719,13 @@ append_rpid_hf();  # Append Remote-Party-ID header field
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
 
-   Example 1.28. append_rpid_hf(prefix, suffix) usage
+   Example 1.27. append_rpid_hf(prefix, suffix) usage
 ...
 # Append Remote-Party-ID header field
 append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes");
 ...
 
-4.20. is_rpid_user_e164()
+4.19. is_rpid_user_e164()
 
    The function checks if the SIP URI received from the database or radius
    server and will potentially be used in Remote-Party-ID header field
@@ -748,68 +735,68 @@ append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes");
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.29. is_rpid_user_e164 usage
+   Example 1.28. is_rpid_user_e164 usage
 ...
 if (is_rpid_user_e164()) {
     # do something here
 };
 ...
 
-4.21. set_uri_user(uri, user)
+4.20. set_uri_user(uri, user)
 
    Sets userpart of SIP URI stored in writable pseudo variable 'uri' to
    value of pseudo variable 'user'.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.30. set_uri_user usage
+   Example 1.29. set_uri_user usage
 ...
 $var(uri) = "sip:user at host";
 $var(user) = "new_user";
 set_uri_user("$var(uri)", "$var(user)");
 ...
 
-4.22. set_uri_host(uri, host)
+4.21. set_uri_host(uri, host)
 
    Sets hostpart of SIP URI stored in writable pseudo variable 'uri' to
    value of pseudo variable 'host'.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.31. set_uri_host usage
+   Example 1.30. set_uri_host usage
 ...
 $var(uri) = "sip:user at host";
 $var(host) = "new_host";
 set_uri_host("$var(uri)", "$var(host)");
 ...
 
-4.23. is_request()
+4.22. is_request()
 
    Return true if the SIP message is a request.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.32. is_request usage
+   Example 1.31. is_request usage
 ...
 if (is_request()) {
         ...
 }
 ...
 
-4.24. is_reply()
+4.23. is_reply()
 
    Return true if the SIP message is a reply.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.33. is_reply usage
+   Example 1.32. is_reply usage
 ...
 if (is_reply()) {
         ...
 }
 ...
 
-4.25. is_gruu([uri])
+4.24. is_gruu([uri])
 
    The function returns true if the uri is GRUU ('gr' parameter is
    present): 1 - pub-gruu; 2 - temp-gruu.
@@ -820,7 +807,37 @@ if (is_reply()) {
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.34. is_gruu() usage
+   Example 1.33. is_gruu() usage
 ...
 if(is_gruu()) { ... }
 ...
+
+4.25. is_supported(option)
+
+   Function returns true if given option is listed in Supported header(s)
+   (if any) of the request. Currently the following options are known:
+   path, 100rel, timer, eventlist, gruu, and outbound.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.34. is_supported() usage
+...
+if (is_supported("outbound")) { ... }
+...
+
+4.26. is_first_hop()
+
+   The function returns true if the proxy is first hop after the original
+   sender. For incoming SIP requests, it means there is only one Via
+   header. For incoming SIP replies, it means that top Record-Route URI is
+   'myself' and source address is not matching it (to avoid detecting in
+   case of local loops). Note that it does not detect spirals, which can
+   have the condition for replies true also in the case of additional SIP
+   reply receival.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.35. is_first_hop() usage
+...
+if(is_first_hop()) { ... }
+...
diff --git a/modules/siputils/doc/siputils_admin.xml b/modules/siputils/doc/siputils_admin.xml
index 8435b9a..eefb56c 100644
--- a/modules/siputils/doc/siputils_admin.xml
+++ b/modules/siputils/doc/siputils_admin.xml
@@ -274,7 +274,7 @@ modparam("auth", "rpid_avp", "$avp(myrpid)")
 
 	<section>
 	<title>Functions</title>
-		<section>
+		<section id="siputils.f.ring_insert_callid">
 			<title>
 				<function moreinfo="none">ring_insert_callid()</function>
 			</title>
@@ -298,8 +298,8 @@ ring_insert_callid();
 ...
 				</programlisting>
 			</example>
-		</section>
-			<section>
+	</section>
+	<section id="siputils.f.options_reply">
 		<title>
 		<function moreinfo="none">options_reply()</function>
 		</title>
@@ -340,7 +340,7 @@ if (uri==myself) {
 		</example>
 	</section>
 
-	<section>
+	<section id="siputils.f.is_user">
 		<title>
 		<function moreinfo="none">is_user(username)</function>
 		</title>
@@ -368,7 +368,7 @@ if (is_user("john")) {
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.has_totag()">
 		<title>
 		<function moreinfo="none">has_totag()</function>
 		</title>
@@ -390,7 +390,7 @@ if (has_totag()) {
 		</example>
 	</section>
 	<section>
-		<title>
+		<title id="siputils.f.uri_param">
 		<function moreinfo="none">uri_param(param)</function>
 		</title>
 		<para>
@@ -417,7 +417,7 @@ if (uri_param("param1")) {
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.uri_param_value">
 		<title>
 		<function moreinfo="none">uri_param(param,value)</function>
 		</title>
@@ -449,7 +449,7 @@ if (uri_param("param1","value1")) {
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.add_uri_param">
 		<title>
 		<function moreinfo="none">add_uri_param(param)</function>
 		</title>
@@ -476,7 +476,7 @@ add_uri_param("nat=yes");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.get_uri_param">
 		<title>
 		<function moreinfo="none">get_uri_param(name, var)</function>
 		</title>
@@ -505,7 +505,7 @@ get_uri_param("nat", "$var(nat)");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.tel2sip">
 		<title>
 		<function moreinfo="none">tel2sip(uri, hostpart, result)</function>
 		</title>
@@ -553,7 +553,7 @@ tel2sip("$ru", $fd", "$ru");
 		</example>
 	</section>
 
-	<section>
+	<section id="siputils.f.is_e164">
 		<title>
 		<function moreinfo="none">is_e164(pseudo-variable)</function>
 		</title>
@@ -581,7 +581,7 @@ if (is_e164("$avp(i:705)") {
 		</example>
 	</section>
 
-	<section>
+	<section id="siputils.f.is_uri_user_e164">
 		<title>
 		<function moreinfo="none">is_uri_user_e164(pseudo-variable)</function>
 		</title>
@@ -608,7 +608,7 @@ if (is_uri_user_e164("$avp(i:705)") {
 		</example>
 	</section>
 
-	<section>
+	<section id="siputils.f.encode_contact">
 		<title>
 		<function moreinfo="none">encode_contact(encoding_prefix,hostpart)</function>
 		</title>
@@ -654,7 +654,7 @@ if (src_ip == 10.0.0.0/8) encode_contact("natted_client","1.2.3.4");
 		</example>
 	</section>
 
-	<section>
+	<section id="siputils.f.decode_contact">
 		<title>
 		<function moreinfo="none">decode_contact()</function>
 		</title>
@@ -681,7 +681,7 @@ if (uri =~ "^sip:natted_client") { decode_contact(); }
 		</example>
 	</section>
 
-	<section>
+	<section id="siputils.f.decode_contact_header">
 		<title>
 		<function moreinfo="none">decode_contact_header()</function>
 		</title>
@@ -711,7 +711,7 @@ reply_route[2] {
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.cmp_uri">
 		<title>
 		<function moreinfo="none">cmp_uri(str1, str2)</function>
 		</title>
@@ -735,7 +735,7 @@ if(cmp_uri("$ru", "sip:kamailio at kamailio.org"))
 		</example>
 	</section>
 
-	<section>
+	<section id="siputils.f.cmp_aor">
 		<title>
 		<function moreinfo="none">cmp_aor(str1, str2)</function>
 		</title>
@@ -759,32 +759,7 @@ if(cmp_aor("$rU at KaMaIlIo.org", "sip:kamailio@$fd"))
 </programlisting>
 		</example>
 	</section>
-	<section>
-		<title>
-			<function moreinfo="none">is_rpid_user_e164()</function>
-		</title>
-		<para>
-		The function checks if the SIP URI received from the database or 
-		radius server and will potentially be used in Remote-Party-ID header 
-		field contains an E164 number (+followed by up to 15 decimal digits) 
-		in its user part.  Check fails, if no such SIP URI exists 
-		(i.e. radius server or database didn't provide this information).
-		</para>
-		<para>
-		This function can be used from REQUEST_ROUTE.
-		</para>
-		<example>
-		<title>is_rpid_user_e164 usage</title>
-		<programlisting format="linespecific">
-...
-if (is_rpid_user_e164()) {
-    # do something here
-};
-...
-</programlisting>
-		</example>
-	</section>
-	<section id="append-rpid-hf-no-params">
+	<section  id="siputils.f.append_rpid_hf">
 		<title>
 			<function moreinfo="none">append_rpid_hf()</function></title>
 		<para>
@@ -807,13 +782,13 @@ append_rpid_hf();  # Append Remote-Party-ID header field
 </programlisting>
 		</example>
 	</section>
-	<section id="append-rpid-hf-params">
+	<section id="siputils.f.append_rpid_hf_params">
 		<title>
 			<function moreinfo="none">append_rpid_hf(prefix, suffix)</function>
 		</title>
 		<para>
 		This function is the same as 
-		<xref linkend="append-rpid-hf-no-params"/>. The only difference is
+		<xref linkend="siputils.f.append_rpid_hf"/>. The only difference is
 		that it accepts two parameters--prefix and suffix to be added to 
 		Remote-Party-ID header field. This function ignores rpid_prefix and 
 		rpid_suffix parameters, instead of that allows to set them in every 
@@ -850,7 +825,7 @@ append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes");
 		</example>
 	</section>
 	<section>
-		<title>
+		<title id="siputils.f.is_rpid_user_e164">
 			<function moreinfo="none">is_rpid_user_e164()</function>
 		</title>
 		<para>
@@ -874,7 +849,7 @@ if (is_rpid_user_e164()) {
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.set_uri_user">
 		<title>
 			<function moreinfo="none">set_uri_user(uri, user)</function>
 		</title>
@@ -896,7 +871,7 @@ set_uri_user("$var(uri)", "$var(user)");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.set_uri_host">
 		<title>
 			<function moreinfo="none">set_uri_host(uri, host)</function>
 		</title>
@@ -918,7 +893,7 @@ set_uri_host("$var(uri)", "$var(host)");
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.is_request">
 		<title>
 		<function moreinfo="none">is_request()</function>
 		</title>
@@ -939,7 +914,7 @@ if (is_request()) {
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="siputils.f.is_reply">
 		<title>
 		<function moreinfo="none">is_reply()</function>
 		</title>
@@ -960,7 +935,7 @@ if (is_reply()) {
 </programlisting>
 		</example>
 	</section>
-	<section id="is-gruu">
+	<section id="siputils.f.is_gruu">
 		<title>
 			<function moreinfo="none">is_gruu([uri])</function>
 		</title>
@@ -989,6 +964,54 @@ if(is_gruu()) { ... }
 </programlisting>
 		</example>
 	</section>
+	<section id="siputils.f.is_supported">
+		<title>
+			<function moreinfo="none">is_supported(option)</function>
+		</title>
+		<para>
+			Function returns true if given option is listed
+			in Supported header(s) (if any) of the request.
+			Currently the following options are known: path,
+			100rel, timer, eventlist, gruu, and outbound.
+			
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title>is_supported() usage</title>
+		<programlisting format="linespecific">
+...
+if (is_supported("outbound")) { ... }
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="siputils.f.is_first_hop">
+		<title>
+			<function moreinfo="none">is_first_hop()</function>
+		</title>
+		<para>
+		The function returns true if the proxy is first hop after the
+		original sender. For incoming SIP requests, it means there is only
+		one Via header. For incoming SIP replies, it means that top
+		Record-Route URI is 'myself' and source address is not matching it
+		(to avoid detecting in case of local loops). Note that it does not
+		detect spirals, which can have the condition for replies true also
+		in the case of additional SIP reply receival.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title>is_first_hop() usage</title>
+		<programlisting format="linespecific">
+...
+if(is_first_hop()) { ... }
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 
 </chapter>
diff --git a/modules/siputils/sipops.c b/modules/siputils/sipops.c
index 3ee7566..357d92c 100644
--- a/modules/siputils/sipops.c
+++ b/modules/siputils/sipops.c
@@ -33,6 +33,11 @@
 
 #include "../../mod_fix.h"
 #include "../../parser/parse_uri.h"
+#include "../../parser/parse_supported.h"
+#include "../../parser/parse_rr.h"
+#include "../../ip_addr.h"
+#include "../../resolve.h"
+#include "../../forward.h"
 #include "../../lib/kcore/cmpapi.h"
 
 #include "sipops.h"
@@ -114,3 +119,86 @@ int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2)
 	}
 	return -1;
 }
+
+int w_is_supported(sip_msg_t *msg, char *_option, char *p2)
+{
+	unsigned long option;
+
+	option = (unsigned long)_option;
+
+	if (parse_supported(msg) < 0)
+		return -1;
+
+	if ((((struct option_tag_body*)msg->supported->parsed)->option_tags_all &
+				option) == 0)
+		return -1;
+	else
+		return 1;
+}
+
+
+int w_is_first_hop(sip_msg_t *msg, char *p1, char *p2)
+{
+	int ret;
+	rr_t* r = NULL;
+	sip_uri_t puri;
+	struct ip_addr *ip;
+
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REQUEST) {
+		if (parse_headers( msg, HDR_VIA2_F, 0 )<0
+				|| (msg->via2==0) || (msg->via2->error!=PARSE_OK))
+		{
+			/* sip request: if more than one via, then not first hop */
+			/* no second via or error */
+			LM_DBG("no 2nd via found - first hop\n");
+			return 1;
+		}
+		return -1;
+	} else if(msg->first_line.type == SIP_REPLY) {
+		/* sip reply: if top record-route is myself
+		 * and not received from myself (loop), then is first hop */
+		if (parse_headers( msg, HDR_EOH_F, 0 )<0) {
+			LM_DBG("error parsing headers\n");
+			return -1;
+		}
+		if(msg->record_route==NULL) {
+			LM_DBG("no record-route header - first hop\n");
+			return 1;
+		}
+		if(parse_rr(msg->record_route)<0) {
+			LM_DBG("failed to parse first record-route header\n");
+			return -1;
+		}
+		r = (rr_t*)msg->record_route->parsed;
+		if(parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &puri)<0) {
+			LM_DBG("failed to parse uri in first record-route header\n");
+			return -1;
+		}
+		if (((ip = str2ip(&(puri.host))) == NULL)
+				&& ((ip = str2ip6(&(puri.host))) == NULL)) {
+			LM_DBG("uri host is not an ip address\n");
+			return -1;
+		}
+		ret = check_self(&puri.host, (puri.port.s)?puri.port_no:0,
+				(puri.transport_val.s)?puri.proto:0);
+		if(ret!=1) {
+			LM_DBG("top record route uri is not myself\n");
+			return -1;
+		}
+		if (ip_addr_cmp(ip, &(msg->rcv.src_ip))
+				&& ((msg->rcv.src_port == puri.port_no)
+					|| ((puri.port.len == 0) && (msg->rcv.src_port == 5060)))
+				&& (puri.proto==msg->rcv.proto
+					|| (puri.proto==0 && msg->rcv.proto==PROTO_UDP)) ) {
+			LM_DBG("source address matches top record route uri - loop\n");
+			return -1;
+		}
+		/* todo - check spirals */
+		return 1;
+	} else {
+		return -1;
+	}
+}
diff --git a/modules/siputils/sipops.h b/modules/siputils/sipops.h
index 7f8f0e0..40ecc7d 100644
--- a/modules/siputils/sipops.h
+++ b/modules/siputils/sipops.h
@@ -39,5 +39,7 @@
 int w_cmp_uri(struct sip_msg *msg, char *uri1, char *uri2);
 int w_cmp_aor(struct sip_msg *msg, char *uri1, char *uri2);
 int w_is_gruu(sip_msg_t *msg, char *uri1, char *p2);
+int w_is_supported(sip_msg_t *msg, char *_option, char *p2);
+int w_is_first_hop(sip_msg_t *msg, char *uri1, char *p2);
 
 #endif
diff --git a/modules/siputils/siputils.c b/modules/siputils/siputils.c
index afa9953..80ba20e 100644
--- a/modules/siputils/siputils.c
+++ b/modules/siputils/siputils.c
@@ -65,6 +65,7 @@
 #include "../../ut.h"
 #include "../../mod_fix.h"
 #include "../../error.h"
+#include "../../parser/parse_option_tags.h"
 
 #include "ring.h"
 #include "options.h"
@@ -112,6 +113,7 @@ static int fixup_free_set_uri(void** param, int param_no);
 static int fixup_tel2sip(void** param, int param_no);
 static int fixup_get_uri_param(void** param, int param_no);
 static int free_fixup_get_uri_param(void** param, int param_no);
+static int fixup_option(void** param, int param_no);
 
 
 char *contact_flds_separator = DEFAULT_SEPARATOR;
@@ -169,6 +171,10 @@ static cmd_export_t cmds[]={
 		0, ANY_ROUTE},
 	{"is_gruu",  (cmd_function)w_is_gruu,                    1, fixup_spve_null,
 		0, ANY_ROUTE},
+	{"is_supported",  (cmd_function)w_is_supported,                    1, fixup_option,
+		0, ANY_ROUTE},
+	{"is_first_hop",  (cmd_function)w_is_first_hop,                    0, 0,
+		0, ANY_ROUTE},
 	{0,0,0,0,0,0}
 };
 
@@ -375,3 +381,69 @@ static int free_fixup_get_uri_param(void** param, int param_no) {
 	LM_ERR("invalid parameter number <%d>\n", param_no);
 	return -1;
 }
+
+/* */
+static int fixup_option(void** param, int param_no) {
+
+    char *option;
+    unsigned int option_len, res;
+
+    option = (char *)*param;
+    option_len = strlen(option);
+
+    if (param_no != 1) {
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+    }
+
+    switch (option_len) {
+    case 4:
+	if (strncasecmp(option, "path", 4) == 0)
+	    res = F_OPTION_TAG_PATH;
+	else if (strncasecmp(option, "gruu", 4) == 0)
+	    res = F_OPTION_TAG_GRUU;
+	else {
+	    LM_ERR("unknown option <%s>\n", option);
+	    return -1;
+	}
+	break;
+    case 5:
+	if (strncasecmp(option, "timer", 5) == 0)
+	    res = F_OPTION_TAG_TIMER;
+	else {
+	    LM_ERR("unknown option <%s>\n", option);
+	    return -1;
+	}
+	break;
+    case 6:
+	if (strncasecmp(option, "100rel", 6) == 0)
+	    res = F_OPTION_TAG_100REL;
+	else {
+	    LM_ERR("unknown option <%s>\n", option);
+	    return -1;
+	}
+	break;
+    case 8:
+	if (strncasecmp(option, "outbound", 8) == 0)
+	    res = F_OPTION_TAG_OUTBOUND;
+	else {
+	    LM_ERR("unknown option <%s>\n", option);
+	    return -1;
+	}
+	break;
+    case 9:
+	if (strncasecmp(option, "eventlist", 9) == 0)
+	    res = F_OPTION_TAG_EVENTLIST;
+	else {
+	    LM_ERR("unknown option <%s>\n", option);
+	    return -1;
+	}
+	break;
+    default:
+	LM_ERR("unknown option <%s>\n", option);
+	return -1;
+    }
+
+    *param = (void *)(long)res;
+    return 0;
+}
diff --git a/modules/sl/README b/modules/sl/README
index 447f700..5d7723d 100644
--- a/modules/sl/README
+++ b/modules/sl/README
@@ -1,4 +1,3 @@
-
 The SL Module - Statless request handling
 
 Bogdan Iancu
@@ -10,7 +9,7 @@ Daniel-Constantin Mierla
    asipto.com
 
    Copyright � 2003 FhG FOKUS
-     _________________________________________________________________
+     __________________________________________________________________
 
    Table of Contents
 
@@ -25,10 +24,10 @@ Daniel-Constantin Mierla
 
         3. Functions
 
-              3.1. sl_send_reply(code, reason) 
-              3.2. send_reply(code, reason) 
-              3.3. sl_reply_error() 
-              3.4. sl_forward _reply([ code, [ reason ] ]) 
+              3.1. sl_send_reply(code, reason)
+              3.2. send_reply(code, reason)
+              3.3. sl_reply_error()
+              3.4. sl_forward _reply([ code, [ reason ] ])
 
         4. Statistics
 
@@ -80,10 +79,10 @@ Chapter 1. Admin Guide
 
    3. Functions
 
-        3.1. sl_send_reply(code, reason) 
-        3.2. send_reply(code, reason) 
-        3.3. sl_reply_error() 
-        3.4. sl_forward _reply([ code, [ reason ] ]) 
+        3.1. sl_send_reply(code, reason)
+        3.2. send_reply(code, reason)
+        3.3. sl_reply_error()
+        3.4. sl_forward _reply([ code, [ reason ] ])
 
    4. Statistics
 
@@ -114,31 +113,30 @@ Chapter 1. Admin Guide
 
 1. Overview
 
-   The  SL  module  allows the SIP server to act as a stateless UA server
-   and  generate  replies  to SIP requests without keeping state. That is
+   The SL module allows the SIP server to act as a stateless UA server and
+   generate replies to SIP requests without keeping state. That is
    beneficial in many scenarios, in which you wish not to burden server's
    memory and scale well.
 
-   The  SL module needs to filter ACKs sent after a local stateless reply
+   The SL module needs to filter ACKs sent after a local stateless reply
    to an INVITE was generated. To recognize such ACKs, ser adds a special
    "signature" in to-tags. This signature is sought for in incoming ACKs,
    and if included, the ACKs are absorbed.
 
-   To  speed  up  the  filtering  process,  the  module  uses  a  timeout
-   mechanism.  When a reply is sent, a timer us set. As long as the timer
-   is  valid,  the  incoming  ACK  requests  will be checked using TO tag
-   value.  Once the timer expires, all the ACK messages are let through -
-   a long time passed till it sent a reply, so it does not expect any ACK
-   that have to be blocked.
-
-   The  ACK  filtering  may  fail  in some rare cases. If you think these
-   matter  to  you, better use stateful processing (TM module) for INVITE
-   processing.  Particularly,  the  problem  happens  when  a UA sends an
-   INVITE  which  already  has a to-tag in it (e.g., a re-INVITE) and the
-   server  want  to  reply  to it. Then, it will keep the current to-tag,
-   which  will  be  mirrored  in  ACK. SER will not see its signature and
-   forward the ACK downstream. Caused harm is not bad--just a useless ACK
-   is forwarded.
+   To speed up the filtering process, the module uses a timeout mechanism.
+   When a reply is sent, a timer us set. As long as the timer is valid,
+   the incoming ACK requests will be checked using TO tag value. Once the
+   timer expires, all the ACK messages are let through - a long time
+   passed till it sent a reply, so it does not expect any ACK that have to
+   be blocked.
+
+   The ACK filtering may fail in some rare cases. If you think these
+   matter to you, better use stateful processing (TM module) for INVITE
+   processing. Particularly, the problem happens when a UA sends an INVITE
+   which already has a to-tag in it (e.g., a re-INVITE) and the server
+   want to reply to it. Then, it will keep the current to-tag, which will
+   be mirrored in ACK. SER will not see its signature and forward the ACK
+   downstream. Caused harm is not bad--just a useless ACK is forwarded.
 
 2. Parameters
 
@@ -170,7 +168,7 @@ modparam("sl", "default_reason", "Server Error")
 
 2.3. bind_tm (int)
 
-   Controls  if SL module should attempt to bind to TM module in order to
+   Controls if SL module should attempt to bind to TM module in order to
    send stateful reply when the transaction is created.
 
    Default value is 1 (enabled).
@@ -182,17 +180,16 @@ modparam("sl", "bind_tm", 0)  # feature disabled
 
 3. Functions
 
-   3.1. sl_send_reply(code, reason) 
-   3.2. send_reply(code, reason) 
-   3.3. sl_reply_error() 
-   3.4. sl_forward _reply([ code, [ reason ] ]) 
+   3.1. sl_send_reply(code, reason)
+   3.2. send_reply(code, reason)
+   3.3. sl_reply_error()
+   3.4. sl_forward _reply([ code, [ reason ] ])
 
-3.1.  sl_send_reply(code, reason)
+3.1. sl_send_reply(code, reason)
 
-   For  the  current  request, a reply is sent back having the given code
-   and  text  reason. The reply is sent stateless, totally independent of
-   the  Transaction  module  and  with no retransmission for the INVITE's
-   replies.
+   For the current request, a reply is sent back having the given code and
+   text reason. The reply is sent stateless, totally independent of the
+   Transaction module and with no retransmission for the INVITE's replies.
 
    Meaning of the parameters is as follows:
      * code - Return code.
@@ -203,19 +200,20 @@ modparam("sl", "bind_tm", 0)  # feature disabled
 sl_send_reply("404", "Not found");
 ...
 
-3.2.  send_reply(code, reason)
+3.2. send_reply(code, reason)
 
-   For  the  current  request, a reply is sent back having the given code
-   and text reason. The reply is sent stateful or stateless, depending of
-   the  TM  module: if a transaction exists for the current request, then
-   the reply is sent statefully, otherwise stateless.
+   For the current request, a reply is sent back having the given code and
+   text reason. The reply is sent stateful or stateless, depending of the
+   TM module: if a transaction exists for the current request, then the
+   reply is sent statefully, otherwise stateless.
 
    Meaning of the parameters is as follows:
      * code - Return code.
      * reason - Reason phrase.
 
-   This   function   can   be  used  from  REQUEST_ROUTE,  FAILURE_ROUTE,
-   BRANCH_ROUTE.
+   This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. It can
+   be used on ONREPLY_ROUTE executed by tm module (upon a t_on_reply()
+   callback).
 
    Example 1.5. send_reply usage
 ...
@@ -224,10 +222,10 @@ send_reply("404", "Not found");
 send_reply("403", "Invalid user - $fU");
 ...
 
-3.3.  sl_reply_error()
+3.3. sl_reply_error()
 
-   Sends  back  an error reply describing the nature of the last internal
-   error.  Usually  this  function should be used after a script function
+   Sends back an error reply describing the nature of the last internal
+   error. Usually this function should be used after a script function
    that returned an error code.
 
    Example 1.6. sl_reply_error usage
@@ -235,11 +233,11 @@ send_reply("403", "Invalid user - $fU");
 sl_reply_error();
 ...
 
-3.4.  sl_forward _reply([ code, [ reason ] ])
+3.4. sl_forward _reply([ code, [ reason ] ])
 
-   Forward  statelessy the current received SIP reply, with the option to
-   change  the status code and reason text. The new code has to be in the
-   same  class.  The received reply is forwarded as well by core when the
+   Forward statelessy the current received SIP reply, with the option to
+   change the status code and reason text. The new code has to be in the
+   same class. The received reply is forwarded as well by core when the
    config execution ended, unless it is dropped from config.
 
    Meaning of the parameters is as follows:
diff --git a/modules/sl/doc/sl_functions.xml b/modules/sl/doc/sl_functions.xml
index bf58ce0..1420e86 100644
--- a/modules/sl/doc/sl_functions.xml
+++ b/modules/sl/doc/sl_functions.xml
@@ -59,8 +59,9 @@ sl_send_reply("404", "Not found");
 		</listitem>
 		</itemizedlist>
 		<para>
-			This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-			BRANCH_ROUTE.
+			This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.
+			It can be used on ONREPLY_ROUTE executed by tm module (upon a
+			t_on_reply() callback).
 		</para>
 		<example>
 		<title><function>send_reply</function> usage</title>
diff --git a/modules/sl/sl.c b/modules/sl/sl.c
index 87449fd..fb8a1ee 100644
--- a/modules/sl/sl.c
+++ b/modules/sl/sl.c
@@ -78,8 +78,6 @@ MODULE_VERSION
 static int default_code = 500;
 static str default_reason = STR_STATIC_INIT("Internal Server Error");
 
-int _sl_filtered_ack_route = -1; /* default disabled */
-
 static int sl_bind_tm = 1;
 static struct tm_binds tmb;
 
@@ -101,7 +99,7 @@ static cmd_export_t cmds[]={
 	{"sl_reply",       w_sl_send_reply,             2, fixup_sl_reply,
 		REQUEST_ROUTE},
 	{"send_reply",     w_send_reply,                2, fixup_sl_reply,
-		REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
+		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE},
 	{"sl_reply_error", w_sl_reply_error,            0, 0,
 		REQUEST_ROUTE},
 	{"sl_forward_reply",  w_sl_forward_reply0,      0, 0,
@@ -176,9 +174,7 @@ static int mod_init(void)
 		}
 	}
 
-	_sl_filtered_ack_route=route_lookup(&event_rt, "sl:filtered-ack");
-	if (_sl_filtered_ack_route>=0 && event_rt.rlist[_sl_filtered_ack_route]==0)
-		_sl_filtered_ack_route=-1; /* disable */
+	sl_lookup_event_routes();
 
 	return 0;
 }
@@ -286,6 +282,9 @@ int send_reply(struct sip_msg *msg, int code, str *reason)
 		}
 	}
 
+	if(msg->first_line.type==SIP_REPLY)
+		goto error;
+
 	LM_DBG("reply in stateless mode (sl)\n");
 	ret = sl_send_reply(msg, code, r);
 
diff --git a/modules/sl/sl_funcs.c b/modules/sl/sl_funcs.c
index 388f79c..c642249 100644
--- a/modules/sl/sl_funcs.c
+++ b/modules/sl/sl_funcs.c
@@ -75,7 +75,24 @@ static char           *tag_suffix;
    we do not filter */
 static unsigned int  *sl_timeout;
 
-extern int _sl_filtered_ack_route;
+static int _sl_filtered_ack_route = -1; /* default disabled */
+
+static int _sl_evrt_local_response = -1; /* default disabled */
+
+/*!
+ * lookup sl event routes
+ */
+void sl_lookup_event_routes(void)
+{
+	_sl_filtered_ack_route=route_lookup(&event_rt, "sl:filtered-ack");
+	if (_sl_filtered_ack_route>=0 && event_rt.rlist[_sl_filtered_ack_route]==0)
+		_sl_filtered_ack_route=-1; /* disable */
+
+	 _sl_evrt_local_response = route_lookup(&event_rt, "sl:local-response");
+	if (_sl_evrt_local_response>=0
+			&& event_rt.rlist[_sl_evrt_local_response]==NULL)
+		_sl_evrt_local_response = -1;
+}
 
 /*!
  * init sl internal structures
@@ -133,7 +150,7 @@ int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag)
 	int backup_mhomed, ret;
 	str text;
 
-	int rt, backup_rt;
+	int backup_rt;
 	struct run_act_ctx ctx;
 	struct sip_msg pmsg;
 
@@ -207,8 +224,7 @@ int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag)
 	ret = msg_send(&dst, buf.s, buf.len);
 	mhomed=backup_mhomed;
 
-	rt = route_lookup(&event_rt, "sl:local-response");
-	if (unlikely(rt >= 0 && event_rt.rlist[rt] != NULL))
+	if (unlikely(_sl_evrt_local_response >= 0))
 	{
 		if (likely(build_sip_msg_from_buf(&pmsg, buf.s, buf.len,
 				inc_msg_no()) == 0))
@@ -277,7 +293,7 @@ int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag)
 			backup_rt = get_route_type();
 			set_route_type(LOCAL_ROUTE);
 			init_run_actions_ctx(&ctx);
-			run_top_route(event_rt.rlist[rt], &pmsg, 0);
+			run_top_route(event_rt.rlist[_sl_evrt_local_response], &pmsg, 0);
 			set_route_type(backup_rt);
 			p_onsend=0;
 
diff --git a/modules/sl/sl_funcs.h b/modules/sl/sl_funcs.h
index 772f106..4654d80 100644
--- a/modules/sl/sl_funcs.h
+++ b/modules/sl/sl_funcs.h
@@ -48,4 +48,6 @@ int sl_reply_error(struct sip_msg *msg);
 
 int sl_get_reply_totag(struct sip_msg *msg, str *totag);
 
+void sl_lookup_event_routes(void);
+
 #endif
diff --git a/modules/snmpstats/README b/modules/snmpstats/README
index 75e2bd3..12d2c31 100644
--- a/modules/snmpstats/README
+++ b/modules/snmpstats/README
@@ -8,7 +8,13 @@ Edited by
 
 Jeffrey Magder
 
+Edited by
+
+Olle E. Johansson
+
    Copyright � 2006 SOMA Networks, Inc.
+
+   Copyright � 2013 Edvina AB, Sollentuna, Sweden
      __________________________________________________________________
 
    Table of Contents
@@ -156,6 +162,10 @@ Chapter 1. Admin Guide
    kamailioDialogLimitAlarmStatus, kamailioDialogLimitMinorAlarm,
    kamailioDialogLimitMajorAlarm
 
+   In Kamailio 4.1 a set of new OIDs was added to reflect the Kamailio
+   configuration, the version, core status (memory, connections),
+   transports and module data.
+
 1.2. SNMP Tables
 
    The SNMPStats module provides several tables, containing more
@@ -254,10 +264,10 @@ Chapter 1. Admin Guide
      * usrloc - all scalars and tables relating to users and contacts are
        dependent on the usrloc module. If the module is not loaded, the
        respective tables will be empty.
-     * dialog - all scalars relating to the number of dialogs are
-       dependent on the presence of the dialog module. Furthermore, if the
-       module is not loaded, then the kamailioDialogLimitMinorEvent, and
-       kamailioDialogLimitMajorEvent alarm will be disabled.
+     * dialog or dialog-ng - all scalars relating to the number of dialogs
+       are dependent on the presence of a dialog module. Furthermore, if
+       the module is not loaded, then the kamailioDialogLimitMinorEvent,
+       and kamailioDialogLimitMajorEvent alarm will be disabled.
 
    The contents of the kamailioSIPMethodSupportedTable change depending on
    which modules are loaded.
@@ -292,7 +302,8 @@ Chapter 1. Admin Guide
    and will be used in determining what is returned for the
    kamailioSIPEntityType scalar. Valid parameters are:
 
-   registrarServer, redirectServer, proxyServer, userAgent, other
+   registrarServer, redirectServer, proxyServer, userAgent,
+   edgeproxyServer, sipcaptureServer,other
 
    Example 1.1. Setting the sipEntityType parameter
 ...
@@ -302,7 +313,9 @@ modparam("snmpstats", "sipEntityType", "proxyServer")
 
    Note that as the above example shows, you can define this parameter
    more than once. This is of course because a given Kamailio instance can
-   take on more than one role.
+   take on more than one role. The edgeproxyServer is an edge server using
+   the outbound module and path extensions. The sipcaptureServer is a
+   Homer Sip Capture server that collect SIP messages.
 
 4.2. MsgQueueMinorThreshold (Integer)
 
@@ -429,7 +442,7 @@ modparam("snmpstats", "export_registrar", 1)
    There are several things that need to be done to get the SNMPStats
    module compiled and up and running.
 
-6.1.  Compiling the SNMPStats Module
+6.1. Compiling the SNMPStats Module
 
    In order for the SNMPStats module to compile, you will need at least
    version 5.3 of the NetSNMP source code. The source can be found at:
@@ -451,7 +464,7 @@ modparam("snmpstats", "export_registrar", 1)
    recommended you install NetSNMP from source to avoid bringing in
    excessive dependencies to the SNMPStats module.
 
-6.2.  Configuring NetSNMP to allow connections from the SNMPStats module.
+6.2. Configuring NetSNMP to allow connections from the SNMPStats module.
 
    The SNMPStats module will communicate with the NetSNMP Master Agent.
    This communication happens over a protocol known as AgentX. This means
@@ -483,7 +496,7 @@ modparam("snmpstats", "export_registrar", 1)
    This tells NetSNMP to act as a master agent, listening on the localhost
    UDP interface at port 705.
 
-6.3.  Configuring the SNMPStats module for communication with a Master Agent
+6.3. Configuring the SNMPStats module for communication with a Master Agent
 
    The previous section explained how to set up a NetSNMP master agent to
    accept AgentX connections. We now need to tell the SNMPStats module how
@@ -503,7 +516,7 @@ modparam("snmpstats", "export_registrar", 1)
    be present on the same machine as Kamailio. localhost could be replaced
    with any other machine.
 
-6.4.  Testing for a proper Configuration
+6.4. Testing for a proper Configuration
 
    As a quick test to make sure that the SNMPStats module sub-agent can
    succesfully connect to the NetSNMP Master agent, start snmpd with the
diff --git a/modules/snmpstats/doc/snmpstats.xml b/modules/snmpstats/doc/snmpstats.xml
index a6f3de8..7fc05bb 100644
--- a/modules/snmpstats/doc/snmpstats.xml
+++ b/modules/snmpstats/doc/snmpstats.xml
@@ -28,11 +28,22 @@
 			<email>jmagder at somanetworks.com</email>
 		</address>
 		</editor>
+		<editor>
+		<firstname>Olle E.</firstname>
+		<surname>Johansson</surname>
+		<address>
+			<email>oej at edvina.net</email>
+		</address>
+		</editor>
 	</authorgroup>
 	<copyright>
 		<year>2006</year>
 		<holder>SOMA Networks, Inc.</holder>
 	</copyright>
+	<copyright>
+		<year>2013</year>
+		<holder>Edvina AB, Sollentuna, Sweden</holder>
+	</copyright>
 	</bookinfo>
 	<toc></toc>
 	
diff --git a/modules/snmpstats/doc/snmpstats_admin.xml b/modules/snmpstats/doc/snmpstats_admin.xml
index 490d3cc..71a7b61 100644
--- a/modules/snmpstats/doc/snmpstats_admin.xml
+++ b/modules/snmpstats/doc/snmpstats_admin.xml
@@ -60,6 +60,11 @@
 			kamailioDialogLimitAlarmStatus, kamailioDialogLimitMinorAlarm,
 			kamailioDialogLimitMajorAlarm
 			</para>
+			<para>
+			In Kamailio 4.1 a set of new OIDs was added to reflect the
+			&kamailio; configuration, the version, core status (memory, connections),
+			transports and module data.
+			</para>
 		</section>
 		<section>
 			<title>SNMP Tables</title>
@@ -203,8 +208,8 @@
 		
 		<listitem>
 		<para>
-		<emphasis>dialog</emphasis> - all scalars relating to the number of dialogs are 
-		dependent on the presence of the dialog module.  Furthermore, if the module is 
+		<emphasis>dialog or dialog-ng</emphasis> - all scalars relating to the number of dialogs are 
+		dependent on the presence of a dialog module.  Furthermore, if the module is 
 		not loaded, then the kamailioDialogLimitMinorEvent, and kamailioDialogLimitMajorEvent
 		alarm will be disabled. 
 		</para>
@@ -243,7 +248,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id ="snmpstats.p.sipentitytape">
 		<title><varname>sipEntityType</varname> (String) </title>
 
 		<para>
@@ -254,7 +259,7 @@
 
 		<para>
 		<emphasis>
-		registrarServer, redirectServer, proxyServer, userAgent, other
+		registrarServer, redirectServer, proxyServer, userAgent, edgeproxyServer, sipcaptureServer,other
 		</emphasis>
 		</para>
 
@@ -271,11 +276,13 @@ modparam("snmpstats", "sipEntityType", "proxyServer")
 		<para>
 		Note that as the above example shows, you can define this parameter more
 		than once.  This is of course because a given Kamailio instance can take on
-		more than one role.
+		more than one role. The edgeproxyServer is an edge server using the outbound
+		module and path extensions. The sipcaptureServer is a Homer Sip Capture
+		server that collect SIP messages.
 		</para>
 	</section>
 
-	<section>
+	<section id ="snmpstats.p.MsqQueueMinorTreshold">
 		<title><varname>MsgQueueMinorThreshold</varname> (Integer)</title>
 
 		<para>
@@ -300,7 +307,7 @@ modparam("snmpstats", "MsgQueueMinorThreshold", 2000)
 		</para>
 	</section>
 	
-	<section>
+	<section id ="snmpstats.p.MsqQueueMajorTreshold">
 		<title><varname>MsgQueueMajorThreshold</varname> (Integer)</title>
 
 		<para>
@@ -325,7 +332,7 @@ modparam("snmpstats", "MsgQueueMajorThreshold", 5000)
 		</para>
 	</section>
 
-	<section>
+	<section id ="snmpstats.p.dlg_minor_treshold">
 		<title><varname>dlg_minor_threshold</varname> (Integer)</title>
 
 		<para>
@@ -349,7 +356,7 @@ modparam("snmpstats", "MsgQueueMajorThreshold", 5000)
 		</para>
 	</section>
 
-	<section>
+	<section id ="snmpstats.p.dlg_major_treshold">
 		<title><varname>dlg_major_threshold</varname> (Integer)</title>
 
 		<para>
@@ -373,7 +380,7 @@ modparam("snmpstats", "MsgQueueMajorThreshold", 5000)
 		</para>
 	</section>
 
-	<section>
+	<section id ="snmpstats.p.snmpgetPath">
 		<title><varname>snmpgetPath</varname> (String)</title>
 
 		<para>
@@ -399,7 +406,7 @@ modparam("snmpstats", "snmpgetPath",     "/my/custom/path/")
 		</example>
 	</section>
 	
-	<section>
+	<section id ="snmpstats.p.snmpCommunity">
 		<title><varname>snmpCommunity</varname> (String)</title>
 
 		<para>
@@ -425,7 +432,7 @@ modparam("snmpstats", "snmpCommunity", "customCommunityString")
 		</example>
 	</section>
 
-	<section>
+	<section id ="snmpstats.p.export_registrar">
 		<title><varname>export_registrar</varname> (int)</title>
 
 		<para>
diff --git a/modules/snmpstats/kamailioNet.c b/modules/snmpstats/kamailioNet.c
new file mode 100644
index 0000000..35492f0
--- /dev/null
+++ b/modules/snmpstats/kamailioNet.c
@@ -0,0 +1,1354 @@
+/*
+ * SNMPStats Module  - Network Statistics
+ *
+ * Kamailio Server Net objects addition
+ * Copyright (C) 2013 Edvina AB, Sollentuna, Sweden
+ * Written by Olle E. Johansson
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * History:
+ * --------
+ * 2013-03-24 initial version (oej)
+ * 
+ * Note: this file originally auto-generated by mib2c 
+ *
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "kamailioNet.h"
+
+#include "snmpstats_globals.h"
+#include "utilities.h"
+#include "../../lib/kcore/statistics.h"
+#include "../../globals.h"
+#include "../../tcp_options.h"
+
+/** Initializes the kamailioNet module */
+void
+init_kamailioNet(void)
+{
+    oid kamailioNetTcpConnEstablished_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,2,1 };
+    oid kamailioNetTcpConnFailed_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,2,2 };
+    oid kamailioNetTcpConnReset_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,2,3 };
+    oid kamailioNetTcpConnSuccess_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,2,4 };
+    oid kamailioNetTcpConnOpen_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,2,5 };
+    oid kamailioNetTcpConnPassiveOpen_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,2,6 };
+    oid kamailioNetTcpConnReject_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,2,8 };
+    oid kamailioNetTcpEnabled_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,1 };
+    oid kamailioNetTcpMaxConns_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,2 };
+    oid kamailioNetTcpConnTimeout_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,3 };
+    oid kamailioNetTcpSendTimeout_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,4 };
+    oid kamailioNetTcpConnLifetime_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,5 };
+    oid kamailioNetTcpNoConnect_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,7 };
+    oid kamailioNetTcpFdCache_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,8 };
+    oid kamailioNetTcpAsync_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,9 };
+    oid kamailioNetTcpAsyncConnWait_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,10 };
+    oid kamailioNetTcpAsyncConnWqMax_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,11 };
+    oid kamailioNetTcpAsyncWqMax_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,12 };
+    oid kamailioNetTcpRdBufSize_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,13 };
+    oid kamailioNetTcpDeferAccept_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,14 };
+    oid kamailioNetTcpDelayedAck_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,15 };
+    oid kamailioNetTcpSynCnt_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,16 };
+    oid kamailioNetTcpLinger_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,17 };
+    oid kamailioNetTcpKeepAlive_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,18 };
+    oid kamailioNetTcpKeepIdle_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,19 };
+    oid kamailioNetTcpKeepIntvl_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,20 };
+    oid kamailioNetTcpKeepCnt_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,21 };
+    oid kamailioNetTcpCrlfPing_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,22 };
+    oid kamailioNetTcpAcceptAliases_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,23 };
+    oid kamailioNetTcpAcceptNoCl_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,1,3,24 };
+
+    /* WebSockets */
+    oid kamailioNetWsConnsActive_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,1 };
+    oid kamailioNetWsConnsActiveMax_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,2 };
+    oid kamailioNetWsConnsFailed_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,3 };
+    oid kamailioNetWsConnsClosedLocal_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,4 };
+    oid kamailioNetWsConnsClosedRemote_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,5 };
+    oid kamailioNetWsFramesRx_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,6 };
+    oid kamailioNetWsFramesTx_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,7 };
+    oid kamailioNetWsHandshakeSuccess_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,8 };
+    oid kamailioNetWsHandshakeFailed_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,2,1,9 };
+
+  DEBUGMSGTL(("kamailioNet", "Initializing\n"));
+
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnEstablished", handle_kamailioNetTcpConnEstablished,
+                               kamailioNetTcpConnEstablished_oid, OID_LENGTH(kamailioNetTcpConnEstablished_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnFailed", handle_kamailioNetTcpConnFailed,
+                               kamailioNetTcpConnFailed_oid, OID_LENGTH(kamailioNetTcpConnFailed_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnReset", handle_kamailioNetTcpConnReset,
+                               kamailioNetTcpConnReset_oid, OID_LENGTH(kamailioNetTcpConnReset_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnSuccess", handle_kamailioNetTcpConnSuccess,
+                               kamailioNetTcpConnSuccess_oid, OID_LENGTH(kamailioNetTcpConnSuccess_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnOped", handle_kamailioNetTcpConnOpen,
+                               kamailioNetTcpConnOpen_oid, OID_LENGTH(kamailioNetTcpConnOpen_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnPassiveOpen", handle_kamailioNetTcpConnPassiveOpen,
+                               kamailioNetTcpConnPassiveOpen_oid, OID_LENGTH(kamailioNetTcpConnPassiveOpen_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnReject", handle_kamailioNetTcpConnReject,
+                               kamailioNetTcpConnReject_oid, OID_LENGTH(kamailioNetTcpConnReject_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpEnabled", handle_kamailioNetTcpEnabled,
+                               kamailioNetTcpEnabled_oid, OID_LENGTH(kamailioNetTcpEnabled_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpMaxConns", handle_kamailioNetTcpMaxConns,
+                               kamailioNetTcpMaxConns_oid, OID_LENGTH(kamailioNetTcpMaxConns_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnTimeout", handle_kamailioNetTcpConnTimeout,
+                               kamailioNetTcpConnTimeout_oid, OID_LENGTH(kamailioNetTcpConnTimeout_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpSendTimeout", handle_kamailioNetTcpSendTimeout,
+                               kamailioNetTcpSendTimeout_oid, OID_LENGTH(kamailioNetTcpSendTimeout_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpConnLifetime", handle_kamailioNetTcpConnLifetime,
+                               kamailioNetTcpConnLifetime_oid, OID_LENGTH(kamailioNetTcpConnLifetime_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpNoConnect", handle_kamailioNetTcpNoConnect,
+                               kamailioNetTcpNoConnect_oid, OID_LENGTH(kamailioNetTcpNoConnect_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpFdCache", handle_kamailioNetTcpFdCache,
+                               kamailioNetTcpFdCache_oid, OID_LENGTH(kamailioNetTcpFdCache_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpAsync", handle_kamailioNetTcpAsync,
+                               kamailioNetTcpAsync_oid, OID_LENGTH(kamailioNetTcpAsync_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpAsyncConnWait", handle_kamailioNetTcpAsyncConnWait,
+                               kamailioNetTcpAsyncConnWait_oid, OID_LENGTH(kamailioNetTcpAsyncConnWait_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpAsyncConnWqMax", handle_kamailioNetTcpAsyncConnWqMax,
+                               kamailioNetTcpAsyncConnWqMax_oid, OID_LENGTH(kamailioNetTcpAsyncConnWqMax_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpAsyncWqMax", handle_kamailioNetTcpAsyncWqMax,
+                               kamailioNetTcpAsyncWqMax_oid, OID_LENGTH(kamailioNetTcpAsyncWqMax_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpRdBufSize", handle_kamailioNetTcpRdBufSize,
+                               kamailioNetTcpRdBufSize_oid, OID_LENGTH(kamailioNetTcpRdBufSize_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpDeferAccept", handle_kamailioNetTcpDeferAccept,
+                               kamailioNetTcpDeferAccept_oid, OID_LENGTH(kamailioNetTcpDeferAccept_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpDelayedAck", handle_kamailioNetTcpDelayedAck,
+                               kamailioNetTcpDelayedAck_oid, OID_LENGTH(kamailioNetTcpDelayedAck_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpSynCnt", handle_kamailioNetTcpSynCnt,
+                               kamailioNetTcpSynCnt_oid, OID_LENGTH(kamailioNetTcpSynCnt_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpLinger", handle_kamailioNetTcpLinger,
+                               kamailioNetTcpLinger_oid, OID_LENGTH(kamailioNetTcpLinger_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpKeepAlive", handle_kamailioNetTcpKeepAlive,
+                               kamailioNetTcpKeepAlive_oid, OID_LENGTH(kamailioNetTcpKeepAlive_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpKeepIdle", handle_kamailioNetTcpKeepIdle,
+                               kamailioNetTcpKeepIdle_oid, OID_LENGTH(kamailioNetTcpKeepIdle_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpKeepIntvl", handle_kamailioNetTcpKeepIntvl,
+                               kamailioNetTcpKeepIntvl_oid, OID_LENGTH(kamailioNetTcpKeepIntvl_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpKeepCnt", handle_kamailioNetTcpKeepCnt,
+                               kamailioNetTcpKeepCnt_oid, OID_LENGTH(kamailioNetTcpKeepCnt_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpCrlfPing", handle_kamailioNetTcpCrlfPing,
+                               kamailioNetTcpCrlfPing_oid, OID_LENGTH(kamailioNetTcpCrlfPing_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpAcceptAliases", handle_kamailioNetTcpAcceptAliases,
+                               kamailioNetTcpAcceptAliases_oid, OID_LENGTH(kamailioNetTcpAcceptAliases_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetTcpAcceptNoCl", handle_kamailioNetTcpAcceptNoCl,
+                               kamailioNetTcpAcceptNoCl_oid, OID_LENGTH(kamailioNetTcpAcceptNoCl_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsConnsActive", handle_kamailioNetWsConnsActive,
+                               kamailioNetWsConnsActive_oid, OID_LENGTH(kamailioNetWsConnsActive_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsConnsActiveMax", handle_kamailioNetWsConnsActiveMax,
+                               kamailioNetWsConnsActiveMax_oid, OID_LENGTH(kamailioNetWsConnsActiveMax_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsConnsFailed", handle_kamailioNetWsConnsFailed,
+                               kamailioNetWsConnsFailed_oid, OID_LENGTH(kamailioNetWsConnsFailed_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsConnsClosedLocal", handle_kamailioNetWsConnsClosedLocal,
+                               kamailioNetWsConnsClosedLocal_oid, OID_LENGTH(kamailioNetWsConnsClosedLocal_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsConnsClosedRemote", handle_kamailioNetWsConnsClosedRemote,
+                               kamailioNetWsConnsClosedRemote_oid, OID_LENGTH(kamailioNetWsConnsClosedRemote_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsFramesRx", handle_kamailioNetWsFramesRx,
+                               kamailioNetWsFramesRx_oid, OID_LENGTH(kamailioNetWsFramesRx_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsFramesTx", handle_kamailioNetWsFramesTx,
+                               kamailioNetWsFramesTx_oid, OID_LENGTH(kamailioNetWsFramesTx_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsHandshakeSuccess", handle_kamailioNetWsHandshakeSuccess,
+                               kamailioNetWsHandshakeSuccess_oid, OID_LENGTH(kamailioNetWsHandshakeSuccess_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetWsHandshakeFailed", handle_kamailioNetWsHandshakeFailed,
+                               kamailioNetWsHandshakeFailed_oid, OID_LENGTH(kamailioNetWsHandshakeFailed_oid),
+                               HANDLER_CAN_RONLY
+        ));
+}
+
+int
+handle_kamailioNetTcpConnEstablished(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+
+	int datafield = get_statistic("established");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnEstablished\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpConnFailed(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+
+	int datafield = get_statistic("connect_failed");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnFailed\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpConnReset(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+	int datafield = get_statistic("con_reset");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnReset\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpConnSuccess(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+
+	int datafield = get_statistic("connect_success");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnSuccess\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpConnOpen(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+	int datafield = get_statistic("current_opened_connections");
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnOpen\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpConnPassiveOpen(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+	int datafield = get_statistic("passive_open");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnPassiveOpen\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpConnReject(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+	int datafield = get_statistic("local_reject");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnReject\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpEnabled(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+	int enabled = (tcp_disable == 0);
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			(u_char *) &enabled, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpEnabled\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpMaxConns(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int maxconn;
+
+    tcp_options_get(&t);
+    maxconn = t.max_connections;
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &maxconn, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpMaxConns\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpAsync(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.async;
+    /* We are never called for a GETNEXT if it's registered as a
+       "instance", as it's "magically" handled for us.  */
+
+    /* a instance handler also only hands us one request at a time, so
+       we don't need to loop over a list of requests; we'll only get one. */
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpAsync\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpConnTimeout(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.connect_timeout_s;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnTimeout\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpSendTimeout(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.send_timeout;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpSendTimeout\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpConnLifetime(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.con_lifetime;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpConnLifetime\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpNoConnect(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value ;
+
+    tcp_options_get(&t);
+    value = t.no_connect;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpNoConnect\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpFdCache(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.con_lifetime;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpFdCache\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpAsyncConnWait(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.tcp_connect_wait;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpAsyncConnWait\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpAsyncConnWqMax(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.tcpconn_wq_max;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpAsyncConnWqMax\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpAsyncWqMax(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.tcp_wq_max;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpAsyncWqMax\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpRdBufSize(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.rd_buf_size;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpRdBufSize\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpDeferAccept(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.defer_accept;
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpDeferAccept\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpDelayedAck(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.delayed_ack;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpDelayedAck\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpSynCnt(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.syncnt;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpSynCnt\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpLinger(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.linger2;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpLinger\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpKeepAlive(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.keepalive;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpKeepAlive\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetTcpKeepIdle(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.keepidle;
+    
+    switch(reqinfo->mode) {
+
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.con_lifetime;
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpKeepIdle\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpKeepIntvl(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.keepintvl;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpKeepIntvl\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpKeepCnt(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.keepcnt;
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpKeepCnt\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpCrlfPing(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.crlf_ping;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpCrlfPing\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+handle_kamailioNetTcpAcceptAliases(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.accept_aliases;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpAcceptAliases\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetTcpAcceptNoCl(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    struct cfg_group_tcp t;
+    unsigned int value;
+
+    tcp_options_get(&t);
+    value = t.accept_no_cl;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			 (u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetTcpAcceptNoCl\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetWsConnsActive(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_current_connections");
+    
+    switch(reqinfo->mode) {
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsConnsActive\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsConnsActiveMax(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_max_concurrent_connections");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+				(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsConnsActiveMax\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsConnsFailed(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_failed_connections");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsConnsFailed\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsConnsClosedLocal(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_local_closed_connections");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsConnsClosedLocal\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsConnsClosedRemote(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_remote_closed_connections");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsConnsClosedRemote\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsFramesRx(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_received_frames");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsFramesRx\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsFramesTx(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_transmitted_frames");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsFramesTx\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsHandshakeSuccess(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_successful_handshakes");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsHandshakeSuccess\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+int
+handle_kamailioNetWsHandshakeFailed(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+   int datafield = get_statistic("ws_failed_handshakes");
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
+			(u_char *) &datafield, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetWsHandshakeFailed\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
diff --git a/modules/snmpstats/kamailioNet.h b/modules/snmpstats/kamailioNet.h
new file mode 100644
index 0000000..d9ca827
--- /dev/null
+++ b/modules/snmpstats/kamailioNet.h
@@ -0,0 +1,78 @@
+/*
+ * SNMPStats Module  - Network Statistics
+ *
+ * Kamailio Server Net objects addition
+ * Copyright (C) 2013 Edvina AB, Sollentuna, Sweden
+ * Written by Olle E. Johansson
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * History:
+ * --------
+ * 2013-04-01 initial version (oej)
+ * 
+ * Note: this file originally auto-generated by mib2c 
+ *
+ */
+#ifndef KAMAILIONET_H
+#define KAMAILIONET_H
+
+/* function declarations */
+void init_kamailioNet(void);
+Netsnmp_Node_Handler handle_kamailioNetTcpConnEstablished;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnFailed;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnReset;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnSuccess;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnOpen;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnPassiveOpen;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnReject;
+Netsnmp_Node_Handler handle_kamailioNetTcpEnabled;
+Netsnmp_Node_Handler handle_kamailioNetTcpMaxConns;
+Netsnmp_Node_Handler handle_kamailioNetTcpAsync;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnTimeout;
+Netsnmp_Node_Handler handle_kamailioNetTcpSendTimeout;
+Netsnmp_Node_Handler handle_kamailioNetTcpConnLifetime;
+Netsnmp_Node_Handler handle_kamailioNetTcpNoConnect;
+Netsnmp_Node_Handler handle_kamailioNetTcpFdCache;
+Netsnmp_Node_Handler handle_kamailioNetTcpAsync;
+Netsnmp_Node_Handler handle_kamailioNetTcpAsyncConnWait;
+Netsnmp_Node_Handler handle_kamailioNetTcpAsyncConnWqMax;
+Netsnmp_Node_Handler handle_kamailioNetTcpAsyncWqMax;
+Netsnmp_Node_Handler handle_kamailioNetTcpRdBufSize;
+Netsnmp_Node_Handler handle_kamailioNetTcpDeferAccept;
+Netsnmp_Node_Handler handle_kamailioNetTcpDelayedAck;
+Netsnmp_Node_Handler handle_kamailioNetTcpSynCnt;
+Netsnmp_Node_Handler handle_kamailioNetTcpLinger;
+Netsnmp_Node_Handler handle_kamailioNetTcpKeepAlive;
+Netsnmp_Node_Handler handle_kamailioNetTcpKeepIdle;
+Netsnmp_Node_Handler handle_kamailioNetTcpKeepIntvl;
+Netsnmp_Node_Handler handle_kamailioNetTcpKeepCnt;
+Netsnmp_Node_Handler handle_kamailioNetTcpCrlfPing;
+Netsnmp_Node_Handler handle_kamailioNetTcpAcceptAliases;
+Netsnmp_Node_Handler handle_kamailioNetTcpAcceptNoCl;
+Netsnmp_Node_Handler handle_kamailioNetWsConnsActive;
+Netsnmp_Node_Handler handle_kamailioNetWsConnsActiveMax;
+Netsnmp_Node_Handler handle_kamailioNetWsConnsFailed;
+Netsnmp_Node_Handler handle_kamailioNetWsConnsClosedLocal;
+Netsnmp_Node_Handler handle_kamailioNetWsConnsClosedRemote;
+Netsnmp_Node_Handler handle_kamailioNetWsFramesRx;
+Netsnmp_Node_Handler handle_kamailioNetWsFramesTx;
+Netsnmp_Node_Handler handle_kamailioNetWsHandshakeSuccess;
+Netsnmp_Node_Handler handle_kamailioNetWsHandshakeFailed;
+
+#endif /* KAMAILIONET_H */
diff --git a/modules/snmpstats/kamailioNetConfig.c b/modules/snmpstats/kamailioNetConfig.c
new file mode 100644
index 0000000..a965869
--- /dev/null
+++ b/modules/snmpstats/kamailioNetConfig.c
@@ -0,0 +1,446 @@
+/*
+ * SNMPStats Module  - Network Statistics
+ *
+ * Kamailio Server Net objects addition
+ * Copyright (C) 2013 Edvina AB, Sollentuna, Sweden
+ * Written by Olle E. Johansson
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * History:
+ * --------
+ * 2013-04-01 initial version (oej)
+ * 
+ * Note: this file originally auto-generated by mib2c 
+ *
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "kamailioNetConfig.h"
+
+#include "snmpstats_globals.h"
+#include "utilities.h"
+#include "../../lib/kcore/statistics.h"
+#include "../../globals.h"
+#include "../../cfg_core.h"
+
+/* Net-snmp version 5.6 defines oid's as const */
+#define CONST
+
+/** Initializes the kamailioNetConfig module */
+void
+init_kamailioNetConfig(void)
+{
+    CONST oid kamailioNetConfUdpTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,1 };
+    CONST oid kamailioNetConfUdpDtlsTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,2 };
+    CONST oid kamailioNetConfTcpTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,3 };
+    CONST oid kamailioNetConfTcpTlsTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,4 };
+    CONST oid kamailioNetConfSctpTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,5 };
+    CONST oid kamailioNetConfSctpTlsTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,6 };
+    CONST oid kamailioNetConfWsTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,7 };
+    CONST oid kamailioNetConfWsTlsTransport_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,8 };
+    CONST oid kamailioNetConfHttpServer_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,9 };
+    CONST oid kamailioNetConfMsrpRelay_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,10 };
+    CONST oid kamailioNetConfStunServer_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,11 };
+    CONST oid kamailioNetConfOutbound_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,4,4,12 };
+
+  DEBUGMSGTL(("kamailioNetConfig", "Initializing\n"));
+
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfUdpTransport", handle_kamailioNetConfUdpTransport,
+                               kamailioNetConfUdpTransport_oid, OID_LENGTH(kamailioNetConfUdpTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfUdpDtlsTransport", handle_kamailioNetConfUdpDtlsTransport,
+                               kamailioNetConfUdpDtlsTransport_oid, OID_LENGTH(kamailioNetConfUdpDtlsTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfTcpTransport", handle_kamailioNetConfTcpTransport,
+                               kamailioNetConfTcpTransport_oid, OID_LENGTH(kamailioNetConfTcpTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfTcpTlsTransport", handle_kamailioNetConfTcpTlsTransport,
+                               kamailioNetConfTcpTlsTransport_oid, OID_LENGTH(kamailioNetConfTcpTlsTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfSctpTransport", handle_kamailioNetConfSctpTransport,
+                               kamailioNetConfSctpTransport_oid, OID_LENGTH(kamailioNetConfSctpTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfSctpTlsTransport", handle_kamailioNetConfSctpTlsTransport,
+                               kamailioNetConfSctpTlsTransport_oid, OID_LENGTH(kamailioNetConfSctpTlsTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfWsTransport", handle_kamailioNetConfWsTransport,
+                               kamailioNetConfWsTransport_oid, OID_LENGTH(kamailioNetConfWsTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfWsTlsTransport", handle_kamailioNetConfWsTlsTransport,
+                               kamailioNetConfWsTlsTransport_oid, OID_LENGTH(kamailioNetConfWsTlsTransport_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfHttpServer", handle_kamailioNetConfHttpServer,
+                               kamailioNetConfHttpServer_oid, OID_LENGTH(kamailioNetConfHttpServer_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfMsrpRelay", handle_kamailioNetConfMsrpRelay,
+                               kamailioNetConfMsrpRelay_oid, OID_LENGTH(kamailioNetConfMsrpRelay_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfStunServer", handle_kamailioNetConfStunServer,
+                               kamailioNetConfStunServer_oid, OID_LENGTH(kamailioNetConfStunServer_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioNetConfOutbound", handle_kamailioNetConfOutbound,
+                               kamailioNetConfOutbound_oid, OID_LENGTH(kamailioNetConfOutbound_oid),
+                               HANDLER_CAN_RONLY
+        ));
+}
+
+int handle_kamailioNetConfUdpTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = 1;	/* By default, implemented */
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			(u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfUdpTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfUdpDtlsTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+
+	/* Note: This transport is not supported in Kamailio. This OID is just a place holder
+		for future work. 
+	*/
+    int value = -1;	/* Not implemented */
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
+			(u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfUdpDtlsTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfTcpTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = 0;	/* Not implemented */
+
+#ifdef USE_TCP
+	if (!tcp_disable) {
+		value = 1;
+	}
+#endif
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfTcpTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfTcpTlsTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = 0;
+
+#ifdef USE_TCP
+	if (!tcp_disable) {
+#ifdef USE_TLS
+		if (module_loaded("tls")) {
+			value = 1;
+		}
+#endif
+		;	/* Empty statement needed here */
+	}
+#endif
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfTcpTlsTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfSctpTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = 0;
+	/* At this point I'm lazy and just check if the transport is compiled. */
+#ifdef USE_SCTP
+	value = 1;
+#endif
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfSctpTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfSctpTlsTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = -1;	/* Not implemented */
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfSctpTlsTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfWsTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = -1;	/* Not implemented */
+    if (module_loaded("tls"))  {
+	value = 1;
+    }
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfWsTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfWsTlsTransport(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    	int value = 0;
+	unsigned int type;
+
+	if (module_loaded("websocket")) {
+		value = snmp_cfg_get_int("websocket", "enabled", &type);
+		if (type != CFG_VAR_INT) {
+			value = 0;
+		}
+	}
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfWsTlsTransport\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfHttpServer(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = 0;
+    if (module_loaded("xhttp"))  {
+	value = 1;
+    }
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfHttpServer\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfMsrpRelay(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = 0;
+    if (module_loaded("msrp"))  {
+	value = 1;
+    }
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfMsrpRelay\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfStunServer(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    int value = 0;
+    if (module_loaded("stun"))  {
+	value = 1;
+    }
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfStunServer\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioNetConfOutbound(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+	int value = 0;	/* Not implemented */
+	unsigned int type;
+	
+	if (module_loaded("outbound")) {
+		value = snmp_cfg_get_int("outbound", "outbound_enabled", &type);
+		if (type != CFG_VAR_INT) {
+			value = 0;
+		}
+	}
+
+	switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &value, sizeof(int));
+            break;
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioNetConfOutbound\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+	}
+
+	return SNMP_ERR_NOERROR;
+}
diff --git a/modules/snmpstats/kamailioNetConfig.h b/modules/snmpstats/kamailioNetConfig.h
new file mode 100644
index 0000000..6399d97
--- /dev/null
+++ b/modules/snmpstats/kamailioNetConfig.h
@@ -0,0 +1,23 @@
+/*
+ * Note: this file originally auto-generated by mib2c using
+ *        $
+ */
+#ifndef KAMAILIONETCONFIG_H
+#define KAMAILIONETCONFIG_H
+
+/* function declarations */
+void init_kamailioNetConfig(void);
+Netsnmp_Node_Handler handle_kamailioNetConfUdpTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfUdpDtlsTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfTcpTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfTcpTlsTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfSctpTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfSctpTlsTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfWsTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfWsTlsTransport;
+Netsnmp_Node_Handler handle_kamailioNetConfHttpServer;
+Netsnmp_Node_Handler handle_kamailioNetConfMsrpRelay;
+Netsnmp_Node_Handler handle_kamailioNetConfStunServer;
+Netsnmp_Node_Handler handle_kamailioNetConfOutbound;
+
+#endif /* KAMAILIONETCONFIG_H */
diff --git a/modules/snmpstats/kamailioServer.c b/modules/snmpstats/kamailioServer.c
new file mode 100644
index 0000000..9d6d3ce
--- /dev/null
+++ b/modules/snmpstats/kamailioServer.c
@@ -0,0 +1,481 @@
+/*
+ *
+ * SNMPStats Module 
+ * Copyright (C) 2006 SOMA Networks, INC.
+ * Written by: Jeffrey Magder (jmagder at somanetworks.com)
+ *
+ * Kamailio Server core objects addition
+ * Copyright (C) 2013 Edvina AB, Sollentuna, Sweden
+ * Written by Olle E. Johansson
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * History:
+ * --------
+ * 2013-03-24 initial version (oej)
+ * 
+ * Note: this file originally auto-generated by mib2c 
+ *
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "kamailioServer.h"
+
+#include "snmpstats_globals.h"
+#include "utilities.h"
+#include "../../lib/kcore/statistics.h"
+#include "../../ver.h"
+#include "../../mem/meminfo.h"
+#include "../../mem/shm_mem.h"
+
+/** Initializes the kamailioServer module */
+void
+init_kamailioServer(void)
+{
+    oid kamailioSrvMaxMemory_oid[] =      { 1,3,6,1,4,1,34352,3,1,3,1,1,1,1 };
+    oid kamailioSrvFreeMemory_oid[] =     { 1,3,6,1,4,1,34352,3,1,3,1,1,1,2 };
+    oid kamailioSrvMaxUsed_oid[] =        { 1,3,6,1,4,1,34352,3,1,3,1,1,1,3 };
+    oid kamailioSrvRealUsed_oid[] =       { 1,3,6,1,4,1,34352,3,1,3,1,1,1,4 };
+    oid kamailioSrvMemFragments_oid[] =   { 1,3,6,1,4,1,34352,3,1,3,1,1,1,5 };
+
+    oid kamailioSrvCnfFullVersion_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,1,2,1 };
+    oid kamailioSrvCnfVerName_oid[] =     { 1,3,6,1,4,1,34352,3,1,3,1,1,2,2 };
+    oid kamailioSrvCnfVerVersion_oid[] =  { 1,3,6,1,4,1,34352,3,1,3,1,1,2,3 };
+    oid kamailioSrvCnfVerArch_oid[] =     { 1,3,6,1,4,1,34352,3,1,3,1,1,2,4 };
+    oid kamailioSrvCnfVerOs_oid[] =       { 1,3,6,1,4,1,34352,3,1,3,1,1,2,5 };
+    oid kamailioSrvCnfVerId_oid[] =       { 1,3,6,1,4,1,34352,3,1,3,1,1,2,6 };
+    oid kamailioSrvCnfVerCompTime_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,1,2,7 };
+    oid kamailioSrvCnfVerCompiler_oid[] = { 1,3,6,1,4,1,34352,3,1,3,1,1,2,8 };
+    oid kamailioSrvCnfVerFlags_oid[] =    { 1,3,6,1,4,1,34352,3,1,3,1,1,2,9 };
+
+     DEBUGMSGTL(("kamailioServer", "Initializing\n"));
+     LM_DBG("initializing Kamailio Server OID's X\n");
+
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvMaxMemory", handle_kamailioSrvMaxMemory,
+                               kamailioSrvMaxMemory_oid, OID_LENGTH(kamailioSrvMaxMemory_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvFreeMemory", handle_kamailioSrvFreeMemory,
+                               kamailioSrvFreeMemory_oid, OID_LENGTH(kamailioSrvFreeMemory_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvMaxUsed", handle_kamailioSrvMaxUsed,
+                               kamailioSrvMaxUsed_oid, OID_LENGTH(kamailioSrvMaxUsed_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvRealUsed", handle_kamailioSrvRealUsed,
+                               kamailioSrvRealUsed_oid, OID_LENGTH(kamailioSrvRealUsed_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvMemFragments", handle_kamailioSrvMemFragments,
+                               kamailioSrvMemFragments_oid, OID_LENGTH(kamailioSrvMemFragments_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfFullVersion", handle_kamailioSrvCnfFullVersion,
+                               kamailioSrvCnfFullVersion_oid, OID_LENGTH(kamailioSrvCnfFullVersion_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerName", handle_kamailioSrvCnfVerName,
+                               kamailioSrvCnfVerName_oid, OID_LENGTH(kamailioSrvCnfVerName_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerVersion", handle_kamailioSrvCnfVerVersion,
+                               kamailioSrvCnfVerVersion_oid, OID_LENGTH(kamailioSrvCnfVerVersion_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerArch", handle_kamailioSrvCnfVerArch,
+                               kamailioSrvCnfVerArch_oid, OID_LENGTH(kamailioSrvCnfVerArch_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerOs", handle_kamailioSrvCnfVerOs,
+                               kamailioSrvCnfVerOs_oid, OID_LENGTH(kamailioSrvCnfVerOs_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerId", handle_kamailioSrvCnfVerId,
+                               kamailioSrvCnfVerId_oid, OID_LENGTH(kamailioSrvCnfVerId_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerCompTime", handle_kamailioSrvCnfVerCompTime,
+                               kamailioSrvCnfVerCompTime_oid, OID_LENGTH(kamailioSrvCnfVerCompTime_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerCompiler", handle_kamailioSrvCnfVerCompiler,
+                               kamailioSrvCnfVerCompiler_oid, OID_LENGTH(kamailioSrvCnfVerCompiler_oid),
+                               HANDLER_CAN_RONLY
+        ));
+    netsnmp_register_scalar(
+        netsnmp_create_handler_registration("kamailioSrvCnfVerFlags", handle_kamailioSrvCnfVerFlags,
+                               kamailioSrvCnfVerFlags_oid, OID_LENGTH(kamailioSrvCnfVerFlags_oid),
+                               HANDLER_CAN_RONLY
+        ));
+}
+
+
+static struct mem_info _stats_shm_mi;
+static ticks_t _stats_shm_tm = 0;
+
+/*! \brief Get memory information from the core directly */
+void stats_shm_update(void)
+{
+	ticks_t t;
+	t = get_ticks();
+	if(t!=_stats_shm_tm) {
+		shm_info(&_stats_shm_mi);
+		_stats_shm_tm = t;
+	}
+}
+
+int handle_kamailioSrvMaxMemory(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    stats_shm_update();
+    int maxmemory = (int) _stats_shm_mi.total_size;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+                        	(u_char *) &maxmemory, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvMaxMemory\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+
+int handle_kamailioSrvFreeMemory(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    stats_shm_update();
+    int freememory = (int) _stats_shm_mi.free;
+
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+                        	(u_char *) &freememory, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvFreeMemory\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvMaxUsed(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    stats_shm_update();
+    int value = (int) _stats_shm_mi.max_used;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+                        	(u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvMaxUsed\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvRealUsed(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    stats_shm_update();
+    int value = (int) _stats_shm_mi.real_used;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+                        	(u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvRealUsed\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvMemFragments(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    stats_shm_update();
+    int value = (int) _stats_shm_mi.total_frags;
+    
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE,
+                        	(u_char *) &value, sizeof(int));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvMemFragments\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfFullVersion(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) full_version, strlen(full_version));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfFullVersion\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfVerName(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_name, strlen(ver_name));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerName\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfVerVersion(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_version, strlen(ver_version));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerVersion\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfVerArch(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_arch, strlen(ver_arch));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerArch\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfVerOs(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_os, strlen(ver_os));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerOs\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfVerId(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_id, strlen(ver_id));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerId\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfVerCompTime(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_compiled_time, strlen(ver_compiled_time));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerCompTime\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int handle_kamailioSrvCnfVerCompiler(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_compiler, strlen(ver_compiler));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerCompiler\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+
+int handle_kamailioSrvCnfVerFlags(netsnmp_mib_handler *handler,
+                          netsnmp_handler_registration *reginfo,
+                          netsnmp_agent_request_info   *reqinfo,
+                          netsnmp_request_info         *requests)
+{
+    switch(reqinfo->mode) {
+
+        case MODE_GET:
+            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
+					(u_char *) ver_flags, strlen(ver_flags));
+            break;
+
+
+        default:
+            /* we should never get here, so this is a really bad error */
+            snmp_log(LOG_ERR, "unknown mode (%d) in handle_kamailioSrvCnfVerFlags\n", reqinfo->mode );
+            return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
diff --git a/modules/snmpstats/kamailioServer.h b/modules/snmpstats/kamailioServer.h
new file mode 100644
index 0000000..bb134cb
--- /dev/null
+++ b/modules/snmpstats/kamailioServer.h
@@ -0,0 +1,55 @@
+/*
+ * SNMPStats Module 
+ * Copyright (C) 2006 SOMA Networks, INC.
+ * Written by: Jeffrey Magder (jmagder at somanetworks.com)
+ *
+ * Kamailio Server core objects addition
+ * Copyright (C) 2013 Edvina AB, Sollentuna, Sweden
+ * Written by Olle E. Johansson
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * History:
+ * --------
+ * 2013-03-24 initial version (oej)
+ * 
+ * Note: this file originally auto-generated by mib2c 
+ *
+ */
+#ifndef KAMAILIOSERVER_H
+#define KAMAILIOSERVER_H
+
+/* function declarations */
+void init_kamailioServer(void);
+Netsnmp_Node_Handler handle_kamailioSrvMaxMemory;
+Netsnmp_Node_Handler handle_kamailioSrvFreeMemory;
+Netsnmp_Node_Handler handle_kamailioSrvMaxUsed;
+Netsnmp_Node_Handler handle_kamailioSrvRealUsed;
+Netsnmp_Node_Handler handle_kamailioSrvMemFragments;
+
+Netsnmp_Node_Handler handle_kamailioSrvCnfFullVersion;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerName;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerVersion;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerArch;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerOs;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerId;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerCompTime;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerCompiler;
+Netsnmp_Node_Handler handle_kamailioSrvCnfVerFlags;
+
+#endif /* KAMAILIOSERVER_H */
diff --git a/modules/snmpstats/mibs/KAMAILIO-MIB b/modules/snmpstats/mibs/KAMAILIO-MIB
index a95d647..1998625 100644
--- a/modules/snmpstats/mibs/KAMAILIO-MIB
+++ b/modules/snmpstats/mibs/KAMAILIO-MIB
@@ -7,6 +7,7 @@
 -- 
 -- Copyright (c) The Internet Society (2006)
 -- Ammendments (c) Soma Networks, Inc. (2006)
+-- Kamailio extras (c) Edvina AB, 2013
 --
 -- All rights reserved.
 -- *****************************************************************
@@ -25,7 +26,11 @@ KAMAILIO-MIB DEFINITIONS ::= BEGIN
         Gauge32
             FROM SNMPv2-SMI
             
-        DateAndTime
+        DateAndTime,
+	TEXTUAL-CONVENTION,
+	DisplayString,
+	RowStatus,
+	TruthValue
             FROM SNMPv2-TC
 
         SnmpAdminString
@@ -72,6 +77,9 @@ KAMAILIO-MIB DEFINITIONS ::= BEGIN
         REVISION   "201301081200Z"
         DESCRIPTION
            "Renamed MIB and mib entries to new product name, Kamailio."
+        REVISION   "201303301200Z"
+        DESCRIPTION
+           "Added Kamailio process information - memory, transports, core configuration"
         ::= { kamailioModules 5 }
 
 --
@@ -94,7 +102,6 @@ KAMAILIO-MIB DEFINITIONS ::= BEGIN
         DESCRIPTION 
         "Sub-tree for Conformance specifications."
         ::= { kamailioMIB 3 }
-                                
 
 --
 -- kamailioObjects sub-components
@@ -117,9 +124,704 @@ KAMAILIO-MIB DEFINITIONS ::= BEGIN
         "Sub-tree for tracking of SIP Dialogs being processed by Kamailio."
     ::= { kamailioObjects 3 }
 
+   kamailioNet OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for tracking of Network Transports being enabled in Kamailio."
+    ::= { kamailioObjects 4 }
+
 -- 
 -- Kamailio Server Objects
 --
+    kamailioSrvMemory OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for Core Memory Statistics." 
+        ::= { kamailioServer 1 }
+
+    kamailioSrvConfig OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for Core configuration - compile flags etc." 
+        ::= { kamailioServer 2 }
+
+    kamailioSrvCounters OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for Core Counters/Statistic variables." 
+        ::= { kamailioServer 3 }
+
+    kamailioSrvProcess OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for Core Processes." 
+        ::= { kamailioServer 4 }
+
+-- 
+-- Kamailio Server Configuration
+--
+
+    kamailioSrvCnfFullVersion OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Full version of Kamailio"
+        ::= { kamailioSrvConfig 1 }
+
+    kamailioSrvCnfVerName OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Version of Kamailio"
+        ::= { kamailioSrvConfig 2 }
+
+    kamailioSrvCnfVerVersion OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Version of Kamailio"
+        ::= { kamailioSrvConfig 3 }
+
+    kamailioSrvCnfVerArch OBJECT-TYPE
+        SYNTAX      DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Architecture Kamailio is compiled for"
+        ::= { kamailioSrvConfig 4 }
+
+    kamailioSrvCnfVerOs	OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Operating System Kamailio is compiled for"
+        ::= { kamailioSrvConfig 5 }
+
+    kamailioSrvCnfVerId	OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Kamailio Version ID"
+        ::= { kamailioSrvConfig 6 }
+
+    kamailioSrvCnfVerCompTime OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Kamailio Build time"
+        ::= { kamailioSrvConfig 7 }
+
+    kamailioSrvCnfVerCompiler OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Kamailio Build compiler used"
+        ::= { kamailioSrvConfig 8 }
+
+    kamailioSrvCnfVerFlags OBJECT-TYPE
+        SYNTAX DisplayString
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Kamailio Build compile time flags"
+        ::= { kamailioSrvConfig 9 }
+
+
+-- 
+-- Kamailio Server Memory data
+--
+    kamailioSrvMaxMemory OBJECT-TYPE
+        SYNTAX      Gauge32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Maximum available Shared Memory"
+        ::= { kamailioSrvMemory 1 }
+
+    kamailioSrvFreeMemory OBJECT-TYPE
+        SYNTAX      Gauge32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Available free memory in the Shared Memory pool"
+        ::= { kamailioSrvMemory 2 }
+
+    kamailioSrvMaxUsed OBJECT-TYPE
+        SYNTAX      Gauge32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Maximum amount of memory used in the Shared Memory pool"
+        ::= { kamailioSrvMemory 3 }
+
+    kamailioSrvRealUsed OBJECT-TYPE
+        SYNTAX      Gauge32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Current amount of memory used in the Shared Memory pool"
+        ::= { kamailioSrvMemory 4 }
+
+    kamailioSrvMemFragments OBJECT-TYPE
+        SYNTAX      Gauge32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Current amount of memory fragments in the Shared Memory pool"
+        ::= { kamailioSrvMemory 5 }
+
+
+-- 
+-- Kamailio Server Core counters
+--
+
+-- 
+-- Kamailio Network Objects
+--
+    kamailioNetTcp OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for TCP Network Transport objects (incl TLS conncetions)." 
+        ::= { kamailioNet 1 }
+
+    kamailioNetWebsocket OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for Websocket Network Transport objects ." 
+        ::= { kamailioNet 2 }
+
+    kamailioNetHttp OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for HTTP Server Transport objects ." 
+        ::= { kamailioNet 3 }
+
+    kamailioNetConfig OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for transport properties"
+        ::= { kamailioNet 4 }
+
+--
+-- TCP connection objects
+--
+    kamailioNetTcpTls OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for TCP/TLS specific objects." 
+        ::= { kamailioNetTcp 1 }
+
+    kamailioNetTcpStat OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for TCP/TLS statistics." 
+        ::= { kamailioNetTcp 2 }
+
+    kamailioNetTcpConfig OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for TCP/TLS configuration data." 
+        ::= { kamailioNetTcp 3 }
+
+--
+-- TCP connection config objects
+--
+    kamailioNetTcpEnabled OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if TCP is enabled in this server."
+        ::= { kamailioNetTcpConfig 1 }
+
+    kamailioNetTcpMaxConns OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Maximum number of TCP connections (tcp_max_connections)"
+        ::= { kamailioNetTcpConfig 2 }
+
+    kamailioNetTcpConnTimeout OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "TCP Connection Timeout (tcp_connect_timeout)"
+        ::= { kamailioNetTcpConfig 3 }
+
+    kamailioNetTcpSendTimeout OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Time in seconds after a TCP connection will be closed if it is not available for writing in this interval (tcp_send_timeout)"
+        ::= { kamailioNetTcpConfig 4 }
+
+    kamailioNetTcpConnLifetime OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Lifetime in seconds for TCP sessions (tcp_connection_lifetime)"
+        ::= { kamailioNetTcpConfig 5 }
+
+    kamailioNetTcpConnLifetime OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Maximum number of tcp connections (tcp_max_connections)"
+        ::= { kamailioNetTcpConfig 6 }
+
+    kamailioNetTcpNoConnect OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "True if Kamailio never tries to set up outbound TCP (or TCP/TLS) connections (tcp_no_connect)"
+        ::= { kamailioNetTcpConfig 7 }
+
+    kamailioNetTcpFdCache OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "If enabled FDs used for sending will be cached inside the process calling tcp_send (tcp_fd_cache)"
+        ::= { kamailioNetTcpConfig 8 }
+
+    kamailioNetTcpAsync OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "True if TCP Async is enabled in this server (tcp_async)"
+        ::= { kamailioNetTcpConfig 9 }
+
+    kamailioNetTcpAsyncConnWait OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "??? No description available "
+        ::= { kamailioNetTcpConfig 10 }
+
+    kamailioNetTcpAsyncConnWait OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "??? No description available "
+        ::= { kamailioNetTcpConfig 10 }
+
+    kamailioNetTcpAsyncConnWqMax OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Async TCP: Maximum bytes queued for write allowed per connection. (tcp_conn_wq_max)"
+        ::= { kamailioNetTcpConfig 11 }
+
+    kamailioNetTcpAsyncWqMax OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Async TCP: Maximum bytes queued for write (tcp__wq_max)"
+        ::= { kamailioNetTcpConfig 12 }
+
+    kamailioNetTcpAsyncWqBlkSize OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Async TCP: Maximum bytes queued for write (tcp_wq_blk_size)"
+        ::= { kamailioNetTcpConfig 12 }
+
+    kamailioNetTcpRdBufSize OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Buffer size used for tcp reads (tcp_rd_buf_size)"
+        ::= { kamailioNetTcpConfig 13 }
+
+    kamailioNetTcpDeferAccept OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Tcp accepts will be delayed until some data is received (tcp_defer_accept)"
+        ::= { kamailioNetTcpConfig 14 }
+
+    kamailioNetTcpDelayedAck OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Initial ACK for opened connections will be delayed and sent with the first data segment (tcp_delayed_ack)"
+        ::= { kamailioNetTcpConfig 15 }
+
+    kamailioNetTcpSynCnt OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of SYN retransmissions before aborting a connect attempt (tcp_syncnt)"
+        ::= { kamailioNetTcpConfig 16 }
+
+    kamailioNetTcpLinger OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Lifetime of orphaned sockets in FIN_WAIT2 state. Linux only. (tcp_linger2)"
+        ::= { kamailioNetTcpConfig 17 }
+
+    kamailioNetTcpKeepAlive OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "True if TCP Keepalives are enabled (tcp_keepalive)"
+        ::= { kamailioNetTcpConfig 18 }
+
+    kamailioNetTcpKeepIdle OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Time before starting to send keepalives, if the connection is idle. Linux only. (tcp_keepidle)"
+        ::= { kamailioNetTcpConfig 19 }
+
+    kamailioNetTcpKeepIntvl OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Time interval between keepalive probes, when the previous probe failed. Linux only. (tcp_keepintvl)"
+        ::= { kamailioNetTcpConfig 20 }
+
+    kamailioNetTcpKeepCnt OBJECT-TYPE
+        SYNTAX  Integer32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of keepalives sent before dropping the connection. Linux only. (tcp_keepcnt)"
+        ::= { kamailioNetTcpConfig 21 }
+
+    kamailioNetTcpCrlfPing OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Enable SIP outbound TCP keep-alive using PING-PONG (CRLFCRLF - CRLF). (tcp_crlf_ping)"
+        ::= { kamailioNetTcpConfig 22 }
+
+    kamailioNetTcpAcceptAliases OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Reuse TCP connections based on aliases (tcp_accept_alias)"
+        ::= { kamailioNetTcpConfig 23 }
+
+    kamailioNetTcpAcceptNoCl OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "True if Content-Length headers are required (tcp_accept_no_cl)"
+        ::= { kamailioNetTcpConfig 24 }
+
+
+	--- RPC settings not found. Still looking.
+	---	connect_wait: 1 Depends on Async
+	---	alias_flags: 1
+	---	new_conn_alias_flags: 2
+	---	max_tls_connections(soft): 2048
+
+--
+-- TCP connection statistic objects
+--
+    kamailioNetTcpConnEstablished OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Incremented each time a TCP connection is established."
+        ::= { kamailioNetTcpStat 1 }
+
+    kamailioNetTcpConnFailed OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of failed active TCP connection attempts."
+        ::= { kamailioNetTcpStat 2 }
+
+    kamailioNetTcpConnReset OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of reset TCP connections"
+        ::= { kamailioNetTcpStat 3 }
+
+    kamailioNetTcpConnSuccess OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of successful TCP connections"
+        ::= { kamailioNetTcpStat 4 }
+
+    kamailioNetTcpConnOpen OBJECT-TYPE
+        SYNTAX      Gauge32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of current open TCP connections"
+        ::= { kamailioNetTcpStat 5 }
+
+    kamailioNetTcpConnPassiveOpen OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Total number of accepted TCP connections (so far)."
+        ::= { kamailioNetTcpStat 6 }
+
+    kamailioNetTcpConnSuccess OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Total number of successfully active opened TCP connections"
+        ::= { kamailioNetTcpStat 7 }
+
+    kamailioNetTcpConnReject OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of rejected incoming TCP connections."
+        ::= { kamailioNetTcpStat 8 }
+
+--
+-- Kamailio Network Configuration
+--
+    kamailioNetConfUdpTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if UDP is active in this server."
+        ::= { kamailioNetConfig 1 }
+
+    kamailioNetConfUdpDtlsTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if UDP/DTLS is active in this server. (Future reservation)"
+        ::= { kamailioNetConfig 2 }
+
+    kamailioNetConfTcpTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if TCP is active in this server."
+        ::= { kamailioNetConfig 3 }
+
+    kamailioNetConfTcpTlsTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if TCP/TLS is active in this server."
+        ::= { kamailioNetConfig 4 }
+
+    kamailioNetConfSctpTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if Sctp is enabled in this server."
+        ::= { kamailioNetConfig 5 }
+
+    kamailioNetConfSctpTlsTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if Sctp/TLS is enabled in this server. (Future reservation)"
+        ::= { kamailioNetConfig 6 }
+
+    kamailioNetConfWsTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if WS - WebSocket Transport- is enabled in this server."
+        ::= { kamailioNetConfig 7 }
+
+    kamailioNetConfWsTlsTransport OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if WSS - WebSocket Transport with TLS- is enabled in this server."
+        ::= { kamailioNetConfig 8 }
+
+    kamailioNetConfHttpServer OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if the embedded HTTP server (xhttp module) is loaded in this server."
+        ::= { kamailioNetConfig 9 }
+
+    kamailioNetConfMsrpRelay OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if the MSRP Relay server is loaded in this server."
+        ::= { kamailioNetConfig 10 }
+
+    kamailioNetConfStunServer OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if the STUN Server server (SIP Outbound) is loaded in this server."
+        ::= { kamailioNetConfig 11 }
+
+    kamailioNetConfOutbound OBJECT-TYPE
+        SYNTAX  TruthValue
+        MAX-ACCESS  read-only
+        STATUS current
+	DEFVAL { false }
+        DESCRIPTION 
+        "True if the SIP Outbound module is loaded in this server."
+        ::= { kamailioNetConfig 12 }
+
+--
+-- Websocket Connection Objects
+--
+    kamailioNetWsStat OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for Websocket statistics." 
+        ::= { kamailioNetWebsocket 1 }
+
+   kamailioNetWsConfig OBJECT-IDENTITY
+        STATUS current
+        DESCRIPTION 
+        "Sub-tree for Websocket configuration objects." 
+        ::= { kamailioNetWebsocket 2 }
+
+--
+-- Kamailio WebSocket Configuration  Objects
+--
+	--- Currently empty.
+
+--
+-- Kamailio WebSocket Statistics  Objects
+--
+
+    kamailioNetWsConnsActive OBJECT-TYPE
+        SYNTAX      Gauge
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "Number of currently active websocket connections"
+        ::= { kamailioNetWsStat 1 }
+
+    kamailioNetWsConnsActiveMax OBJECT-TYPE
+        SYNTAX      Gauge
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The maximum number of active websocket connections since process start"
+        ::= { kamailioNetWsStat 2 }
+
+    kamailioNetWsConnsFailed OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The number of failed websocket connections since process start"
+        ::= { kamailioNetWsStat 3 }
+
+    kamailioNetWsConnsClosedLocal OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The number of locally closed websocket connections"
+        ::= { kamailioNetWsStat 4 }
+
+    kamailioNetWsConnsClosedRemote OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The number of closed websocket connections by remote peer"
+        ::= { kamailioNetWsStat 5 }
+
+    kamailioNetWsFramesRx OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The number of received websocket frames"
+        ::= { kamailioNetWsStat 6 }
+
+    kamailioNetWsFramesTx OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The number of transmitted websocket frames"
+        ::= { kamailioNetWsStat 7 }
+
+    kamailioNetWsHandshakeSuccess OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The number of transmitted websocket frames"
+        ::= { kamailioNetWsStat 8 }
+
+    kamailioNetWsHandshakeFailed OBJECT-TYPE
+        SYNTAX      Counter32
+        MAX-ACCESS  read-only
+        STATUS current
+        DESCRIPTION 
+        "The number of transmitted websocket frames"
+        ::= { kamailioNetWsStat 9 }
 
 
 --
diff --git a/modules/snmpstats/mibs/KAMAILIO-SIP-COMMON-MIB b/modules/snmpstats/mibs/KAMAILIO-SIP-COMMON-MIB
index 0705f16..3ceec33 100644
--- a/modules/snmpstats/mibs/KAMAILIO-SIP-COMMON-MIB
+++ b/modules/snmpstats/mibs/KAMAILIO-SIP-COMMON-MIB
@@ -113,7 +113,6 @@ KAMAILIO-SIP-COMMON-MIB DEFINITIONS ::= BEGIN
               Registrar: A registrar is a server that accepts
               REGISTER requests and places the information it
               receives in those requests into the location service
-
               for the domain it handles.
 
               Copyright (C) The Internet Society (2005). This version
@@ -332,8 +331,14 @@ KAMAILIO-SIP-COMMON-MIB DEFINITIONS ::= BEGIN
              transport protocol is currently not being used. 
 	     
              The bits are assigned as follows:
-             
-             other(0), udp(1), tcp(2), sctp(3), tls(4)"
+		bit 0: a protocol other than those defined here
+       		bit 1: User Datagram Protocol
+       		bit 2: Transmission Control Protocol
+       		bit 3: Stream Control Transmission Protocol
+       		bit 4: Transport Layer Security Protocol over TCP
+       		bit 5: Transport Layer Security Protocol over SCTP
+       		bit 6: WebSocket transport
+       		bit 7: WebSocket transport over HTTP/TLS (WSS)"
        ::= { kamailioSIPPortEntry 4 }
 
    --
diff --git a/modules/snmpstats/mibs/KAMAILIO-TC b/modules/snmpstats/mibs/KAMAILIO-TC
index 828ce2b..81d1459 100644
--- a/modules/snmpstats/mibs/KAMAILIO-TC
+++ b/modules/snmpstats/mibs/KAMAILIO-TC
@@ -23,7 +23,7 @@ IMPORTS
 
 
 kamailioTcModule MODULE-IDENTITY
-	LAST-UPDATED	"201301081200Z"
+	LAST-UPDATED	"201304041200Z"
 	ORGANIZATION	"Kamailio"
 	CONTACT-INFO
 		"http://www.kamailio.org"
@@ -51,16 +51,22 @@ KamailioSIPTransportProtocol ::= TEXTUAL-CONVENTION
                  bit 1   : User Datagram Protocol.
                  bit 2   : Transmission Control Protocol.
                  bit 3   : Stream Control Transmission Protocol.
-                 bit 4   : Transport Layer Security Protocol."
+                 bit 4   : Transport Layer Security Protocol.
+                 bit 5   : SCTP/Transport Layer Security Protocol.
+                 bit 6   : WebSocket transport (http)
+		 bit 7   : WebSocket over HTTP/TLS (wss)"
            SYNTAX     BITS {
                             other(0),  -- none of the following
 
                             udp(1),
                             tcp(2),
                             sctp(3),
-                            tls(4)
+                            tls(4),
+                            sctp_tls(5),
+			    ws(6),
+			    wss(7)
            }
---         REFERENCE "RFC 3261, Section 18"
+--         REFERENCE "RFC 4780, SipTCTransportProtocol"
 
 KamailioSIPEntityRole ::= TEXTUAL-CONVENTION
            STATUS current
@@ -68,13 +74,20 @@ KamailioSIPEntityRole ::= TEXTUAL-CONVENTION
                 "This convention defines the role of a SIP entity.
                  Examples of SIP entities are proxies, user agents,
                  redirect servers, registrars or combinations of
-                 the above."
+                 the above.
+		Kamailio adds the role 'edgeproxyServer' for
+		operation of a SIP outbound edge proxy node.
+		Kamailio adds the role 'sipcaptureServer' for
+		operation of a Homer SIPcapture node."
+		"
            SYNTAX BITS {
                             other(0),
                             userAgent(1),
                             proxyServer(2),
                             redirectServer(3),
                             registrarServer(4)
+                            edgeproxyServer(5)
+                            sipcaptureServer(6)
            }
 
 
@@ -87,7 +100,6 @@ KamailioSIPMethodIdentifier ::= TEXTUAL-CONVENTION
              of all defined SIP methods.
 
              Experimental support of extension methods is
-
              acceptable and expected.  Extention methods are
              those defined in Internet-Draft documents but
              not yet allocated an official number by IANA.
diff --git a/modules/snmpstats/snmpSIPCommonObjects.c b/modules/snmpstats/snmpSIPCommonObjects.c
index f4244d5..44ffa9d 100644
--- a/modules/snmpstats/snmpSIPCommonObjects.c
+++ b/modules/snmpstats/snmpSIPCommonObjects.c
@@ -502,6 +502,12 @@ int handleSipEntityType( modparam_t type, void* val)
 	else if (strcasecmp(strEntityType, "registrarServer") == 0) {
 		kamailioEntityType |= TC_SIP_ENTITY_ROLE_REGISTRAR_SERVER;
 	}
+	else if (strcasecmp(strEntityType, "edgeproxyServer") == 0) {
+		kamailioEntityType |= TC_SIP_ENTITY_ROLE_EDGEPROXY_SERVER;
+	}
+	else if (strcasecmp(strEntityType, "sipcaptureServer") == 0) {
+		kamailioEntityType |= TC_SIP_ENTITY_ROLE_SIPCAPTURE_SERVER;
+	}
 	else {
 		LM_ERR("The configuration file specified sipEntityType=%s,"
 				" an unknown type\n", strEntityType);
diff --git a/modules/snmpstats/snmpSIPMethodSupportedTable.c b/modules/snmpstats/snmpSIPMethodSupportedTable.c
index 756dfce..92cc8b6 100644
--- a/modules/snmpstats/snmpSIPMethodSupportedTable.c
+++ b/modules/snmpstats/snmpSIPMethodSupportedTable.c
@@ -140,23 +140,16 @@ void init_kamailioSIPMethodSupportedTable(void)
 	 * NOTE: My way of checking what METHODS we support is probably wrong.
 	 * Please feel free to correct it! */
 	
-	if (module_loaded("sl")) {
-		createRow(1, "METHOD_INVITE");
-		createRow(2, "METHOD_CANCEL");
-		createRow(3, "METHOD_ACK");
-	}
-
-	if (module_loaded("tm")) {
-		createRow(4, "METHOD_BYE");
-	}
+	createRow(1, "METHOD_INVITE");
+	createRow(2, "METHOD_CANCEL");
+	createRow(3, "METHOD_ACK");
+	createRow(4, "METHOD_BYE");
 
 	if (module_loaded("options") || module_loaded("siputils")) {
 		createRow(6, "METHOD_OPTIONS");
 	}
 
-	if (module_loaded("dialog")) {
-		createRow(7, "METHOD_UPDATE");
-	}
+	createRow(7, "METHOD_UPDATE");
 
 	if (module_loaded("registrar")) {
 		createRow(8, "METHOD_REGISTER");
@@ -166,9 +159,6 @@ void init_kamailioSIPMethodSupportedTable(void)
 
 	createRow(5,  "METHOD_INFO");
 	createRow(9,  "METHOD_MESSAGE");
-
-	/* I'm not sure what these guys are, so saying we support them by
-	 * default.  */
 	createRow(12, "METHOD_PRACK");
 	createRow(13, "METHOD_REFER");
 	createRow(14, "METHOD_PUBLISH");
diff --git a/modules/snmpstats/snmpSIPPortTable.c b/modules/snmpstats/snmpSIPPortTable.c
index 5d57c2e..89f88f4 100644
--- a/modules/snmpstats/snmpSIPPortTable.c
+++ b/modules/snmpstats/snmpSIPPortTable.c
@@ -28,7 +28,8 @@
  * History:
  * --------
  * 2006-11-23 initial version (jmagder)
- * 2013-02-24 Added WS, WSS and SCTP support (oej)
+ * 2013-02-24 Added SCTP support (oej)
+ * 2013-04-07 Added IPv6 support (oej)
  * 
  * Originally Generated with mib2c using mib2c.array-user.conf
  *
@@ -65,18 +66,21 @@ size_t kamailioSIPPortTable_oid_len = OID_LENGTH(kamailioSIPPortTable_oid);
  * Note: This function returns a newly allocated block of memory.  Make sure to
  * deallocate the memory when you no longer need it. 
  */
-oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID) 
+static oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID) 
 {
 	oid *currentOIDIndex;
 	int i;
+	int family = ipType == 1 ? AF_INET : AF_INET6;
+	int num_octets = family == AF_INET ? NUM_IP_OCTETS : NUM_IPV6_OCTETS;
 
 	/* The size needs to be large enough such that it can store the ipType
 	 * (one octet), the prefixed length (one octet), the number of
 	 * octets to the IP Address (NUM_IP_OCTETS), and the port. */
-	*sizeOfOID = NUM_IP_OCTETS + 3;
+	*sizeOfOID = num_octets + 3;
 
 	/* Allocate space for the OID Index.  */
 	currentOIDIndex = pkg_malloc((*sizeOfOID) * sizeof(oid));
+	LM_DBG("----> Size of OID %d \n", *sizeOfOID);
 
 	if (currentOIDIndex == NULL) {
 		LM_ERR("failed to create a row for kamailioSIPPortTable\n");
@@ -86,14 +90,15 @@ oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID)
 
 	/* Assign the OID Index */
 	currentOIDIndex[0] = ipType;
-	currentOIDIndex[1] = NUM_IP_OCTETS;
+	currentOIDIndex[1] = num_octets;
 		
-	for (i = 0; i < NUM_IP_OCTETS; i++) {
+	for (i = 0; i < num_octets; i++) {
 		currentOIDIndex[i+2] = ipAddress[i];
 	}
 
 	/* Extract out the port number */
-	currentOIDIndex[NUM_IP_OCTETS+2] = ipAddress[NUM_IP_OCTETS];
+	currentOIDIndex[num_octets + 2] = ipAddress[num_octets];
+	LM_DBG("----> Port number %d Family %s \n", ipAddress[num_octets], ipType == 1 ? "IPv4" : "IPv6");
 
 	return currentOIDIndex;
 }
@@ -105,23 +110,22 @@ oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID)
  *
  * Note: NULL will be returned on an error 
  */
-kamailioSIPPortTable_context *getRow(int ipType, int *ipAddress) 
+kamailioSIPPortTable_context *getRow(int ipType, int *ipAddress)
 {
 	int lengthOfOID;
 	oid *currentOIDIndex = createIndex(ipType, ipAddress, &lengthOfOID);
+	netsnmp_index theIndex;
+	kamailioSIPPortTable_context *rowToReturn;
+	int num_octets = ipType == 1 ? NUM_IP_OCTETS : NUM_IPV6_OCTETS;
 
 	if (currentOIDIndex == NULL)
 	{
 		return NULL;
 	}
 
-	netsnmp_index theIndex;
-
 	theIndex.oids = currentOIDIndex;
 	theIndex.len  = lengthOfOID;
 
-	kamailioSIPPortTable_context *rowToReturn;
-
 	/* Lets check to see if there is an existing row. */
 	rowToReturn = CONTAINER_FIND(cb.container, &theIndex);
 	
@@ -149,8 +153,8 @@ kamailioSIPPortTable_context *getRow(int ipType, int *ipAddress)
 	rowToReturn->index.len  = lengthOfOID;
 	rowToReturn->index.oids = currentOIDIndex;
 
-	memcpy(rowToReturn->kamailioSIPStringIndex, currentOIDIndex, NUM_IP_OCTETS + 3);
-	rowToReturn->kamailioSIPStringIndex_len = NUM_IP_OCTETS + 3;
+	memcpy(rowToReturn->kamailioSIPStringIndex, currentOIDIndex, num_octets + 3);
+	rowToReturn->kamailioSIPStringIndex_len = num_octets + 3;
 
 	/* Insert the new row into the table */
 	CONTAINER_INSERT(cb.container, rowToReturn);
@@ -166,11 +170,11 @@ kamailioSIPPortTable_context *getRow(int ipType, int *ipAddress)
  * to an integer so that if the function is called again with another
  * 'protocol', we can continue from the last index. 
  */
-void createRowsFromIPList(int *theList, int listSize, int protocol, 
-		int *snmpIndex) {
+static void createRowsFromIPList(int *theList, int listSize, int protocol, 
+		int *snmpIndex, int family) {
 
 	kamailioSIPPortTable_context *currentRow;
-	
+	int num_octets = family == AF_INET ? NUM_IP_OCTETS : NUM_IPV6_OCTETS;
 	int curIndexOfIP;
 	int curSocketIdx;
 	int valueToAssign;
@@ -187,14 +191,6 @@ void createRowsFromIPList(int *theList, int listSize, int protocol,
 	{
 		valueToAssign = TC_TRANSPORT_PROTOCOL_TLS;
 	}
-	else if (protocol == PROTO_WS)
-	{
-		valueToAssign = TC_TRANSPORT_PROTOCOL_WS;
-	}
-	else if (protocol == PROTO_WSS)
-	{
-		valueToAssign = TC_TRANSPORT_PROTOCOL_WSS;
-	}
 	else if (protocol == PROTO_SCTP)
 	{
 		valueToAssign = TC_SIP_TRANSPORT_PROTOCOL_SCTP;
@@ -207,11 +203,13 @@ void createRowsFromIPList(int *theList, int listSize, int protocol,
 	/* Create all rows with respect to the given protocol */
 	for (curSocketIdx=0; curSocketIdx < listSize; curSocketIdx++) {
 
-		curIndexOfIP   = (NUM_IP_OCTETS + 1) * curSocketIdx;
+		curIndexOfIP   = (num_octets + 1) * curSocketIdx;
 		
 		/* Retrieve an existing row, or a new row if one doesn't
-		 * allready exist. */
-		currentRow = getRow(1, &theList[curIndexOfIP]);
+		 * already exist. 
+		 * RFC 4001 defined IPv4 as 1, IPv6 as 2
+		*/
+		currentRow = getRow(family == AF_INET? 1 : 2, &theList[curIndexOfIP]);
 
 		if (currentRow == NULL) {
 			LM_ERR("failed to create all the "
@@ -240,43 +238,55 @@ void init_kamailioSIPPortTable(void)
 	int *UDPList = NULL;
 	int *TCPList = NULL;
 	int *TLSList = NULL;
-	int *WSList = NULL;
-	int *WSSList = NULL;
 	int *SCTPList = NULL;
 
+	int *UDP6List = NULL;
+	int *TCP6List = NULL;
+	int *TLS6List = NULL;
+	int *SCTP6List = NULL;
+
 	int numUDPSockets;
 	int numTCPSockets; 
 	int numTLSSockets;
-	int numWSSockets;
-	int numWSSSockets;
 	int numSCTPSockets;
+
+	int numUDP6Sockets;
+	int numTCP6Sockets; 
+	int numTLS6Sockets;
+	int numSCTP6Sockets;
 	
 	/* Retrieve the list of the number of UDP and TCP sockets. */
-	numUDPSockets = get_socket_list_from_proto(&UDPList, PROTO_UDP);
-	numTCPSockets = get_socket_list_from_proto(&TCPList, PROTO_TCP);
-	numTLSSockets = get_socket_list_from_proto(&TLSList, PROTO_TLS);
-	numWSSockets = get_socket_list_from_proto(&WSList, PROTO_WS);
-	numWSSSockets = get_socket_list_from_proto(&WSSList, PROTO_WSS);
-	numSCTPSockets = get_socket_list_from_proto(&SCTPList, PROTO_SCTP);
+	numUDPSockets = get_socket_list_from_proto_and_family(&UDPList, PROTO_UDP, AF_INET);
+	numUDP6Sockets = get_socket_list_from_proto_and_family(&UDP6List, PROTO_UDP, AF_INET6);
+	numTCPSockets = get_socket_list_from_proto_and_family(&TCPList, PROTO_TCP, AF_INET);
+	numTCP6Sockets = get_socket_list_from_proto_and_family(&TCP6List, PROTO_TCP, AF_INET6);
+	numTLSSockets = get_socket_list_from_proto_and_family(&TLSList, PROTO_TLS, AF_INET);
+	numTLS6Sockets = get_socket_list_from_proto_and_family(&TLS6List, PROTO_TLS, AF_INET6);
+	numSCTPSockets = get_socket_list_from_proto_and_family(&SCTPList, PROTO_SCTP, AF_INET);
+	numSCTP6Sockets = get_socket_list_from_proto_and_family(&SCTP6List, PROTO_SCTP, AF_INET6);
+
+	LM_DBG("-----> Sockets UDP %d UDP6 %d TCP %d TCP6 %d TLS %d TLS6 %d SCTP %d SCTP6 %d\n",
+		numUDPSockets, numUDP6Sockets, numTCPSockets, numTCP6Sockets, numTLSSockets, numTLS6Sockets, numSCTPSockets, numSCTP6Sockets);
 
 	/* Generate all rows, using all retrieved interfaces. */
-	createRowsFromIPList(UDPList, numUDPSockets, PROTO_UDP, &curSNMPIndex);
-
+	createRowsFromIPList(UDPList, numUDPSockets, PROTO_UDP, &curSNMPIndex, AF_INET);
 	curSNMPIndex = 0;
-	
-	createRowsFromIPList(TCPList, numTCPSockets, PROTO_TCP, &curSNMPIndex);
+	createRowsFromIPList(UDP6List, numUDP6Sockets, PROTO_UDP, &curSNMPIndex, AF_INET6);
 
 	curSNMPIndex = 0;
-	createRowsFromIPList(TLSList, numTLSSockets, PROTO_TLS, &curSNMPIndex);
-
+	createRowsFromIPList(TCPList, numTCPSockets, PROTO_TCP, &curSNMPIndex, AF_INET);
 	curSNMPIndex = 0;
-	createRowsFromIPList(WSList, numWSSockets, PROTO_WS, &curSNMPIndex);
+	createRowsFromIPList(TCP6List, numTCP6Sockets, PROTO_TCP, &curSNMPIndex, AF_INET6);
 
 	curSNMPIndex = 0;
-	createRowsFromIPList(WSSList, numWSSSockets, PROTO_WSS, &curSNMPIndex);
+	createRowsFromIPList(TLSList, numTLSSockets, PROTO_TLS, &curSNMPIndex, AF_INET);
+	curSNMPIndex = 0;
+	createRowsFromIPList(TLS6List, numTLS6Sockets, PROTO_TLS, &curSNMPIndex, AF_INET6);
 
 	curSNMPIndex = 0;
-	createRowsFromIPList(SCTPList, numSCTPSockets, PROTO_SCTP, &curSNMPIndex);
+	createRowsFromIPList(SCTPList, numSCTPSockets, PROTO_SCTP, &curSNMPIndex, AF_INET);
+	curSNMPIndex = 0;
+	createRowsFromIPList(SCTP6List, numSCTP6Sockets, PROTO_SCTP, &curSNMPIndex, AF_INET6);
 }
 
  
diff --git a/modules/snmpstats/snmpSIPPortTable.h b/modules/snmpstats/snmpSIPPortTable.h
index 8165b3e..f2b9cdd 100644
--- a/modules/snmpstats/snmpSIPPortTable.h
+++ b/modules/snmpstats/snmpSIPPortTable.h
@@ -47,9 +47,9 @@ extern "C" {
 
 #include "../../config.h"
 
-#define SIP_PORT_TABLE_STR_INDEX_SIZE 10
+#define SIP_PORT_TABLE_STR_INDEX_SIZE 22
 
-/* This strucutre represents a single row in the table. */
+/* This structure represents a single row in the table. */
 typedef struct kamailioSIPPortTable_context_s 
 {
 
@@ -87,11 +87,9 @@ void  initialize_table_kamailioSIPPortTable(void);
 int   kamailioSIPPortTable_get_value(netsnmp_request_info *, netsnmp_index *, 
 		netsnmp_table_request_info *);
 
-const kamailioSIPPortTable_context * kamailioSIPPortTable_get_by_idx(
-		netsnmp_index *);
+const kamailioSIPPortTable_context *kamailioSIPPortTable_get_by_idx(netsnmp_index *);
 
-const kamailioSIPPortTable_context * kamailioSIPPortTable_get_by_idx_rs(
-		netsnmp_index *, int row_status);
+const kamailioSIPPortTable_context * kamailioSIPPortTable_get_by_idx_rs(netsnmp_index *, int row_status);
 
 /*
  * oid declarations
diff --git a/modules/snmpstats/snmpSIPServerObjects.c b/modules/snmpstats/snmpSIPServerObjects.c
index 07e64e4..4ab497d 100644
--- a/modules/snmpstats/snmpSIPServerObjects.c
+++ b/modules/snmpstats/snmpSIPServerObjects.c
@@ -196,7 +196,7 @@ int handle_kamailioSIPProxyStatefulness(netsnmp_mib_handler *handler,
 {
 	int statefullness;
 
-	if (module_loaded("dialog")) 
+	if (module_loaded("dialog") || module_loaded("dialog_ng")) 
 	{
 		statefullness = PROXY_STATEFULNESS_CALL_STATEFUL;
 	}
diff --git a/modules/snmpstats/snmpstats.c b/modules/snmpstats/snmpstats.c
index 18df08c..06f44ef 100644
--- a/modules/snmpstats/snmpstats.c
+++ b/modules/snmpstats/snmpstats.c
@@ -4,6 +4,8 @@
  * SNMPStats Module 
  * Copyright (C) 2006 SOMA Networks, INC.
  * Written by: Jeffrey Magder (jmagder at somanetworks.com)
+ * Copyright (C) 2013 Edvina AB, Sollentuna, Sweden
+ * Updated and extended by: Olle E. Johansson (oej at edvina.net)
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -25,6 +27,7 @@
  * History:
  * --------
  * 2006-11-23 initial version (jmagder)
+ * 2013-04-01 updates of the MIB with core memory, tcp stats and much more (oej)
  * 
  * There are some important points to understanding the SNMPStat modules
  * architecture.
@@ -79,7 +82,8 @@
 #include "snmpstats.h"
 #include "snmpstats_globals.h"
 #include "../../timer.h"
-#include "../../cfg/cfg_struct.h"
+#include "../../cfg/cfg_select.h"
+#include "../../cfg/cfg_ctx.h"
 
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
@@ -127,7 +131,6 @@ static int  mod_child_init(int rank);
  * log a useful message and kill the AgentX Sub-Agent child process */
 static void mod_destroy(void);
 
-
 static proc_export_t mod_procs[] = {
 	{"SNMP AgentX",  0,  0, agentx_child, 1 },
 	{0,0,0,0,0}
@@ -366,6 +369,8 @@ static int mod_init(void)
 	register_procs(1);
 	/* add child to update local config framework structures */
 	cfg_register_child(1);
+	/* Initialize config framework in utilities.c */
+	config_context_init();
 
 	return 0;
 }
diff --git a/modules/snmpstats/snmpstats_globals.h b/modules/snmpstats/snmpstats_globals.h
index 470c38f..1eb37ed 100644
--- a/modules/snmpstats/snmpstats_globals.h
+++ b/modules/snmpstats/snmpstats_globals.h
@@ -64,12 +64,17 @@
 #define TC_SIP_TRANSPORT_PROTOCOL_TCP   (128>>2)
 #define TC_SIP_TRANSPORT_PROTOCOL_SCTP  (128>>3)
 #define TC_SIP_TRANSPORT_PROTOCOL_TLS   (128>>4)
+#define TC_SIP_TRANSPORT_PROTOCOL_SCTP_TLS   (128>>5)
+#define TC_SIP_TRANSPORT_PROTOCOL_WS    (128 >> 6)
+#define TC_SIP_TRANSPORT_PROTOCOL_WSS   (128 >> 7)
 
 #define TC_SIP_ENTITY_ROLE_OTHER            (128 >> 0)
 #define TC_SIP_ENTITY_ROLE_USER_AGENT       (128 >> 1)
 #define TC_SIP_ENTITY_ROLE_PROXY_SERVER     (128 >> 2)
 #define TC_SIP_ENTITY_ROLE_REDIRECT_SERVER  (128 >> 3)
 #define TC_SIP_ENTITY_ROLE_REGISTRAR_SERVER (128 >> 4)
+#define TC_SIP_ENTITY_ROLE_EDGEPROXY_SERVER (128 >> 5)
+#define TC_SIP_ENTITY_ROLE_SIPCAPTURE_SERVER (128 >> 6)
 
 #define TC_SIP_OPTION_TAG_REQUIRE       (128 >> 0)
 #define TC_SIP_OPTION_TAG_PROXY_REQUIRE (128 >> 1)
@@ -88,8 +93,9 @@
 #define TC_TRANSPORT_PROTOCOL_TCP   (128 >> 2)
 #define TC_TRANSPORT_PROTOCOL_SCTP  (128 >> 3)
 #define TC_TRANSPORT_PROTOCOL_TLS   (128 >> 4)
-#define TC_TRANSPORT_PROTOCOL_WS    (128 >> 5)
-#define TC_TRANSPORT_PROTOCOL_WSS   (128 >> 6)
+#define TC_TRANSPORT_PROTOCOL_SCRTP_TLS   (128 >> 5)
+#define TC_TRANSPORT_PROTOCOL_WS    (128 >> 6)
+#define TC_TRANSPORT_PROTOCOL_WSS   (128 >> 7)
 
 /*
  * Textual Conventions for BITS types - ends
diff --git a/modules/snmpstats/sub_agent.c b/modules/snmpstats/sub_agent.c
index e0760aa..57890de 100644
--- a/modules/snmpstats/sub_agent.c
+++ b/modules/snmpstats/sub_agent.c
@@ -63,6 +63,9 @@
 #include "snmpSIPContactTable.h"
 #include "snmpSIPRegUserLookupTable.h"
 #include "snmpMIBNotifications.h"
+#include "kamailioServer.h"
+#include "kamailioNet.h"
+#include "kamailioNetConfig.h"
 
 #include "../../dprint.h"
 #include "../../cfg/cfg_struct.h"
@@ -91,6 +94,8 @@ static int initialize_agentx(void)
 {
 	/* We register with a master agent */
 	register_with_master_agent(AGENT_PROCESS_NAME);
+
+	LM_DBG("Initializing Kamailio OID's for SNMPD MasterX\n");
 	
 	/* Initialize all scalars, and let the master agent know we want to
 	 * handle all OID's pertaining to these scalars. */
@@ -106,6 +111,10 @@ static int initialize_agentx(void)
 	init_kamailioSIPRegUserTable();
 	init_kamailioSIPContactTable();
 	init_kamailioSIPRegUserLookupTable();
+	init_kamailioServer();
+	init_kamailioNet();
+	init_kamailioNetConfig();
+	LM_DBG("Done initializing Kamailio OID's for SNMPD MasterX\n");
 
 	/* In case we recevie a request to stop (kill -TERM or kill -INT) */
 	keep_running = 1;
@@ -117,6 +126,7 @@ static int initialize_agentx(void)
 		agent_check_and_process(1); /* 0 == don't block */
 	}
 
+	LM_DBG("Shutting down Kamailio SNMPD MasterX sub agent.\n");
 	snmp_shutdown(AGENT_PROCESS_NAME);
 	SOCK_CLEANUP;
 	exit (0);
@@ -181,10 +191,12 @@ void register_with_master_agent(char *name_to_register_under)
 	/* Initialize TCP if necessary.  (Its here for WIN32) compatibility. */
 	SOCK_STARTUP;
 
+	LM_DBG("Connecting to SNMPD MasterX\n");
 	/* Read in our configuration file to determine master agent ping times
 	 * what port communication is to take place over, etc. */
 	init_agent("snmpstats");
 
 	/* Use a name we can register our agent under. */
 	init_snmp(name_to_register_under);
+	LM_DBG("** Connected to SNMPD MasterX\n");
 }
diff --git a/modules/snmpstats/utilities.c b/modules/snmpstats/utilities.c
index 59537dc..a7f5b28 100644
--- a/modules/snmpstats/utilities.c
+++ b/modules/snmpstats/utilities.c
@@ -45,9 +45,13 @@
 #include "../../str.h"
 #include "../../locking.h"
 #include "../../mem/mem.h"
+#include "../../cfg/cfg.h"
+#include "../../cfg/cfg_ctx.h"
 
 #include "../../lib/kcore/kstats_wrapper.h"
 
+static cfg_ctx_t  *ctx = NULL;
+
 /*!
  * This function copies an Kamailio "str" datatype into a '\\0' terminated char*
  * string. 
@@ -146,3 +150,46 @@ char * convertTMToSNMPDateAndTime(struct tm *timeStructure)
 
 	return dateAndTime;
 }
+
+/* module initialization function */
+int config_context_init(void)
+{
+	if (cfg_register_ctx(&ctx, NULL)) {
+		LOG(L_ERR, "cfg_rpc: failed to register cfg context\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*! \brief Get config framework variable 
+ * type will return cfg_type - CFG_VAR_INT, CFG_VAR_STRING, CFG_VAR_STR
+ * If type is CFG_VAR_UNSET then call failed and return value should be ignored.
+*/
+int snmp_cfg_get_int(char *arg_group, char *arg_name, unsigned int *type)
+{
+	void	*val;
+	unsigned int	val_type;
+	int res;
+
+	str group, name;
+
+	group.s = arg_group;
+	group.len = strlen(arg_group);
+	name.s = arg_name;
+	name.len = strlen(arg_name);
+
+	*type = CFG_VAR_UNSET;
+
+	res = cfg_get_by_name(ctx, &group, NULL, &name, &val, &val_type);
+	if (res < 0) {
+		LM_ERR("Failed to get the variable\n");
+		return -1;
+	} else if (res > 0) {
+		LM_ERR("Variable exists, but it is not readable via RPC interface\n");
+		return -1;
+	}
+	LM_DBG("Config framework variable %s:%s retrieved %d\n", arg_group, arg_name, (int)(long) val);
+	*type = val_type;
+	return (int) (long) val;
+}
diff --git a/modules/snmpstats/utilities.h b/modules/snmpstats/utilities.h
index d4e4b6e..9c6ff8e 100644
--- a/modules/snmpstats/utilities.h
+++ b/modules/snmpstats/utilities.h
@@ -72,4 +72,14 @@ int get_statistic(char *statName);
  * counted on to be around if this function is called again. */
 char * convertTMToSNMPDateAndTime(struct tm *timeStructure);
 
+/*! \brief Get config framework variable 
+ * type will return cfg_type - CFG_VAR_INT, CFG_VAR_STRING, CFG_VAR_STR
+ * If type is CFG_VAR_UNSET then call failed and return value should be ignored.
+*/
+int snmp_cfg_get_int(char *arg_group, char *arg_name, unsigned int *type);
+
+/*! Initialize config framework */
+int config_context_init(void);
+
+
 #endif
diff --git a/modules/sqlops/README b/modules/sqlops/README
index c81bd05..52f0171 100644
--- a/modules/sqlops/README
+++ b/modules/sqlops/README
@@ -170,7 +170,7 @@ modparam("sqlops", "sqlres", "ra")
    4.3. sql_pvquery(connection, query, result)
    4.4. sql_result_free(result)
 
-4.1. sql_query(connection, query[, result])
+4.1.  sql_query(connection, query[, result])
 
    Make an SQL query using 'connection' and store data in 'result'.
      * connection - the name of the connection to be used for the query
@@ -193,7 +193,7 @@ xlog("number of rows in table domain: $dbr(ra=>rows)\n");
 sql_result_free("ra");
 ...
 
-4.2. sql_xquery(connection, query, result)
+4.2.  sql_xquery(connection, query, result)
 
    Make an SQL query using 'connection' and store data in 'result' xavp.
      * connection - the name of the connection to be used for the query
@@ -212,7 +212,7 @@ sql_xquery("ca", "select * from domain", "ra");
   xlog("first domain: $xavp(ra=>domain) with id: $xavp(ra=>domain_id)\n");
 ...
 
-4.3. sql_pvquery(connection, query, result)
+4.3.  sql_pvquery(connection, query, result)
 
    Make an SQL query using 'connection' and store data in arbitrary pseudo
    variables specified by 'result' parameter.
@@ -244,7 +244,7 @@ sql_pvquery("ca", "select 'col1', 2, NULL, 'sip:test at example.com'",
         "$var(a), $avp(col2), $xavp(item[0]=>s), $ru");
 ...
 
-4.4. sql_result_free(result)
+4.4.  sql_result_free(result)
 
    Free data in SQL 'result'.
 
diff --git a/modules/sst/README b/modules/sst/README
index b9ae9c6..da1ff6f 100644
--- a/modules/sst/README
+++ b/modules/sst/README
@@ -170,7 +170,7 @@ Chapter 1. Admin Guide
 3.1. Kamailio Modules
 
    The following modules must be loaded before this module:
-     * dialog - dialog module and its dependencies. (tm)
+     * dialog or dialog-ng - dialog module and its dependencies. (tm)
      * sl - stateless module.
 
 3.2. External Libraries or Applications
diff --git a/modules/sst/doc/sst_admin.xml b/modules/sst/doc/sst_admin.xml
index 132678a..5c77123 100644
--- a/modules/sst/doc/sst_admin.xml
+++ b/modules/sst/doc/sst_admin.xml
@@ -123,7 +123,8 @@
 		<itemizedlist>
 		<listitem>
 		<para>
-		<emphasis>dialog</emphasis> - dialog module and its dependencies. (tm)
+		<emphasis>dialog</emphasis> or <emphasis>dialog-ng</emphasis>
+		- dialog module and its dependencies. (tm)
 		</para>
 		</listitem>
 		<listitem>
@@ -151,7 +152,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="sst.p.enable_stats">
 		<title><varname>enable_stats</varname> (integer)</title>
 
 		<para>If the statistics support should be enabled or
@@ -175,7 +176,7 @@ modparam("sst", "enable_stats", 0)
 		</example>
 	</section>
 
-	<section>
+	<section id="sst.p.min_se">
 		<title><varname>min_se</varname> (integer)</title>
 
 		<para>The value is used to set the proxies MIN-SE
@@ -203,7 +204,7 @@ modparam("sst", "min_se", 2400)
 		</example>
 	</section>
 
-	<section>
+	<section id="sst.p.timeout_avp">
 		<title><varname>timeout_avp</varname> (string)</title>
 
 		<para>This parameter MUST be set to the same value as the
@@ -229,7 +230,7 @@ modparam("sst", "timeout_avp", "$avp(i:10)")
 </programlisting>
 		</example>
 	</section>
-	<section>
+	<section id="sst.p.reject_to_small">
 		<title><varname>reject_to_small</varname> (integer)</title>
 
 		<para>In the initial INVITE if the UAC has requested a
@@ -259,7 +260,7 @@ modparam("sst", "reject_to_small", 0)
 </programlisting>
 		</example>
 	</section>
-<section>
+	<section id="sst.p.sst_flag">
 		<title><varname>sst_flag</varname> (integer)</title>
 		
 		<para>Keeping with &kamailio;, the module will not do
@@ -305,7 +306,7 @@ route {
 	</section>
 	<section>
 	<title>Functions</title>
-	<section>
+	<section id="sst.f.sstCheckMin">
 		<title>
 		<function moreinfo="none">sstCheckMin(send_reply_flag)</function>
 		</title>
diff --git a/modules/sst/sst_handlers.c b/modules/sst/sst_handlers.c
index 4ecbc1f..2a7b007 100644
--- a/modules/sst/sst_handlers.c
+++ b/modules/sst/sst_handlers.c
@@ -55,7 +55,7 @@
 
 #include "../../pvar.h"
 #include "../../lib/kcore/parse_sst.h"
-#include "../../lib/kcore/parse_supported.h"
+#include "../../parser/parse_supported.h"
 #include "../../mem/mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../data_lump.h"
@@ -884,8 +884,8 @@ static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo)
 	 * it is not found if unsuccessfull.
 	 */
 	if ((rtn = parse_supported(msg)) == 0) {
-		if ((((struct supported_body*)msg->supported->parsed)->supported_all
-						& F_SUPPORTED_TIMER)) {
+		if ((((struct option_tag_body*)msg->supported->parsed)->option_tags_all
+						& F_OPTION_TAG_TIMER)) {
 			minfo->supported = 1;
 		}
 	}
diff --git a/modules/statistics/README b/modules/statistics/README
index f279e76..04b1bbd 100644
--- a/modules/statistics/README
+++ b/modules/statistics/README
@@ -107,8 +107,7 @@ modparam("statistics", "variable", "active_calls/no_reset")
    Meaning of the parameters is as follows:
      * variable - variable to be updated (it can be a string or a
        pseudovariable);
-     * value - value to update with; it may be also negative (it can be a
-       string or pseudovariable).
+     * value - value to update with; it may be also negative.
 
    This function can be used from ANY_ROUTE.
 
diff --git a/modules/stun/Makefile b/modules/stun/Makefile
new file mode 100644
index 0000000..beced1f
--- /dev/null
+++ b/modules/stun/Makefile
@@ -0,0 +1,13 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=stun.so
+LIBS=
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+include ../../Makefile.modules
diff --git a/modules/stun/README b/modules/stun/README
new file mode 100644
index 0000000..d572a2f
--- /dev/null
+++ b/modules/stun/README
@@ -0,0 +1,72 @@
+STUN Module
+
+Peter Dunkley
+
+   Crocodile RCS Ltd
+
+   Copyright � 2013 Crocodile RCS Ltd
+
+   Copyright � 2001-2003 FhG Fokus
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+        4. Functions
+        5. MI Commands
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+   4. Functions
+   5. MI Commands
+
+1. Overview
+
+   This module provides limited STUN server (RFC 5389) support for
+   Kamailio. It's built for providing STUN support in the SIP signalling
+   channel, not being a standalone STUN/TURN server.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * None
+
+2.2. External Libraries or Applications
+
+   The following libraries must be installed before running Kamailio with
+   this module loaded:
+     * none.
+
+3. Parameters
+
+   None
+
+4. Functions
+
+   None
+
+5. MI Commands
+
+   None
diff --git a/modules/stun/config.c b/modules/stun/config.c
new file mode 100644
index 0000000..422d376
--- /dev/null
+++ b/modules/stun/config.c
@@ -0,0 +1,45 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file 
+ * \brief STUN :: Configuration
+ * \ingroup stun
+ */
+
+#include "../../cfg/cfg.h"
+#include "config.h"
+
+struct cfg_group_stun default_stun_cfg = {
+		0,	/* Read only variable to mark if stun is enabled */
+	    };
+
+void *stun_cfg = &default_stun_cfg;
+
+cfg_def_t stun_cfg_def[] = {
+	{ "stun_enabled", CFG_VAR_INT | CFG_ATOMIC | CFG_READONLY,
+	  0, 0, 0, 0,
+	  "If set to one (true) STUN is enabled." },
+
+	{0, 0, 0, 0, 0, 0}
+};
diff --git a/modules/stun/config.h b/modules/stun/config.h
new file mode 100644
index 0000000..2855e54
--- /dev/null
+++ b/modules/stun/config.h
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file 
+ * \brief STUN :: Configuration Framework support
+ * \ingroup stun
+ */
+
+
+#ifndef _STUN_CONFIG_H
+#define _STUN_CONFIG_H
+
+#include "../../cfg/cfg.h"
+
+struct cfg_group_stun {
+	int stun_active;
+};
+
+extern struct cfg_group_stun default_stun_cfg;
+extern void *stun_cfg;
+extern cfg_def_t stun_cfg_def[];
+
+#endif /* _STUN_CONFIG_H */
diff --git a/modules/stun/doc/Makefile b/modules/stun/doc/Makefile
new file mode 100644
index 0000000..51ff7d1
--- /dev/null
+++ b/modules/stun/doc/Makefile
@@ -0,0 +1,4 @@
+docs = stun.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules/stun/doc/stun.xml b/modules/stun/doc/stun.xml
new file mode 100644
index 0000000..e9c6ca8
--- /dev/null
+++ b/modules/stun/doc/stun.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>STUN Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+		<author>
+		<firstname>Peter</firstname>
+		<surname>Dunkley</surname>
+		<affiliation><orgname>Crocodile RCS Ltd</orgname></affiliation>
+		<address>
+			<email>peter.dunkley at crocodile-rcs.com</email>
+		</address>
+		</author>
+	</authorgroup>
+	<copyright>
+		<year>2013</year>
+		<holder>Crocodile RCS Ltd</holder>
+	</copyright>
+	<copyright>
+		<year>2001-2003</year>
+		<holder>FhG Fokus</holder>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+	
+	<xi:include href="stun_admin.xml"/>
+</book>
diff --git a/modules/stun/doc/stun_admin.xml b/modules/stun/doc/stun_admin.xml
new file mode 100644
index 0000000..4ab4a70
--- /dev/null
+++ b/modules/stun/doc/stun_admin.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>This module provides limited STUN server (RFC 5389) support for
+	&kamailio;. It's built for providing STUN support in the SIP signalling
+	channel, not being a standalone STUN/TURN server.</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>None</emphasis></para>
+		</listitem>
+		</itemizedlist>
+		</para>
+	</section>
+
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries must be installed before running
+		&kamailio; with this module loaded:
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>none</emphasis>.</para>
+		</listitem>
+		</itemizedlist>
+		</para>
+	</section>
+	</section>
+
+
+	<section>
+	<title>Parameters</title>
+	<para><emphasis>None</emphasis></para>
+	</section>
+
+	<section>
+	<title>Functions</title>
+	<para><emphasis>None</emphasis></para>
+	</section>
+
+	<section>
+	<title>MI Commands</title>
+	<para><emphasis>None</emphasis></para>
+	</section>
+
+</chapter>
+
diff --git a/modules/stun/kam_stun.c b/modules/stun/kam_stun.c
new file mode 100644
index 0000000..c9c5dd3
--- /dev/null
+++ b/modules/stun/kam_stun.c
@@ -0,0 +1,967 @@
+/*
+ * $Id$
+ *
+ * Portions Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * Based on "ser_stun.c". Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <arpa/inet.h>
+#include "kam_stun.h"
+#include "../../forward.h"
+
+/*
+ * ****************************************************************************
+ *                     Declaration of functions                               *
+ * ****************************************************************************
+ */
+static int stun_parse_header(struct stun_msg* req, USHORT_T* error_code);
+static int stun_parse_body(
+				struct stun_msg* req,
+				struct stun_unknown_att** unknown,
+				USHORT_T* error_code);
+static void stun_delete_unknown_attrs(struct stun_unknown_att* unknown);
+static struct stun_unknown_att* stun_alloc_unknown_attr(USHORT_T type);
+static int stun_add_address_attr(struct stun_msg* res, 
+						UINT_T		af,
+						USHORT_T	port,
+						UINT_T*		ip_addr,
+						USHORT_T	type,
+						int do_xor);
+static int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown);
+static int add_error_code(struct stun_msg* res, USHORT_T error_code);
+static int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad);
+static int reallock_buffer(struct stun_buffer* buffer, UINT_T len);
+static int buf_copy(struct stun_buffer* msg, void* source, UINT_T len);
+static void clean_memory(struct stun_msg* req,
+				struct stun_msg* res,	struct stun_unknown_att* unknown);
+static int stun_create_response(
+						struct stun_msg* req,
+						struct stun_msg* res,
+						struct receive_info* ri,
+						struct stun_unknown_att* unknown, 
+						UINT_T error_code);
+static int stun_add_common_text_attr(struct stun_msg* res, USHORT_T type, char* value, 
+							USHORT_T pad);
+
+
+/*
+ * ****************************************************************************
+ *                      Definition of functions                               *
+ * ****************************************************************************
+ */
+ 
+/* 
+ * process_stun_msg(): 
+ * 			buf - incoming message
+ * 			len - length of incoming message
+ * 			ri  - information about socket that received a message and 
+ *                also information about sender (its IP, port, protocol)
+ * 
+ * This function ensures processing of incoming message. It's common for both
+ * TCP and UDP protocol. There is no other function as an interface.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ * 
+ */
+int process_stun_msg(char* buf, unsigned len, struct receive_info* ri)
+{
+	struct stun_msg 			msg_req;
+	struct stun_msg 			msg_res;
+	struct dest_info			dst;
+	struct stun_unknown_att*	unknown;
+	USHORT_T					error_code;
+	 
+	memset(&msg_req, 0, sizeof(msg_req));
+	memset(&msg_res, 0, sizeof(msg_res));
+	
+	msg_req.msg.buf.s = buf;
+	msg_req.msg.buf.len = len;	
+	unknown = NULL;
+	error_code = RESPONSE_OK;
+	
+	if (stun_parse_header(&msg_req, &error_code) != 0) {
+		goto error;
+	}
+	
+	if (error_code == RESPONSE_OK) {
+		if (stun_parse_body(&msg_req, &unknown, &error_code) != 0) {
+			goto error;
+		}
+	}
+	
+	if (stun_create_response(&msg_req, &msg_res, ri,  
+							unknown, error_code) != 0) {
+		goto error;
+	}
+	
+	init_dst_from_rcv(&dst, ri);
+
+#ifdef EXTRA_DEBUG	
+	struct ip_addr ip;
+	su2ip_addr(&ip, &dst.to);
+	LOG(L_DBG, "DEBUG: process_stun_msg: decoded request from (%s:%d)\n", ip_addr2a(&ip), 
+		su_getport(&dst.to));
+#endif
+	
+	/* send STUN response */
+	if (msg_send(&dst, msg_res.msg.buf.s, msg_res.msg.buf.len) != 0) {
+		goto error;
+	}
+	
+#ifdef EXTRA_DEBUG
+	LOG(L_DBG, "DEBUG: process_stun_msg: send response\n");
+#endif
+	clean_memory(&msg_req, &msg_res, unknown);
+	return 0;
+	
+error:
+#ifdef EXTRA_DEBUG
+	LOG(L_DBG, "DEBUG: process_stun_msg: failed to decode request\n");
+#endif
+	clean_memory(&msg_req, &msg_res, unknown);
+	return FATAL_ERROR;
+}
+
+/*
+ * stun_parse_header():
+ * 			- req: request from host that should be processed
+ * 			- error_code: indication of any protocol error
+ * 
+ * This function ensures parsing of incoming header.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+
+static int stun_parse_header(struct stun_msg* req, USHORT_T* error_code)
+{
+	
+	if (sizeof(req->hdr) > req->msg.buf.len) {
+		/* the received message does not contain whole header */
+		LOG(L_INFO, "INFO: stun_parse_header: incomplete header of STUN message\n");
+		/* Any better solution? IMHO it's not possible to send error response
+		 * because the transaction ID is not available.
+		 */
+		return FATAL_ERROR;
+	}
+	
+	memcpy(&req->hdr, req->msg.buf.s, sizeof(struct stun_hdr));
+	req->hdr.type = ntohs(req->hdr.type);
+	
+	/* the SER supports only Binding Request right now */ 
+	if (req->hdr.type != BINDING_REQUEST) {
+		LOG(L_INFO, "INFO: stun_parse_header: unsupported type of STUN message: %x\n", 
+					req->hdr.type);
+		/* resending of same message is not welcome */
+		*error_code = GLOBAL_FAILURE_ERR;
+	}
+	
+	req->hdr.len = ntohs(req->hdr.len);
+	
+	/* check if there is correct magic cookie */
+	req->old = (req->hdr.id.magic_cookie == htonl(MAGIC_COOKIE)) ? 0 : 1;
+
+#ifdef EXTRA_DEBUG
+	LOG(L_DBG, "DEBUG: stun_parse_header: request is old: %i\n", req->old);
+#endif
+	return 0;
+}
+
+/*
+ * stun_parse_body():
+ * 			- req: request from host that should be processed
+ * 			- unknown: this is a link list header of attributes 
+ * 					   that are unknown to SER; defaul value is NULL
+ * 			- error_code: indication of any protocol error
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static int stun_parse_body(
+				struct stun_msg* req,
+				struct stun_unknown_att** unknown,
+				USHORT_T* error_code)
+{
+	int not_parsed;
+	struct stun_attr attr;
+	USHORT_T attr_size;
+	UINT_T padded_len;
+	struct stun_unknown_att*	tmp_unknown;
+	struct stun_unknown_att*	body;
+	char*	buf;
+	
+	attr_size = sizeof(struct stun_attr);
+	buf = &req->msg.buf.s[sizeof(struct stun_hdr)];
+	
+	/* 
+	 * Mark the body lenght as unparsed.
+	 */
+	not_parsed = req->msg.buf.len - sizeof(struct stun_hdr);
+	
+	if (not_parsed != req->hdr.len) {
+#ifdef EXTRA_DEBUG
+		LOG(L_DBG, "DEBUG: stun_parse_body: body too short to be valid\n");
+#endif
+		*error_code = BAD_REQUEST_ERR;
+		return 0; 
+	}
+	
+	tmp_unknown = *unknown;
+	body = NULL;
+	
+	while (not_parsed > 0 && *error_code == RESPONSE_OK) {
+		memset(&attr, 0, attr_size);
+		
+		/* check if there are 4 bytes for attribute type and its value */
+		if (not_parsed < 4) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: stun_parse_body: attribute header short to be valid\n");
+#endif
+			*error_code = BAD_REQUEST_ERR;
+			continue;
+		}
+		
+		memcpy(&attr, buf, attr_size);
+		
+		buf += attr_size;
+		not_parsed -= attr_size;
+		
+		/* check if there is enought unparsed space for attribute's value */
+		if (not_parsed < ntohs(attr.len)) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: stun_parse_body: remaining message is shorter then attribute length\n");
+#endif
+			*error_code = BAD_REQUEST_ERR;
+			continue;
+		}
+		
+		/* check if the attribute is known to the server */
+		switch (ntohs(attr.type)) {			
+			case REALM_ATTR:
+			case NONCE_ATTR:
+			case MAPPED_ADDRESS_ATTR:
+			case XOR_MAPPED_ADDRESS_ATTR:
+			case ALTERNATE_SERVER_ATTR:
+			case RESPONSE_ADDRESS_ATTR:
+			case SOURCE_ADDRESS_ATTR:
+			case REFLECTED_FROM_ATTR:		
+			case CHANGE_REQUEST_ATTR:
+			case CHANGED_ADDRESS_ATTR:
+				padded_len = ntohs(attr.len);
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_parse_body: known attributes\n");
+#endif
+				break;
+			
+			/* following attributes must be padded to 4 bytes */
+			case USERNAME_ATTR:
+			case ERROR_CODE_ATTR:
+			case UNKNOWN_ATTRIBUTES_ATTR:
+			case SOFTWARE_ATTR:
+				padded_len = PADDED_TO_FOUR(ntohs(attr.len));
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_parse_body: padded to four\n");
+#endif
+				break;
+
+			/* MESSAGE_INTEGRITY must be padded to sixty four bytes*/
+			case MESSAGE_INTEGRITY_ATTR:
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_parse_body: message integrity attribute found\n");
+#endif
+				padded_len = PADDED_TO_SIXTYFOUR(ntohs(attr.len));
+				break;
+			
+			case FINGERPRINT_ATTR:
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint attribute found\n");
+#endif
+				padded_len = SHA_DIGEST_LENGTH;
+
+				if (not_parsed > SHA_DIGEST_LENGTH) {
+#ifdef EXTRA_DEBUG
+					LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is not the last attribute\n");
+#endif
+					/* fingerprint must be last parameter in request */
+					*error_code = BAD_REQUEST_ERR;
+					continue;
+				}
+				break;
+			
+			default:
+				/* 
+				 * the attribute is uknnown to the server
+				 * let see if it's necessary to generate error response 
+				 */
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: low endian: attr - 0x%x   const - 0x%x\n", ntohs(attr.type), MANDATORY_ATTR);
+		    LOG(L_DBG, "DEBUG: big endian: attr - 0x%x   const - 0x%x\n", attr.type, htons(MANDATORY_ATTR));
+#endif
+				if (ntohs(attr.type) <= MANDATORY_ATTR) {
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_parse_body: mandatory unknown attribute found - 0x%x\n", ntohs(attr.type));
+#endif		
+					tmp_unknown = stun_alloc_unknown_attr(attr.type);
+					if (tmp_unknown == NULL) {
+						return FATAL_ERROR;
+					}
+					if (*unknown == NULL) {
+						*unknown = body = tmp_unknown;
+					}
+					else { 
+						body->next = tmp_unknown;
+						body = body->next;
+					}
+				}
+#ifdef EXTRA_DEBUG
+        else {
+				  LOG(L_DBG, "DEBUG: stun_parse_body: optional unknown attribute found - 0x%x\n", ntohs(attr.type));
+        }
+#endif
+				padded_len = ntohs(attr.len);
+				break;
+		}
+		
+		/* check if there is enough unparsed space for the padded attribute
+		   (the padded length might be greater then the attribute length)
+		 */
+		if (not_parsed < padded_len) {
+			break;
+		}
+		buf += padded_len;
+		not_parsed -= padded_len;
+	}  /* while */
+	
+	/*
+	 * The unknown attribute error code must set after parsing of whole body
+	 * because it's necessary to obtain all of unknown attributes! 
+	 */
+	if (*error_code == RESPONSE_OK && *unknown != NULL) {
+		*error_code = UNKNOWN_ATTRIBUTE_ERR;
+	} 
+	
+	return 0;
+}
+
+/*
+ * stun_create_response():
+ * 			- req: original request from host
+ * 			- res: this will represent response to host
+ * 			- ri: information about request, necessary because of IP 
+ * 				  address and port 
+ *			- unknown: link list of unknown attributes
+ * 			- error_code: indication of any protocol error
+ * 
+ * The function stun_create_response ensures creating response to a host.
+ * The type of response depends on value of error_code parameter.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory  
+ */
+
+static int stun_create_response(
+						struct stun_msg* req,
+						struct stun_msg* res,
+						struct receive_info* ri,
+						struct stun_unknown_att* unknown, 
+						UINT_T error_code)
+{
+	/*
+	 * Alloc some space for response.
+	 * Optimalization? - maybe it would be better to use biggish static array.
+	 */
+	res->msg.buf.s = (char *) pkg_malloc(sizeof(char)*STUN_MSG_LEN);
+	if (res->msg.buf.s == NULL) {
+		LOG(L_ERR, "ERROR: STUN: out of memory\n");
+		return FATAL_ERROR;
+	}
+	
+	memset(res->msg.buf.s, 0, sizeof(char)*STUN_MSG_LEN); 
+	res->msg.buf.len = 0;
+	res->msg.empty = STUN_MSG_LEN;
+	
+	/* use magic cookie and transaction ID from request */
+	memcpy(&res->hdr.id, &req->hdr.id, sizeof(struct transaction_id));
+	/* the correct body length will be added ASAP it will be known */ 
+	res->hdr.len = htons(0);
+	
+	if (error_code == RESPONSE_OK) {
+#ifdef EXTRA_DEBUG
+		LOG(L_DBG, "DEBUG: stun_create_response: creating normal response\n");
+#endif
+		res->hdr.type = htons(BINDING_RESPONSE);
+		
+		/* copy header into msg buffer */
+		if (buf_copy(&res->msg, (void *) &res->hdr, 
+					sizeof(struct stun_hdr)) != 0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: stun_create_response: failed to copy buffer\n");
+#endif
+			return FATAL_ERROR;
+		}
+
+		/* 
+		 * If the SER received message in old format, then the body will 
+		 * contain MAPPED-ADDRESS attribute instead of XOR-MAPPED-ADDRESS
+		 * attribute.
+		 */		
+		if (req->old == 0) {
+			if (stun_add_address_attr(res, ri->src_ip.af, ri->src_port, 
+						  ri->src_ip.u.addr32, XOR_MAPPED_ADDRESS_ATTR, 
+						  XOR) != 0) {
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
+#endif
+				return FATAL_ERROR;
+			}
+		}
+		else {
+			if (stun_add_address_attr(res, ri->src_ip.af, ri->src_port, 
+						ri->src_ip.u.addr32, MAPPED_ADDRESS_ATTR, !XOR) != 0) {
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
+#endif
+				return FATAL_ERROR;
+			}
+		}
+	}
+	else {
+#ifdef EXTRA_DEBUG
+		LOG(L_DBG, "DEBUG: stun_create_response: creating error response\n");
+#endif
+		res->hdr.type = htons(BINDING_ERROR_RESPONSE);
+		
+		if (buf_copy(&res->msg, (void *) &res->hdr, 
+								sizeof(struct stun_hdr)) != 0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: stun_create_response: failed to copy buffer\n");
+#endif
+			return FATAL_ERROR;
+		}
+		
+		if (add_error_code(res, error_code) != 0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: stun_create_response: failed to add error code\n");
+#endif
+			return FATAL_ERROR;
+		}
+		
+		if (unknown != NULL) {
+			if (add_unknown_attr(res, unknown) != 0) {
+#ifdef EXTRA_DEBUG
+				LOG(L_DBG, "DEBUG: stun_create_response: failed to add unknown attribute\n");
+#endif
+				return FATAL_ERROR;
+			}
+		} 
+	}
+	
+	if (req->old == 0) {
+		/* 
+		 * add optional information about server; attribute SOFTWARE is part of 
+		 * rfc5389.txt
+		 * */
+		if (stun_add_common_text_attr(res, SOFTWARE_ATTR, SERVER_HDR, PAD4)!=0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: stun_create_response: failed to add common text attribute\n");
+#endif
+			return FATAL_ERROR;
+		}
+	}	
+	
+	res->hdr.len = htons(res->msg.buf.len - sizeof(struct stun_hdr));
+	memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
+	       sizeof(USHORT_T));
+	
+	return 0;
+}
+
+/*
+ * add_unknown_attr()
+ * 			- res: response representation
+ * 			- unknown: link list of unknown attributes
+ * 
+ * The function add_unknown_attr ensures copy of link list of unknown 
+ * attributes into response buffer.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ * 
+ */
+static int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown)
+{
+	struct stun_attr attr;
+	struct stun_unknown_att* tmp_unknown;
+	UINT_T		counter;
+	USHORT_T	orig_len;
+
+	counter = 0;
+	orig_len = res->msg.buf.len;
+	tmp_unknown = unknown;
+	
+	attr.type = htons(UNKNOWN_ATTRIBUTES_ATTR);
+	attr.len = htons(0);
+	
+	if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
+#ifdef EXTRA_DEBUG
+		LOG(L_DBG, "DEBUG: add_unknown_attr: failed to copy buffer\n");
+#endif
+		return FATAL_ERROR;
+	}
+	
+	while (tmp_unknown != NULL) {
+		if (buf_copy(&res->msg, (void *)&tmp_unknown->type, 
+								sizeof(USHORT_T)) != 0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: add_unknown_attr: failed to copy unknown attribute\n");
+#endif
+			return FATAL_ERROR;
+		}
+		tmp_unknown = tmp_unknown->next;
+		++counter;
+	}
+	
+	attr.len = htons(res->msg.buf.len - orig_len);
+	memcpy(&res->msg.buf.s[orig_len], (void *)&attr, sizeof(struct stun_attr));
+	
+	/* check if there is an odd number of unknown attributes and if yes, 
+	 * repeat one of them because of padding to 32
+	 */
+	if (counter/2 != 0 && unknown != NULL) {
+		if (buf_copy(&res->msg, (void *)&unknown->type, sizeof(USHORT_T))!=0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: add_unknown_attr: failed to padd\n");
+#endif
+			return FATAL_ERROR;
+		}
+	}	
+	
+	return 0;
+}
+
+/*
+ * add_error_code()
+ * 			- res: response representation
+ * 			- error_code: value of error type
+ * 
+ * The function add_error_code ensures copy of link list of unknown 
+ * attributes into response buffer.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static int add_error_code(struct stun_msg* res, USHORT_T error_code)
+{
+	struct stun_attr attr;
+	USHORT_T	orig_len;
+	USHORT_T	two_bytes;
+	int			text_pad;
+	char		err[2];
+	
+	orig_len = res->msg.buf.len;
+	text_pad = 0;
+	
+	/* the type and length will be copy as last one because of unknown length*/
+	if (res->msg.buf.len < sizeof(struct stun_attr)) {
+		if (reallock_buffer(&res->msg, sizeof(struct stun_attr)) != 0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: add_error_code: failed to reallocate buffer\n");
+#endif
+			return FATAL_ERROR;
+		}
+	}
+	res->msg.buf.len += sizeof(struct stun_attr);
+	res->msg.empty -= sizeof(struct stun_attr);
+	
+	/* first two bytes are empty */
+	two_bytes = 0x0000;
+	
+	if (buf_copy(&res->msg, (void *) &two_bytes, sizeof(USHORT_T)) != 0) {
+#ifdef EXTRA_DEBUG
+		LOG(L_DBG, "DEBUG: add_error_code: failed to copy buffer\n");
+#endif
+		return FATAL_ERROR;
+	}
+	
+	err[0] = error_code / 100;
+	err[1] = error_code % 100;
+	if (buf_copy(&res->msg, (void *) err, sizeof(UCHAR_T)*2) != 0) {
+		return FATAL_ERROR;
+	}
+	
+	switch (error_code) {
+		case TRY_ALTERNATE_ERR:
+			text_pad = copy_str_to_buffer(res, TRY_ALTERNATE_TXT, PAD4); 
+			break;
+		case BAD_REQUEST_ERR:
+			text_pad = copy_str_to_buffer(res, BAD_REQUEST_TXT, PAD4); 
+			break;
+		case UNAUTHORIZED_ERR:
+			text_pad = copy_str_to_buffer(res, UNAUTHORIZED_TXT, PAD4); 
+			break;
+		case UNKNOWN_ATTRIBUTE_ERR:
+			text_pad = copy_str_to_buffer(res, UNKNOWN_ATTRIBUTE_TXT, PAD4);
+			break;
+		case STALE_CREDENTIALS_ERR:
+			text_pad = copy_str_to_buffer(res, STALE_CREDENTIALS_TXT, PAD4); 
+			break;
+		case INTEGRITY_CHECK_ERR:
+			text_pad = copy_str_to_buffer(res, INTEGRITY_CHECK_TXT, PAD4); 
+			break;
+		case MISSING_USERNAME_ERR:
+			text_pad = copy_str_to_buffer(res, MISSING_USERNAME_TXT, PAD4); 
+			break;
+		case USE_TLS_ERR:
+			text_pad = copy_str_to_buffer(res, USE_TLS_TXT, PAD4); 
+			break;
+		case MISSING_REALM_ERR:
+			text_pad = copy_str_to_buffer(res, MISSING_REALM_TXT, PAD4); 
+			break;
+		case MISSING_NONCE_ERR:
+			text_pad = copy_str_to_buffer(res, MISSING_NONCE_TXT, PAD4); 
+			break;
+		case UNKNOWN_USERNAME_ERR:
+			text_pad = copy_str_to_buffer(res, UNKNOWN_USERNAME_TXT, PAD4); 
+			break;
+		case STALE_NONCE_ERR:
+			text_pad = copy_str_to_buffer(res, STALE_NONCE_TXT, PAD4);
+			break;
+		case SERVER_ERROR_ERR:
+			text_pad = copy_str_to_buffer(res, SERVER_ERROR_TXT, PAD4); 
+			break;
+		case GLOBAL_FAILURE_ERR:
+			text_pad = copy_str_to_buffer(res, GLOBAL_FAILURE_TXT, PAD4); 
+			break;
+		default:
+			LOG(L_ERR, "ERROR: STUN: Unknown error code.\n");
+			break;
+	}
+	if (text_pad < 0) {
+#ifdef EXTRA_DEBUG
+		LOG(L_DBG, "DEBUG: add_error_code: text_pad is negative\n");
+#endif
+		goto error;
+	}
+	attr.type = htons(ERROR_CODE_ATTR);
+	/* count length of "value" field -> without type and lehgth field */
+	attr.len = htons(res->msg.buf.len - orig_len - 
+					 text_pad - sizeof(struct stun_attr));
+	memcpy(&res->msg.buf.s[orig_len], (void *)&attr, sizeof(struct stun_attr));
+	
+	return 0;
+
+error:
+	return FATAL_ERROR;
+}
+
+/*
+ * copy_str_to_buffer()
+ * 			- res: response representation
+ * 			- data: text data, in our case almost text representation of error
+ * 			- pad: the size of pad (for how much bytes the string should be 
+ * 				   padded
+ * 
+ * The function copy_str_to_buffer ensures copy of text buffer into response
+ * buffer.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad)
+{
+	USHORT_T	pad_len;
+	UINT_T		data_len;
+	UCHAR_T		empty[pad];
+	
+	data_len = strlen(data);
+	memset(&empty, 0, pad);
+	
+	pad_len = (pad - data_len%pad) % pad;
+	
+	if (buf_copy(&res->msg, (void *) data, sizeof(UCHAR_T)*data_len) != 0) {
+#ifdef EXTRA_DEBUG
+		LOG(L_DBG, "DEBUG: copy_str_to_buffer: failed to copy buffer\n");
+#endif
+		return FATAL_ERROR;
+	}
+	
+	if (pad_len != 0) {
+		if (buf_copy(&res->msg, &empty, pad_len) != 0) {
+#ifdef EXTRA_DEBUG
+			LOG(L_DBG, "DEBUG: copy_str_to_buffer: failed to pad\n");
+#endif
+			return FATAL_ERROR;
+		}	
+	}
+
+	return pad_len;	
+}
+
+/*
+ * stun_add_address_attr()
+ * 			- res: response representation
+ * 			- af: address family
+ * 			- port: port
+ * 			- ip_addr: represent both IPv4 and IPv6, the differences is in 
+ * 			length  
+ * 			- type: type of attribute
+ * 			- do_xor: if the port should be XOR-ed or not.
+ * 
+ * The function stun_add_address_attr ensures copy of any IP attribute into
+ * response buffer.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static int stun_add_address_attr(struct stun_msg* res, 
+						UINT_T		af,
+						USHORT_T	port,
+						UINT_T*		ip_addr,
+						USHORT_T	type,
+						int do_xor)
+{
+	struct stun_attr attr;
+	int		 ip_struct_len;
+	UINT_T	 id[IP_ADDR];
+	int i;
+	
+	ip_struct_len = 0;
+	attr.type = htons(type);
+	res->ip_addr.port = htons((do_xor) ? (port ^ MAGIC_COOKIE_2B) : port);
+	switch(af) {
+		case AF_INET:
+			ip_struct_len = sizeof(struct stun_ip_addr) - 3*sizeof(UINT_T);
+			res->ip_addr.family = htons(IPV4_FAMILY);
+			memcpy(res->ip_addr.ip, ip_addr, IPV4_LEN);
+			res->ip_addr.ip[0] = (do_xor) ? 
+				res->ip_addr.ip[0] ^ htonl(MAGIC_COOKIE) : res->ip_addr.ip[0];
+			break;
+		case AF_INET6:
+			ip_struct_len = sizeof(struct stun_ip_addr);
+			res->ip_addr.family = htons(IPV6_FAMILY);
+			memcpy(&res->ip_addr.ip, ip_addr, IPV6_LEN);
+			memcpy(id, &res->hdr.id, sizeof(struct transaction_id));
+			for (i=0; i<IP_ADDR; i++) {
+				res->ip_addr.ip[i] = (do_xor) ? 
+							res->ip_addr.ip[i] ^ id[i] : res->ip_addr.ip[i];
+			}
+			break;
+		default:
+			break;
+	}
+	
+	attr.len = htons(ip_struct_len);
+	
+	/* copy type and attribute's length */ 
+	if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
+		return FATAL_ERROR;
+	}
+	
+	/* copy family, port and IP */
+	if (buf_copy(&res->msg, (void *) &res->ip_addr, ip_struct_len) != 0) {
+		return FATAL_ERROR;
+	}
+
+	return 0;
+}
+
+/*
+ * stun_alloc_unknown_attr()
+ * 			- type: type of unknown attribute
+ * 
+ * The function stun_alloc_unknown_attr ensures allocationg new element for
+ * the link list of unknown attributes.
+ * 
+ * Return value: pointer to new element of link list in positive case
+ * 				 NULL if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static struct stun_unknown_att* stun_alloc_unknown_attr(USHORT_T type)
+{
+	struct stun_unknown_att* attr;
+
+	attr = (struct stun_unknown_att *) pkg_malloc(sizeof(struct stun_unknown_att));
+	if (attr == NULL) {
+		LOG(L_ERR, "ERROR: STUN: out of memory\n");
+		return NULL;
+	}
+	
+	attr->type = type;
+	attr->next = NULL;
+	
+	return attr;
+}
+
+/*
+ * stun_delete_unknown_attrs()
+ * 			- unknown: link list of unknown attributes
+ * 
+ * The function stun_delete_unknown_attrs ensures deleting of link list
+ * 
+ * Return value: none
+ */
+static void stun_delete_unknown_attrs(struct stun_unknown_att* unknown)
+{
+	struct stun_unknown_att* tmp_unknown;
+	
+	if (unknown == NULL) {
+		return;
+	}
+	
+	while(unknown->next) {
+		tmp_unknown = unknown->next;
+		unknown->next = tmp_unknown->next;
+		pkg_free(tmp_unknown);		
+	}
+	pkg_free(unknown);
+}
+
+/*
+ * buf_copy()
+ * 			- msg: buffer where the data will be copy to
+ * 			- source: source data buffer
+ * 			- len: number of bytes that should be copied
+ * 
+ * The function buf_copy copies "len" bytes from source into msg buffer
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static int buf_copy(struct stun_buffer* msg, void* source, UINT_T len)
+{
+	if (msg->empty < len) {
+		if (reallock_buffer(msg, len) != 0) {
+			return FATAL_ERROR;
+		}
+	}
+	
+	memcpy(&msg->buf.s[msg->buf.len], source, len);
+	msg->buf.len += len;
+	msg->empty -= len;
+	
+	return 0;
+}
+
+/*
+ * reallock_buffer()
+ * 			- buffer: original buffer
+ * 			- len: represents minimum of bytes that must be available after 
+ * 					reallocation
+ * 
+ * The function reallock_buffer reallocks buffer. New buffer's length will be 
+ * original length plus bigger from len and STUN_MSG_LEN constant.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static int reallock_buffer(struct stun_buffer* buffer, UINT_T len)
+{
+	char*	tmp_buf;
+	UINT_T	new_len;
+	
+	new_len = (STUN_MSG_LEN < len) ? STUN_MSG_LEN+len : STUN_MSG_LEN;
+	
+	tmp_buf = (char *) pkg_realloc(buffer->buf.s, 
+								   buffer->buf.len + buffer->empty + new_len);
+	if (tmp_buf == 0) {
+		LOG(L_ERR, "ERROR: STUN: out of memory\n");
+		return FATAL_ERROR;
+	}
+	
+	buffer->buf.s = tmp_buf;
+	buffer->empty += new_len;
+
+	return 0;
+}
+
+/*
+ * clean_memory()
+ * 			- res: structure representing response message
+ * 			- unknown: link list of unknown attributes
+ * 
+ * The function clean_memory should free dynamic allocated memory.
+ * 
+ * Return value: none
+ */
+static void clean_memory(struct stun_msg* req,
+				struct stun_msg* res,	struct stun_unknown_att* unknown)
+{
+#ifdef DYN_BUF
+	pkg_free(req->msg.buf.s);
+#endif
+
+	if (res->msg.buf.s != NULL) {
+		pkg_free(res->msg.buf.s);
+	}
+	stun_delete_unknown_attrs(unknown);
+}
+
+/*
+ * stun_add_common_text_attr()
+ * 			- res: structure representing response
+ * 			- type: type of attribute
+ * 			- value: attribute's value
+ * 			- pad: size of pad
+ * 
+ * The function stun_add_common_text_attr copy attribute with string value 
+ * into response buffer.
+ * 
+ * Return value:	0	if there is no environment error
+ * 					-1	if there is some enviroment error such as insufficiency
+ * 						of memory
+ */
+static int stun_add_common_text_attr(struct stun_msg* res, 
+							  USHORT_T type, 
+							  char* value, 
+							  USHORT_T pad)
+{
+	struct stun_attr attr;
+	
+	if (value == NULL) {
+		LOG(L_INFO, "INFO: stun_add_common_text_attr: value is NULL\n");
+		return 0;
+	}
+	
+	attr.type = htons(type);
+	attr.len = htons(strlen(value));
+	
+	if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
+		return FATAL_ERROR;
+	}
+	
+	if (copy_str_to_buffer(res, value, pad) < 0) {
+		return FATAL_ERROR;
+	}
+	
+	return 0;
+	
+}
diff --git a/modules/stun/kam_stun.h b/modules/stun/kam_stun.h
new file mode 100644
index 0000000..a5a55c6
--- /dev/null
+++ b/modules/stun/kam_stun.h
@@ -0,0 +1,147 @@
+/*
+ * $Id$
+ *
+ * Portions Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * Based on "ser_stun.h". Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _kam_stun_h
+#define _kam_stun_h
+
+#include "../../str.h"
+#include "../../tcp_conn.h"
+#include "../../ip_addr.h"
+#include "../../stun.h"
+
+/* STUN message types supported by Kamailio */
+#define BINDING_REQUEST		0x0001
+#define BINDING_RESPONSE	0x0101
+#define BINDING_ERROR_RESPONSE	0x0111
+
+/* common STUN attributes */
+#define MAPPED_ADDRESS_ATTR	0x0001
+#define USERNAME_ATTR		0x0006
+#define MESSAGE_INTEGRITY_ATTR	0x0008
+#define ERROR_CODE_ATTR		0x0009
+#define UNKNOWN_ATTRIBUTES_ATTR	0x000A
+
+/* STUN attributes defined by rfc5389 */
+#define REALM_ATTR		0x0014
+#define NONCE_ATTR		0x0015
+#define XOR_MAPPED_ADDRESS_ATTR	0x0020 
+#define FINGERPRINT_ATTR	0x8028
+#define SOFTWARE_ATTR		0x8022
+#define ALTERNATE_SERVER_ATTR	0x8023
+
+/* STUN attributes defined by rfc3489 */
+#define RESPONSE_ADDRESS_ATTR	0x0002
+#define CHANGE_REQUEST_ATTR	0x0003
+#define SOURCE_ADDRESS_ATTR	0x0004
+#define CHANGED_ADDRESS_ATTR	0x0005
+#define REFLECTED_FROM_ATTR	0x000b
+
+/* STUN error codes supported by Kamailio */
+#define RESPONSE_OK		200
+#define TRY_ALTERNATE_ERR	300
+#define BAD_REQUEST_ERR		400
+#define UNAUTHORIZED_ERR	401
+#define UNKNOWN_ATTRIBUTE_ERR	420
+#define STALE_CREDENTIALS_ERR	430
+#define INTEGRITY_CHECK_ERR	431
+#define MISSING_USERNAME_ERR	432
+#define USE_TLS_ERR		433
+#define MISSING_REALM_ERR	434
+#define MISSING_NONCE_ERR	435
+#define UNKNOWN_USERNAME_ERR	436
+#define STALE_NONCE_ERR		438
+#define SERVER_ERROR_ERR	500
+#define GLOBAL_FAILURE_ERR	600
+
+#define TRY_ALTERNATE_TXT      "Try Alternate"
+#define BAD_REQUEST_TXT        "Bad Request"
+#define UNAUTHORIZED_TXT       "Unauthorized"
+#define UNKNOWN_ATTRIBUTE_TXT  "Unknown Attribute"
+#define STALE_CREDENTIALS_TXT  "Stale Credentials"
+#define INTEGRITY_CHECK_TXT    "Integrity Check Failure"
+#define MISSING_USERNAME_TXT   "Missing Username"
+#define USE_TLS_TXT            "Use TLS"
+#define MISSING_REALM_TXT      "Missing Realm"
+#define MISSING_NONCE_TXT      "Missing Nonce"
+#define UNKNOWN_USERNAME_TXT   "Unknown Username"
+#define STALE_NONCE_TXT        "Stale Nonce"
+#define SERVER_ERROR_TXT       "Server Error"
+#define GLOBAL_FAILURE_TXT     "Global Failure"
+
+/* other stuff */
+#define MAGIC_COOKIE_2B		0x2112	/* because of XOR for port */
+#define MANDATORY_ATTR		0x7fff
+#define PAD4			4
+#define PAD64			64
+#define STUN_MSG_LEN		516
+#define IPV4_LEN		4
+#define IPV6_LEN		16
+#define IPV4_FAMILY		0x0001
+#define IPV6_FAMILY		0x0002
+#define	FATAL_ERROR		-1
+#define IP_ADDR			4
+#define XOR			1
+
+#ifndef SHA_DIGEST_LENGTH
+#define SHA_DIGEST_LENGTH	20
+#endif
+
+/** padd len to a multiple of sz.
+ *  sz must be a power of the form 2^k (e.g. 2, 4, 8, 16 ...)
+ */
+#define PADD_TO(len, sz)	(((len) + (sz)-1) & (~((sz) - 1)))
+
+#define PADDED_TO_FOUR(len)	PADD_TO(len, 4)
+#define PADDED_TO_SIXTYFOUR(len) PADD_TO(len, 64)
+
+struct stun_ip_addr {
+	USHORT_T family; /* 0x01: IPv4; 0x02: IPv6 */
+	USHORT_T port;
+	UINT_T ip[IP_ADDR];
+};
+
+struct stun_buffer {
+	str buf;
+	USHORT_T empty;	/* number of free bytes in buf before it'll be necessary
+			   to realloc the buf */
+};
+
+struct stun_unknown_att {
+	USHORT_T type;
+	struct stun_unknown_att* next;
+};
+
+struct stun_msg {
+	struct stun_hdr hdr;
+	struct stun_ip_addr ip_addr; /* XOR values for rfc3489bis, normal values
+					for rfc3489 */
+	struct stun_buffer msg;
+	UCHAR_T old; /* true: the format of message is in accordance with
+			rfc3489 */ 
+};
+
+int process_stun_msg(char* buf, unsigned len, struct receive_info* ri);
+
+#endif  /* _kam_stun_h */
diff --git a/modules/stun/stun_mod.c b/modules/stun/stun_mod.c
new file mode 100644
index 0000000..ae1c981
--- /dev/null
+++ b/modules/stun/stun_mod.c
@@ -0,0 +1,74 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../../dprint.h"
+#include "../../events.h"
+#include "../../ip_addr.h"
+#include "../../sr_module.h"
+#include "kam_stun.h"
+#include "config.h"
+
+MODULE_VERSION
+
+static int mod_init(void);
+static int stun_msg_receive(void *data);
+
+struct module_exports exports= 
+{
+	"stun",
+	DEFAULT_DLFLAGS,	/* dlopen flags */
+	0,			/* Exported functions */
+	0,			/* Exported parameters */
+	0,			/* exported statistics */
+	0,			/* exported MI functions */
+	0,			/* exported pseudo-variables */
+	0,			/* extra processes */
+	mod_init,		/* module initialization function */
+	0,			/* response function */
+	0,			/* destroy function */
+	0			/* per-child initialization function */
+};
+
+static int mod_init(void)
+{
+	if (sr_event_register_cb(SREV_STUN_IN, stun_msg_receive) != 0)
+	{
+		LM_ERR("registering STUN receive call-back\n");
+		return -1;
+	}
+
+        if (cfg_declare("stun", stun_cfg_def, &default_stun_cfg,
+                        cfg_sizeof(stun), &stun_cfg)) {
+                LM_ERR("declaring config framework variable\n");
+                return -1;
+        }
+        default_stun_cfg.stun_active = 1;
+
+	return 0;
+}
+
+int stun_msg_receive(void *data)
+{
+	stun_event_info_t *sev = (stun_event_info_t *) data;
+	return process_stun_msg(sev->buf, sev->len, sev->rcv);
+}
diff --git a/modules/textops/README b/modules/textops/README
index 06c28b5..03bb9fc 100644
--- a/modules/textops/README
+++ b/modules/textops/README
@@ -1,3 +1,4 @@
+
 textops Module
 
 Andrei Pelinescu-Onciul
@@ -24,7 +25,7 @@ Juha Heinanen
    <jh at tutpro.com>
 
    Copyright � 2003 FhG FOKUS
-     __________________________________________________________________
+     _________________________________________________________________
 
    Table of Contents
 
@@ -41,44 +42,44 @@ Juha Heinanen
 
         3. Functions
 
-              3.1. search(re)
-              3.2. search_body(re)
-              3.3. search_hf(hf, re, flags)
-              3.4. search_append(re, txt)
-              3.5. search_append_body(re, txt)
-              3.6. replace(re, txt)
-              3.7. replace_body(re, txt)
-              3.8. replace_all(re, txt)
-              3.9. replace_body_all(re, txt)
-              3.10. replace_body_atonce(re, txt)
-              3.11. subst('/re/repl/flags')
-              3.12. subst_uri('/re/repl/flags')
-              3.13. subst_user('/re/repl/flags')
-              3.14. subst_body('/re/repl/flags')
-              3.15. subst_hf(hf, subexp, flags)
-              3.16. set_body(txt,content_type)
-              3.17. set_reply_body(txt,content_type)
-              3.18. filter_body(content_type)
-              3.19. append_to_reply(txt)
-              3.20. append_hf(txt)
-              3.21. append_hf(txt, hdr)
-              3.22. insert_hf(txt)
-              3.23. insert_hf(txt, hdr)
-              3.24. append_urihf(prefix, suffix)
-              3.25. is_present_hf(hf_name)
-              3.26. is_present_hf_re(hf_name_re)
-              3.27. append_time()
-              3.28. append_time_to_request()
-              3.29. is_method(name)
-              3.30. remove_hf(hname)
-              3.31. remove_hf_re(re)
-              3.32. has_body(), has_body(mime)
-              3.33. is_audio_on_hold()
-              3.34. is_privacy(privacy_type)
-              3.35. in_list(subject, list, separator)
-              3.36. cmp_str(str1, str2)
-              3.37. cmp_istr(str1, str2)
-              3.38. starts_with(str1, str2)
+              3.1. search(re) 
+              3.2. search_body(re) 
+              3.3. search_hf(hf, re, flags) 
+              3.4. search_append(re, txt) 
+              3.5. search_append_body(re, txt) 
+              3.6. replace(re, txt) 
+              3.7. replace_body(re, txt) 
+              3.8. replace_all(re, txt) 
+              3.9. replace_body_all(re, txt) 
+              3.10. replace_body_atonce(re, txt) 
+              3.11. subst('/re/repl/flags') 
+              3.12. subst_uri('/re/repl/flags') 
+              3.13. subst_user('/re/repl/flags') 
+              3.14. subst_body('/re/repl/flags') 
+              3.15. subst_hf(hf, subexp, flags) 
+              3.16. set_body(txt,content_type) 
+              3.17. set_reply_body(txt,content_type) 
+              3.18. filter_body(content_type) 
+              3.19. append_to_reply(txt) 
+              3.20. append_hf(txt) 
+              3.21. append_hf(txt, hdr) 
+              3.22. insert_hf(txt) 
+              3.23. insert_hf(txt, hdr) 
+              3.24. append_urihf(prefix, suffix) 
+              3.25. is_present_hf(hf_name) 
+              3.26. is_present_hf_re(hf_name_re) 
+              3.27. append_time() 
+              3.28. append_time_to_request() 
+              3.29. is_method(name) 
+              3.30. remove_hf(hname) 
+              3.31. remove_hf_re(re) 
+              3.32. has_body(), has_body(mime) 
+              3.33. is_audio_on_hold() 
+              3.34. is_privacy(privacy_type) 
+              3.35. in_list(subject, list, separator) 
+              3.36. cmp_str(str1, str2) 
+              3.37. cmp_istr(str1, str2) 
+              3.38. starts_with(str1, str2) 
 
         4. Known Limitations
 
@@ -86,7 +87,7 @@ Juha Heinanen
 
         1. Functions
 
-              1.1. load_textops(*import_structure)
+              1.1. load_textops(*import_structure) 
 
    List of Examples
 
@@ -144,44 +145,44 @@ Chapter 1. Admin Guide
 
    3. Functions
 
-        3.1. search(re)
-        3.2. search_body(re)
-        3.3. search_hf(hf, re, flags)
-        3.4. search_append(re, txt)
-        3.5. search_append_body(re, txt)
-        3.6. replace(re, txt)
-        3.7. replace_body(re, txt)
-        3.8. replace_all(re, txt)
-        3.9. replace_body_all(re, txt)
-        3.10. replace_body_atonce(re, txt)
-        3.11. subst('/re/repl/flags')
-        3.12. subst_uri('/re/repl/flags')
-        3.13. subst_user('/re/repl/flags')
-        3.14. subst_body('/re/repl/flags')
-        3.15. subst_hf(hf, subexp, flags)
-        3.16. set_body(txt,content_type)
-        3.17. set_reply_body(txt,content_type)
-        3.18. filter_body(content_type)
-        3.19. append_to_reply(txt)
-        3.20. append_hf(txt)
-        3.21. append_hf(txt, hdr)
-        3.22. insert_hf(txt)
-        3.23. insert_hf(txt, hdr)
-        3.24. append_urihf(prefix, suffix)
-        3.25. is_present_hf(hf_name)
-        3.26. is_present_hf_re(hf_name_re)
-        3.27. append_time()
-        3.28. append_time_to_request()
-        3.29. is_method(name)
-        3.30. remove_hf(hname)
-        3.31. remove_hf_re(re)
-        3.32. has_body(), has_body(mime)
-        3.33. is_audio_on_hold()
-        3.34. is_privacy(privacy_type)
-        3.35. in_list(subject, list, separator)
-        3.36. cmp_str(str1, str2)
-        3.37. cmp_istr(str1, str2)
-        3.38. starts_with(str1, str2)
+        3.1. search(re) 
+        3.2. search_body(re) 
+        3.3. search_hf(hf, re, flags) 
+        3.4. search_append(re, txt) 
+        3.5. search_append_body(re, txt) 
+        3.6. replace(re, txt) 
+        3.7. replace_body(re, txt) 
+        3.8. replace_all(re, txt) 
+        3.9. replace_body_all(re, txt) 
+        3.10. replace_body_atonce(re, txt) 
+        3.11. subst('/re/repl/flags') 
+        3.12. subst_uri('/re/repl/flags') 
+        3.13. subst_user('/re/repl/flags') 
+        3.14. subst_body('/re/repl/flags') 
+        3.15. subst_hf(hf, subexp, flags) 
+        3.16. set_body(txt,content_type) 
+        3.17. set_reply_body(txt,content_type) 
+        3.18. filter_body(content_type) 
+        3.19. append_to_reply(txt) 
+        3.20. append_hf(txt) 
+        3.21. append_hf(txt, hdr) 
+        3.22. insert_hf(txt) 
+        3.23. insert_hf(txt, hdr) 
+        3.24. append_urihf(prefix, suffix) 
+        3.25. is_present_hf(hf_name) 
+        3.26. is_present_hf_re(hf_name_re) 
+        3.27. append_time() 
+        3.28. append_time_to_request() 
+        3.29. is_method(name) 
+        3.30. remove_hf(hname) 
+        3.31. remove_hf_re(re) 
+        3.32. has_body(), has_body(mime) 
+        3.33. is_audio_on_hold() 
+        3.34. is_privacy(privacy_type) 
+        3.35. in_list(subject, list, separator) 
+        3.36. cmp_str(str1, str2) 
+        3.37. cmp_istr(str1, str2) 
+        3.38. starts_with(str1, str2) 
 
    4. Known Limitations
 
@@ -189,17 +190,18 @@ Chapter 1. Admin Guide
 
    1.1. Known Limitations
 
-   The module implements text based operations over the SIP message
-   processed by Kamailio. SIP is a text based protocol and the module
-   provides a large set of very useful functions to manipulate the message
-   at text level, e.g., regular expression search and replace, Perl-like
-   substitutions, checks for method type, header presence, insert of new
-   header and date, etc.
+   The  module  implements  text  based  operations  over the SIP message
+   processed  by  Kamailio.  SIP  is a text based protocol and the module
+   provides  a  large  set  of  very  useful  functions to manipulate the
+   message  at  text  level, e.g., regular expression search and replace,
+   Perl-like  substitutions,  checks  for  method  type, header presence,
+   insert of new header and date, etc.
 
 1.1. Known Limitations
 
-   search ignores folded lines. For example, search("(From|f):.*@foo.bar")
-   doesn't match the following From header field:
+   search ignores folded lines. For example,
+   search("(From|f):.*@foo.bar")  doesn't match the following From header
+   field:
 From: medabeda
  <sip:medameda at foo.bar>;tag=1234
 
@@ -215,59 +217,59 @@ From: medabeda
 
 2.2. External Libraries or Applications
 
-   The following libraries or applications must be installed before
+   The  following  libraries  or  applications  must  be installed before
    running Kamailio with this module loaded:
      * None.
 
 3. Functions
 
-   3.1. search(re)
-   3.2. search_body(re)
-   3.3. search_hf(hf, re, flags)
-   3.4. search_append(re, txt)
-   3.5. search_append_body(re, txt)
-   3.6. replace(re, txt)
-   3.7. replace_body(re, txt)
-   3.8. replace_all(re, txt)
-   3.9. replace_body_all(re, txt)
-   3.10. replace_body_atonce(re, txt)
-   3.11. subst('/re/repl/flags')
-   3.12. subst_uri('/re/repl/flags')
-   3.13. subst_user('/re/repl/flags')
-   3.14. subst_body('/re/repl/flags')
-   3.15. subst_hf(hf, subexp, flags)
-   3.16. set_body(txt,content_type)
-   3.17. set_reply_body(txt,content_type)
-   3.18. filter_body(content_type)
-   3.19. append_to_reply(txt)
-   3.20. append_hf(txt)
-   3.21. append_hf(txt, hdr)
-   3.22. insert_hf(txt)
-   3.23. insert_hf(txt, hdr)
-   3.24. append_urihf(prefix, suffix)
-   3.25. is_present_hf(hf_name)
-   3.26. is_present_hf_re(hf_name_re)
-   3.27. append_time()
-   3.28. append_time_to_request()
-   3.29. is_method(name)
-   3.30. remove_hf(hname)
-   3.31. remove_hf_re(re)
-   3.32. has_body(), has_body(mime)
-   3.33. is_audio_on_hold()
-   3.34. is_privacy(privacy_type)
-   3.35. in_list(subject, list, separator)
-   3.36. cmp_str(str1, str2)
-   3.37. cmp_istr(str1, str2)
-   3.38. starts_with(str1, str2)
-
-3.1. search(re)
+   3.1. search(re) 
+   3.2. search_body(re) 
+   3.3. search_hf(hf, re, flags) 
+   3.4. search_append(re, txt) 
+   3.5. search_append_body(re, txt) 
+   3.6. replace(re, txt) 
+   3.7. replace_body(re, txt) 
+   3.8. replace_all(re, txt) 
+   3.9. replace_body_all(re, txt) 
+   3.10. replace_body_atonce(re, txt) 
+   3.11. subst('/re/repl/flags') 
+   3.12. subst_uri('/re/repl/flags') 
+   3.13. subst_user('/re/repl/flags') 
+   3.14. subst_body('/re/repl/flags') 
+   3.15. subst_hf(hf, subexp, flags) 
+   3.16. set_body(txt,content_type) 
+   3.17. set_reply_body(txt,content_type) 
+   3.18. filter_body(content_type) 
+   3.19. append_to_reply(txt) 
+   3.20. append_hf(txt) 
+   3.21. append_hf(txt, hdr) 
+   3.22. insert_hf(txt) 
+   3.23. insert_hf(txt, hdr) 
+   3.24. append_urihf(prefix, suffix) 
+   3.25. is_present_hf(hf_name) 
+   3.26. is_present_hf_re(hf_name_re) 
+   3.27. append_time() 
+   3.28. append_time_to_request() 
+   3.29. is_method(name) 
+   3.30. remove_hf(hname) 
+   3.31. remove_hf_re(re) 
+   3.32. has_body(), has_body(mime) 
+   3.33. is_audio_on_hold() 
+   3.34. is_privacy(privacy_type) 
+   3.35. in_list(subject, list, separator) 
+   3.36. cmp_str(str1, str2) 
+   3.37. cmp_istr(str1, str2) 
+   3.38. starts_with(str1, str2) 
+
+3.1.  search(re)
 
    Searches for the re in the message.
 
    Meaning of the parameters is as follows:
      * re - Regular expression.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.1. search usage
@@ -275,14 +277,14 @@ From: medabeda
 if ( search("[Ss][Ii][Pp]") ) { /*....*/ };
 ...
 
-3.2. search_body(re)
+3.2.  search_body(re)
 
    Searches for the re in the body of the message.
 
    Meaning of the parameters is as follows:
      * re - Regular expression.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.2. search_body usage
@@ -290,18 +292,18 @@ if ( search("[Ss][Ii][Pp]") ) { /*....*/ };
 if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
 ...
 
-3.3. search_hf(hf, re, flags)
+3.3.  search_hf(hf, re, flags)
 
    Searches for the re in the body of a header field.
 
    Meaning of the parameters is as follows:
      * hf - header field name.
      * re - regular expression.
-     * flags - control flags - it has to be one of: a - all headers
-       matching the name; f - only first header matching the name; l -
+     * flags  -  control  flags  -  it  has to be one of: a - all headers
+       matching  the  name;  f - only first header matching the name; l -
        only the last header matching the name.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.3. search_body usage
@@ -309,7 +311,7 @@ if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
 if ( search_hf("From", ":test@", "a") ) { /*....*/ };
 ...
 
-3.4. search_append(re, txt)
+3.4.  search_append(re, txt)
 
    Searches for the first match of re and appends txt after it.
 
@@ -317,7 +319,7 @@ if ( search_hf("From", ":test@", "a") ) { /*....*/ };
      * re - Regular expression.
      * txt - String to be appended.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.4. search_append usage
@@ -325,16 +327,16 @@ if ( search_hf("From", ":test@", "a") ) { /*....*/ };
 search_append("[Oo]pen[Ss]er", " SIP Proxy");
 ...
 
-3.5. search_append_body(re, txt)
+3.5.  search_append_body(re, txt)
 
-   Searches for the first match of re in the body of the message and
+   Searches  for  the  first  match  of re in the body of the message and
    appends txt after it.
 
    Meaning of the parameters is as follows:
      * re - Regular expression.
      * txt - String to be appended.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.5. search_append_body usage
@@ -342,7 +344,7 @@ search_append("[Oo]pen[Ss]er", " SIP Proxy");
 search_append_body("[Oo]pen[Ss]er", " SIP Proxy");
 ...
 
-3.6. replace(re, txt)
+3.6.  replace(re, txt)
 
    Replaces the first occurrence of re with txt.
 
@@ -350,7 +352,7 @@ search_append_body("[Oo]pen[Ss]er", " SIP Proxy");
      * re - Regular expression.
      * txt - String.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.6. replace usage
@@ -358,16 +360,16 @@ search_append_body("[Oo]pen[Ss]er", " SIP Proxy");
 replace("openser", "Kamailio SIP Proxy");
 ...
 
-3.7. replace_body(re, txt)
+3.7.  replace_body(re, txt)
 
-   Replaces the first occurrence of re in the body of the message with
+   Replaces  the  first  occurrence of re in the body of the message with
    txt.
 
    Meaning of the parameters is as follows:
      * re - Regular expression.
      * txt - String.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.7. replace_body usage
@@ -375,7 +377,7 @@ replace("openser", "Kamailio SIP Proxy");
 replace_body("openser", "Kamailio SIP Proxy");
 ...
 
-3.8. replace_all(re, txt)
+3.8.  replace_all(re, txt)
 
    Replaces all occurrence of re with txt.
 
@@ -383,7 +385,7 @@ replace_body("openser", "Kamailio SIP Proxy");
      * re - Regular expression.
      * txt - String.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.8. replace_all usage
@@ -391,16 +393,16 @@ replace_body("openser", "Kamailio SIP Proxy");
 replace_all("openser", "Kamailio SIP Proxy");
 ...
 
-3.9. replace_body_all(re, txt)
+3.9.  replace_body_all(re, txt)
 
-   Replaces all occurrence of re in the body of the message with txt.
+   Replaces  all  occurrence  of  re in the body of the message with txt.
    Matching is done on a per-line basis.
 
    Meaning of the parameters is as follows:
      * re - Regular expression.
      * txt - String.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.9. replace_body_all usage
@@ -408,16 +410,16 @@ replace_all("openser", "Kamailio SIP Proxy");
 replace_body_all("openser", "Kamailio SIP Proxy");
 ...
 
-3.10. replace_body_atonce(re, txt)
+3.10.  replace_body_atonce(re, txt)
 
-   Replaces all occurrence of re in the body of the message with txt.
+   Replaces  all  occurrence  of  re in the body of the message with txt.
    Matching is done over the whole body.
 
    Meaning of the parameters is as follows:
      * re - Regular expression.
      * txt - String.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.10. replace_body_atonce usage
@@ -427,19 +429,19 @@ if(has_body() && replace_body_atonce("^.+$", ""))
         remove_hf("Content-Type");
 ...
 
-3.11. subst('/re/repl/flags')
+3.11.  subst('/re/repl/flags')
 
    Replaces re with repl (sed or perl like).
 
    Meaning of the parameters is as follows:
-     * '/re/repl/flags' - sed like regular expression. flags can be a
-       combination of i (case insensitive), g (global) or s (match newline
-       don't treat it as end of line).
+     * '/re/repl/flags'  -  sed  like  regular expression. flags can be a
+       combination  of  i  (case  insensitive),  g  (global)  or s (match
+       newline don't treat it as end of line).
        're' - is regular expresion
        'repl' - is replacement string - may contain pseudo-varibales
        'flags' - substitution flags (i - ignore case, g - global)
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.11. subst usage
@@ -448,25 +450,25 @@ if(has_body() && replace_body_atonce("^.+$", ""))
 if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1\u\2/ig') ) {};
 
 # replace the uri in to: with the value of avp sip_address (just an example)
-if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\2/ig') )
- {};
+if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\2/ig')
+) {};
 
 ...
 
-3.12. subst_uri('/re/repl/flags')
+3.12.  subst_uri('/re/repl/flags')
 
    Runs the re substitution on the message uri (like subst but works only
    on the uri)
 
    Meaning of the parameters is as follows:
-     * '/re/repl/flags' - sed like regular expression. flags can be a
-       combination of i (case insensitive), g (global) or s (match newline
-       don't treat it as end of line).
+     * '/re/repl/flags'  -  sed  like  regular expression. flags can be a
+       combination  of  i  (case  insensitive),  g  (global)  or s (match
+       newline don't treat it as end of line).
        're' - is regular expresion
        'repl' - is replacement string - may contain pseudo-varibales
        'flags' - substitution flags (i - ignore case, g - global)
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.12. subst_uri usage
@@ -477,24 +479,25 @@ if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:3463\1@\2;orig_uri=\0/i')){$
 
 # adds the avp 'uri_prefix' as prefix to numeric uris, and save the original
 # uri (\0 match) as a parameter: orig_uri (just an example)
-if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\0/i')){$
+if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\0/i')){
+$
 
 ...
 
-3.13. subst_user('/re/repl/flags')
+3.13.  subst_user('/re/repl/flags')
 
-   Runs the re substitution on the message uri (like subst_uri but works
+   Runs  the re substitution on the message uri (like subst_uri but works
    only on the user portion of the uri)
 
    Meaning of the parameters is as follows:
-     * '/re/repl/flags' - sed like regular expression. flags can be a
-       combination of i (case insensitive), g (global) or s (match newline
-       don't treat it as end of line).
+     * '/re/repl/flags'  -  sed  like  regular expression. flags can be a
+       combination  of  i  (case  insensitive),  g  (global)  or s (match
+       newline don't treat it as end of line).
        're' - is regular expresion
        'repl' - is replacement string - may contain pseudo-varibales
        'flags' - substitution flags (i - ignore case, g - global)
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.13. subst usage
@@ -508,19 +511,19 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$
 
 ...
 
-3.14. subst_body('/re/repl/flags')
+3.14.  subst_body('/re/repl/flags')
 
    Replaces re with repl (sed or perl like) in the body of the message.
 
    Meaning of the parameters is as follows:
-     * '/re/repl/flags' - sed like regular expression. flags can be a
-       combination of i (case insensitive), g (global) or s (match newline
-       don't treat it as end of line).
+     * '/re/repl/flags'  -  sed  like  regular expression. flags can be a
+       combination  of  i  (case  insensitive),  g  (global)  or s (match
+       newline don't treat it as end of line).
        're' - is regular expresion
        'repl' - is replacement string - may contain pseudo-varibales
        'flags' - substitution flags (i - ignore case, g - global)
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.14. subst_body usage
@@ -529,19 +532,19 @@ if ( subst_body('/^o=(.*) /o=$fU /') ) {};
 
 ...
 
-3.15. subst_hf(hf, subexp, flags)
+3.15.  subst_hf(hf, subexp, flags)
 
    Perl-like substitutions in the body of a header field.
 
    Meaning of the parameters is as follows:
      * hf - header field name.
-     * subexp - substitution expression in the same format as of the
+     * subexp  -  substitution  expression  in  the same format as of the
        'subst' function parameter.
-     * flags - control flags - it has to be one of: a - all headers
-       matching the name; f - only first header matching the name; l -
+     * flags  -  control  flags  -  it  has to be one of: a - all headers
+       matching  the  name;  f - only first header matching the name; l -
        only the last header matching the name.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.15. search_body usage
@@ -549,16 +552,16 @@ if ( subst_body('/^o=(.*) /o=$fU /') ) {};
 if ( subst_hf("From", "/:test@/:best@/", "a") ) { /*....*/ };
 ...
 
-3.16. set_body(txt,content_type)
+3.16.  set_body(txt,content_type)
 
    Set body to a SIP message.
 
    Meaning of the parameters is as follows:
      * txt - text for the body, can include pseudo-variables.
-     * content_type - value of Content-Type header, can include
+     * content_type   -   value   of  Content-Type  header,  can  include
        pseudo-variables.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.16. set_body usage
@@ -566,16 +569,16 @@ if ( subst_hf("From", "/:test@/:best@/", "a") ) { /*....*/ };
 set_body("test", "text/plain");
 ...
 
-3.17. set_reply_body(txt,content_type)
+3.17.  set_reply_body(txt,content_type)
 
    Set body to a SIP reply to be generated by Kamailio.
 
    Meaning of the parameters is as follows:
      * txt - text for the body, can include pseudo-variables.
-     * content_type - value of Content-Type header, can include
+     * content_type   -   value   of  Content-Type  header,  can  include
        pseudo-variables.
 
-   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  FAILURE_ROUTE,
    BRANCH_ROUTE.
 
    Example 1.17. set_reply_body usage
@@ -583,15 +586,15 @@ set_body("test", "text/plain");
 set_reply_body("test", "text/plain");
 ...
 
-3.18. filter_body(content_type)
+3.18.  filter_body(content_type)
 
-   Filters multipart/mixed body by leaving out all other body parts except
-   the first body part of given type.
+   Filters  multipart/mixed  body  by  leaving  out  all other body parts
+   except the first body part of given type.
 
    Meaning of the parameters is as follows:
      * content_type - Content type to be left in the body.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.18. filter_body usage
@@ -606,14 +609,14 @@ if (has_body("multipart/mixed")) {
 }
 ...
 
-3.19. append_to_reply(txt)
+3.19.  append_to_reply(txt)
 
    Append txt as header to the reply.
 
    Meaning of the parameters is as follows:
      * txt - String which may contains pseudo-variables.
 
-   This function can be used from REQUEST_ROUTE, BRANCH_ROUTE,
+   This   function   can   be   used  from  REQUEST_ROUTE,  BRANCH_ROUTE,
    FAILURE_ROUTE, ERROR_ROUTE.
 
    Example 1.19. append_to_reply usage
@@ -622,21 +625,21 @@ append_to_reply("Foo: bar\r\n");
 append_to_reply("Foo: $rm at $Ts\r\n");
 ...
 
-3.20. append_hf(txt)
+3.20.  append_hf(txt)
 
    Appends 'txt' as header after the last header field.
 
    Meaning of the parameters is as follows:
-     * txt - Header field to be appended. The value can contain
+     * txt  -  Header  field  to  be  appended.  The  value  can  contain
        pseudo-variables which will be replaced at run time.
 
-   Note: Headers which are added in main route cannot be removed in
+   Note:  Headers  which  are  added  in  main route cannot be removed in
    further routes (e.g. failure routes). So, the idea is not to add there
-   any headers that you might want to remove later. To add headers
-   temporarely use the branch route because the changes you do there are
+   any  headers  that  you  might  want  to  remove later. To add headers
+   temporarely  use the branch route because the changes you do there are
    per-branch.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.20. append_hf usage
@@ -645,16 +648,16 @@ append_hf("P-hint: VOICEMAIL\r\n");
 append_hf("From-username: $fU\r\n");
 ...
 
-3.21. append_hf(txt, hdr)
+3.21.  append_hf(txt, hdr)
 
    Appends 'txt' as header after first 'hdr' header field.
 
    Meaning of the parameters is as follows:
-     * txt - Header field to be appended. The value can contain
+     * txt  -  Header  field  to  be  appended.  The  value  can  contain
        pseudo-variables which will be replaced at run time.
      * hdr - Header name after which the 'txt' is appended.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.21. append_hf usage
@@ -663,15 +666,15 @@ append_hf("P-hint: VOICEMAIL\r\n", "Call-ID");
 append_hf("From-username: $fU\r\n", "Call-ID");
 ...
 
-3.22. insert_hf(txt)
+3.22.  insert_hf(txt)
 
    Inserts 'txt' as header before the first header field.
 
    Meaning of the parameters is as follows:
-     * txt - Header field to be inserted. The value can contain
+     * txt  -  Header  field  to  be  inserted.  The  value  can  contain
        pseudo-variables which will be replaced at run time.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.22. insert_hf usage
@@ -680,16 +683,16 @@ insert_hf("P-hint: VOICEMAIL\r\n");
 insert_hf("To-username: $tU\r\n");
 ...
 
-3.23. insert_hf(txt, hdr)
+3.23.  insert_hf(txt, hdr)
 
    Inserts 'txt' as header before first 'hdr' header field.
 
    Meaning of the parameters is as follows:
-     * txt - Header field to be inserted. The value can contain
+     * txt  -  Header  field  to  be  inserted.  The  value  can  contain
        pseudo-variables which will be replaced at run time.
      * hdr - Header name before which the 'txt' is inserted.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.23. insert_hf usage
@@ -698,7 +701,7 @@ insert_hf("P-hint: VOICEMAIL\r\n", "Call-ID");
 insert_hf("To-username: $tU\r\n", "Call-ID");
 ...
 
-3.24. append_urihf(prefix, suffix)
+3.24.  append_urihf(prefix, suffix)
 
    Append header field name with original Request-URI in middle.
 
@@ -706,7 +709,7 @@ insert_hf("To-username: $tU\r\n", "Call-ID");
      * prefix - string (usually at least header field name).
      * suffix - string (usually at least line terminator).
 
-   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  FAILURE_ROUTE,
    BRANCH_ROUTE.
 
    Example 1.24. append_urihf usage
@@ -714,19 +717,19 @@ insert_hf("To-username: $tU\r\n", "Call-ID");
 append_urihf("CC-Diversion: ", "\r\n");
 ...
 
-3.25. is_present_hf(hf_name)
+3.25.  is_present_hf(hf_name)
 
    Return true if a header field is present in message.
 
 Note
 
-   The function is also able to distinguish the compact names. For exmaple
-   "From" will match with "f"
+   The  function  is  also  able  to  distinguish  the compact names. For
+   exmaple "From" will match with "f"
 
    Meaning of the parameters is as follows:
      * hf_name - Header field name.(long or compact form)
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.25. is_present_hf usage
@@ -734,15 +737,15 @@ Note
 if (is_present_hf("From")) log(1, "From HF Present");
 ...
 
-3.26. is_present_hf_re(hf_name_re)
+3.26.  is_present_hf_re(hf_name_re)
 
-   Return true if a header field whose name matches regular expression
+   Return  true  if  a header field whose name matches regular expression
    'hf_name_re' is present in message.
 
    Meaning of the parameters is as follows:
      * hf_name_re - Regular expression to match header field name.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.26. is_present_hf_re usage
@@ -750,11 +753,11 @@ if (is_present_hf("From")) log(1, "From HF Present");
 if (is_present_hf_re("^P-")) log(1, "There are headers starting with P-\n");
 ...
 
-3.27. append_time()
+3.27.  append_time()
 
    Adds a time header to the reply of the request. You must use it before
-   functions that are likely to send a reply, e.g., save() from
-   'registrar' module. Header format is: "Date: %a, %d %b %Y %H:%M:%S
+   functions  that  are  likely  to  send  a  reply,  e.g.,  save()  from
+   'registrar'  module.  Header  format  is: "Date: %a, %d %b %Y %H:%M:%S
    GMT", with the legend:
      * %a abbreviated week of day name (locale)
      * %d day of month as decimal number
@@ -766,7 +769,7 @@ if (is_present_hf_re("^P-")) log(1, "There are headers starting with P-\n");
 
    Return true if a header was succesfully appended.
 
-   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  FAILURE_ROUTE,
    BRANCH_ROUTE.
 
    Example 1.27. append_time usage
@@ -774,9 +777,9 @@ if (is_present_hf_re("^P-")) log(1, "There are headers starting with P-\n");
 append_time();
 ...
 
-3.28. append_time_to_request()
+3.28.  append_time_to_request()
 
-   Adds a time header to the request. Header format is: "Date: %a, %d %b
+   Adds  a time header to the request. Header format is: "Date: %a, %d %b
    %Y %H:%M:%S GMT", with the legend:
      * %a abbreviated week of day name (locale)
      * %d day of month as decimal number
@@ -788,7 +791,7 @@ append_time();
 
    Return true if a header was succesfully appended.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
    Example 1.28. append_time_to_request usage
@@ -797,19 +800,19 @@ if(!is_present_hf("Date"))
     append_time_to_request();
 ...
 
-3.29. is_method(name)
+3.29.  is_method(name)
 
-   Check if the method of the message matches the name. If name is a known
-   method (invite, cancel, ack, bye, options, info, update, register,
-   message, subscribe, notify, refer, prack), the function performs method
-   ID testing (integer comparison) instead of ignore case string
-   comparison.
+   Check  if  the  method  of  the message matches the name. If name is a
+   known  method  (invite,  cancel,  ack,  bye,  options,  info,  update,
+   register,  message,  subscribe,  notify,  refer,  prack), the function
+   performs method ID testing (integer comparison) instead of ignore case
+   string comparison.
 
-   The 'name' can be a list of methods in the form of
-   'method1|method2|...'. In this case, the function returns true if the
+   The   'name'   can   be   a   list   of   methods   in   the  form  of
+   'method1|method2|...'.  In this case, the function returns true if the
    SIP message's method is one from the list. IMPORTANT NOTE: in the list
    must be only methods defined in Kamailio with ID (invite, cancel, ack,
-   bye, options, info, update, register, message, subscribe, notify,
+   bye,  options,  info,  update,  register,  message, subscribe, notify,
    refer, prack, publish; for more see:
    http://www.iana.org/assignments/sip-parameters).
 
@@ -819,7 +822,7 @@ if(!is_present_hf("Date"))
    Meaning of the parameters is as follows:
      * name - SIP method name
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE, and BRANCH_ROUTE.
 
    Example 1.29. is_method usage
@@ -834,9 +837,9 @@ if(is_method("OPTION|UPDATE"))
 }
 ...
 
-3.30. remove_hf(hname)
+3.30.  remove_hf(hname)
 
-   Remove from message all headers with name "hname". Header matching is
+   Remove  from message all headers with name "hname". Header matching is
    case-insensitive. Matches and removes also the compact header forms.
 
    Returns true if at least one header is found and removed.
@@ -844,7 +847,7 @@ if(is_method("OPTION|UPDATE"))
    Meaning of the parameters is as follows:
      * hname - header name to be removed.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.30. remove_hf usage
@@ -859,9 +862,9 @@ remove_hf("Contact")
 remove_hf("m")
 ...
 
-3.31. remove_hf_re(re)
+3.31.  remove_hf_re(re)
 
-   Remove from message all headers with name matching regular expression
+   Remove  from message all headers with name matching regular expression
    "re"
 
    Returns true if at least one header is found and removed.
@@ -869,7 +872,7 @@ remove_hf("m")
    Meaning of the parameters is as follows:
      * re - regular expression to match the header name to be removed.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.31. remove_hf_re usage
@@ -880,19 +883,19 @@ if(remove_hf_re("^P-"))
 }
 ...
 
-3.32. has_body(), has_body(mime)
+3.32.  has_body(), has_body(mime)
 
-   The function returns true if the SIP message has a body attached. The
-   checked includes also the "Content-Lenght" header presence and value.
+   The  function returns true if the SIP message has a body attached. The
+   checked includes also the "Content-Length" header presence and value.
 
-   If a parameter is given, the mime described will be also checked
+   If  a  parameter  is  given,  the  mime described will be also checked
    against the "Content-Type" header.
 
    Meaning of the parameters is as follows:
-     * mime - mime to be checked against the "Content-Type" header. If not
-       present or 0, this check will be disabled.
+     * mime  -  mime  to be checked against the "Content-Type" header. If
+       not present or 0, this check will be disabled.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.32. has_body usage
@@ -903,12 +906,12 @@ if(has_body("application/sdp"))
 }
 ...
 
-3.33. is_audio_on_hold()
+3.33.  is_audio_on_hold()
 
-   The function returns true if the SIP message has a body attached and at
-   least one audio stream in on hold.
+   The  function  returns true if the SIP message has a body attached and
+   at least one audio stream in on hold.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.33. is_audio_on_hold usage
@@ -919,14 +922,14 @@ if(is_audio_on_hold())
 }
 ...
 
-3.34. is_privacy(privacy_type)
+3.34.  is_privacy(privacy_type)
 
-   The function returns true if the SIP message has a Privacy header field
-   that includes the given privacy_type among its privacy values. See
-   http://www.iana.org/assignments/sip-priv-values for possible privacy
-   type values.
+   The  function  returns  true  if  the SIP message has a Privacy header
+   field  that  includes the given privacy_type among its privacy values.
+   See   http://www.iana.org/assignments/sip-priv-values   for   possible
+   privacy type values.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.34. is_privacy usage
@@ -937,11 +940,11 @@ if(is_privacy("id"))
 }
 ...
 
-3.35. in_list(subject, list, separator)
+3.35.  in_list(subject, list, separator)
 
-   Function checks if subject string is found in list string where list
-   items are separated by separator string. Subject and list strings may
-   contain pseudo variables. Separator string needs to be one character
+   Function  checks  if subject string is found in list string where list
+   items  are separated by separator string. Subject and list strings may
+   contain  pseudo  variables. Separator string needs to be one character
    long. Returns 1 if subject is found and -1 otherwise.
 
    Function can be used from all kinds of routes.
@@ -955,12 +958,12 @@ if (in_list("$var(subject)", "$var(list)", ",") {
 }
 ...
 
-3.36. cmp_str(str1, str2)
+3.36.  cmp_str(str1, str2)
 
    The function returns true if the two parameters matches as string case
    sensitive comparison.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.36. cmp_str usage
@@ -971,12 +974,12 @@ if(cmp_str("$rU", "kamailio"))
 }
 ...
 
-3.37. cmp_istr(str1, str2)
+3.37.  cmp_istr(str1, str2)
 
    The function returns true if the two parameters matches as string case
    insensitive comparison.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.37. cmp_str usage
@@ -987,12 +990,12 @@ if(cmp_istr("$rU at you", "kamailio at YOU"))
 }
 ...
 
-3.38. starts_with(str1, str2)
+3.38.  starts_with(str1, str2)
 
-   The function returns true if the first string starts with the second
+   The  function  returns true if the first string starts with the second
    string.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   This   function   can   be  used  from  REQUEST_ROUTE,  ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
    Example 1.38. starts_with usage
@@ -1005,8 +1008,9 @@ if (starts_with("$rU", "+358"))
 
 4. Known Limitations
 
-   Search functions are applied to the original request, i.e., they ignore
-   all changes resulting from message processing in Kamailio script.
+   Search  functions  are  applied  to  the  original request, i.e., they
+   ignore  all  changes  resulting  from  message  processing in Kamailio
+   script.
 
 Chapter 2. Developer Guide
 
@@ -1014,16 +1018,16 @@ Chapter 2. Developer Guide
 
    1. Functions
 
-        1.1. load_textops(*import_structure)
+        1.1. load_textops(*import_structure) 
 
 1. Functions
 
-   1.1. load_textops(*import_structure)
+   1.1. load_textops(*import_structure) 
 
-1.1. load_textops(*import_structure)
+1.1.  load_textops(*import_structure)
 
    For programmatic use only--import the Textops API.
 
    Meaning of the parameters is as follows:
-     * import_structure - Pointer to the import structure - see "struct
+     * import_structure  -  Pointer to the import structure - see "struct
        textops_binds" in modules/textops/api.h
diff --git a/modules/textops/doc/textops_admin.xml b/modules/textops/doc/textops_admin.xml
index a1001e6..07caee9 100644
--- a/modules/textops/doc/textops_admin.xml
+++ b/modules/textops/doc/textops_admin.xml
@@ -1238,7 +1238,7 @@ if(remove_hf_re("^P-"))
 		<para>
 		The function returns <emphasis>true</emphasis> if the SIP message
 		has a body attached. The checked includes also the 
-		<quote>Content-Lenght</quote> header presence and value.
+		<quote>Content-Length</quote> header presence and value.
 		</para>
 		<para>
 		If a parameter is given, the mime described will be also checked against
diff --git a/modules/textops/textops.c b/modules/textops/textops.c
index 86e47a8..1085019 100644
--- a/modules/textops/textops.c
+++ b/modules/textops/textops.c
@@ -1813,8 +1813,7 @@ static int fixup_in_list(void** param, int param_no)
 static int fixup_free_in_list(void** param, int param_no)
 {
     if ((param_no == 1) || (param_no == 2)) {
- 	LM_WARN("free function has not been defined for spve\n");
- 	return 0;
+	return fixup_free_spve_null(param, 1);
     }
  
     if (param_no == 3) return 0;
diff --git a/modules/textops/txt_var.c b/modules/textops/txt_var.c
index 45fb6bb..6792f56 100644
--- a/modules/textops/txt_var.c
+++ b/modules/textops/txt_var.c
@@ -94,6 +94,8 @@ int tr_txt_eval_re(struct sip_msg *msg, tr_param_t *tp, int subtype,
 			{
 				LM_ERR("subst result too big %d, increase buffer size\n",
 						result->len);
+				pkg_free(result->s);
+				pkg_free(result);
 				goto error;
 			}
 			memcpy(tr_txt_buf, result->s, result->len);
diff --git a/modules/textopsx/README b/modules/textopsx/README
index 3a1769b..d53e2eb 100644
--- a/modules/textopsx/README
+++ b/modules/textopsx/README
@@ -1,4 +1,3 @@
-
 Textopsx Module
 
 Andrei Pelinescu-Onciul
@@ -11,7 +10,7 @@ Daniel-Constantin Mierla
    <miconda at gmail.com>
 
    Copyright � 2003 FhG FOKUS
-     _________________________________________________________________
+     __________________________________________________________________
 
    Table of Contents
 
@@ -20,20 +19,20 @@ Daniel-Constantin Mierla
         1. Overview
         2. Functions
 
-              2.1. msg_apply_changes() 
-              2.2. change_reply_status(code, reason) 
-              2.3. remove_body() 
-              2.4. keep_hf(regexp) 
-              2.5. fnmatch(value, expr [, flags]) 
-              2.6. append_hf_value(hf, hvalue) 
-              2.7. insert_hf_value(hf, hvalue) 
-              2.8. remove_hf_value(hf_par) 
-              2.9. remove_hf_value2(hf_par) 
-              2.10. assign_hf_value(hf, hvalue) 
-              2.11. assign_hf_value2(hf, hvalue) 
-              2.12. include_hf_value(hf, hvalue) 
-              2.13. exclude_hf_value(hf, hvalue) 
-              2.14. hf_value_exists(hf, hvalue) 
+              2.1. msg_apply_changes()
+              2.2. change_reply_status(code, reason)
+              2.3. remove_body()
+              2.4. keep_hf(regexp)
+              2.5. fnmatch(value, expr [, flags])
+              2.6. append_hf_value(hf, hvalue)
+              2.7. insert_hf_value(hf, hvalue)
+              2.8. remove_hf_value(hf_par)
+              2.9. remove_hf_value2(hf_par)
+              2.10. assign_hf_value(hf, hvalue)
+              2.11. assign_hf_value2(hf, hvalue)
+              2.12. include_hf_value(hf, hvalue)
+              2.13. exclude_hf_value(hf, hvalue)
+              2.14. hf_value_exists(hf, hvalue)
               2.15. Selects
 
                     2.15.1. @hf_value
@@ -65,20 +64,20 @@ Chapter 1. Admin Guide
    1. Overview
    2. Functions
 
-        2.1. msg_apply_changes() 
-        2.2. change_reply_status(code, reason) 
-        2.3. remove_body() 
-        2.4. keep_hf(regexp) 
-        2.5. fnmatch(value, expr [, flags]) 
-        2.6. append_hf_value(hf, hvalue) 
-        2.7. insert_hf_value(hf, hvalue) 
-        2.8. remove_hf_value(hf_par) 
-        2.9. remove_hf_value2(hf_par) 
-        2.10. assign_hf_value(hf, hvalue) 
-        2.11. assign_hf_value2(hf, hvalue) 
-        2.12. include_hf_value(hf, hvalue) 
-        2.13. exclude_hf_value(hf, hvalue) 
-        2.14. hf_value_exists(hf, hvalue) 
+        2.1. msg_apply_changes()
+        2.2. change_reply_status(code, reason)
+        2.3. remove_body()
+        2.4. keep_hf(regexp)
+        2.5. fnmatch(value, expr [, flags])
+        2.6. append_hf_value(hf, hvalue)
+        2.7. insert_hf_value(hf, hvalue)
+        2.8. remove_hf_value(hf_par)
+        2.9. remove_hf_value2(hf_par)
+        2.10. assign_hf_value(hf, hvalue)
+        2.11. assign_hf_value2(hf, hvalue)
+        2.12. include_hf_value(hf, hvalue)
+        2.13. exclude_hf_value(hf, hvalue)
+        2.14. hf_value_exists(hf, hvalue)
         2.15. Selects
 
               2.15.1. @hf_value
@@ -87,40 +86,40 @@ Chapter 1. Admin Guide
 
 1. Overview
 
-   This  module  implements  functions for SIP message text operations in
-   routing  block  configurations.  It  adds  new features similar to the
+   This module implements functions for SIP message text operations in
+   routing block configurations. It adds new features similar to the
    textops module (textops eXtentions).
 
 2. Functions
 
-   2.1. msg_apply_changes() 
-   2.2. change_reply_status(code, reason) 
-   2.3. remove_body() 
-   2.4. keep_hf(regexp) 
-   2.5. fnmatch(value, expr [, flags]) 
-   2.6. append_hf_value(hf, hvalue) 
-   2.7. insert_hf_value(hf, hvalue) 
-   2.8. remove_hf_value(hf_par) 
-   2.9. remove_hf_value2(hf_par) 
-   2.10. assign_hf_value(hf, hvalue) 
-   2.11. assign_hf_value2(hf, hvalue) 
-   2.12. include_hf_value(hf, hvalue) 
-   2.13. exclude_hf_value(hf, hvalue) 
-   2.14. hf_value_exists(hf, hvalue) 
+   2.1. msg_apply_changes()
+   2.2. change_reply_status(code, reason)
+   2.3. remove_body()
+   2.4. keep_hf(regexp)
+   2.5. fnmatch(value, expr [, flags])
+   2.6. append_hf_value(hf, hvalue)
+   2.7. insert_hf_value(hf, hvalue)
+   2.8. remove_hf_value(hf_par)
+   2.9. remove_hf_value2(hf_par)
+   2.10. assign_hf_value(hf, hvalue)
+   2.11. assign_hf_value2(hf, hvalue)
+   2.12. include_hf_value(hf, hvalue)
+   2.13. exclude_hf_value(hf, hvalue)
+   2.14. hf_value_exists(hf, hvalue)
    2.15. Selects
 
         2.15.1. @hf_value
         2.15.2. @hf_value2
         2.15.3. @hf_value_exists
 
-2.1.  msg_apply_changes()
+2.1. msg_apply_changes()
 
-   Use  this  function to apply changes performed on SIP request content.
-   Be  careful  when  using  this  function;  due  to special handling of
-   changes  to  the  SIP message buffer so far, using this function might
-   change the behaviour of your config. Do test your config properly!
+   Use this function to apply changes performed on SIP message content. Be
+   careful when using this function; due to special handling of changes to
+   the SIP message buffer so far, using this function might change the
+   behaviour of your config. Do test your config properly!
 
-   This function can be used from REQUEST_ROUTE.
+   This function can be used from REQUEST_ROUTE or ONREPLY_ROUTE.
 
    Example 1.1. msg_apply_changes() usage
 ...
@@ -135,7 +134,7 @@ if(msg_apply_changes())
 }
 ...
 
-2.2.  change_reply_status(code, reason)
+2.2. change_reply_status(code, reason)
 
    Intercept a SIP reply (in an onreply_route) and change its status code
    and reason phrase prior to forwarding it.
@@ -156,7 +155,7 @@ onreply_route {
 }
 ...
 
-2.3.  remove_body()
+2.3. remove_body()
 
    Use this function to remove the body of SIP requests or replies.
 
@@ -167,11 +166,11 @@ onreply_route {
 remove_body();
 ...
 
-2.4.  keep_hf(regexp)
+2.4. keep_hf(regexp)
 
    Remove headers that don't match the regular expression regexp. Several
-   header  are ignored always (thus not removed): Via, From, To, Call-ID,
-   CSeq,  Content-Lenght,  Content-Type,  Max-Forwards,  Contact,  Route,
+   header are ignored always (thus not removed): Via, From, To, Call-ID,
+   CSeq, Content-Length, Content-Type, Max-Forwards, Contact, Route,
    Record-Route -- these can be removed one by one with remove_hf().
 
    This function can be used from ANY_ROUTE.
@@ -181,13 +180,13 @@ remove_body();
 keep_hf("User-Agent");
 ...
 
-2.5.  fnmatch(value, expr [, flags])
+2.5. fnmatch(value, expr [, flags])
 
-   Match  the  value  against the expr using shell-style pattern for file
-   name  matching (see man page for C function fnmatch()). It is known to
+   Match the value against the expr using shell-style pattern for file
+   name matching (see man page for C function fnmatch()). It is known to
    be faster and use less-memory than regular expressions.
 
-   Parameter  'flags'  is  optional and can be 'i' to do case insensitive
+   Parameter 'flags' is optional and can be 'i' to do case insensitive
    matching.
 
    This function can be used from ANY_ROUTE.
@@ -200,15 +199,15 @@ if(fnmatch("$rU", "123*"))
 }
 ...
 
-2.6.  append_hf_value(hf, hvalue)
+2.6. append_hf_value(hf, hvalue)
 
    Append new header value after an existing header, if no index acquired
-   append  at  the  end  of list. Note that a header may consist of comma
+   append at the end of list. Note that a header may consist of comma
    delimited list of values.
 
    Meaning of the parameters is as follows:
-     * hf  -  Header  field  to be appended. Format: HFNAME [ [IDX] ]. If
-       index  is  not  specified  new  header  is  inserted at the end of
+     * hf - Header field to be appended. Format: HFNAME [ [IDX] ]. If
+       index is not specified new header is inserted at the end of
        message.
      * hvalue - Value to be added, config var formatting supported.
 
@@ -216,20 +215,20 @@ if(fnmatch("$rU", "123*"))
 ...
 append_hf_value("foo", "gogo;stamp=$Ts")   # add new header
 append_hf_value("foo[1]", "gogo")  # add new value behind first value
-append_hf_value("foo[-1]", "$var(Bar)") # try add value to the last header, if
-not exists add new header
+append_hf_value("foo[-1]", "$var(Bar)") # try add value to the last header, if n
+ot exists add new header
 ...
 
-2.7.  insert_hf_value(hf, hvalue)
+2.7. insert_hf_value(hf, hvalue)
 
-   Insert  new  header  value  before  an  existing  header,  if no index
-   acquired insert before first hf header. Note that a header may consist
-   of  comma  delimited list of values. To insert value behing last value
-   use appenf_hf_value.
+   Insert new header value before an existing header, if no index acquired
+   insert before first hf header. Note that a header may consist of comma
+   delimited list of values. To insert value behing last value use
+   appenf_hf_value.
 
    Meaning of the parameters is as follows:
-     * hf  -  Header  field  to be appended. Format: HFNAME [ [IDX] ]. If
-       index  is  not  specified  new  header  is  inserted at the top of
+     * hf - Header field to be appended. Format: HFNAME [ [IDX] ]. If
+       index is not specified new header is inserted at the top of
        message.
      * hvalue - Value to be added, config var formatting supported.
 
@@ -240,14 +239,14 @@ insert_hf_value("foo", "$avp(foo)")   # add new header at the top of list
 insert_hf_value("foo[1]", "gogo") # try add to the first header
 ...
 
-2.8.  remove_hf_value(hf_par)
+2.8. remove_hf_value(hf_par)
 
-   Remove  the  header value from existing header, Note that a header may
+   Remove the header value from existing header, Note that a header may
    consist of comma delimited list of values.
 
    Meaning of the parameters is as follows:
-     * hf_par  - Header field/param to be removed. Format: HFNAME [ [IDX]
-       ] [. PARAM ] If asterisk is specified as index then all values are
+     * hf_par - Header field/param to be removed. Format: HFNAME [ [IDX] ]
+       [. PARAM ] If asterisk is specified as index then all values are
        affected.
 
    Example 1.8. remove_hf_value usage
@@ -259,35 +258,35 @@ remove_hf_value("foo.bar")  # delete parameter
 remove_hf_value("foo[*].bar") # for each foo delete bar parameters
 ...
 
-2.9.  remove_hf_value2(hf_par)
+2.9. remove_hf_value2(hf_par)
 
-   Remove  specified  header  or  parameter.  It  is  expected  header in
-   Authorization  format (comma delimiters are not treated as multi-value
+   Remove specified header or parameter. It is expected header in
+   Authorization format (comma delimiters are not treated as multi-value
    delimiters).
 
    Meaning of the parameters is as follows:
-     * hf_par  -  Header/param to be removed. Format: HFNAME [ [IDX] ] [.
-       PARAM  ]  If  asterisk  is  specified as index then all values are
+     * hf_par - Header/param to be removed. Format: HFNAME [ [IDX] ] [.
+       PARAM ] If asterisk is specified as index then all values are
        affected.
 
    Example 1.9. remove_hf_value2 usage
 ...
 remove_hf_value2("foo")  # remove foo[1]
-remove_hf_value2("foo[*]")  # remove all foo's headers, the same as remove_hf_h
-eader("foo[*]");
+remove_hf_value2("foo[*]")  # remove all foo's headers, the same as remove_hf_he
+ader("foo[*]");
 remove_hf_value2("foo[-1]") # last foo
 remove_hf_value2("foo.bar")  # delete parameter
 remove_hf_value2("foo[*].bar") # for each foo delete bar parameters
 ...
 
-2.10.  assign_hf_value(hf, hvalue)
+2.10. assign_hf_value(hf, hvalue)
 
    Assign value to specified header value / param.
 
    Meaning of the parameters is as follows:
-     * hf_para  -  Header  field  value  /  param to be appended. Format:
-       HFNAME  [ [IDX] ] [. PARAM] If asterisk is specified as index then
-       all values are affected.
+     * hf_para - Header field value / param to be appended. Format: HFNAME
+       [ [IDX] ] [. PARAM] If asterisk is specified as index then all
+       values are affected.
      * hvalue - Value to be assigned, config var formatting supported. If
        value is empty then no equal sign apears in param.
 
@@ -302,16 +301,16 @@ assign_hf_value("foo[*]", "")  # remove all foo's, empty value remains
 assign_hf_value("foo[*].bar", "")  # set empty value (ex. lr)
 ...
 
-2.11.  assign_hf_value2(hf, hvalue)
+2.11. assign_hf_value2(hf, hvalue)
 
-   Assign   value   to   specified  header.  It  is  expected  header  in
-   Authorization  format (comma delimiters are not treated as multi-value
+   Assign value to specified header. It is expected header in
+   Authorization format (comma delimiters are not treated as multi-value
    delimiters).
 
    Meaning of the parameters is as follows:
-     * hf_para  -  Header  field  value  /  param to be appended. Format:
-       HFNAME  [ [IDX] ] [. PARAM] If asterisk is specified as index then
-       all values are affected.
+     * hf_para - Header field value / param to be appended. Format: HFNAME
+       [ [IDX] ] [. PARAM] If asterisk is specified as index then all
+       values are affected.
      * hvalue - Value to be assigned, config var formatting supported. If
        value is empty then no equal sign apears in param.
 
@@ -322,7 +321,7 @@ assign_hf_value2("foo[-1]", "gogo")  # foo[last_foo]
 assign_hf_value2("foo[*].bar", "")  # set empty value (ex. lr)
 ...
 
-2.12.  include_hf_value(hf, hvalue)
+2.12. include_hf_value(hf, hvalue)
 
    Add value in set if not exists, eg. "Supported: path,100rel".
 
@@ -335,7 +334,7 @@ assign_hf_value2("foo[*].bar", "")  # set empty value (ex. lr)
 include_hf_value("Supported", "path");
 ...
 
-2.13.  exclude_hf_value(hf, hvalue)
+2.13. exclude_hf_value(hf, hvalue)
 
    Remove value from set if exists, eg. "Supported: path,100rel".
 
@@ -348,13 +347,13 @@ include_hf_value("Supported", "path");
 exclude_hf_value("Supported", "100rel");
 ...
 
-2.14.  hf_value_exists(hf, hvalue)
+2.14. hf_value_exists(hf, hvalue)
 
-   Check     if     value     exists    in    set.    Alternate    select
+   Check if value exists in set. Alternate select
    @hf_value_exists.HF.VALUE may be used. It returns one or zero.
 
    Meaning of the parameters is as follows:
-     * hf  - Header field name to be affected. Underscores are treated as
+     * hf - Header field name to be affected. Underscores are treated as
        dashes.
      * hvalue - config var formatting supported.
 
@@ -373,28 +372,27 @@ if (@hf_value_exists.supported.path == "1") {
 
 2.15.1. @hf_value
 
-   Get  value  of  required  header-value  or  param. Note that functions
-   called  'value2'  works with Authorization-like headers where comma is
-   not  treated  as value delimiter. Formats: @hf_value.HFNAME[IDX] # idx
-   value,  negative  value counts from bottom @hf_value.HFNAME.PARAM_NAME
-   @hf_value.HFNAME[IDX].PARAM_NAME  @hf_value.HFNAME.p.PARAM_NAME  #  or
-   .param.,    useful    if    requred   called   "uri",   "p",   "param"
-   @hf_value.HFNAME[IDX].p.PARAM_NAME  # dtto @hf_value.HFNAME[IDX].uri #
-   (<  & > excluded) @hf_value.HFNAME[*] # return comma delimited list of
+   Get value of required header-value or param. Note that functions called
+   'value2' works with Authorization-like headers where comma is not
+   treated as value delimiter. Formats: @hf_value.HFNAME[IDX] # idx value,
+   negative value counts from bottom @hf_value.HFNAME.PARAM_NAME
+   @hf_value.HFNAME[IDX].PARAM_NAME @hf_value.HFNAME.p.PARAM_NAME # or
+   .param., useful if requred called "uri", "p", "param"
+   @hf_value.HFNAME[IDX].p.PARAM_NAME # dtto @hf_value.HFNAME[IDX].uri #
+   (< & > excluded) @hf_value.HFNAME[*] # return comma delimited list of
    all values (combines headers) @hf_value.HFNAME # the same as above [*]
-   but  may  be  parsed  by  cfg.y @hf_value.HFNAME[*].uri # return comma
-   delimited  list  of  uris  (< & > excluded) @hf_value.HFNAME.uri # the
-   same as above [*] but may be parsed by cfg.y
-   @hf_value.HFNAME[IDX].name   #  returns  name  part,  quotes  excluded
-   @hf_value.HFNAME.name   #   returns  name  part  of  the  first  value
-   @hf_value2.HFNAME     #     returns     value    of    first    header
-   @hf_value2.HFNAME[IDX]    #    returns    value    of   idx's   header
-   @hf_value2.HFNAME.PARAM_NAME         @hf_value2.HFNAME[IDX].PARAM_NAME
-   @hf_value.HFNAME[IDX].uri    #    return    URI,    quotes    excluded
-   @hf_value.HFNAME.p.uri  #  returns  param  named  uri,  not URI itself
-   @hf_value.HFNAME.p.name  #  returns  param named name, not name itself
-   @hf_value.HFNAME[IDX].uri.name  #  any sel_any_uri nested features may
-   be used @hf_value.HFNAME[IDX].nameaddr.name # select_any_nameaddr
+   but may be parsed by cfg.y @hf_value.HFNAME[*].uri # return comma
+   delimited list of uris (< & > excluded) @hf_value.HFNAME.uri # the same
+   as above [*] but may be parsed by cfg.y @hf_value.HFNAME[IDX].name #
+   returns name part, quotes excluded @hf_value.HFNAME.name # returns name
+   part of the first value @hf_value2.HFNAME # returns value of first
+   header @hf_value2.HFNAME[IDX] # returns value of idx's header
+   @hf_value2.HFNAME.PARAM_NAME @hf_value2.HFNAME[IDX].PARAM_NAME
+   @hf_value.HFNAME[IDX].uri # return URI, quotes excluded
+   @hf_value.HFNAME.p.uri # returns param named uri, not URI itself
+   @hf_value.HFNAME.p.name # returns param named name, not name itself
+   @hf_value.HFNAME[IDX].uri.name # any sel_any_uri nested features may be
+   used @hf_value.HFNAME[IDX].nameaddr.name # select_any_nameaddr
 
    Meaning of the parameters is as follows:
      * HFNAME - Header field name. Underscores are treated as dashes.
diff --git a/modules/textopsx/doc/functions.xml b/modules/textopsx/doc/functions.xml
index 322bd41..57d6d31 100644
--- a/modules/textopsx/doc/functions.xml
+++ b/modules/textopsx/doc/functions.xml
@@ -5,18 +5,18 @@
 <section id="textopsx.functions" xmlns:xi="http://www.w3.org/2001/XInclude">
     <title>Functions</title>
 
-	<section id="textopsx.msg_apply_changes">
+	<section id="textopsx.f.msg_apply_changes">
 		<title>
 		<function moreinfo="none">msg_apply_changes()</function>
 		</title>
 		<para>
-		Use this function to apply changes performed on SIP request content. Be
+		Use this function to apply changes performed on SIP message content. Be
 		careful when using this function;  due to special handling of changes
 		to the SIP message buffer so far, using this function might change
 		the behaviour of your config.  Do test your config properly!
 		</para>
    		<para>
-		This function can be used from REQUEST_ROUTE.
+		This function can be used from REQUEST_ROUTE or ONREPLY_ROUTE.
 		</para>
 		<example>
 		<title><function>msg_apply_changes()</function> usage</title>
@@ -36,7 +36,7 @@ if(msg_apply_changes())
 		</example>
 	</section>
 
-    <section id="textopsx.change_reply_status">
+    <section id="textopsx.f.change_reply_status">
 	<title>
 	    <function>change_reply_status(code, reason)</function>
 	</title>
@@ -73,7 +73,7 @@ onreply_route {
 	</example>
     </section>
 
-	<section id="textopsx.remove_body">
+	<section id="textopsx.f.remove_body">
 		<title>
 		<function moreinfo="none">remove_body()</function>
 		</title>
@@ -93,14 +93,14 @@ remove_body();
 		</example>
 	</section>
 
-	<section id="textopsx.keep_hf">
+	<section id="textopsx.f.keep_hf">
 		<title>
 		<function moreinfo="none">keep_hf(regexp)</function>
 		</title>
 		<para>
 			Remove headers that don't match the regular expression regexp.
 			Several header are ignored always (thus not removed): Via, From,
-			To, Call-ID, CSeq, Content-Lenght, Content-Type, Max-Forwards,
+			To, Call-ID, CSeq, Content-Length, Content-Type, Max-Forwards,
 			Contact, Route, Record-Route -- these can be removed one by one
 			with remove_hf().
 		</para>
@@ -117,7 +117,7 @@ keep_hf("User-Agent");
 		</example>
 	</section>
 
-	<section id="textopsx.fnmatch">
+	<section id="textopsx.f.fnmatch">
 		<title>
 		<function moreinfo="none">fnmatch(value, expr [, flags])</function>
 		</title>
@@ -146,7 +146,7 @@ if(fnmatch("$rU", "123*"))
 		</example>
 	</section>
 
-    <section id="append_hf_value">
+    <section id="textopsx.f.append_hf_value">
 	<title>
 	    <function>append_hf_value(hf, hvalue)</function>
 	</title>
@@ -178,7 +178,7 @@ append_hf_value("foo[-1]", "$var(Bar)") # try add value to the last header, if n
 	</example>
     </section>
 
-    <section id="insert_hf_value">
+    <section id="textopsx.f.insert_hf_value">
 	<title>
 	    <function>insert_hf_value(hf, hvalue)</function>
 	</title>
@@ -211,7 +211,7 @@ insert_hf_value("foo[1]", "gogo") # try add to the first header
 	</example>
     </section>
 
-    <section id="remove_hf_value">
+    <section id="textopsx.f.remove_hf_value">
 	<title>
 	    <function>remove_hf_value(hf_par)</function>
 	</title>
@@ -240,7 +240,7 @@ remove_hf_value("foo[*].bar") # for each foo delete bar parameters
 	</example>
     </section>
 
-    <section id="remove_hf_value2">
+    <section id="textopsx.f.remove_hf_value2">
 	<title>
 	    <function>remove_hf_value2(hf_par)</function>
 	</title>
@@ -270,7 +270,7 @@ remove_hf_value2("foo[*].bar") # for each foo delete bar parameters
 	</example>
     </section>
 
-    <section id="assign_hf_value">
+    <section id="textopsx.f.assign_hf_value">
 	<title>
 	    <function>assign_hf_value(hf, hvalue)</function>
 	</title>
@@ -307,7 +307,7 @@ assign_hf_value("foo[*].bar", "")  # set empty value (ex. lr)
 	</example>
     </section>
 
-    <section id="assign_hf_value2">
+    <section id="textopsx.f.assign_hf_value2">
 	<title>
 	    <function>assign_hf_value2(hf, hvalue)</function>
 	</title>
@@ -339,7 +339,7 @@ assign_hf_value2("foo[*].bar", "")  # set empty value (ex. lr)
 	</example>
     </section>
 
-    <section id="include_hf_value">
+    <section id="textopsx.f.include_hf_value">
 	<title>
 	    <function>include_hf_value(hf, hvalue)</function>
 	</title>
@@ -367,7 +367,7 @@ include_hf_value("Supported", "path");
 	</example>
     </section>
 
-    <section id="exclude_hf_value">
+    <section id="textopsx.f.exclude_hf_value">
 	<title>
 	    <function>exclude_hf_value(hf, hvalue)</function>
 	</title>
@@ -395,7 +395,7 @@ exclude_hf_value("Supported", "100rel");
 	</example>
     </section>
 
-    <section id="hf_value_exists">
+    <section id="textopsx.f.hf_value_exists">
 	<title>
 	    <function>hf_value_exists(hf, hvalue)</function>
 	</title>
@@ -432,7 +432,7 @@ if (@hf_value_exists.supported.path == "1") {
 
 	<section>
 	<title>Selects</title>
-    <section id="sel.hf_value">
+    <section id="textopsx.sel.hf_value">
 	<title>@hf_value</title>
 	<para>
 		Get value of required header-value or param. Note that functions called 'value2'
@@ -492,13 +492,13 @@ $prt = @hf_value2.authorization.integrity_protected;
 	    </programlisting>
 	</example>
     </section>
-    <section id="sel.hf_value2">
+    <section id="textopsx.sel.hf_value2">
 	<title>@hf_value2</title>
 	<para>
 		TBA.
 	</para>
     </section>
-    <section id="sel.hf_value_exists">
+    <section id="textopsx.sel.hf_value_exists">
 	<title>@hf_value_exists</title>
 	<para>
 		TBA.
diff --git a/modules/textopsx/textopsx.c b/modules/textopsx/textopsx.c
index bbe1ff1..2a7273d 100644
--- a/modules/textopsx/textopsx.c
+++ b/modules/textopsx/textopsx.c
@@ -79,7 +79,7 @@ extern select_row_t sel_declaration[];
 /* cfg functions */
 static cmd_export_t cmds[] = {
 	{"msg_apply_changes",    (cmd_function)msg_apply_changes_f,     0,
-		0, REQUEST_ROUTE },
+		0, REQUEST_ROUTE|ONREPLY_ROUTE },
 	{"change_reply_status",	 change_reply_status_f,	                2,
 		change_reply_status_fixup, ONREPLY_ROUTE },
 	{"remove_body",          (cmd_function)w_remove_body_f,         0,
@@ -152,7 +152,7 @@ static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2)
 	str obuf;
 	sip_msg_t tmp;
 
-	if(get_route_type()!=REQUEST_ROUTE)
+	if(msg->first_line.type!=SIP_REPLY && get_route_type()!=REQUEST_ROUTE)
 	{
 		LM_ERR("invalid usage - not in request route\n");
 		return -1;
@@ -160,9 +160,14 @@ static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2)
 
 	init_dest_info(&dst);
 	dst.proto = PROTO_UDP;
-	obuf.s = build_req_buf_from_sip_req(msg,
-			(unsigned int*)&obuf.len, &dst,
-			BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
+	if(msg->first_line.type == SIP_REPLY) {
+		obuf.s = generate_res_buf_from_sip_res(msg,
+				(unsigned int*)&obuf.len, BUILD_NO_VIA1_UPDATE);
+	} else {
+		obuf.s = build_req_buf_from_sip_req(msg,
+				(unsigned int*)&obuf.len, &dst,
+				BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
+	}
 	if(obuf.s == NULL)
 	{
 		LM_ERR("couldn't update msg buffer content\n");
@@ -216,9 +221,9 @@ static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2)
 	pkg_free(obuf.s);
 
 	/* reparse the message */
-	LM_DBG("SIP Request content updated - reparsing\n");
+	LM_DBG("SIP message content updated - reparsing\n");
 	if (parse_msg(msg->buf, msg->len, msg)!=0){
-		LM_ERR("parse_msg failed\n");
+		LM_ERR("parsing new sip message failed\n");
 		return -1;
 	}
 
diff --git a/modules/timer/doc/timer.xml b/modules/timer/doc/timer.xml
index 9a64f91..0385bad 100644
--- a/modules/timer/doc/timer.xml
+++ b/modules/timer/doc/timer.xml
@@ -55,7 +55,7 @@
 
 		<title>Parameters</title>
 
-		<section id="declare_timer">
+		<section id="timer.p.declare_timer">
 			<title><varname>declare_timer</varname> (string)</title>
 			<para>
 			Declares timer route which will be called in specific interval.
@@ -88,7 +88,7 @@
 	<section id="timer.functions">
 		<title>Functions</title>
 
-		<section id="timer_enable">
+		<section id="timer.p.timer_enable">
 			<title>
 				<function>timer_enable(timer_id, enable_disable)</function>
 			</title>
diff --git a/modules/tls/README b/modules/tls/README
index 8a42844..cdd3493 100644
--- a/modules/tls/README
+++ b/modules/tls/README
@@ -1,4 +1,3 @@
-
 TLS Module
 
 Andrei Pelinescu-Onciul
@@ -6,7 +5,7 @@ Andrei Pelinescu-Onciul
    iptelorg GmbH
 
    Copyright � 2007 iptelorg GmbH
-     _________________________________________________________________
+     __________________________________________________________________
 
    Table of Contents
 
@@ -64,7 +63,10 @@ Andrei Pelinescu-Onciul
               11.3. tls.options
               11.4. tls.reload
 
-        12. History
+        12. Status
+
+              12.1. License
+              12.2. History
 
    List of Examples
 
@@ -167,21 +169,24 @@ Chapter 1. Admin Guide
         11.3. tls.options
         11.4. tls.reload
 
-   12. History
+   12. Status
+
+        12.1. License
+        12.2. History
 
 1. Overview
 
-   This  module  implements  the  TLS  transport  for  Kamailio using the
-   OpenSSL  library  (http://www.openssl.org).  To enable the TLS support
-   this  module  must  be  loaded and enable_tls=yes must be added to the
-   Kamailio config file
+   This module implements the TLS transport for Kamailio using the OpenSSL
+   library (http://www.openssl.org). To enable the TLS support this module
+   must be loaded and enable_tls=yes must be added to the Kamailio config
+   file
 
 2. Quick Start
 
    Make sure you have a proper certificate and private key and either use
-   the  certificate  and  private_key module parameters, or make sure the
+   the certificate and private_key module parameters, or make sure the
    certificate and key are in the same PEM file, named cert.pem an placed
-   in  [your-cfg-install-prefix]/etc/kamailio/.  Don't forget to load the
+   in [your-cfg-install-prefix]/etc/kamailio/. Don't forget to load the
    tls module and to enable TLS (add enable_tls=yes to your config).
 
    Example 1.1. quick start config
@@ -200,51 +205,50 @@ route{
 
 3. Important Notes
 
-   The  TLS  module  needs  some  special  options enabled when compiling
+   The TLS module needs some special options enabled when compiling
    Kamailio. These options are enabled by default, however in case you're
-   using  a  modified  Kamailio  version  or Makefile, make sure that you
-   enable  -DUSE_TLS  and  -DTLS_HOOKS  (or compile with make TLS_HOOKS=1
-   which  will  take  care  of  both  options).  To quickly check if your
-   Kamailio  version was compiled with these options, run kamailio -V and
+   using a modified Kamailio version or Makefile, make sure that you
+   enable -DUSE_TLS and -DTLS_HOOKS (or compile with make TLS_HOOKS=1
+   which will take care of both options). To quickly check if your
+   Kamailio version was compiled with these options, run kamailio -V and
    look for USE_TLS and TLS_HOOKS among the flags.
 
-   This  module  includes  several  workarounds  for various Openssl bugs
-   (like  compression  and  Kerberos  using  the wrong memory allocations
-   functions,  low  memory  problems  a.s.o).  On  startup it will try to
-   enable  the  needed  workarounds based on the openssl library version.
-   Each  time  a known problem is detected and a workaround is enabled, a
-   message  will  be logged. In general it is recommended to compile this
-   module on the same machine or a similar machine to where kamailio will
-   be  run  or  to  link it statically with libssl. For example if on the
-   compile  machine  openssl  does not have the kerberos support enabled,
-   but  on  the  target  machine  a  kerberos  enabled openssl library is
-   installed,  kamailio  cannot  apply  the  needed  workarounds and will
-   refuse  to  start.  The same thing will happen if the openssl versions
-   are   too  different  (to  force  kamailio  startup  anyway,  see  the
-   tls_force_run module parameter).
-
-   Try   to   avoid  using  keys  larger  then  1024  bytes.  Large  keys
-   significantly  slow  down  the TLS connection handshake, thus limiting
-   the maximum Kamailio TLS connection rate.
-
-   Compression  is  fully  supported  if  you  have  a new enough Openssl
-   version  (starting  with 0.9.8). Although there are some problems with
-   zlib  compression  in  currently  deployed Openssl versions (up to and
-   including  0.9.8d,  see  openssl  bug  #1468),  the  TLS  module  will
-   automatically  switch  to  its  own  fixed  version. Note however that
-   starting with sr 3.1 compression is not enabled by default, due to the
-   huge  extra memory consumption that it causes (about 10x more memory).
-   To  enable  it  use modparam("tls", "tls_disable_compression", 0) (see
+   This module includes several workarounds for various Openssl bugs (like
+   compression and Kerberos using the wrong memory allocations functions,
+   low memory problems a.s.o). On startup it will try to enable the needed
+   workarounds based on the openssl library version. Each time a known
+   problem is detected and a workaround is enabled, a message will be
+   logged. In general it is recommended to compile this module on the same
+   machine or a similar machine to where kamailio will be run or to link
+   it statically with libssl. For example if on the compile machine
+   openssl does not have the kerberos support enabled, but on the target
+   machine a kerberos enabled openssl library is installed, kamailio
+   cannot apply the needed workarounds and will refuse to start. The same
+   thing will happen if the openssl versions are too different (to force
+   kamailio startup anyway, see the tls_force_run module parameter).
+
+   Try to avoid using keys larger then 1024 bytes. Large keys
+   significantly slow down the TLS connection handshake, thus limiting the
+   maximum Kamailio TLS connection rate.
+
+   Compression is fully supported if you have a new enough Openssl version
+   (starting with 0.9.8). Although there are some problems with zlib
+   compression in currently deployed Openssl versions (up to and including
+   0.9.8d, see openssl bug #1468), the TLS module will automatically
+   switch to its own fixed version. Note however that starting with sr 3.1
+   compression is not enabled by default, due to the huge extra memory
+   consumption that it causes (about 10x more memory). To enable it use
+   modparam("tls", "tls_disable_compression", 0) (see
    tls_disable_compression).
 
-   The  TLS  module  includes workarounds for the following known openssl
-   bugs:    openssl   #1204   (disable   SS_OP_TLS_BLOCK_PADDING_BUG   if
-   compression  is  enabled,  for  versions  between  0.9.8  and 0.9.8c),
-   openssl  #1468 (fix zlib compression memory allocation), openssl #1467
-   (kerberos support will be disabled if the openssl version is less than
-   0.9.8e-beta1)  and  openssl  #1491  (stop  using  tls  in  low  memory
-   situations  due  to  the very high risk of openssl crashing or leaking
-   memory). The bug reports can be viewed at http://rt.openssl.org/.
+   The TLS module includes workarounds for the following known openssl
+   bugs: openssl #1204 (disable SS_OP_TLS_BLOCK_PADDING_BUG if compression
+   is enabled, for versions between 0.9.8 and 0.9.8c), openssl #1468 (fix
+   zlib compression memory allocation), openssl #1467 (kerberos support
+   will be disabled if the openssl version is less than 0.9.8e-beta1) and
+   openssl #1491 (stop using tls in low memory situations due to the very
+   high risk of openssl crashing or leaking memory). The bug reports can
+   be viewed at http://rt.openssl.org/.
 
 4. Compiling the TLS Module
 
@@ -259,33 +263,33 @@ make all include_modules=tls
 
    .
 
-   However  in some cases the openssl library requires linking with other
+   However in some cases the openssl library requires linking with other
    libraries. For example compiling the openssl library with kerberos and
-   zlib-shared  support  will require linking the tls module with libkrb5
-   and  libz.  In  this  case  just  add TLS_EXTRA_LIBS="library list" to
-   make's command line. E.g.:
+   zlib-shared support will require linking the tls module with libkrb5
+   and libz. In this case just add TLS_EXTRA_LIBS="library list" to make's
+   command line. E.g.:
 make TLS_EXTRA_LIBS="-lkrb5 -lz" all include_modules=tls
 
-   In  general,  if Kamailio fails to start with a symbol not found error
-   when  trying  to  load  the  tls module (check the log), it means some
+   In general, if Kamailio fails to start with a symbol not found error
+   when trying to load the tls module (check the log), it means some
    needed library was not linked and it must be added to TLS_EXTRA_LIBS
 
 5. TLS and Low Memory
 
    The openssl library doesn't handle very well low memory situations. If
    memory allocations start to fail (due to memory shortage), openssl can
-   crash  or  cause memory leaks (making the memory shortage even worse).
-   As  of  this  writing  all  openssl  versions were affected (includind
-   0.9.8e),  see  openssl  bug #1491. The tls module has some workarounds
-   for    preventing    this    problem    (see   low_mem_treshold1   and
-   low_mem_threshold2),  however  starting  Kamailio  with  enough shared
-   memory  is higly recommended. When this is not possible a quick way to
-   significantly  reduce  openssl  memory usage it to disable compression
-   (see tls_disable_compression).
+   crash or cause memory leaks (making the memory shortage even worse). As
+   of this writing all openssl versions were affected (includind 0.9.8e),
+   see openssl bug #1491. The tls module has some workarounds for
+   preventing this problem (see low_mem_treshold1 and low_mem_threshold2),
+   however starting Kamailio with enough shared memory is higly
+   recommended. When this is not possible a quick way to significantly
+   reduce openssl memory usage it to disable compression (see
+   tls_disable_compression).
 
 6. TLS Debugging
 
-   Debugging  messages  can be selectively enabled by recompiling the tls
+   Debugging messages can be selectively enabled by recompiling the tls
    module with a combination of the following defines:
      * TLS_WR_DEBUG - debug messages for the write/send part.
      * TLS_RD_DEBUG - debug messages for the read/receive part.
@@ -299,39 +303,39 @@ make -C modules/tls extra_defs="-DTLS_WR_DEBUG -DTLS_RD_DEBUG"
 
 7. Known Limitations
 
-   The  private  key  must  not  encrypted (Kamailio cannot ask you for a
+   The private key must not encrypted (Kamailio cannot ask you for a
    password on startup).
 
-   The  TLS  certificate  verifications  ignores  the  certificate  name,
-   subject  altname  and ip extensions, it just checks if the certificate
-   is  signed by a recognized CA. One can use the select framework to try
-   to  overcome  this limitation (check in the script for the contents of
-   various  certificate  fields), but this is not only slow, but also not
-   exactly standard conforming (the verification should happen during TLS
+   The TLS certificate verifications ignores the certificate name, subject
+   altname and ip extensions, it just checks if the certificate is signed
+   by a recognized CA. One can use the select framework to try to overcome
+   this limitation (check in the script for the contents of various
+   certificate fields), but this is not only slow, but also not exactly
+   standard conforming (the verification should happen during TLS
    connection establishment and not after).
 
    TLS specific config reloading is not safe, so for now better don't use
    it, especially under heavy traffic.
 
-   This  documentation  is  incomplete.  The  provided  selects  are  not
+   This documentation is incomplete. The provided selects are not
    documented. A list with all the ones implemented by the TLS module can
-   be     seen     under     doc/select_list/select_tls.txt     or     or
-   http://sip-router.org/docbook/sip-router/branch/master/select_list/sel
-   ect_list.html#select_list.tls.
+   be seen under doc/select_list/select_tls.txt or or
+   http://sip-router.org/docbook/sip-router/branch/master/select_list/sele
+   ct_list.html#select_list.tls.
 
 8. Quick Certificate Howto
 
-   There  are  various ways to create, sign certificates and manage small
-   CAs   (Certificate  Authorities).  If  you  want  a  GUI,  try  tinyca
-   (http://tinyca.sm-zone.net/),  a  very  nice  and  small CA management
-   application.  If  you  are  in a hurry and everything you have are the
+   There are various ways to create, sign certificates and manage small
+   CAs (Certificate Authorities). If you want a GUI, try tinyca
+   (http://tinyca.sm-zone.net/), a very nice and small CA management
+   application. If you are in a hurry and everything you have are the
    installed openssl libraries and utilities, read on.
 
    Assumptions: we run our own CA.
 
-   Warning:  in  this  example no key is encrypted. The client and server
+   Warning: in this example no key is encrypted. The client and server
    private keys must not be encrypted (Kamailio doesn't support encrypted
-   keys),  so  make  sure  the  corresponding  files are readable only by
+   keys), so make sure the corresponding files are readable only by
    trusted people. You should use a password for your CA private key.
 
 Assumptions
@@ -367,8 +371,8 @@ RANDFILE        = $dir/private/.rand    # private random number file
 If this is not the case create a new openssl config file that uses the above
 paths for the default CA and add to all the openssl commands:
  -config filename. E.g.:
-        openssl ca -config my_openssl.cnf -in kamailio1_cert_req.pem -out kamai
-lio1_cert.pem
+        openssl ca -config my_openssl.cnf -in kamailio1_cert_req.pem -out kamail
+io1_cert.pem
 
 
 Creating CA certificate
@@ -390,16 +394,16 @@ Creating CA certificate
         chmod 600 demoCA/private/cakey.pem
 
 3. create CA self-signed certificate
-        openssl req -out demoCA/cacert.pem   -x509 -new -key demoCA/private/cak
-ey.pem
+        openssl req -out demoCA/cacert.pem   -x509 -new -key demoCA/private/cake
+y.pem
 
 
 Creating a server/client certificate
 ------------------------------------
 1. create a certificate request (and its private key in privkey.pem)
         openssl req -out kamailio1_cert_req.pem -new -nodes
-        WARNING: the organization name should be the same as in the CA certific
-ate.
+        WARNING: the organization name should be the same as in the CA certifica
+te.
 
 2. sign it with the ca certificate
         openssl ca -in kamailio1_cert_req.pem -out kamailio1_cert.pem
@@ -418,14 +422,13 @@ Setting Kamailio to use the certificate
          this is the default place Kamailio searches for).
 
 3. set up Kamailio.cfg to use the certificate
-        if your Kamailio certificate name is different from cert.pem or it is n
-ot
+        if your Kamailio certificate name is different from cert.pem or it is no
+t
         placed in Kamailio cfg. directory, add to your kamailio.cfg:
                 modparam("tls", "certificate", "/path/cert_file_name")
 
 4. set up Kamailio to use the private key
-        if your private key is not contained in the same file as the certificat
-e
+        if your private key is not contained in the same file as the certificate
         (or the certificate name is not the default cert.pem), add to your
          Kamailio.cfg:
                 modparam("tls", "private_key", "/path/private_key_file")
@@ -489,20 +492,24 @@ Revoking a certificate and using a CRL
 9.1. tls_method (string)
 
    Sets the SSL/TLS protocol method. Possible values are:
-     * TLSv1  -  only TLSv1 connections are accepted. This is the default
-       and recommended method (if you want to be rfc3261 conformant don't
-       change it).
+     * TLSv1.2 - only TLSv1.2 connections are accepted (available starting
+       with openssl/libssl v1.0.1e)
+     * TLSv1.1 - only TLSv1.1 connections are accepted (available starting
+       with openssl/libssl v1.0.1)
+     * TLSv1 - only TLSv1 connections are accepted. This is the default
+       value.
      * SSLv3 - only SSLv3 connections are accepted
-     * SSLv2  -  only  SSLv2  connections,  for  old  clients.  Note: you
+     * SSLv2 - only SSLv2 connections, for old clients. Note: you
        shouldn't use SSLv2 for anything which should be highly secure.
-     * SSLv23  -  any  of  the  above  methods will be accepted, with the
-       following limitation: the initial SSL hello message must be V2 (in
-       the  initial  hello  all  the  supported  protocols are advertised
-       enabling  switching  to  a  higher  and more secure version). This
-       means  connections  from  SSLv3  or  TLSv1  clients  will  not  be
-       accepted.
-
-   If   rfc3261   conformance   is  desired,  TLSv1  must  be  used.  For
+       Newer versions of libssl don't include support for it anymore.
+     * SSLv23 - any of the SSLv2, SSLv3 and TLSv1 methods will be
+       accepted, with the following limitation: the initial SSL hello
+       message must be V2 (in the initial hello all the supported
+       protocols are advertised enabling switching to a higher and more
+       secure version). This means connections from SSLv3 or TLSv1 clients
+       will be accepted.
+
+   If rfc3261 conformance is desired, TLSv1 must be used. For
    compatibility with older clients SSLv23 is a good option.
 
    Example 1.3. Set tls_method parameter
@@ -512,17 +519,17 @@ modparam("tls", "tls_method", "TLSv1")
 
 9.2. certificate (string)
 
-   Sets  the certificate file name. The certificate file can also contain
+   Sets the certificate file name. The certificate file can also contain
    the private key in PEM format.
 
-   If  the  file  name starts with a '.' the path will be relative to the
-   working  directory (at runtime). If it starts with a '/' it will be an
-   absolute  path  and  if  it starts with anything else the path will be
-   relative  to  the  main  config  file directory (e.g.: for kamailio -f
+   If the file name starts with a '.' the path will be relative to the
+   working directory (at runtime). If it starts with a '/' it will be an
+   absolute path and if it starts with anything else the path will be
+   relative to the main config file directory (e.g.: for kamailio -f
    /etc/kamailio/kamailio.cfg it will be relative to /etc/kamailio/).
 
-   Warning:  try not to use certificate with keys longer then 1024 bytes.
-   Longer  keys  will  severely impact performance, in particular the TLS
+   Warning: try not to use certificate with keys longer then 1024 bytes.
+   Longer keys will severely impact performance, in particular the TLS
    connection rate.
 
    The default value is [SER_CFG_DIR]/cert.pem.
@@ -536,15 +543,15 @@ modparam("tls", "certificate", "/usr/local/etc/kamailio/my_certificate.pem")
 
    Sets the private key file name.
 
-   If  the  file  name starts with a '.' the path will be relative to the
-   working  directory (at runtime). If it starts with a '/' it will be an
-   absolute  path  and  if  it starts with anything else the path will be
-   relative  to  the  main  config  file directory (e.g.: for kamailio -f
+   If the file name starts with a '.' the path will be relative to the
+   working directory (at runtime). If it starts with a '/' it will be an
+   absolute path and if it starts with anything else the path will be
+   relative to the main config file directory (e.g.: for kamailio -f
    /etc/kamailio/kamailio.cfg it will be relative to /etc/kamailio/).
 
-   Note:  the  private  key  can  be  contained  in  the same file as the
-   certificate  (just  append  it  to  the  certificate  file,  e.g.: cat
-   pkey.pem >> cert.pem)
+   Note: the private key can be contained in the same file as the
+   certificate (just append it to the certificate file, e.g.: cat pkey.pem
+   >> cert.pem)
 
    The default value is [SER_CFG_DIR]/cert.pem.
 
@@ -555,24 +562,23 @@ modparam("tls", "private", "/usr/local/etc/kamailio/my_pkey.pem")
 
 9.4. ca_list (string)
 
-   Sets  the  CA  list  file  name.  This file contains a list of all the
-   trusted  CAs  certificates.  If  a  signature  in  a certificate chain
-   belongs to one of the listed CAs, the authentication will succeed.
+   Sets the CA list file name. This file contains a list of all the
+   trusted CAs certificates. If a signature in a certificate chain belongs
+   to one of the listed CAs, the authentication will succeed.
 
-   If  the  file  name starts with a '.' the path will be relative to the
-   working  directory (at runtime). If it starts with a '/' it will be an
-   absolute  path  and  if  it starts with anything else the path will be
-   relative  to  the  main  config  file directory (e.g.: for kamailio -f
+   If the file name starts with a '.' the path will be relative to the
+   working directory (at runtime). If it starts with a '/' it will be an
+   absolute path and if it starts with anything else the path will be
+   relative to the main config file directory (e.g.: for kamailio -f
    /etc/kamailio/kamailio.cfg it will be relative to /etc/kamailio/).
 
    By default the CA file is not set.
 
    An easy way to create the CA list is to append each trusted trusted CA
-   certificate   in   the  PEM  format  to  one  file,  e.g.:  for  f  in
+   certificate in the PEM format to one file, e.g.: for f in
    trusted_cas/*.pem ; do cat "$f" >> ca_list.pem ; done .
 
-   See  also  verify_certificate,  verify_depth,  require_certificate and
-   crl.
+   See also verify_certificate, verify_depth, require_certificate and crl.
 
    Example 1.6. Set ca_list parameter
 ...
@@ -581,16 +587,16 @@ modparam("tls", "ca_list", "/usr/local/etc/kamailio/ca_list.pem")
 
 9.5. crl (string)
 
-   Sets  the  certificate revocation list file name. This file contains a
-   list  of  revoked  certificates.  Any  attempt  to  verify  a  revoked
+   Sets the certificate revocation list file name. This file contains a
+   list of revoked certificates. Any attempt to verify a revoked
    certificate will fail.
 
    If not set, no crl list will be used.
 
-   If  the  file  name starts with a '.' the path will be relative to the
-   working  directory (at runtime). If it starts with a '/' it will be an
-   absolute  path  and  if  it starts with anything else the path will be
-   relative  to  the  main  config  file directory (e.g.: for kamailio -f
+   If the file name starts with a '.' the path will be relative to the
+   working directory (at runtime). If it starts with a '/' it will be an
+   absolute path and if it starts with anything else the path will be
+   relative to the main config file directory (e.g.: for kamailio -f
    /etc/kamailio/kamailio.cfg it will be relative to /etc/kamailio/).
 
 Note
@@ -600,8 +606,8 @@ Note
 
    By default the crl file is not set.
 
-   To  update  the crl in a running Kamailio, make sure you configure tls
-   via  a  separate  tls  config  file  (the config modparam) and issue a
+   To update the crl in a running Kamailio, make sure you configure tls
+   via a separate tls config file (the config modparam) and issue a
    tls.reload RPC call, e.g.:
  $ kamcmd tls.reload
 
@@ -618,7 +624,7 @@ Note
    To display the CRL contents use:
  $ openssl crl -in crl.pem -noout -text
 
-   See     also    ca_list,    verify_certificate,    verify_depth    and
+   See also ca_list, verify_certificate, verify_depth and
    require_certificate.
 
    Example 1.7. Set crl parameter
@@ -628,10 +634,10 @@ modparam("tls", "crl", "/usr/local/etc/kamailio/crl.pem")
 
 9.6. verify_certificate (boolean)
 
-   If   enabled   it   will  force  certificate  verification.  For  more
-   information see the verify(1) openssl man page.
+   If enabled it will force certificate verification. For more information
+   see the verify(1) openssl man page.
 
-   Note:  the certificate verification will always fail if the ca_list is
+   Note: the certificate verification will always fail if the ca_list is
    empty.
 
    See also: ca_list, require_certificate, verify_depth.
@@ -645,8 +651,8 @@ modparam("tls", "verify_certificate", 1)
 
 9.7. verify_depth (integer)
 
-   Sets   how   far   up  the  certificate  chain  will  the  certificate
-   verification go in the search for a trusted CA.
+   Sets how far up the certificate chain will the certificate verification
+   go in the search for a trusted CA.
 
    See also: ca_list, require_certificate, verify_certificate,
 
@@ -659,8 +665,8 @@ modparam("tls", "verify_depth", 9)
 
 9.8. require_certificate (boolean)
 
-   When  enabled  it  will  require  a  certificate from a client. If the
-   client  does not offer a certificate and verify_certificate is on, the
+   When enabled it will require a certificate from a client. If the client
+   does not offer a certificate and verify_certificate is on, the
    certificate verification will fail.
 
    The default value is off.
@@ -673,10 +679,10 @@ modparam("tls", "require_certificate", 1)
 9.9. cipher_list (string)
 
    Sets the list of accepted ciphers. The list consists of cipher strings
-   separated  by  colons.  For more information on the cipher list format
-   see the cipher(1) openssl man page.
+   separated by colons. For more information on the cipher list format see
+   the cipher(1) openssl man page.
 
-   The  default  value  is not set (all the Openssl supported ciphers are
+   The default value is not set (all the Openssl supported ciphers are
    enabled).
 
    Example 1.11. Set cipher_list parameter
@@ -687,18 +693,18 @@ modparam("tls", "cipher_list", "HIGH")
 9.10. send_timeout (int)
 
    This parameter is obsolete and cannot be used in newer TLS versions (>
-   Kamailio  3.0).  In  these  versions  the  send_timeout is replaced by
+   Kamailio 3.0). In these versions the send_timeout is replaced by
    tcp_send_timeout (common with all the tcp connections).
 
 9.11. handshake_timeout (int)
 
    This parameter is obsolete and cannot be used in newer TLS versions (>
-   Kamailio  3.0). In these versions the handshake_timeout is replaced by
+   Kamailio 3.0). In these versions the handshake_timeout is replaced by
    tcp_connect_timeout (common with all the tcp connections).
 
 9.12. connection_timeout (int)
 
-   Sets  the  amount  of  time after which an idle TLS connection will be
+   Sets the amount of time after which an idle TLS connection will be
    closed, if no I/O ever occured after the initial open. If an I/O event
    occurs, the timeout will be extended with tcp_connection_lifetime. The
    value is expressed in seconds.
@@ -707,7 +713,7 @@ modparam("tls", "cipher_list", "HIGH")
 
    If the value set is -1, the connection will never be close on idle.
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.connection_timeout.
 
    Example 1.12. Set connection_timeout parameter
@@ -720,10 +726,10 @@ modparam("tls", "connection_timeout", 60)
 
 9.13. tls_disable_compression (boolean)
 
-   If   set   compression  over  SSL/TLS  will  be  disabled.  Note  that
-   compression  uses  a  lot  of  memory  (about  10x  more then with the
-   compression  disabled),  so  if you want to minimize memory usage is a
-   good idea to disable it.
+   If set compression over SSL/TLS will be disabled. Note that compression
+   uses a lot of memory (about 10x more then with the compression
+   disabled), so if you want to minimize memory usage is a good idea to
+   disable it.
 
    By default compression is disabled.
 
@@ -734,83 +740,80 @@ modparam("tls", "tls_disable_compression", 0) # enable
 
 9.14. ssl_release_buffers (integer)
 
-   Release  internal OpenSSL read or write buffers as soon as they are no
-   longer  needed.  Combined with ssl_free_list_max_len has the potential
-   of  saving  a  lot  of  memory  (  ~ 32k per connection in the default
-   configuration,  or 16k + ssl_max_send_fragment). For sr versions > 3.0
-   it  makes  little sense to disable it (0) since the tls module already
+   Release internal OpenSSL read or write buffers as soon as they are no
+   longer needed. Combined with ssl_free_list_max_len has the potential of
+   saving a lot of memory ( ~ 32k per connection in the default
+   configuration, or 16k + ssl_max_send_fragment). For sr versions > 3.0
+   it makes little sense to disable it (0) since the tls module already
    has its own internal buffering.
 
-   A  value  of -1 would not change this option from its openssl default.
+   A value of -1 would not change this option from its openssl default.
    Use 0 or 1 for enable/disable.
 
    By default the value is 1 (enabled).
 
 Note
 
-   This  option  is  supported only for OpenSSL versions >= 1.0.0. On all
-   the  other  versions  attempting to change the default will trigger an
-   error.
+   This option is supported only for OpenSSL versions >= 1.0.0. On all the
+   other versions attempting to change the default will trigger an error.
 
    Example 1.15. Set ssl_release_buffers parameter
 modparam("tls", "ssl_release_buffers", 1)
 
 9.15. ssl_free_list_max_len (integer)
 
-   Sets  the maximum number of free memory chunks, that OpenSSL will keep
+   Sets the maximum number of free memory chunks, that OpenSSL will keep
    per connection. Setting it to 0 would cause any unused memory chunk to
    be immediately freed, reducing the memory footprint. A too large value
    would result in extra memory consumption.
 
    Should be combined with ssl_release_buffers.
 
-   A  value of -1 has a special meaning: the OpenSSL default will be used
-   (no  attempt  on changing the value will be made). For OpenSSL 1.0 the
+   A value of -1 has a special meaning: the OpenSSL default will be used
+   (no attempt on changing the value will be made). For OpenSSL 1.0 the
    internal default is 32.
 
    By default the value is 0 (no freelist).
 
 Note
 
-   This  option  is  supported only for OpenSSL versions >= 1.0.0. On all
-   the  other  versions  attempting to change the default will trigger an
-   error.
+   This option is supported only for OpenSSL versions >= 1.0.0. On all the
+   other versions attempting to change the default will trigger an error.
 
    Example 1.16. Set ssl_freelist_max_len parameter
 modparam("tls", "ssl_freelist_max_len", 0)
 
 9.16. ssl_max_send_fragment (integer)
 
-   Sets  the  maximum number of bytes (from the clear text) sent into one
-   TLS  or  SSL  record.  Valid  values  are  between 512 and 16384. Note
-   however  that even valid low values might not be big enough to allow a
+   Sets the maximum number of bytes (from the clear text) sent into one
+   TLS or SSL record. Valid values are between 512 and 16384. Note however
+   that even valid low values might not be big enough to allow a
    succesfull handshake (try minimum 1024).
 
-   Lower  values  would  lead to less memory usage, but values lower then
-   the  typical  Kamailio  write  size  would  incur a slight performance
-   penalty.  Good  values  are  bigger  then  the size of the biggest SIP
-   packet  one  normally  expects  to forward. For example in most setups
-   2048 would be a good value.
+   Lower values would lead to less memory usage, but values lower then the
+   typical Kamailio write size would incur a slight performance penalty.
+   Good values are bigger then the size of the biggest SIP packet one
+   normally expects to forward. For example in most setups 2048 would be a
+   good value.
 
 Note
 
    Values on the lower side, even if valid (> 512), might not allow for a
    succesfull initial handshake. This happens if the certificate does not
-   fit  inside  one  send  fragment. Values lower then 1024 should not be
-   used.  Even with higher values, if the handshake fails, try increasing
+   fit inside one send fragment. Values lower then 1024 should not be
+   used. Even with higher values, if the handshake fails, try increasing
    the value.
 
-   A  value of -1 has a special meaning: the OpenSSL default will be used
+   A value of -1 has a special meaning: the OpenSSL default will be used
    (no attempt on changing the value will be made).
 
-   By  default  the  value  is -1 (the OpenSSL default, which at least in
+   By default the value is -1 (the OpenSSL default, which at least in
    OpenSSL 1.0.0 is ~ 16k).
 
 Note
 
-   This  option  is  supported only for OpenSSL versions >= 0.9.9. On all
-   the  other  versions  attempting to change the default will trigger an
-   error.
+   This option is supported only for OpenSSL versions >= 0.9.9. On all the
+   other versions attempting to change the default will trigger an error.
 
    Example 1.17. Set ssl_max_send_fragment parameter
 modparam("tls", "ssl_max_send_fragment", 4096)
@@ -818,18 +821,18 @@ modparam("tls", "ssl_max_send_fragment", 4096)
 9.17. ssl_read_ahead (boolean)
 
    Enables read ahead, reducing the number of internal OpenSSL BIO read()
-   calls.  This  option has only debugging value, in normal circumstances
-   it should not be changed from the default.
+   calls. This option has only debugging value, in normal circumstances it
+   should not be changed from the default.
 
-   When  disabled  OpenSSL  will  make  at  least  2 BIO read() calls per
-   received  record: one to get the record header and one to get the rest
+   When disabled OpenSSL will make at least 2 BIO read() calls per
+   received record: one to get the record header and one to get the rest
    of the record.
 
    The TLS module buffers internally all read()s and defines its own fast
-   BIO  so  enabling this option would only cause more memory consumption
+   BIO so enabling this option would only cause more memory consumption
    and a minor slow-down (extra memcpy).
 
-   A  value of -1 has a special meaning: the OpenSSL default will be used
+   A value of -1 has a special meaning: the OpenSSL default will be used
    (no attempt on changing the value will be made).
 
    By default the value is 0 (disabled).
@@ -839,15 +842,15 @@ modparam("tls", "ssl_read_ahead", 1)
 
 9.18. send_close_notify (boolean)
 
-   Enables/disables  sending  close  notify  alerts  prior to closing the
-   corresponding  TCP  connection.  Sending the close notify prior to tcp
-   shutdown  is "nicer" from a TLS point of view, but it has a measurable
-   performance   impact.   Default:   off.   Can   be   set   at  runtime
+   Enables/disables sending close notify alerts prior to closing the
+   corresponding TCP connection. Sending the close notify prior to tcp
+   shutdown is "nicer" from a TLS point of view, but it has a measurable
+   performance impact. Default: off. Can be set at runtime
    (tls.send_close_notify).
 
    The default value is 0 (off).
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.send_close_notify.
 
    Example 1.19. Set send_close_notify parameter
@@ -860,13 +863,13 @@ modparam("tls", "send_close_notify", 1)
 
 9.19. con_ct_wq_max (integer)
 
-   Sets  the maximum allowed per connection clear-text send queue size in
-   bytes.  This  queue  is  used  when  data cannot be encrypted and sent
+   Sets the maximum allowed per connection clear-text send queue size in
+   bytes. This queue is used when data cannot be encrypted and sent
    immediately because of an ongoing TLS/SSL level renegotiation.
 
    The default value is 65536 (64 Kb).
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.con_ct_wq_max.
 
    Example 1.21. Set con_ct_wq_max parameter
@@ -879,13 +882,13 @@ modparam("tls", "con_ct_wq_max", 1048576)
 
 9.20. ct_wq_max (integer)
 
-   Sets  the  maximum  total number of bytes queued in all the clear-text
-   send  queues.  These queues are used when data cannot be encrypted and
+   Sets the maximum total number of bytes queued in all the clear-text
+   send queues. These queues are used when data cannot be encrypted and
    sent immediately because of an ongoing TLS/SSL level renegotiation.
 
    The default value is 10485760 (10 Mb).
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.ct_wq_max.
 
    Example 1.23. Set ct_wq_max parameter
@@ -898,13 +901,12 @@ modparam("tls", "ct_wq_max", 4194304)
 
 9.21. ct_wq_blk_size (integer)
 
-   Minimum  block size for the internal clear-text send queues (debugging
-   /  advanced  tunning).  Good  values  are multiple of typical datagram
-   sizes.
+   Minimum block size for the internal clear-text send queues (debugging /
+   advanced tunning). Good values are multiple of typical datagram sizes.
 
    The default value is 4096.
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.ct_wq_blk_size.
 
    Example 1.25. Set ct_wq_blk_size parameter
@@ -921,7 +923,7 @@ modparam("tls", "ct_wq_blk_size", 2048)
 
    The default value is 3 (L_DBG).
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.log.
 
    Example 1.27. Set tls_log parameter
@@ -935,14 +937,14 @@ modparam("tls", "tls_log", 10)
 
 9.23. tls_debug (int)
 
-   Sets  the  log  level at which TLS debug messages will be logged. Note
+   Sets the log level at which TLS debug messages will be logged. Note
    that TLS debug messages are enabled only if the TLS module is compiled
-   with   debugging   enabled  (e.g.  -DTLS_WR_DEBUG,  -DTLS_RD_DEBUG  or
+   with debugging enabled (e.g. -DTLS_WR_DEBUG, -DTLS_RD_DEBUG or
    -DTLS_BIO_DEBUG).
 
    The default value is 3 (L_DBG).
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.debug.
 
    Example 1.29. Set tls_debug parameter
@@ -959,20 +961,20 @@ modparam("tls", "tls_debug", 10)
    Sets the minimal free memory from which attempts to open or accept new
    TLS connections will start to fail. The value is expressed in KB.
 
-   The  default value depends on whether the openssl library used handles
-   well  low  memory  situations  (openssl bug #1491). As of this writing
-   this is not true for any openssl version (including 0.9.8e).
+   The default value depends on whether the openssl library used handles
+   well low memory situations (openssl bug #1491). As of this writing this
+   is not true for any openssl version (including 0.9.8e).
 
-   If  an  ill-behaved  openssl  version is detected, a very conservative
-   value  is  choosed,  which  depends  on the maximum possible number of
-   simultaneously  created  TLS  connections  (and  hence  on the process
+   If an ill-behaved openssl version is detected, a very conservative
+   value is choosed, which depends on the maximum possible number of
+   simultaneously created TLS connections (and hence on the process
    number).
 
    The following values have a special meaning:
      * -1 - use the default value
      * 0 - disable (TLS connections will not fail preemptively)
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.low_mem_threshold1.
 
    See also low_mem_threshold2.
@@ -987,24 +989,24 @@ modparam("tls", "low_mem_threshold1", -1)
 
 9.25. low_mem_threshold2 (integer)
 
-   Sets  the  minimal  free  memory  from which TLS operations on already
+   Sets the minimal free memory from which TLS operations on already
    established TLS connections will start to fail preemptively. The value
    is expressed in KB.
 
-   The  default value depends on whether the openssl library used handles
-   well  low  memory  situations  (openssl bug #1491). As of this writing
-   this is not true for any openssl version (including 0.9.8e).
+   The default value depends on whether the openssl library used handles
+   well low memory situations (openssl bug #1491). As of this writing this
+   is not true for any openssl version (including 0.9.8e).
 
-   If  an  ill-behaved  openssl  version is detected, a very conservative
-   value  is  choosed,  which  depends  on the maximum possible number of
-   simultaneously  created  TLS  connections  (and  hence  on the process
+   If an ill-behaved openssl version is detected, a very conservative
+   value is choosed, which depends on the maximum possible number of
+   simultaneously created TLS connections (and hence on the process
    number).
 
    The following values have a special meaning:
      * -1 - use the default value
      * 0 - disable (TLS operations will not fail preemptively)
 
-   It  can  be  changed also at runtime, via the RPC interface and config
+   It can be changed also at runtime, via the RPC interface and config
    framework. The config variable name is tls.low_mem_threshold2.
 
    See also low_mem_threshold1.
@@ -1019,16 +1021,16 @@ modparam("tls", "low_mem_threshold2", -1)
 
 9.26. tls_force_run (boolean)
 
-   If  enabled  Kamailio  will  start  even if some of the openssl sanity
+   If enabled Kamailio will start even if some of the openssl sanity
    checks fail (turn it on at your own risk).
 
-   Currently  failing  any  of the following sanity checks will not allow
+   Currently failing any of the following sanity checks will not allow
    Kamailio to start:
-     * the  version  of  the  library the TLS module was compiled with is
-       "too  different"  from  the  library used at runtime. The versions
-       should  have the same major, minor and fix level (e.g.: 0.9.8a and
-       0.9.8c are ok, but 0.9.8 and 0.9.9 are not)
-     * the  openssl  library  used  at  compile  time and the one used at
+     * the version of the library the TLS module was compiled with is "too
+       different" from the library used at runtime. The versions should
+       have the same major, minor and fix level (e.g.: 0.9.8a and 0.9.8c
+       are ok, but 0.9.8 and 0.9.9 are not)
+     * the openssl library used at compile time and the one used at
        runtime have different kerberos options
 
    By default tls_force_run is disabled.
@@ -1040,7 +1042,7 @@ modparam("tls", "tls_force_run", 11)
 
 9.27. session_cache (boolean)
 
-   If  enabled  Kamailio  will  do  caching  of  the  TLS  sessions data,
+   If enabled Kamailio will do caching of the TLS sessions data,
    generation a session_id and sending it back to client.
 
    By default TLS session caching is disabled (0).
@@ -1064,10 +1066,10 @@ modparam("tls", "session_id", "my-session-id-context")
 
 9.29. renegotiation (boolean)
 
-   If  enabled  Kamailio  will  allow  renegotiations  of  TLS connection
-   initiated  by  the  client.  This may expose to a security risk if the
-   client  is  not  a trusted peer and keeps renegotiating, consuming CPU
-   and bandwidth resources.
+   If enabled Kamailio will allow renegotiations of TLS connection
+   initiated by the client. This may expose to a security risk if the
+   client is not a trusted peer and keeps renegotiating, consuming CPU and
+   bandwidth resources.
 
    By default TLS renegotiation is disabled (0).
 
@@ -1078,22 +1080,23 @@ modparam("tls", "renegotiation", 1)
 
 9.30. config (string)
 
-   Sets the name of the TLS specific config file.
+   Sets the name of the TLS specific config file or config directory.
 
-   If  set  the  TLS  module  will  load  a special config file, in which
-   different  TLS  parameters  can  be specified on a per role (server or
-   client)  and domain basis (for now only IPs). The corresponding module
-   parameters will be ignored.
+   If set the TLS module will load a special config file or config files
+   from config directory, in which different TLS parameters can be
+   specified on a per role (server or client) and domain basis (for now
+   only IPs). The corresponding module parameters will be ignored.
 
-   If  the  file  name starts with a '.' the path will be relative to the
-   working  directory (at runtime). If it starts with a '/' it will be an
-   absolute  path  and  if  it starts with anything else the path will be
-   relative  to  the  main  config  file directory (e.g.: for kamailio -f
-   /etc/kamailio/kamailio.cfg it will be relative to /etc/kamailio/).
+   If the file or directory name starts with a '.' the path will be
+   relative to the working directory (at runtime). If it starts with a '/'
+   it will be an absolute path and if it starts with anything else the
+   path will be relative to the main config file directory (e.g.: for
+   kamailio -f /etc/kamailio/kamailio.cfg it will be relative to
+   /etc/kamailio/).
 
    By default no config file is specified.
 
-   The  following  parameters  can  be  set  in the config file, for each
+   The following parameters can be set in the config file, for each
    domain:
      * tls_method
      * verify_certificate
@@ -1105,14 +1108,14 @@ modparam("tls", "renegotiation", 1)
      * crl
      * cipher_list
 
-   All  the  parameters  that  take  filenames as values will be resolved
-   using  the  same rules as for the tls config filename itself: starting
-   with  a  '.'  means  relative to the working directory, a '/' means an
-   absolute  path  and  anything else a path relative to the directory of
-   the current Kamailio main config file.
+   All the parameters that take filenames as values will be resolved using
+   the same rules as for the tls config filename itself: starting with a
+   '.' means relative to the working directory, a '/' means an absolute
+   path and anything else a path relative to the directory of the current
+   Kamailio main config file.
 
    Kamailio acts as a server when it accepts a connection and as a client
-   when  it  initiates  a  new  connection  by  itself  (it  connects  to
+   when it initiates a new connection by itself (it connects to
    something).
 
    Example 1.39. Short config file
@@ -1139,7 +1142,7 @@ certificate = local_cert.pem
 verify_depth = 3
 ca_list = local_ca.pem
 
-   For  a  more  complete  example check the tls.cfg distributed with the
+   For a more complete example check the tls.cfg distributed with the
    Kamailio source (kamailio/modules/tls/tls.cfg).
 
    Example 1.40. Set config parameter
@@ -1147,7 +1150,7 @@ ca_list = local_ca.pem
 modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg")
 ...
 
-   It  can  be changed also at runtime. The new config will not be loaded
+   It can be changed also at runtime. The new config will not be loaded
    immediately, but after the first tls.reload RPC call.
 
    Example 1.41. Change and reload tls config at runtime
@@ -1160,8 +1163,8 @@ modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg")
 
 10.1. is_peer_verified()
 
-   Returns  true  if  the connection on which the message was received is
-   TLS , the peer presented an X509 certificate and the certificate chain
+   Returns true if the connection on which the message was received is TLS
+   , the peer presented an X509 certificate and the certificate chain
    verified ok. It can be used only in a request route.
 
    Example 1.42. is_peer_verified usage
@@ -1179,7 +1182,7 @@ modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg")
 
 11.1. tls.info
 
-   List  internal information related to the TLS module in a short list -
+   List internal information related to the TLS module in a short list -
    max connections, opened connections and the write queue size.
 
    Parameters:
@@ -1201,26 +1204,27 @@ modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg")
 
 11.4. tls.reload
 
-   Reload   the   external  TLS  configuration  file.  (Does  not  reload
-   modparam() parameters)
+   Reload the external TLS configuration file. (Does not reload modparam()
+   parameters)
 
    Parameters:
      * None.
 
-12. History
+12. Status
+
+   12.1. License
+   12.2. History
+
+12.1. License
+
+   Most of the code for this module has been released under BSD by
+   iptelorg. The GPL parts are released with an exception to link with
+   OpenSSL toolkit software components.
 
-   This  module  was  put together by Jan Janak <jan at iptel.org> from code
-   based on the experimental tls core addon
-   (http://cvs.berlios.de/cgi-bin/viewcvs.cgi/ser/experimental/tls/),
-   code  originally  written  by  Peter Griffiths and later maintained by
-   Cesc  Santasusana  and  from  an  iptelorg  tls code addon, written by
-   Andrei Pelinescu-Onciul <andrei at iptel.org>. Jan also added support for
-   multiple  domains,  a  tls specific config, config reloading and a tls
-   specific select framework.
+12.2. History
 
-   For  Kamailio  3.1  most  of  the  TLS  specific  code  was completely
-   re-written  to  add  support for asynchronous TLS and fix several long
-   standing bugs.
+   For version 3.1 most of the TLS specific code was completely re-written
+   to add support for asynchronous TLS and fix several long standing bugs.
 
-   The   code   is   currently   maintained  by  Andrei  Pelinescu-Onciul
+   The code is currently maintained by Andrei Pelinescu-Onciul
    <andrei at iptel.org>.
diff --git a/modules/tls/doc/functions.xml b/modules/tls/doc/functions.xml
index fc0369e..6582a88 100644
--- a/modules/tls/doc/functions.xml
+++ b/modules/tls/doc/functions.xml
@@ -14,7 +14,7 @@
 
 	<title>Functions</title>
 
-	<section id="tls.is_peer_verfied">
+	<section id="tls.f.is_peer_verfied">
 		<title><function>is_peer_verified()</function></title>
 		<para>
 			Returns true if the connection on which the message was received
diff --git a/modules/tls/doc/history.xml b/modules/tls/doc/history.xml
index bc17e22..627fe55 100644
--- a/modules/tls/doc/history.xml
+++ b/modules/tls/doc/history.xml
@@ -8,25 +8,26 @@
 
 ]>
 
-<section id="tls.history">
-    <sectioninfo>
-    </sectioninfo>
-
-	<title>History</title>
+<section id="tls.status">
+	<title>Status</title>
+	<section id="tls.license">
+	<title>License</title>
 		<para>
-			This module was put together by Jan Janak <email>jan at iptel.org</email> from code 
-			based on the experimental tls core addon (<ulink url="http://cvs.berlios.de/cgi-bin/viewcvs.cgi/ser/experimental/tls/">http://cvs.berlios.de/cgi-bin/viewcvs.cgi/ser/experimental/tls/</ulink>), 
-			code originally written by Peter Griffiths and later maintained by Cesc Santasusana and 
-			from an iptelorg tls code addon, written by Andrei Pelinescu-Onciul <email>andrei at iptel.org</email>.
-			Jan also added support for multiple domains, a tls specific config, config reloading and a 
-			tls specific select framework.
+			Most of the code for this module has been released under BSD by
+			iptelorg. The GPL parts are released with an exception to link
+			with OpenSSL toolkit software components.
 		</para>
+	</section>
+	<section id="tls.history">
+	<title>History</title>
 		<para>
-			For &kamailio; 3.1 most of the TLS specific code was completely
+			For version 3.1 most of the TLS specific code was completely
 			re-written to add support for asynchronous TLS and fix several
 			long standing bugs.
 		</para>
 		<para>
-			The code is currently maintained by Andrei Pelinescu-Onciul <email>andrei at iptel.org</email>.
+			The code is currently maintained by Andrei Pelinescu-Onciul
+			<email>andrei at iptel.org</email>.
 		</para>
+	</section>
 </section>
diff --git a/modules/tls/doc/params.xml b/modules/tls/doc/params.xml
index 7a86124..46de16f 100644
--- a/modules/tls/doc/params.xml
+++ b/modules/tls/doc/params.xml
@@ -13,7 +13,7 @@
 
     <title>Parameters</title>
 
-	<section id="tls_method">
+	<section id="tls.p.tls_method">
 	<title><varname>tls_method</varname> (string)</title>
 	<para>
 		Sets the SSL/TLS protocol method. Possible values are:
@@ -21,7 +21,20 @@
 	<itemizedlist>
 			<listitem>
 				<para>
-				<emphasis>TLSv1</emphasis> - only TLSv1 connections are accepted. This is the default and recommended method (if you want to be rfc3261  conformant don't change it).
+				<emphasis>TLSv1.2</emphasis> - only TLSv1.2 connections are accepted
+				(available starting with openssl/libssl v1.0.1e)
+				</para>
+			</listitem>
+			<listitem>
+				<para>
+				<emphasis>TLSv1.1</emphasis> - only TLSv1.1 connections are accepted
+				(available starting with openssl/libssl v1.0.1)
+				</para>
+			</listitem>
+			<listitem>
+				<para>
+				<emphasis>TLSv1</emphasis> - only TLSv1 connections are accepted.
+				This is the default value.
 				</para>
 			</listitem>
 			<listitem>
@@ -31,12 +44,18 @@
 			</listitem>
 			<listitem>
 				<para>
-				<emphasis>SSLv2</emphasis> - only SSLv2 connections, for old clients. Note: you shouldn't use SSLv2 for anything which should be highly secure.
+				<emphasis>SSLv2</emphasis> - only SSLv2 connections, for old clients.
+				Note: you shouldn't use SSLv2 for anything which should be highly secure.
+				Newer versions of libssl don't include support for it anymore.
 				</para>
 			</listitem>
 			<listitem>
 				<para>
-				<emphasis>SSLv23</emphasis> - any of the above methods will be accepted, with the following limitation: the initial SSL hello message must be V2 (in the initial hello all the supported protocols are advertised enabling switching to a higher and more secure version). This means connections from SSLv3 or TLSv1 clients will not be accepted.
+				<emphasis>SSLv23</emphasis> - any of the SSLv2, SSLv3 and TLSv1 methods
+				will be accepted, with the following limitation: the initial SSL hello
+				message must be V2 (in the initial hello all the supported protocols
+				are advertised enabling switching to a higher and more secure version).
+				This means connections from SSLv3 or TLSv1 clients will be accepted.
 				</para>
 			</listitem>
 	</itemizedlist>
@@ -53,7 +72,7 @@ modparam("tls", "tls_method", "TLSv1")
 	</example>
 	</section>
 
-	<section id="certificate">
+	<section id="tls.p.certificate">
 	<title><varname>certificate</varname> (string)</title>
 	<para>
 		Sets the certificate file name. The certificate file can also contain
@@ -84,7 +103,7 @@ modparam("tls", "certificate", "/usr/local/etc/kamailio/my_certificate.pem")
 	</example>
 	</section>
 
-	<section id="private_key">
+	<section id="tls.p.private_key">
 	<title><varname>private_key</varname> (string)</title>
 	<para>
 		Sets the private key file name.
@@ -114,7 +133,7 @@ modparam("tls", "private", "/usr/local/etc/kamailio/my_pkey.pem")
 	</example>
 	</section>
 
-<section id="ca_list">
+	<section id="tls.p.ca_list">
 	<title><varname>ca_list</varname> (string)</title>
 	<para>
 		Sets the CA list file name. This file contains a list of all the
@@ -153,7 +172,7 @@ modparam("tls", "ca_list", "/usr/local/etc/kamailio/ca_list.pem")
 	</example>
 	</section>
 
-<section id="crl">
+	<section id="tls.p.crl">
 	<title><varname>crl</varname> (string)</title>
 	<para>
 		Sets the certificate revocation list file name. This file contains a
@@ -223,7 +242,7 @@ modparam("tls", "crl", "/usr/local/etc/kamailio/crl.pem")
 	</example>
 	</section>
 
-<section id="verify_certificate">
+<section id="tls.p.verify_certificate">
 	<title><varname>verify_certificate</varname> (boolean)</title>
 	<para>
 		If enabled it will force certificate verification. For more information see the <ulink url="http://www.openssl.org/docs/apps/verify.html">verify(1)</ulink> openssl man page.
@@ -247,7 +266,7 @@ modparam("tls", "verify_certificate", 1)
 	</example>
 	</section>
 
-<section id="verify_depth">
+<section id="tls.p.verify_depth">
 	<title><varname>verify_depth</varname> (integer)</title>
 	<para>
 		Sets how far up the certificate chain will the certificate verification go in the search for a trusted CA.
@@ -268,7 +287,7 @@ modparam("tls", "verify_depth", 9)
 	</example>
 	</section>
 
-<section id="require_certificate">
+<section id="tls.p.require_certificate">
 	<title><varname>require_certificate</varname> (boolean)</title>
 	<para>
 		When enabled it will require a certificate from a client. If the client does not offer a certificate and <varname>verify_certificate</varname> is on, the certificate verification will fail.
@@ -286,7 +305,7 @@ modparam("tls", "require_certificate", 1)
 	</example>
 	</section>
 
-<section id="cipher_list">
+<section id="tls.p.cipher_list">
 	<title><varname>cipher_list</varname> (string)</title>
 	<para>
 		Sets the list of accepted ciphers. The list consists of cipher strings separated by colons. For more information on the cipher list format see the <ulink url="http://www.openssl.org/docs/apps/ciphers.html">cipher(1)</ulink> openssl man page.
@@ -304,7 +323,7 @@ modparam("tls", "cipher_list", "HIGH")
 	</example>
 	</section>
 
-	<section id="send_timeout">
+	<section id="tls.p.send_timeout">
 	<title><varname>send_timeout</varname> (int)</title>
 	<para>
 		This parameter is <emphasis>obsolete</emphasis> and cannot be used
@@ -314,7 +333,7 @@ modparam("tls", "cipher_list", "HIGH")
 	</para>
 	</section>
 
-	<section id="handshake_timeout">
+	<section id="tls.p.handshake_timeout">
 	<title><varname>handshake_timeout</varname> (int)</title>
 	<para>
 		This parameter is <emphasis>obsolete</emphasis> and cannot be used
@@ -324,7 +343,7 @@ modparam("tls", "cipher_list", "HIGH")
 	</para>
 	</section>
 
-	<section id="connection_timeout">
+	<section id="tls.p.connection_timeout">
 	<title><varname>connection_timeout</varname> (int)</title>
 	<para>
 		Sets the amount of time after which an idle TLS connection will be
@@ -358,7 +377,7 @@ modparam("tls", "connection_timeout", 60)
 	</example>
 	</section>
 
-	<section id="tls_disable_compression">
+	<section id="tls.p.tls_disable_compression">
 	<title><varname>tls_disable_compression</varname> (boolean)</title>
 	<para>
 		If set compression over SSL/TLS will be disabled.
@@ -380,7 +399,7 @@ modparam("tls", "tls_disable_compression", 0) # enable
 	</section>
 
 
-<section id="ssl_release_buffers">
+<section id="tls.p.ssl_release_buffers">
 	<title><varname>ssl_release_buffers</varname> (integer)</title>
 	<para>
 		Release internal OpenSSL read or write buffers as soon as they are
@@ -415,7 +434,7 @@ modparam("tls", "ssl_release_buffers", 1)
 	</section>
 
 
-<section id="ssl_freelist_max_len">
+<section id="tls.p.ssl_freelist_max_len">
 	<title><varname>ssl_free_list_max_len</varname> (integer)</title>
 	<para>
 		Sets the maximum number of free memory chunks, that OpenSSL will keep
@@ -451,7 +470,7 @@ modparam("tls", "ssl_freelist_max_len", 0)
 	</section>
 
 
-<section id="ssl_max_send_fragment">
+<section id="tls.p.ssl_max_send_fragment">
 	<title><varname>ssl_max_send_fragment</varname> (integer)</title>
 	<para>
 		Sets the maximum number of bytes (from the clear text) sent into
@@ -501,7 +520,7 @@ modparam("tls", "ssl_max_send_fragment", 4096)
 	</section>
 
 
-<section id="ssl_read_ahead">
+<section id="tls.p.ssl_read_ahead">
 	<title><varname>ssl_read_ahead</varname> (boolean)</title>
 	<para>
 		Enables read ahead, reducing the number of internal OpenSSL BIO read()
@@ -534,7 +553,7 @@ modparam("tls", "ssl_read_ahead", 1)
 	</section>
 
 
-	<section id="send_close_notify">
+	<section id="tls.p.send_close_notify">
 	<title><varname>send_close_notify</varname> (boolean)</title>
 	<para>
 		Enables/disables sending close notify alerts prior to closing the
@@ -567,7 +586,7 @@ modparam("tls", "send_close_notify", 1)
 	</section>
 
 
-	<section id="con_ct_wq_max">
+	<section id="tls.p.con_ct_wq_max">
 	<title><varname>con_ct_wq_max</varname> (integer)</title>
 	<para>
 		Sets the maximum allowed per connection clear-text send queue size in
@@ -598,7 +617,7 @@ modparam("tls", "con_ct_wq_max", 1048576)
 	</section>
 
 
-	<section id="ct_wq_max">
+	<section id="tls.p.ct_wq_max">
 	<title><varname>ct_wq_max</varname> (integer)</title>
 	<para>
 		Sets the maximum total number of bytes queued in all the clear-text
@@ -629,7 +648,7 @@ modparam("tls", "ct_wq_max", 4194304)
 	</section>
 
 
-	<section id="ct_wq_blk_size">
+	<section id="tls.p.ct_wq_blk_size">
 	<title><varname>ct_wq_blk_size</varname> (integer)</title>
 	<para>
 		Minimum block size for the internal clear-text send queues
@@ -660,7 +679,7 @@ modparam("tls", "ct_wq_blk_size", 2048)
 	</section>
 
 
-	<section id="tls_log">
+	<section id="tls.p.tls_log">
 	<title><varname>tls_log</varname> (int)</title>
 	<para>
 		Sets the log level at which TLS related messages will be logged.
@@ -690,7 +709,7 @@ modparam("tls", "tls_log", 10)
 	</section>
 
 
-	<section id="tls_debug">
+	<section id="tls.p.tls_debug">
 	<title><varname>tls_debug</varname> (int)</title>
 	<para>
 		Sets the log level at which TLS debug messages will be logged.
@@ -723,7 +742,7 @@ modparam("tls", "tls_debug", 10)
 	</section>
 
 
-<section id="low_mem_threshold1">
+<section id="tls.p.low_mem_threshold1">
 	<title><varname>low_mem_threshold1</varname> (integer)</title>
 	<para>
 		Sets the minimal free memory from which attempts to open or accept
@@ -773,7 +792,7 @@ modparam("tls", "low_mem_threshold1", -1)
 	</example>
 	</section>
 
-<section id="low_mem_threshold2">
+<section id="tls.p.low_mem_threshold2">
 	<title><varname>low_mem_threshold2</varname> (integer)</title>
 	<para>
 		Sets the minimal free memory from which TLS operations on already established TLS connections will start to fail preemptively.  The value is expressed in KB.
@@ -822,7 +841,7 @@ modparam("tls", "low_mem_threshold2", -1)
 	</example>
 	</section>
 
-	<section id="tls_force_run">
+	<section id="tls.p.tls_force_run">
 	<title><varname>tls_force_run</varname> (boolean)</title>
 	<para>
 		If enabled Kamailio  will start even if some of the openssl sanity checks fail (turn it on at your own risk).
@@ -855,7 +874,7 @@ modparam("tls", "tls_force_run", 11)
 	</example>
 	</section>
 
-	<section id="session_cache">
+	<section id="tls.p.session_cache">
 	<title><varname>session_cache</varname> (boolean)</title>
 	<para>
 		If enabled &kamailio; will do caching of the TLS sessions data, generation a session_id and sending
@@ -874,7 +893,7 @@ modparam("tls", "session_cache", 1)
 	</example>
 	</section>
 
-	<section id="session_id">
+	<section id="tls.p.session_id">
 	<title><varname>session_id</varname> (str)</title>
 	<para>
 		The value for session ID context, making sense when session caching is enabled.
@@ -892,7 +911,7 @@ modparam("tls", "session_id", "my-session-id-context")
 	</example>
 	</section>
 
-	<section id="renegotiation">
+	<section id="tls.p.renegotiation">
 	<title><varname>renegotiation</varname> (boolean)</title>
 	<para>
 		If enabled &kamailio;  will allow renegotiations of TLS connection initiated by the client. This may
@@ -912,19 +931,19 @@ modparam("tls", "renegotiation", 1)
 	</example>
 	</section>
 
-	<section id="config">
+	<section id="tls.p.config">
 	<title><varname>config</varname> (string)</title>
 	<para>
-		Sets the name of the TLS specific config file.
+		Sets the name of the TLS specific config file or config directory.
 	</para>
 	<para>
-		If set the TLS module will load a special config file, in which
+		If set the TLS module will load a special config file or config files from config directory, in which
 		different TLS parameters can be specified on a per role (server or
 		client) and domain basis (for now only IPs). The corresponding module
 		parameters will be ignored.
 	</para>
 	<para>
-		If the file name starts with a '.' the path will be relative to the
+		If the file or directory name starts with a '.' the path will be relative to the
 		working directory (<emphasis>at runtime</emphasis>). If it starts
 		with a '/' it will be an absolute path and if it starts with anything
 		else the path will be relative to the main config file directory
diff --git a/modules/tls/doc/rpc.xml b/modules/tls/doc/rpc.xml
index 940dbbf..924490e 100644
--- a/modules/tls/doc/rpc.xml
+++ b/modules/tls/doc/rpc.xml
@@ -12,7 +12,7 @@
 	<sectioninfo>
 	</sectioninfo>
 	<title>RPC Commands</title>
-	<section id="tls.info">
+	<section id="tls.r.tls.info">
 		<title><function>tls.info</function></title>
 		<para>
 			List internal information related to the TLS module in 
@@ -26,7 +26,7 @@
                         </para></listitem>
                 </itemizedlist>
 	</section>
-	<section id="tls.list">
+	<section id="tls.r.tls.list">
 		<title><function>tls.list</function></title>
 		<para>
 			List details about all active TLS connections.
@@ -38,7 +38,7 @@
                         </para></listitem>
                 </itemizedlist>
 	</section>
-	<section id="tls.options">
+	<section id="tls.r.tls.options">
 		<title><function>tls.options</function></title>
 		<para>
 			List the current TLS configuration.
@@ -50,7 +50,7 @@
                         </para></listitem>
                 </itemizedlist>
 	</section>
-	<section id="tls.reload">
+	<section id="tls.r.tls.reload">
 		<title><function>tls.reload</function></title>
 		<para>
 			Reload the external TLS configuration file. (Does not reload 
diff --git a/modules/tls/fixed_c_zlib.h b/modules/tls/fixed_c_zlib.h
index b6470fb..e35bd45 100644
--- a/modules/tls/fixed_c_zlib.h
+++ b/modules/tls/fixed_c_zlib.h
@@ -1,4 +1,5 @@
-/* $Id$
+/*
+ * TLS module
  * 
  * This file contains modified zlib compression functions
  * originally part of crypto/comp/c_zlib.c from the openssl library 
diff --git a/modules/tls/sbufq.h b/modules/tls/sbufq.h
index 5c1de5b..35c2f33 100644
--- a/modules/tls/sbufq.h
+++ b/modules/tls/sbufq.h
@@ -1,6 +1,6 @@
 /* 
- * $Id$
- * 
+ * TLS module
+ *
  * Copyright (C) 2010 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
diff --git a/modules/tls/tls_bio.c b/modules/tls/tls_bio.c
index f21a974..dc8ceba 100644
--- a/modules/tls/tls_bio.c
+++ b/modules/tls/tls_bio.c
@@ -1,4 +1,6 @@
 /* 
+ * TLS module
+ *
  * Copyright (C) 2010 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
diff --git a/modules/tls/tls_bio.h b/modules/tls/tls_bio.h
index 83128db..9d9bdcf 100644
--- a/modules/tls/tls_bio.h
+++ b/modules/tls/tls_bio.h
@@ -1,4 +1,6 @@
 /* 
+ * TLS module
+ *
  * Copyright (C) 2010 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
diff --git a/modules/tls/tls_cfg.c b/modules/tls/tls_cfg.c
index 228f15d..c92f742 100644
--- a/modules/tls/tls_cfg.c
+++ b/modules/tls/tls_cfg.c
@@ -1,4 +1,6 @@
 /* 
+ * TLS module
+ *
  * Copyright (C) 2010 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -33,6 +35,7 @@
 #include "../../ut.h"
 #include "../../pt.h"
 #include "../../mem/shm_mem.h"
+#include "../../dprint.h"
 
 struct cfg_group_tls default_tls_cfg = {
 	0, /* tls_force_run */
diff --git a/modules/tls/tls_cfg.h b/modules/tls/tls_cfg.h
index 86b8816..f7a4c4e 100644
--- a/modules/tls/tls_cfg.h
+++ b/modules/tls/tls_cfg.h
@@ -1,5 +1,5 @@
 /* 
- * $Id$
+ * TLS module
  * 
  * Copyright (C) 2010 iptelorg GmbH
  *
diff --git a/modules/tls/tls_config.c b/modules/tls/tls_config.c
index 0083893..f05c211 100644
--- a/modules/tls/tls_config.c
+++ b/modules/tls/tls_config.c
@@ -1,28 +1,19 @@
 /*
- * $Id$
+ * TLS module
  *
- * TLS module - Configuration file parser
+ * Copyright (C) 2010 iptelorg GmbH
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
- * Copyright (C) 2005,2006 iptelorg GmbH
- *
- * This file is part of SIP-router, a free SIP server.
- *
- * SIP-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * SIP-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /*!
  * \file
@@ -45,11 +36,14 @@
 #include "../../trim.h"
 #include "../../ut.h"
 #include "../../cfg/cfg.h"
+#include "../../stats.h"
+
+#include <dirent.h>
+#include <sys/stat.h>
 
 static tls_domains_cfg_t* cfg = NULL;
 static tls_domain_t* domain = NULL;
 
-#ifdef USE_IPV6
 static int parse_ipv6(struct ip_addr* ip, cfg_token_t* token, 
 					  cfg_parser_t* st)
 {
@@ -77,7 +71,6 @@ static int parse_ipv6(struct ip_addr* ip, cfg_token_t* token,
 	    st->file, token->start.line, token->start.col);
 	return -1;
 }
-#endif /* USE_IPV6 */
 
 
 static int parse_ipv4(struct ip_addr* ip, cfg_token_t* token, 
@@ -117,10 +110,12 @@ static int parse_ipv4(struct ip_addr* ip, cfg_token_t* token,
 
 
 static cfg_option_t methods[] = { 
-	{"SSLv2",  .val = TLS_USE_SSLv2},
-	{"SSLv3",  .val = TLS_USE_SSLv3},
-	{"SSLv23", .val = TLS_USE_SSLv23},
-	{"TLSv1",  .val = TLS_USE_TLSv1},
+	{"SSLv2",   .val = TLS_USE_SSLv2},
+	{"SSLv3",   .val = TLS_USE_SSLv3},
+	{"SSLv23",  .val = TLS_USE_SSLv23},
+	{"TLSv1",   .val = TLS_USE_TLSv1},
+	{"TLSv1.1", .val = TLS_USE_TLSv1_1},
+	{"TLSv1.2", .val = TLS_USE_TLSv1_2},
 	{0}
 };
 
@@ -202,14 +197,7 @@ static int parse_hostport(int* type, struct ip_addr* ip, unsigned int* port,
 	}
 
 	if (t.type == '[') {
-#ifdef USE_IPV6
 		if (parse_ipv6(ip, &t, st) < 0) return -1;
-#else
-		ERR("%s:%d:%d: IPv6 address  not supported (compiled without IPv6"
-				" support)\n", 
-		    st->file, t.start.line, t.start.col);
-		return -1;
-#endif /* USE_IPV6 */
 	} else if (t.type == CFG_TOKEN_ALPHA) {
 		opt = cfg_lookup_token(token_default, &t.val);
 		if (opt) {
@@ -345,29 +333,106 @@ static int parse_domain(void* param, cfg_parser_t* st, unsigned int flags)
  */
 tls_domains_cfg_t* tls_load_config(str* filename)
 {
-	cfg_parser_t* parser;
-	str empty;
-
-	parser = NULL;
-	if ((cfg = tls_new_cfg()) == NULL) goto error;
-
-	empty.s = 0;
-	empty.len = 0;
-	if ((parser = cfg_parser_init(&empty, filename)) == NULL) {
-		ERR("tls: Error while initializing configuration file parser.\n");
+    cfg_parser_t* parser;
+    str empty;
+    struct stat file_status;
+    char tmp_name[13] = "configXXXXXX";
+    str filename_str;
+    DIR *dir;
+    struct dirent *ent;
+    int out_fd, in_fd, filename_is_directory;
+    char *file_path, ch;
+
+    parser = NULL;
+    memset(&file_status, 0, sizeof(struct stat));
+    dir = (DIR *)NULL;
+    in_fd = out_fd = filename_is_directory = 0;
+    file_path = (char *)0;
+
+    if ((cfg = tls_new_cfg()) == NULL) goto error;
+
+    if (stat(filename->s, &file_status) != 0) {
+	LOG(L_ERR, "cannot stat config file %s\n", filename->s);
+	goto error;
+    }
+    if (S_ISDIR(file_status.st_mode)) {
+	filename_is_directory = 1;
+	dir = opendir(filename->s);
+	if (dir == NULL) {
+	    LOG(L_ERR, "cannot open directory file %s\n", filename->s);
+	    goto error;
+	}
+	out_fd = mkstemp(&(tmp_name[0]));
+	if (out_fd == -1) {
+	    LOG(L_ERR, "cannot make tmp file %s\n", &(tmp_name[0]));
+	    goto error;
+	}
+	while ((ent = readdir(dir)) != NULL) {
+	    file_path = pkg_malloc(filename->len + 1 + 256);
+	    memcpy(file_path, filename->s, filename->len);
+	    file_path[filename->len] = '/';
+	    strcpy(file_path + filename->len + 1, ent->d_name);
+	    if (stat(file_path, &file_status) != 0) {
+		LOG(L_ERR, "cannot get status of config file %s\n",
+		    file_path);
 		goto error;
+	    }
+	    if (S_ISREG(file_status.st_mode)) {
+		in_fd = open(file_path, O_RDONLY);
+		if (in_fd == -1) {
+		    LOG(L_ERR, "cannot open config file %s\n",
+			file_path);
+		    goto error;
+		}
+		pkg_free(file_path);
+		while (read(in_fd, &ch, 1)) {
+		    write(out_fd, &ch, 1);
+		}
+		close(in_fd);
+		in_fd = 0;
+		ch = '\n';
+		write(out_fd, &ch, 1);
+	    }
 	}
+	closedir(dir);
+	close(out_fd);
+	dir = (DIR *)NULL;
+	out_fd = 0;
+    }
 
-	cfg_section_parser(parser, parse_domain, NULL);
+    empty.s = 0;
+    empty.len = 0;
+    if (filename_is_directory) {
+	filename_str.s = &(tmp_name[0]);
+	filename_str.len = strlen(&(tmp_name[0]));
+	if ((parser = cfg_parser_init(&empty, &filename_str)) == NULL) {
+	    ERR("tls: Error while initializing configuration file parser.\n");
+	    unlink(&(tmp_name[0]));
+	    goto error;
+	}
+	unlink(&(tmp_name[0]));
+    } else {
+	if ((parser = cfg_parser_init(&empty, filename)) == NULL) {
+	    ERR("tls: Error while initializing configuration file parser.\n");
+	    goto error;
+	}	
+    }
 
-	if (sr_cfg_parse(parser)) goto error;
-	cfg_parser_close(parser);
-	return cfg;
+    cfg_section_parser(parser, parse_domain, NULL);
+    if (sr_cfg_parse(parser)) goto error;
+    cfg_parser_close(parser);
+    return cfg;
 
  error:
-	if (parser) cfg_parser_close(parser);
-	if (cfg) tls_free_cfg(cfg);
-	return 0;
+    if (dir) closedir(dir);
+    if (out_fd > 0) {
+	close(out_fd);
+	unlink(&(tmp_name[0]));
+    }
+    if (file_path) pkg_free(file_path);
+    if (parser) cfg_parser_close(parser);
+    if (cfg) tls_free_cfg(cfg);
+    return 0;
 }
 
 
@@ -386,5 +451,20 @@ int tls_parse_method(str* method)
     opt = cfg_lookup_token(methods, method);
     if (!opt) return -1;
 
+#if OPENSSL_VERSION_NUMBER < 0x1000100fL
+	if(opt->val == TLS_USE_TLSv1_1) {
+		LM_ERR("tls v1.1 not supported by this libssl version: %ld\n",
+				(long)OPENSSL_VERSION_NUMBER);
+		return -1;
+	}
+#endif
+#if OPENSSL_VERSION_NUMBER < 0x1000105fL
+	if(opt->val == TLS_USE_TLSv1_2) {
+		LM_ERR("tls v1.2 not supported by this libssl version: %ld\n",
+				(long)OPENSSL_VERSION_NUMBER);
+		return -1;
+	}
+#endif
+
     return opt->val;
 }
diff --git a/modules/tls/tls_config.h b/modules/tls/tls_config.h
index 038c5c0..709e4e9 100644
--- a/modules/tls/tls_config.h
+++ b/modules/tls/tls_config.h
@@ -1,33 +1,19 @@
-/*
- * $Id$
- *
- * TLS module - Configuration file parser
+/* 
+ * TLS module
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005,2006 iptelorg GmbH
  *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info at iptel.org
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /*!
  * \file
diff --git a/modules/tls/tls_ct_q.h b/modules/tls/tls_ct_q.h
index 8e3005b..183c2f7 100644
--- a/modules/tls/tls_ct_q.h
+++ b/modules/tls/tls_ct_q.h
@@ -1,4 +1,6 @@
 /* 
+ * TLS module
+ *
  * Copyright (C) 2010 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
diff --git a/modules/tls/tls_ct_wrq.c b/modules/tls/tls_ct_wrq.c
index 1702d37..f5b7d2f 100644
--- a/modules/tls/tls_ct_wrq.c
+++ b/modules/tls/tls_ct_wrq.c
@@ -1,4 +1,6 @@
 /* 
+ * TLS module
+ *
  * Copyright (C) 2010 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
diff --git a/modules/tls/tls_ct_wrq.h b/modules/tls/tls_ct_wrq.h
index ffdcd0b..fa679f7 100644
--- a/modules/tls/tls_ct_wrq.h
+++ b/modules/tls/tls_ct_wrq.h
@@ -1,4 +1,6 @@
 /* 
+ * TLS module
+ *
  * Copyright (C) 2010 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
diff --git a/modules/tls/tls_domain.c b/modules/tls/tls_domain.c
index d353b81..b8362f4 100644
--- a/modules/tls/tls_domain.c
+++ b/modules/tls/tls_domain.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2001-2003 FhG FOKUS
+ * TLS module
+ *
  * Copyright (C) 2005,2006 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -33,6 +34,7 @@
 #include "../../mem/shm_mem.h"
 #include "../../pt.h"
 #include "../../cfg/cfg.h"
+#include "../../dprint.h"
 #include "tls_server.h"
 #include "tls_util.h"
 #include "tls_mod.h"
diff --git a/modules/tls/tls_domain.h b/modules/tls/tls_domain.h
index e4d1319..15652bc 100644
--- a/modules/tls/tls_domain.h
+++ b/modules/tls/tls_domain.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2001-2003 FhG FOKUS
+ * TLS module
+ *
  * Copyright (C) 2005,2006 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -48,6 +49,12 @@ enum tls_method {
 	TLS_USE_SSLv23_cli,
 	TLS_USE_SSLv23_srv,
 	TLS_USE_SSLv23,
+	TLS_USE_TLSv1_1_cli,
+	TLS_USE_TLSv1_1_srv,
+	TLS_USE_TLSv1_1,
+	TLS_USE_TLSv1_2_cli,
+	TLS_USE_TLSv1_2_srv,
+	TLS_USE_TLSv1_2,
 	TLS_METHOD_MAX
 };
 
diff --git a/modules/tls/tls_dump_vf.c b/modules/tls/tls_dump_vf.c
index fc91581..4b95c51 100644
--- a/modules/tls/tls_dump_vf.c
+++ b/modules/tls/tls_dump_vf.c
@@ -1,5 +1,5 @@
 /*
- * $Id$
+ * TLS module
  *
  * Copyright (C) 2006 enum.at
  *
@@ -18,6 +18,11 @@
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Exception: permission to copy, modify, propagate, and distribute a work
+ * formed by combining OpenSSL toolkit software and the code in this file,
+ * such as linking with software components and libraries released under
+ * OpenSSL project license.
  */
 /** log the verification failure reason.
  * @file tls_dump_vf.c
diff --git a/modules/tls/tls_dump_vf.h b/modules/tls/tls_dump_vf.h
index e2480b2..97b370b 100644
--- a/modules/tls/tls_dump_vf.h
+++ b/modules/tls/tls_dump_vf.h
@@ -1,5 +1,5 @@
 /*
- * $Id$
+ * TLS module
  *
  * Copyright (C) 2006 enum.at
  *
@@ -18,6 +18,11 @@
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Exception: permission to copy, modify, propagate, and distribute a work
+ * formed by combining OpenSSL toolkit software and the code in this file,
+ * such as linking with software components and libraries released under
+ * OpenSSL project license.
  */
 /** log the verification failure reason.
  * @file tls_dump_vf.h
diff --git a/modules/tls/tls_init.c b/modules/tls/tls_init.c
index b629afa..cc796c6 100644
--- a/modules/tls/tls_init.c
+++ b/modules/tls/tls_init.c
@@ -1,33 +1,19 @@
-/*
- * $Id$
- *
- * TLS module - OpenSSL initialization funtions
+/* 
+ * TLS module
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005,2006 iptelorg GmbH
  *
- * This file is part of SIP-router, a free SIP server.
- *
- * SIP-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * SIP-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/*
- * History:
- * --------
- *  2007-01-26  openssl kerberos malloc bug detection/workaround (andrei)
- *  2007-02-23  openssl low memory bugs workaround (andrei)
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 /*! \defgroup tls SIP-router TLS support
@@ -132,7 +118,7 @@ to compile on the  _target_ system)"
 int openssl_kssl_malloc_bug=0; /* is openssl bug #1467 present ? */
 #endif
 
-const SSL_METHOD* ssl_methods[TLS_USE_SSLv23 + 1];
+const SSL_METHOD* ssl_methods[TLS_METHOD_MAX];
 
 #ifdef NO_TLS_MALLOC_DBG
 #undef TLS_MALLOC_DBG /* extra malloc debug info from openssl */
@@ -341,6 +327,8 @@ int tls_h_init_si(struct socket_info *si)
  */
 static void init_ssl_methods(void)
 {
+	memset(ssl_methods, 0, sizeof(ssl_methods));
+
 #ifndef OPENSSL_NO_SSL2
 	ssl_methods[TLS_USE_SSLv2_cli - 1] = SSLv2_client_method();
 	ssl_methods[TLS_USE_SSLv2_srv - 1] = SSLv2_server_method();
@@ -350,14 +338,26 @@ static void init_ssl_methods(void)
 	ssl_methods[TLS_USE_SSLv3_cli - 1] = SSLv3_client_method();
 	ssl_methods[TLS_USE_SSLv3_srv - 1] = SSLv3_server_method();
 	ssl_methods[TLS_USE_SSLv3 - 1] = SSLv3_method();
-	
+
 	ssl_methods[TLS_USE_TLSv1_cli - 1] = TLSv1_client_method();
 	ssl_methods[TLS_USE_TLSv1_srv - 1] = TLSv1_server_method();
 	ssl_methods[TLS_USE_TLSv1 - 1] = TLSv1_method();
-	
+
 	ssl_methods[TLS_USE_SSLv23_cli - 1] = SSLv23_client_method();
 	ssl_methods[TLS_USE_SSLv23_srv - 1] = SSLv23_server_method();
 	ssl_methods[TLS_USE_SSLv23 - 1] = SSLv23_method();
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL
+	ssl_methods[TLS_USE_TLSv1_1_cli - 1] = TLSv1_1_client_method();
+	ssl_methods[TLS_USE_TLSv1_1_srv - 1] = TLSv1_1_server_method();
+	ssl_methods[TLS_USE_TLSv1_1 - 1] = TLSv1_1_method();
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000105fL
+	ssl_methods[TLS_USE_TLSv1_2_cli - 1] = TLSv1_2_client_method();
+	ssl_methods[TLS_USE_TLSv1_2_srv - 1] = TLSv1_2_server_method();
+	ssl_methods[TLS_USE_TLSv1_2 - 1] = TLSv1_2_method();
+#endif
 }
 
 
diff --git a/modules/tls/tls_init.h b/modules/tls/tls_init.h
index 7101949..5f06acb 100644
--- a/modules/tls/tls_init.h
+++ b/modules/tls/tls_init.h
@@ -1,32 +1,19 @@
-/*
- * $Id$
- * 
- * TLS module - OpenSSL initialization funtions
+/* 
+ * TLS module
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005,2006 iptelorg GmbH
  *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info at iptel.org
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /*!
  * \file
diff --git a/modules/tls/tls_locking.c b/modules/tls/tls_locking.c
index d85b14c..d35de8f 100644
--- a/modules/tls/tls_locking.c
+++ b/modules/tls/tls_locking.c
@@ -1,5 +1,5 @@
 /*
- * $Id$
+ * TLS module
  *
  * Copyright (C) 2007 iptelorg GmbH 
  *
@@ -15,13 +15,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-/*
- * tls locking and atomic ops related init functions
- *
- * History:
- * --------
- *  2007-01-22  created by andrei
- */
+
 /*!
  * \file
  * \brief SIP-router TLS support :: Locking
diff --git a/modules/tls/tls_locking.h b/modules/tls/tls_locking.h
index 2efb636..056efcd 100644
--- a/modules/tls/tls_locking.h
+++ b/modules/tls/tls_locking.h
@@ -1,5 +1,5 @@
 /*
- * $Id$
+ * TLS module
  *
  * Copyright (C) 2007 iptelorg GmbH 
  *
diff --git a/modules/tls/tls_mod.c b/modules/tls/tls_mod.c
index a6cd958..d8e30b3 100644
--- a/modules/tls/tls_mod.c
+++ b/modules/tls/tls_mod.c
@@ -1,43 +1,21 @@
 /*
- * $Id$
+ * TLS module
  *
- * TLS module - module interface
+ * Copyright (C) 2007 iptelorg GmbH 
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
- * Copyright (C) 2005,2006 iptelorg GmbH
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * This file is part of SIP-router, a free SIP server.
- *
- * SIP-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * SIP-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * History:
- * -------
- * 2003-03-11: New module interface (janakj)
- * 2003-03-16: flags export parameter added (janakj)
- * 2003-04-05: default_uri #define used (jiri)
- * 2003-04-06: db connection closed in mod_init (janakj)
- * 2004-06-06  updated to the new DB api, cleanup: static dbf & handler,
- *              calls to domain_db_{bind,init,close,ver} (andrei)
- * 2007-02-09  updated to the new tls_hooks api and renamed tls hooks hanlder
- *              functions to avoid conflicts: s/tls_/tls_h_/   (andrei)
- * 2010-03-19  new parameters to control advanced openssl lib options
- *              (mostly work on 1.0.0+): ssl_release_buffers, ssl_read_ahead,
- *              ssl_freelist_max_len, ssl_max_send_fragment   (andrei)
- * 2010-05-27  migrated to the runtime cfg framework (andrei)
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
+
 /** SIP-router TLS support :: Module interface.
  * @file
  * @ingroup tls
@@ -60,6 +38,7 @@
 #include "../../shm_init.h"
 #include "../../rpc_lookup.h"
 #include "../../cfg/cfg.h"
+#include "../../dprint.h"
 #include "tls_init.h"
 #include "tls_server.h"
 #include "tls_domain.h"
diff --git a/modules/tls/tls_mod.h b/modules/tls/tls_mod.h
index 462e5d0..d72f357 100644
--- a/modules/tls/tls_mod.h
+++ b/modules/tls/tls_mod.h
@@ -1,32 +1,19 @@
-/*
- * $Id$
- *
+/* 
  * TLS module - module interface
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005 iptelorg GmbH
  *
- * This file is part of sip-router, a free SIP server.
- *
- * sip-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the sip-router software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info at iptel.org
- *
- * sip-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /** SIP-router TLS support :: module interface.
  * @file
diff --git a/modules/tls/tls_rpc.c b/modules/tls/tls_rpc.c
index 956154b..458a215 100644
--- a/modules/tls/tls_rpc.c
+++ b/modules/tls/tls_rpc.c
@@ -1,9 +1,6 @@
 /*
- * $Id$
- *
  * TLS module - management interface
  *
- * Copyright (C) 2001-2003 FhG FOKUS
  * Copyright (C) 2005 iptelorg GmbH
  *
  * This file is part of sip-router, a free SIP server.
@@ -32,6 +29,7 @@
 #include "../../tcp_info.h"
 #include "../../timer.h"
 #include "../../cfg/cfg.h"
+#include "../../dprint.h"
 #include "tls_init.h"
 #include "tls_mod.h"
 #include "tls_domain.h"
diff --git a/modules/tls/tls_rpc.h b/modules/tls/tls_rpc.h
index 558bf0d..0d8e958 100644
--- a/modules/tls/tls_rpc.h
+++ b/modules/tls/tls_rpc.h
@@ -1,9 +1,6 @@
 /*
- * $Id$
+ * TLS module
  *
- * TLS module - management interface
- *
- * Copyright (C) 2001-2003 FhG FOKUS
  * Copyright (C) 2005 iptelorg GmbH
  *
  * This file is part of sip-router, a free SIP server.
diff --git a/modules/tls/tls_select.c b/modules/tls/tls_select.c
index 6186f0b..6305448 100644
--- a/modules/tls/tls_select.c
+++ b/modules/tls/tls_select.c
@@ -1,10 +1,6 @@
 /*
- * $Id$
- *
  * TLS module - select interface
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005 iptelorg GmbH
  * Copyright (C) 2006 enum.at
  *
@@ -23,6 +19,11 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Exception: permission to copy, modify, propagate, and distribute a work
+ * formed by combining OpenSSL toolkit software and the code in this file,
+ * such as linking with software components and libraries released under
+ * OpenSSL project license.
  */
 /** SIP-router TLS support :: Select interface.
  * @file
@@ -38,6 +39,7 @@
 #include "../../tcp_conn.h"
 #include "../../ut.h"
 #include "../../cfg/cfg.h"
+#include "../../dprint.h"
 #include "tls_server.h"
 #include "tls_select.h"
 #include "tls_mod.h"
diff --git a/modules/tls/tls_select.h b/modules/tls/tls_select.h
index 0757d19..3d5b8d0 100644
--- a/modules/tls/tls_select.h
+++ b/modules/tls/tls_select.h
@@ -1,10 +1,6 @@
 /*
- * $Id$
- *
  * TLS module - select interface
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005,2006 iptelorg GmbH
  * Copyright (C) 2006 enum.at
  *
@@ -28,6 +24,11 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Exception: permission to copy, modify, propagate, and distribute a work
+ * formed by combining OpenSSL toolkit software and the code in this file,
+ * such as linking with software components and libraries released under
+ * OpenSSL project license.
  */
 /*!
  * \file
diff --git a/modules/tls/tls_server.c b/modules/tls/tls_server.c
index f71956d..4b8db14 100644
--- a/modules/tls/tls_server.c
+++ b/modules/tls/tls_server.c
@@ -1,9 +1,6 @@
 /*
- * $Id$
- *
  * TLS module - main server part
- * 
- * Copyright (C) 2001-2003 FhG FOKUS
+ *
  * Copyright (C) 2005-2010 iptelorg GmbH
  *
  * This file is part of SIP-router, a free SIP server.
diff --git a/modules/tls/tls_server.h b/modules/tls/tls_server.h
index 4b00d06..d564425 100644
--- a/modules/tls/tls_server.h
+++ b/modules/tls/tls_server.h
@@ -1,9 +1,6 @@
 /*
- * $Id$
- *
  * TLS module - main server part
  * 
- * Copyright (C) 2001-2003 FhG FOKUS
  * Copyright (C) 2005-2010 iptelorg GmbH
  *
  * This file is part of SIP-router, a free SIP server.
diff --git a/modules/tls/tls_util.c b/modules/tls/tls_util.c
index da0050d..d8ffba2 100644
--- a/modules/tls/tls_util.c
+++ b/modules/tls/tls_util.c
@@ -1,27 +1,19 @@
-/*
- * $Id$
- *
- * TLS module - common functions
+/* 
+ * TLS module
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005 iptelorg GmbH
  *
- * This file is part of SIP-router, a free SIP server.
- *
- * SIP-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * SIP-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #define _GNU_SOURCE 1 /* Needed for strndup */
@@ -30,6 +22,7 @@
 #include <libgen.h>
 #include "../../mem/shm_mem.h"
 #include "../../globals.h"
+#include "../../dprint.h"
 #include "tls_mod.h"
 #include "tls_util.h"
 /*!
diff --git a/modules/tls/tls_util.h b/modules/tls/tls_util.h
index 07c6e3b..c345024 100644
--- a/modules/tls/tls_util.h
+++ b/modules/tls/tls_util.h
@@ -1,32 +1,19 @@
-/*
- * $Id$
- *
- * TLS module - common functions
- *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
- * COpyright (C) 2005 iptelorg GmbH
- *
- * This file is part of sip-router, a free SIP server.
- *
- * sip-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
+/* 
+ * TLS module
  *
- * For a license to use the sip-router software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info at iptel.org
+ * Copyright (C) 2010 iptelorg GmbH
  *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /*!
  * \file
diff --git a/modules/tls/tls_verify.c b/modules/tls/tls_verify.c
index e2faf3d..4751555 100644
--- a/modules/tls/tls_verify.c
+++ b/modules/tls/tls_verify.c
@@ -1,27 +1,19 @@
-/*
- * $Id$
+/* 
+ * TLS module
  *
- * TLS module - certificate verification function
+ * Copyright (C) 2005 iptelorg GmbH
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
- * COpyright (C) 2005 iptelorg GmbH
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * This file is part of sip-router, a free SIP server.
- *
- * sip-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * sip-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include "../../dprint.h"
diff --git a/modules/tls/tls_verify.h b/modules/tls/tls_verify.h
index 7b93bb3..68b0662 100644
--- a/modules/tls/tls_verify.h
+++ b/modules/tls/tls_verify.h
@@ -1,32 +1,19 @@
-/*
- * $Id$
- *
+/* 
  * TLS module - certificate verification function
  *
- * Copyright (C) 2001-2003 FhG FOKUS
- * Copyright (C) 2004,2005 Free Software Foundation, Inc.
- * COpyright (C) 2005 iptelorg GmbH
- *
- * This file is part of SIP-router, a free SIP server.
- *
- * SIP-router is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the SIP-router software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info at iptel.org
+ * Copyright (C) 2005 iptelorg GmbH
  *
- * SIP-router is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /*!
  * \file
diff --git a/modules/tm/README b/modules/tm/README
index 351e847..8c6fde0 100644
--- a/modules/tm/README
+++ b/modules/tm/README
@@ -65,6 +65,8 @@ Juha Heinanen
               4.41. local_cancel_reason (boolean)
               4.42. e2e_cancel_reason (boolean)
               4.43. remap_503_500 (boolean)
+              4.44. failure_exec_mode (boolean)
+              4.45. dns_reuse_rcv_socket (boolean)
 
         5. Functions
 
@@ -74,48 +76,50 @@ Juha Heinanen
               5.4. t_relay_to_tls([ip, port])
               5.5. t_relay_to_sctp([ip, port])
               5.6. t_on_failure(failure_route)
-              5.7. t_on_reply(onreply_route)
-              5.8. t_on_branch(branch_route)
-              5.9. t_newtran()
-              5.10. t_reply(code, reason_phrase)
-              5.11. t_lookup_request()
-              5.12. t_retransmit_reply()
-              5.13. t_release()
-              5.14. t_forward_nonack([ip, port])
-              5.15. t_forward_nonack_udp(ip, port)
-              5.16. t_forward_nonack_tcp(ip, port)
-              5.17. t_forward_nonack_tls(ip, port)
-              5.18. t_forward_nonack_sctp(ip, port)
-              5.19. t_set_fr(fr_inv_timeout [, fr_timeout])
-              5.20. t_reset_fr()
-              5.21. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
-              5.22. t_reset_max_lifetime()
-              5.23. t_set_retr(retr_t1_interval, retr_t2_interval)
-              5.24. t_reset_retr()
-              5.25. t_set_auto_inv_100(0|1)
-              5.26. t_branch_timeout()
-              5.27. t_branch_replied()
-              5.28. t_any_timeout()
-              5.29. t_any_replied()
-              5.30. t_grep_status("code")
-              5.31. t_is_canceled()
-              5.32. t_is_expired()
-              5.33. t_relay_cancel()
-              5.34. t_lookup_cancel([1])
-              5.35. t_drop_replies([mode])
-              5.36. t_save_lumps()
-              5.37. t_load_contacts()
-              5.38. t_next_contacts()
-              5.39. t_next_contact_flows()
-              5.40. t_check_status(re)
-              5.41. t_check_trans()
-              5.42. t_set_disable_6xx(0|1)
-              5.43. t_set_disable_failover(0|1)
-              5.44. t_set_disable_internal_reply(0|1)
-              5.45. t_replicate(params)
-              5.46. t_relay_to(proxy, flags)
-              5.47. t_set_no_e2e_cancel_reason(0|1)
-              5.48. t_is_set(target)
+              5.7. t_on_branch_failure(branch_failure_route)
+              5.8. t_on_reply(onreply_route)
+              5.9. t_on_branch(branch_route)
+              5.10. t_newtran()
+              5.11. t_reply(code, reason_phrase)
+              5.12. t_lookup_request()
+              5.13. t_retransmit_reply()
+              5.14. t_release()
+              5.15. t_forward_nonack([ip, port])
+              5.16. t_forward_nonack_udp(ip, port)
+              5.17. t_forward_nonack_tcp(ip, port)
+              5.18. t_forward_nonack_tls(ip, port)
+              5.19. t_forward_nonack_sctp(ip, port)
+              5.20. t_set_fr(fr_inv_timeout [, fr_timeout])
+              5.21. t_reset_fr()
+              5.22. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
+              5.23. t_reset_max_lifetime()
+              5.24. t_set_retr(retr_t1_interval, retr_t2_interval)
+              5.25. t_reset_retr()
+              5.26. t_set_auto_inv_100(0|1)
+              5.27. t_branch_timeout()
+              5.28. t_branch_replied()
+              5.29. t_any_timeout()
+              5.30. t_any_replied()
+              5.31. t_grep_status("code")
+              5.32. t_is_canceled()
+              5.33. t_is_expired()
+              5.34. t_relay_cancel()
+              5.35. t_lookup_cancel([1])
+              5.36. t_drop_replies([mode])
+              5.37. t_save_lumps()
+              5.38. t_load_contacts()
+              5.39. t_next_contacts()
+              5.40. t_next_contact_flow()
+              5.41. t_check_status(re)
+              5.42. t_check_trans()
+              5.43. t_set_disable_6xx(0|1)
+              5.44. t_set_disable_failover(0|1)
+              5.45. t_set_disable_internal_reply(0|1)
+              5.46. t_replicate(params)
+              5.47. t_relay_to(proxy, flags)
+              5.48. t_set_no_e2e_cancel_reason(0|1)
+              5.49. t_is_set(target)
+              5.50. t_use_uac_headers()
 
         6. TM Module API
 
@@ -133,6 +137,10 @@ Juha Heinanen
                     6.2.5. int t_cancel_suspend(unsigned int hash_index,
                             unsigned int label)
 
+        7. Event Routes
+
+              7.1. event_route[tm:branch-failure]
+
    List of Examples
 
    1.1. Set fr_timer parameter
@@ -178,47 +186,52 @@ Juha Heinanen
    1.41. Set local_cancel_reason parameter
    1.42. Set e2e_cancel_reason parameter
    1.43. Set remap_503_500 parameter
-   1.44. t_relay usage
-   1.45. t_relay_to_udp usage
-   1.46. t_on_failure usage
-   1.47. t_on_reply usage
-   1.48. t_on_branch usage
-   1.49. t_newtran usage
-   1.50. t_reply usage
-   1.51. t_lookup_request usage
-   1.52. t_retransmit_reply usage
-   1.53. t_release usage
-   1.54. t_forward_nonack usage
-   1.55. t_set_fr usage
-   1.56. t_reset_fr usage
-   1.57. t_set_max_lifetime usage
-   1.58. t_reset_max_lifetime usage
-   1.59. t_set_retr usage
-   1.60. t_reset_retr usage
-   1.61. t_set_auto_inv_100 usage
-   1.62. t_branch_timeout usage
-   1.63. t_branch_replied usage
-   1.64. t_any_timeout usage
-   1.65. t_any_replied usage
-   1.66. t_grep_status usage
-   1.67. t_is_canceled usage
-   1.68. t_is_expired usage
-   1.69. t_relay_cancel usage
-   1.70. t_lookup_cancel usage
-   1.71. t_drop_replies() usage
-   1.72. t_save_lumps() usage
-   1.73. t_load_contacts usage
-   1.74. t_next_contacts usage
-   1.75. t_next_contact_flows usage
-   1.76. t_check_status usage
-   1.77. t_check_trans usage
-   1.78. t_set_disable_6xx usage
-   1.79. t_set_disable_failover usage
-   1.80. t_set_disable_internal_reply usage
-   1.81. t_replicate usage
-   1.82. t_replicate usage
-   1.83. t_set_no_e2e_cancel_reason usage
+   1.44. Set failure_exec_mode parameter
+   1.45. Set dns_reuse_rcv_socket parameter
+   1.46. t_relay usage
+   1.47. t_relay_to_udp usage
+   1.48. t_on_failure usage
+   1.49. t_on_branch_failure usage
+   1.50. t_on_reply usage
+   1.51. t_on_branch usage
+   1.52. t_newtran usage
+   1.53. t_reply usage
+   1.54. t_lookup_request usage
+   1.55. t_retransmit_reply usage
+   1.56. t_release usage
+   1.57. t_forward_nonack usage
+   1.58. t_set_fr usage
+   1.59. t_reset_fr usage
+   1.60. t_set_max_lifetime usage
+   1.61. t_reset_max_lifetime usage
+   1.62. t_set_retr usage
+   1.63. t_reset_retr usage
+   1.64. t_set_auto_inv_100 usage
+   1.65. t_branch_timeout usage
+   1.66. t_branch_replied usage
+   1.67. t_any_timeout usage
+   1.68. t_any_replied usage
+   1.69. t_grep_status usage
+   1.70. t_is_canceled usage
+   1.71. t_is_expired usage
+   1.72. t_relay_cancel usage
+   1.73. t_lookup_cancel usage
+   1.74. t_drop_replies() usage
+   1.75. t_save_lumps() usage
+   1.76. t_load_contacts usage
+   1.77. t_next_contacts usage
+   1.78. t_next_contact_flow usage
+   1.79. t_check_status usage
+   1.80. t_check_trans usage
+   1.81. t_set_disable_6xx usage
+   1.82. t_set_disable_failover usage
+   1.83. t_set_disable_internal_reply usage
    1.84. t_replicate usage
+   1.85. t_replicate usage
+   1.86. t_set_no_e2e_cancel_reason usage
+   1.87. t_replicate usage
+   1.88. t_use_uac_headers usage
+   1.89. event_route[tm:branch-failure] usage
 
 Chapter 1. Admin Guide
 
@@ -272,6 +285,8 @@ Chapter 1. Admin Guide
         4.41. local_cancel_reason (boolean)
         4.42. e2e_cancel_reason (boolean)
         4.43. remap_503_500 (boolean)
+        4.44. failure_exec_mode (boolean)
+        4.45. dns_reuse_rcv_socket (boolean)
 
    5. Functions
 
@@ -281,48 +296,50 @@ Chapter 1. Admin Guide
         5.4. t_relay_to_tls([ip, port])
         5.5. t_relay_to_sctp([ip, port])
         5.6. t_on_failure(failure_route)
-        5.7. t_on_reply(onreply_route)
-        5.8. t_on_branch(branch_route)
-        5.9. t_newtran()
-        5.10. t_reply(code, reason_phrase)
-        5.11. t_lookup_request()
-        5.12. t_retransmit_reply()
-        5.13. t_release()
-        5.14. t_forward_nonack([ip, port])
-        5.15. t_forward_nonack_udp(ip, port)
-        5.16. t_forward_nonack_tcp(ip, port)
-        5.17. t_forward_nonack_tls(ip, port)
-        5.18. t_forward_nonack_sctp(ip, port)
-        5.19. t_set_fr(fr_inv_timeout [, fr_timeout])
-        5.20. t_reset_fr()
-        5.21. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
-        5.22. t_reset_max_lifetime()
-        5.23. t_set_retr(retr_t1_interval, retr_t2_interval)
-        5.24. t_reset_retr()
-        5.25. t_set_auto_inv_100(0|1)
-        5.26. t_branch_timeout()
-        5.27. t_branch_replied()
-        5.28. t_any_timeout()
-        5.29. t_any_replied()
-        5.30. t_grep_status("code")
-        5.31. t_is_canceled()
-        5.32. t_is_expired()
-        5.33. t_relay_cancel()
-        5.34. t_lookup_cancel([1])
-        5.35. t_drop_replies([mode])
-        5.36. t_save_lumps()
-        5.37. t_load_contacts()
-        5.38. t_next_contacts()
-        5.39. t_next_contact_flows()
-        5.40. t_check_status(re)
-        5.41. t_check_trans()
-        5.42. t_set_disable_6xx(0|1)
-        5.43. t_set_disable_failover(0|1)
-        5.44. t_set_disable_internal_reply(0|1)
-        5.45. t_replicate(params)
-        5.46. t_relay_to(proxy, flags)
-        5.47. t_set_no_e2e_cancel_reason(0|1)
-        5.48. t_is_set(target)
+        5.7. t_on_branch_failure(branch_failure_route)
+        5.8. t_on_reply(onreply_route)
+        5.9. t_on_branch(branch_route)
+        5.10. t_newtran()
+        5.11. t_reply(code, reason_phrase)
+        5.12. t_lookup_request()
+        5.13. t_retransmit_reply()
+        5.14. t_release()
+        5.15. t_forward_nonack([ip, port])
+        5.16. t_forward_nonack_udp(ip, port)
+        5.17. t_forward_nonack_tcp(ip, port)
+        5.18. t_forward_nonack_tls(ip, port)
+        5.19. t_forward_nonack_sctp(ip, port)
+        5.20. t_set_fr(fr_inv_timeout [, fr_timeout])
+        5.21. t_reset_fr()
+        5.22. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
+        5.23. t_reset_max_lifetime()
+        5.24. t_set_retr(retr_t1_interval, retr_t2_interval)
+        5.25. t_reset_retr()
+        5.26. t_set_auto_inv_100(0|1)
+        5.27. t_branch_timeout()
+        5.28. t_branch_replied()
+        5.29. t_any_timeout()
+        5.30. t_any_replied()
+        5.31. t_grep_status("code")
+        5.32. t_is_canceled()
+        5.33. t_is_expired()
+        5.34. t_relay_cancel()
+        5.35. t_lookup_cancel([1])
+        5.36. t_drop_replies([mode])
+        5.37. t_save_lumps()
+        5.38. t_load_contacts()
+        5.39. t_next_contacts()
+        5.40. t_next_contact_flow()
+        5.41. t_check_status(re)
+        5.42. t_check_trans()
+        5.43. t_set_disable_6xx(0|1)
+        5.44. t_set_disable_failover(0|1)
+        5.45. t_set_disable_internal_reply(0|1)
+        5.46. t_replicate(params)
+        5.47. t_relay_to(proxy, flags)
+        5.48. t_set_no_e2e_cancel_reason(0|1)
+        5.49. t_is_set(target)
+        5.50. t_use_uac_headers()
 
    6. TM Module API
 
@@ -340,6 +357,10 @@ Chapter 1. Admin Guide
               6.2.5. int t_cancel_suspend(unsigned int hash_index,
                       unsigned int label)
 
+   7. Event Routes
+
+        7.1. event_route[tm:branch-failure]
+
 1. Overview
 
    The TM module enables stateful processing of SIP transactions. Stateful
@@ -629,6 +650,8 @@ failure_route["serial"]
    4.41. local_cancel_reason (boolean)
    4.42. e2e_cancel_reason (boolean)
    4.43. remap_503_500 (boolean)
+   4.44. failure_exec_mode (boolean)
+   4.45. dns_reuse_rcv_socket (boolean)
 
 4.1. fr_timer (integer)
 
@@ -1502,6 +1525,39 @@ modparam("tm", "e2e_cancel_reason", 0)
 modparam("tm", "remap_503_500", 0)
 ...
 
+4.44. failure_exec_mode (boolean)
+
+   Add local failed branches in timer to be cosidered for failure routing
+   blocks. If disabled, relay functions will return false in case the
+   branch could not be forwarded (default behaviour before v4.1.0).
+
+   Default value is 0 (disabled).
+
+   Example 1.44. Set failure_exec_mode parameter
+...
+modparam("tm", "failure_exec_mode", 1)
+...
+
+4.45. dns_reuse_rcv_socket (boolean)
+
+   Control reuse of the receive socket for additional branches added by
+   dns failover. If set to 1, the receive socket is used for sending out
+   the new branches, unless the socket is forced explicitely in
+   configuration file. If set to 0, selected socket is done depending on
+   value of global parameter mhomed (if mhomed=0, then the first listen
+   socket is used, otherwise the socket is selected based on routing
+   rules).
+
+   Do enable it with caution, it might create troubles on dns results with
+   different transport layer. Better let it disabled and enable mhomed.
+
+   Default value is 0 (disabled).
+
+   Example 1.45. Set dns_reuse_rcv_socket parameter
+...
+modparam("tm", "dns_reuse_rcv_socket", 1)
+...
+
 5. Functions
 
    5.1. t_relay([host, port])
@@ -1510,48 +1566,50 @@ modparam("tm", "remap_503_500", 0)
    5.4. t_relay_to_tls([ip, port])
    5.5. t_relay_to_sctp([ip, port])
    5.6. t_on_failure(failure_route)
-   5.7. t_on_reply(onreply_route)
-   5.8. t_on_branch(branch_route)
-   5.9. t_newtran()
-   5.10. t_reply(code, reason_phrase)
-   5.11. t_lookup_request()
-   5.12. t_retransmit_reply()
-   5.13. t_release()
-   5.14. t_forward_nonack([ip, port])
-   5.15. t_forward_nonack_udp(ip, port)
-   5.16. t_forward_nonack_tcp(ip, port)
-   5.17. t_forward_nonack_tls(ip, port)
-   5.18. t_forward_nonack_sctp(ip, port)
-   5.19. t_set_fr(fr_inv_timeout [, fr_timeout])
-   5.20. t_reset_fr()
-   5.21. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
-   5.22. t_reset_max_lifetime()
-   5.23. t_set_retr(retr_t1_interval, retr_t2_interval)
-   5.24. t_reset_retr()
-   5.25. t_set_auto_inv_100(0|1)
-   5.26. t_branch_timeout()
-   5.27. t_branch_replied()
-   5.28. t_any_timeout()
-   5.29. t_any_replied()
-   5.30. t_grep_status("code")
-   5.31. t_is_canceled()
-   5.32. t_is_expired()
-   5.33. t_relay_cancel()
-   5.34. t_lookup_cancel([1])
-   5.35. t_drop_replies([mode])
-   5.36. t_save_lumps()
-   5.37. t_load_contacts()
-   5.38. t_next_contacts()
-   5.39. t_next_contact_flows()
-   5.40. t_check_status(re)
-   5.41. t_check_trans()
-   5.42. t_set_disable_6xx(0|1)
-   5.43. t_set_disable_failover(0|1)
-   5.44. t_set_disable_internal_reply(0|1)
-   5.45. t_replicate(params)
-   5.46. t_relay_to(proxy, flags)
-   5.47. t_set_no_e2e_cancel_reason(0|1)
-   5.48. t_is_set(target)
+   5.7. t_on_branch_failure(branch_failure_route)
+   5.8. t_on_reply(onreply_route)
+   5.9. t_on_branch(branch_route)
+   5.10. t_newtran()
+   5.11. t_reply(code, reason_phrase)
+   5.12. t_lookup_request()
+   5.13. t_retransmit_reply()
+   5.14. t_release()
+   5.15. t_forward_nonack([ip, port])
+   5.16. t_forward_nonack_udp(ip, port)
+   5.17. t_forward_nonack_tcp(ip, port)
+   5.18. t_forward_nonack_tls(ip, port)
+   5.19. t_forward_nonack_sctp(ip, port)
+   5.20. t_set_fr(fr_inv_timeout [, fr_timeout])
+   5.21. t_reset_fr()
+   5.22. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
+   5.23. t_reset_max_lifetime()
+   5.24. t_set_retr(retr_t1_interval, retr_t2_interval)
+   5.25. t_reset_retr()
+   5.26. t_set_auto_inv_100(0|1)
+   5.27. t_branch_timeout()
+   5.28. t_branch_replied()
+   5.29. t_any_timeout()
+   5.30. t_any_replied()
+   5.31. t_grep_status("code")
+   5.32. t_is_canceled()
+   5.33. t_is_expired()
+   5.34. t_relay_cancel()
+   5.35. t_lookup_cancel([1])
+   5.36. t_drop_replies([mode])
+   5.37. t_save_lumps()
+   5.38. t_load_contacts()
+   5.39. t_next_contacts()
+   5.40. t_next_contact_flow()
+   5.41. t_check_status(re)
+   5.42. t_check_trans()
+   5.43. t_set_disable_6xx(0|1)
+   5.44. t_set_disable_failover(0|1)
+   5.45. t_set_disable_internal_reply(0|1)
+   5.46. t_replicate(params)
+   5.47. t_relay_to(proxy, flags)
+   5.48. t_set_no_e2e_cancel_reason(0|1)
+   5.49. t_is_set(target)
+   5.50. t_use_uac_headers()
 
 5.1. t_relay([host, port])
 
@@ -1572,7 +1630,7 @@ modparam("tm", "remap_503_500", 0)
    Returns a negative value on failure -- you may still want to send a
    negative reply upstream statelessly not to leave upstream UAC in lurch.
 
-   Example 1.44. t_relay usage
+   Example 1.46. t_relay usage
 ...
 if (!t_relay())
 {
@@ -1599,7 +1657,7 @@ if (!t_relay())
    derived from the message uri (using sip sepcific DNS lookups), but with
    the protocol corresponding to the function name.
 
-   Example 1.45. t_relay_to_udp usage
+   Example 1.47. t_relay_to_udp usage
 ...
 if (src_ip==10.0.0.0/8)
         t_relay_to_udp("1.2.3.4", "5060"); # sent to 1.2.3.4:5060 over udp
@@ -1639,7 +1697,7 @@ else
    Meaning of the parameters is as follows:
      * failure_route - Failure route block to be called.
 
-   Example 1.46. t_on_failure usage
+   Example 1.48. t_on_failure usage
 ...
 route {
     t_on_failure("1");
@@ -1656,7 +1714,40 @@ failure_route[1] {
    See test/onr.cfg for a more complex example of combination of serial
    with parallel forking.
 
-5.7. t_on_reply(onreply_route)
+5.7. t_on_branch_failure(branch_failure_route)
+
+   Sets the branch_failure routing block, to which control is passed on
+   each negative response to a transaction. This route is run before
+   deciding if the transaction is complete. In the referred block, you can
+   start a new branch which is required for failover of multiple outbound
+   flows (RFC 5626). Note that the set of commands which are usable within
+   a branch_failure route is limited to a subset of the failure_rotue
+   commands including logging, rewriting URI and initiating new branches.
+   Any other commands may generate errors or result in unpredictable
+   behavior. Note that whenever failure_route is entered, uri is reset to
+   value which it had on relaying. If it temporarily changed during a
+   reply_route processing, subsequent reply_route will ignore the changed
+   value and use again the original one.
+
+   Function Parameters:
+     * branch_failure_route - Name of the branch_failure route block to be
+       called (it is prefixed internally with 'tm:branch-failure:').
+
+   Example 1.49. t_on_branch_failure usage
+...
+route {
+    t_on_branch_failure("myroute");
+    t_relay();
+}
+
+event_route[tm:branch-failure:myroute] {
+    if (t_check_status("430|403") {
+        unregister("location", "$tu", "$T_reply_ruid");
+    }
+}
+...
+
+5.8. t_on_reply(onreply_route)
 
    Sets the reply routing block, to which control is passed when a reply
    for the current transaction is received. Note that the set of commands
@@ -1665,7 +1756,7 @@ failure_route[1] {
    Meaning of the parameters is as follows:
      * onreply_route - Onreply route block to be called.
 
-   Example 1.47. t_on_reply usage
+   Example 1.50. t_on_reply usage
 ...
 loadmodule "/usr/local/lib/ser/modules/nathelper.so"
 ...
@@ -1686,7 +1777,7 @@ es');
         }
 }
 
-5.8. t_on_branch(branch_route)
+5.9. t_on_branch(branch_route)
 
    Sets the branch routing block, to which control is passed after forking
    (when a new branch is created). For now branch routes are intended only
@@ -1697,7 +1788,7 @@ es');
    Meaning of the parameters is as follows:
      * branch_route - branch route block to be called.
 
-   Example 1.48. t_on_branch usage
+   Example 1.51. t_on_branch usage
 ...
 route {
         t_on_branch("1");
@@ -1710,13 +1801,13 @@ branch_route[1] {
         }
 }
 
-5.9. t_newtran()
+5.10. t_newtran()
 
    Creates a new transaction, returns a negative value on error. This is
    the only way a script can add a new transaction in an atomic way.
    Typically, it is used to deploy a UAS.
 
-   Example 1.49. t_newtran usage
+   Example 1.52. t_newtran usage
 ...
 if (t_newtran()) {
     log("UAS logic");
@@ -1726,7 +1817,7 @@ if (t_newtran()) {
 
    See test/uas.cfg for more examples.
 
-5.10. t_reply(code, reason_phrase)
+5.11. t_reply(code, reason_phrase)
 
    Sends a stateful reply after a transaction has been established. See
    t_newtran for usage.
@@ -1735,12 +1826,12 @@ if (t_newtran()) {
      * code - Reply code number.
      * reason_phrase - Reason string.
 
-   Example 1.50. t_reply usage
+   Example 1.53. t_reply usage
 ...
 t_reply("404", "Not found");
 ...
 
-5.11. t_lookup_request()
+5.12. t_lookup_request()
 
    Checks if a transaction exists. Returns a positive value if so,
    negative otherwise. Most likely you will not want to use it, as a
@@ -1748,33 +1839,33 @@ t_reply("404", "Not found");
    none was found. However this is safely (atomically) done using
    t_newtran.
 
-   Example 1.51. t_lookup_request usage
+   Example 1.54. t_lookup_request usage
 ...
 if (t_lookup_request()) {
     ...
 };
 ...
 
-5.12. t_retransmit_reply()
+5.13. t_retransmit_reply()
 
    Retransmits a reply sent previously by UAS transaction.
 
-   Example 1.52. t_retransmit_reply usage
+   Example 1.55. t_retransmit_reply usage
 ...
 t_retransmit_reply();
 ...
 
-5.13. t_release()
+5.14. t_release()
 
    Remove transaction from memory (it will be first put on a wait timer to
    absorb delayed messages).
 
-   Example 1.53. t_release usage
+   Example 1.56. t_release usage
 ...
 t_release();
 ...
 
-5.14. t_forward_nonack([ip, port])
+5.15. t_forward_nonack([ip, port])
 
    Mainly for internal usage -- forward a non-ACK request statefully.
    Variants of this functions can enforce a specific transport protocol.
@@ -1783,28 +1874,28 @@ t_release();
      * ip - IP address where the message should be sent.
      * port - Port number.
 
-   Example 1.54. t_forward_nonack usage
+   Example 1.57. t_forward_nonack usage
 ...
 t_forward_nonack("1.2.3.4", "5060");
 ...
 
-5.15. t_forward_nonack_udp(ip, port)
+5.16. t_forward_nonack_udp(ip, port)
 
    See function t_forward_nonack([ip, port]).
 
-5.16. t_forward_nonack_tcp(ip, port)
+5.17. t_forward_nonack_tcp(ip, port)
 
    See function t_forward_nonack([ip, port]).
 
-5.17. t_forward_nonack_tls(ip, port)
+5.18. t_forward_nonack_tls(ip, port)
 
    See function t_forward_nonack([ip, port]).
 
-5.18. t_forward_nonack_sctp(ip, port)
+5.19. t_forward_nonack_sctp(ip, port)
 
    See function t_forward_nonack([ip, port]).
 
-5.19. t_set_fr(fr_inv_timeout [, fr_timeout])
+5.20. t_set_fr(fr_inv_timeout [, fr_timeout])
 
    Sets the fr_inv_timeout and optionally fr_timeout for the current
    transaction or for transactions created during the same script
@@ -1822,7 +1913,7 @@ t_forward_nonack("1.2.3.4", "5060");
 
    See also: fr_timer, fr_inv_timer, t_reset_fr().
 
-   Example 1.55. t_set_fr usage
+   Example 1.58. t_set_fr usage
 ...
 route {
         t_set_fr(10000); # set only fr invite timeout to 10s
@@ -1838,7 +1929,7 @@ branch_route[1] {
         }
 }
 
-5.20. t_reset_fr()
+5.21. t_reset_fr()
 
    Resets the fr_inv_timer and fr_timer for the current transaction to the
    default values (set using the tm module parameters fr_inv_timer and
@@ -1849,7 +1940,7 @@ branch_route[1] {
 
    See also: fr_timer, fr_inv_timer, t_set_fr.
 
-   Example 1.56. t_reset_fr usage
+   Example 1.59. t_reset_fr usage
 ...
 route {
 ...
@@ -1857,7 +1948,7 @@ route {
 ...
 }
 
-5.21. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
+5.22. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
 
    Sets the maximum lifetime for the current INVITE or non-INVITE
    transaction, or for transactions created during the same script
@@ -1875,7 +1966,7 @@ route {
 
    See also: max_inv_lifetime, max_noninv_lifetime, t_reset_max_lifetime.
 
-   Example 1.57. t_set_max_lifetime usage
+   Example 1.60. t_set_max_lifetime usage
 ...
 route {
     if (src_ip=1.2.3.4)
@@ -1886,7 +1977,7 @@ route {
                                           # INVITE and to 15s if not
 }
 
-5.22. t_reset_max_lifetime()
+5.23. t_reset_max_lifetime()
 
    Resets the the maximum lifetime for the current INVITE or non-INVITE
    transaction to the default value (set using the tm module parameter
@@ -1897,7 +1988,7 @@ route {
 
    See also: max_inv_lifetime, max_noninv_lifetime, t_set_max_lifetime.
 
-   Example 1.58. t_reset_max_lifetime usage
+   Example 1.61. t_reset_max_lifetime usage
 ...
 route {
 ...
@@ -1905,7 +1996,7 @@ route {
 ...
 }
 
-5.23. t_set_retr(retr_t1_interval, retr_t2_interval)
+5.24. t_set_retr(retr_t1_interval, retr_t2_interval)
 
    Sets the retr_t1_interval and retr_t2_interval for the current
    transaction or for transactions created during the same script
@@ -1935,7 +2026,7 @@ route {
 
    See also: retr_timer1, retr_timer2, t_reset_retr().
 
-   Example 1.59. t_set_retr usage
+   Example 1.62. t_set_retr usage
 ...
 route {
         t_set_retr(250, 0); # set only T1 to 250 ms
@@ -1951,7 +2042,7 @@ branch_route[1] {
         }
 }
 
-5.24. t_reset_retr()
+5.25. t_reset_retr()
 
    Resets the retr_timer1 and retr_timer2 for the current transaction to
    the default values (set using the tm module parameters retr_timer1 and
@@ -1962,7 +2053,7 @@ branch_route[1] {
 
    See also: retr_timer1, retr_timer2, t_set_retr.
 
-   Example 1.60. t_reset_retr usage
+   Example 1.63. t_reset_retr usage
 ...
 route {
 ...
@@ -1970,7 +2061,7 @@ route {
 ...
 }
 
-5.25. t_set_auto_inv_100(0|1)
+5.26. t_set_auto_inv_100(0|1)
 
    Switch automatically sending 100 replies to INVITEs on/off on a per
    transaction basis. It overrides the auto_inv_100 value for the current
@@ -1978,7 +2069,7 @@ route {
 
    See also: auto_inv_100.
 
-   Example 1.61. t_set_auto_inv_100 usage
+   Example 1.64. t_set_auto_inv_100 usage
 ...
 route {
 ...
@@ -1987,12 +2078,13 @@ route {
 ...
 }
 
-5.26. t_branch_timeout()
+5.27. t_branch_timeout()
 
    Returns true if the failure route is executed for a branch that did
-   timeout. It can be used only from the failure_route.
+   timeout. It can be used from failure_route and branch-failure event
+   route.
 
-   Example 1.62. t_branch_timeout usage
+   Example 1.65. t_branch_timeout usage
 ...
 failure_route[0]{
         if (t_branch_timeout()){
@@ -2001,13 +2093,14 @@ failure_route[0]{
         }
 }
 
-5.27. t_branch_replied()
+5.28. t_branch_replied()
 
    Returns true if the failure route is executed for a branch that did
    receive at least one reply in the past (the "current" reply is not
-   taken into account). It can be used only from the failure_route.
+   taken into account). It can be used from failure_route and
+   branch-failure event route.
 
-   Example 1.63. t_branch_replied usage
+   Example 1.66. t_branch_replied usage
 ...
 failure_route[0]{
         if (t_branch_timeout()){
@@ -2019,12 +2112,12 @@ failure_route[0]{
         }
 }
 
-5.28. t_any_timeout()
+5.29. t_any_timeout()
 
    Returns true if at least one of the current transactions branches did
    timeout.
 
-   Example 1.64. t_any_timeout usage
+   Example 1.67. t_any_timeout usage
 ...
 failure_route[0]{
         if (!t_branch_timeout()){
@@ -2035,13 +2128,13 @@ failure_route[0]{
         }
 }
 
-5.29. t_any_replied()
+5.30. t_any_replied()
 
    Returns true if at least one of the current transactions branches did
    receive some reply in the past. If called from a failure or onreply
    route, the "current" reply is not taken into account.
 
-   Example 1.65. t_any_replied usage
+   Example 1.68. t_any_replied usage
 ...
 onreply_route[0]{
         if (!t_any_replied()){
@@ -2050,12 +2143,12 @@ onreply_route[0]{
         }
 }
 
-5.30. t_grep_status("code")
+5.31. t_grep_status("code")
 
    Returns true if "code" is the final reply received (or locally
    generated) in at least one of the current transactions branches.
 
-   Example 1.66. t_grep_status usage
+   Example 1.69. t_grep_status usage
 ...
 onreply_route[0]{
         if (t_grep_status("486")){
@@ -2064,11 +2157,11 @@ onreply_route[0]{
         }
 }
 
-5.31. t_is_canceled()
+5.32. t_is_canceled()
 
    Returns true if the current transaction was canceled.
 
-   Example 1.67. t_is_canceled usage
+   Example 1.70. t_is_canceled usage
 ...
 failure_route[0]{
         if (t_is_canceled()){
@@ -2077,12 +2170,12 @@ failure_route[0]{
         }
 }
 
-5.32. t_is_expired()
+5.33. t_is_expired()
 
    Returns true if the current transaction has already been expired, i.e.
    the max_inv_lifetime/max_noninv_lifetime interval has already elapsed.
 
-   Example 1.68. t_is_expired usage
+   Example 1.71. t_is_expired usage
 ...
 failure_route[0]{
         if (t_is_expired()){
@@ -2091,7 +2184,7 @@ failure_route[0]{
         }
 }
 
-5.33. t_relay_cancel()
+5.34. t_relay_cancel()
 
    Forwards the CANCEL if the corresponding INVITE transaction exists. The
    function is supposed to be used at the very beginning of the script,
@@ -2103,7 +2196,7 @@ failure_route[0]{
    CANCELs were successfully sent to the pending branches, true if the
    INVITE was not found, and false in case of any error.
 
-   Example 1.69. t_relay_cancel usage
+   Example 1.72. t_relay_cancel usage
 if (method == CANCEL) {
         if (!t_relay_cancel()) {  # implicit drop if relaying was successful,
                                   # nothing to do
@@ -2116,7 +2209,7 @@ if (method == CANCEL) {
         # do the same as for INVITEs
 }
 
-5.34. t_lookup_cancel([1])
+5.35. t_lookup_cancel([1])
 
    Returns true if the corresponding INVITE transaction exists for a
    CANCEL request. The function can be called at the beginning of the
@@ -2130,7 +2223,7 @@ if (method == CANCEL) {
    overwritten with the flags of the INVITE. isflagset() can be used to
    check the flags of the previously forwarded INVITE in this case.
 
-   Example 1.70. t_lookup_cancel usage
+   Example 1.73. t_lookup_cancel usage
 if (method == CANCEL) {
         if (t_lookup_cancel()) {
                 log("INVITE transaction exists");
@@ -2148,7 +2241,7 @@ if (method == CANCEL) {
         # do the same as for INVITEs
 }
 
-5.35. t_drop_replies([mode])
+5.36. t_drop_replies([mode])
 
    Drops all the previously received replies in failure_route block to
    make sure that none of them is picked up again.
@@ -2160,7 +2253,7 @@ if (method == CANCEL) {
    Dropping replies works only if a new branch is added to the
    transaction, or it is explicitly replied in the script!
 
-   Example 1.71. t_drop_replies() usage
+   Example 1.74. t_drop_replies() usage
 ...
 failure_route[0]{
         if (t_check_status("5[0-9][0-9]")){
@@ -2176,7 +2269,7 @@ failure_route[0]{
         }
 }
 
-5.36. t_save_lumps()
+5.37. t_save_lumps()
 
    Forces the modifications of the processed SIP message to be saved in
    shared memory before t_relay() is called. The new branches which are
@@ -2191,7 +2284,7 @@ failure_route[0]{
    The transaction must be created by t_newtran() before calling
    t_save_lumps().
 
-   Example 1.72. t_save_lumps() usage
+   Example 1.75. t_save_lumps() usage
 route {
         ...
         t_newtran();
@@ -2216,7 +2309,7 @@ failure_route[1] {
         t_relay();
 }
 
-5.37. t_load_contacts()
+5.38. t_load_contacts()
 
    This is the first of the three functions that can be used to implement
    serial/parallel forking based on q and +sip.instance values of
@@ -2242,15 +2335,15 @@ failure_route[1] {
    before branches with lower ones when serial forking takes place.
 
    After calling t_load_contacts(), function t_next_contacts() and
-   possibly also t_next_contact_flows() need to be called one or more
-   times in order to retrieve the branches based on their q value.
+   possibly also t_next_contact_flow() need to be called one or more times
+   in order to retrieve the branches based on their q value.
 
    Function returns 1 if loading of contacts succeeded or there was
    nothing to do. In case of an error, function returns -1 (see syslog).
 
    This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.
 
-   Example 1.73. t_load_contacts usage
+   Example 1.76. t_load_contacts usage
 ...
 if (!t_load_contacts()) {
         sl_send_reply("500", "Server Internal Error - Cannot load contacts");
@@ -2258,7 +2351,7 @@ if (!t_load_contacts()) {
 };
 ...
 
-5.38. t_next_contacts()
+5.39. t_next_contacts()
 
    Function t_next_contacts() is the second of the three functions that
    can be used to implement serial/parallel forking based on the q value
@@ -2268,7 +2361,7 @@ if (!t_load_contacts()) {
    highest priority contacts in contacts_avp, but only one contact with
    the same +sip.instance value is included. Duplicate contacts are added
    to contact_flows_avp for later consumption by function
-   next_contact_flows(). Upon each call, Request URI is rewritten with the
+   next_contact_flow(). Upon each call, Request URI is rewritten with the
    first contact and the remaining contacts (if any) are added as
    branches. Then all highest priority contacts are removed from
    contacts_avp.
@@ -2291,7 +2384,7 @@ if (!t_load_contacts()) {
    contact_flows_avp are not anymore set. Based on that test, you can then
    use t_set_fr() function to set timers according to your needs.
 
-   Example 1.74. t_next_contacts usage
+   Example 1.77. t_next_contacts usage
 ...
 # First call after t_load_contacts() when transaction does not exist yet
 # and contacts should be available
@@ -2310,33 +2403,37 @@ if (!t_next_contacts()) {
 };
 ...
 
-5.39. t_next_contact_flows()
+5.40. t_next_contact_flow()
 
-   Function t_next_contact_flows() is the last of the three functions that
+   Function t_next_contact_flow() is the last of the three functions that
    can be used to implement serial/parallel forking based on the q value
-   of the individual branches in a destination set.
+   and instance value of individual branches in a destination set.
 
-   Function adds to request a new destination set that includes contacts
-   from contact_flows_avp, but only one contact with same +sip.instance
-   value is included. Upon each call, Request URI is rewritten with first
-   contact (if any) and the remaining contacts (if any) are added as
-   branches. Then the used contacts are removed from contact_flows_avp.
+   Function adds a new branch to the request that includes the first
+   contact from contact_flows_avp that matches the +sip.instance value of
+   the flow that has failed. Upon each call, Request URI is rewritten with
+   the contact. The used contact is removed from contact_flows_avp.
 
    Function does nothing if there are no contact_flows_avp values.
 
    Function returns 1 if contact_flows_avp was not empty and a destination
    set was successfully added, returns -2 if contacts_avp was empty and
    thus there was nothing to do, and returns -1 in case of an error (see
-   syslog). This function can be used from REQUEST_ROUTE and
-   FAILURE_ROUTE.
+   syslog). This function can be used from a BRANCH_FAILURE event route.
 
-   Example 1.75. t_next_contact_flows usage
+   Example 1.78. t_next_contact_flow usage
 ...
-if (!t_next_contact_flows())
-    t_next_contacts();
+event_route[tm:branch-failure:outbound]
+{
+        if (t_next_contact_flow())
+        {
+                t_relay();
+        } else {
+                xlog("L_INFO", "No more flows\n");
+        }
 ...
 
-5.40. t_check_status(re)
+5.41. t_check_status(re)
 
    Returns true if the regular expresion "re" match the reply code of the
    response message as follows:
@@ -2347,14 +2444,14 @@ if (!t_next_contact_flows())
 
    This function can be used from ANY_ROUTE .
 
-   Example 1.76. t_check_status usage
+   Example 1.79. t_check_status usage
 ...
 if (t_check_status("(487)|(408)")) {
     log("487 or 408 negative reply\n");
 }
 ...
 
-5.41. t_check_trans()
+5.42. t_check_trans()
 
    t_check_trans() can be used to quickly check if a message belongs or is
    related to a transaction. It behaves differently for different types of
@@ -2399,12 +2496,12 @@ Note
 
    See also: t_lookup_request(), t_lookup_cancel().
 
-   Example 1.77. t_check_trans usage
+   Example 1.80. t_check_trans usage
 if ( method == "CANCEL" && !t_check_trans())
         sl_reply("403", "cancel out of the blue forbidden");
 # note: in this example t_check_trans() can be replaced by t_lookup_cancel()
 
-5.42. t_set_disable_6xx(0|1)
+5.43. t_set_disable_6xx(0|1)
 
    Turn off/on 6xx replies special rfc conformant handling on a per
    transaction basis. If turned off (t_set_disable_6xx("1")) 6XXs will be
@@ -2414,7 +2511,7 @@ if ( method == "CANCEL" && !t_check_trans())
 
    See also: disable_6xx_block.
 
-   Example 1.78. t_set_disable_6xx usage
+   Example 1.81. t_set_disable_6xx usage
 ...
 route {
 ...
@@ -2423,13 +2520,13 @@ route {
 ...
 }
 
-5.43. t_set_disable_failover(0|1)
+5.44. t_set_disable_failover(0|1)
 
    Turn off/on dns failover on a per transaction basis.
 
    See also: use_dns_failover.
 
-   Example 1.79. t_set_disable_failover usage
+   Example 1.82. t_set_disable_failover usage
 ...
 route {
 ...
@@ -2438,11 +2535,11 @@ route {
 ...
 }
 
-5.44. t_set_disable_internal_reply(0|1)
+5.45. t_set_disable_internal_reply(0|1)
 
    Turn off/on sending internally a SIP reply in case of relay errors.
 
-   Example 1.80. t_set_disable_internal_reply usage
+   Example 1.83. t_set_disable_internal_reply usage
 ...
 t_set_disable_internal_reply(1); # turn off sending internal reply on error
 if(!t_relay()) {
@@ -2450,7 +2547,7 @@ if(!t_relay()) {
 }
 ...
 
-5.45. t_replicate(params)
+5.46. t_replicate(params)
 
    Replicate the SIP request to a specific address.
 
@@ -2472,7 +2569,7 @@ if(!t_relay()) {
      * hostport - address in "host:port" format. It can be given via an
        AVP.
 
-   Example 1.81. t_replicate usage
+   Example 1.84. t_replicate usage
 ...
 # sent to 1.2.3.4:5060 over tcp
 t_replicate("sip:1.2.3.4:5060;transport=tcp");
@@ -2485,7 +2582,7 @@ t_replicate("sip:$var(h);transport=tls");
 t_replicate_to_udp("1.2.3.4", "5060");
 ...
 
-5.46. t_relay_to(proxy, flags)
+5.47. t_relay_to(proxy, flags)
 
    Forward the SIP request to a specific address, controlling internal
    behavior via flags.
@@ -2506,7 +2603,7 @@ t_replicate_to_udp("1.2.3.4", "5060");
           + 0x02 - do not generate reply on internal error.
           + 0x04 - disable dns failover.
 
-   Example 1.82. t_replicate usage
+   Example 1.85. t_replicate usage
 ...
 # sent to 1.2.3.4:5060 over tcp
 t_relay_to("tcp:1.2.3.4:5060");
@@ -2518,7 +2615,7 @@ t_relay_to("tls:1.2.3.4");
 t_relay_to("0x01");
 ...
 
-5.47. t_set_no_e2e_cancel_reason(0|1)
+5.48. t_set_no_e2e_cancel_reason(0|1)
 
    Enables/disables reason header (RFC 3326) copying from the triggering
    received CANCEL to the generated hop-by-hop CANCEL. 0 enables and 1
@@ -2529,7 +2626,7 @@ t_relay_to("0x01");
 
    See also: e2e_cancel_reason.
 
-   Example 1.83. t_set_no_e2e_cancel_reason usage
+   Example 1.86. t_set_no_e2e_cancel_reason usage
 ...
 route {
 ...
@@ -2539,7 +2636,7 @@ opying
 ...
 }
 
-5.48. t_is_set(target)
+5.49. t_is_set(target)
 
    Return true if the attribute specified by 'target' is set for
    transaction.
@@ -2552,12 +2649,25 @@ opying
      * onreply_route - the function returns true if an onreply route is
        set to be executed.
 
-   Example 1.84. t_replicate usage
+   Example 1.87. t_replicate usage
 ...
 if(!t_is_set("failure_route"))
     LM_DBG("no failure route will be executed for current transaction\n");
 ...
 
+5.50. t_use_uac_headers()
+
+   Set internal flags to tell tm to use UAC side for building headers for
+   local generated requests (ACK, CANCEL) - useful when changing From/To
+   headers using other functions than uac_replace_[from|to]().
+
+   It returns true.
+
+   Example 1.88. t_use_uac_headers usage
+...
+t_use_uac_headers();
+...
+
 6. TM Module API
 
    6.1. Defines
@@ -2724,3 +2834,29 @@ action *route)
      * label - transaction identifier.
 
    Return value: 0 - success, <0 - error.
+
+7. Event Routes
+
+   7.1. event_route[tm:branch-failure]
+
+7.1. event_route[tm:branch-failure]
+
+   Named branch failure routes can be defined to run when when a failure
+   response is received. This allows handling failures on individual
+   branches, for example, retrying an alternative outbound flow.
+
+   The format of the event_route name is "tm:branch-failure:<name>" and is
+   enabled with the t_on_branch_failure function. This event_route uses
+   the BRANCH_FAILURE_ROUTE route type.
+
+   Example 1.89. event_route[tm:branch-failure] usage
+...
+route {
+    t_on_branch_failure("myroute");
+    t_relay();
+}
+
+event_route[tm:branch-failure:myroute] {
+    xlog("L_INFO", "Received $T_reply_code to $rm message\n");
+}
+...
diff --git a/modules/tm/doc/api.xml b/modules/tm/doc/api.xml
index 2a627ab..0a3c751 100644
--- a/modules/tm/doc/api.xml
+++ b/modules/tm/doc/api.xml
@@ -157,7 +157,7 @@ end of body
 		This function together with t_continue() can be used to
 		implement asynchronous actions: t_suspend() saves the transaction,
 		returns its identifiers, and t_continue() continues the
-		SIP request processing. (The request processing does not continue
+		SIP request/response processing. (The request/response processing does not continue
 		from the same point in the script, a separate route block defined
 		by the parameter of t_continue() is executed instead. The reply lock
 		is held during the route block execution.)
diff --git a/modules/tm/doc/event_routes.xml b/modules/tm/doc/event_routes.xml
new file mode 100644
index 0000000..5742ede
--- /dev/null
+++ b/modules/tm/doc/event_routes.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="tm.event_routes" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+    </sectioninfo>
+
+    <title>Event Routes</title>
+
+    <section id="tm.e.branch-failure">
+	<title>
+	    <function moreinfo="none">event_route[tm:branch-failure]</function>
+	</title>
+	<para>
+	    Named branch failure routes can be defined to run when when a failure response is received.
+            This allows handling failures on individual branches, for example, retrying an alternative outbound flow.
+	</para>
+        <para>
+	    The format of the event_route name is "tm:branch-failure:<name>" and is enabled with the t_on_branch_failure function.
+            This event_route uses the BRANCH_FAILURE_ROUTE route type.
+        </para>
+	<example>
+	    <title><function>event_route[tm:branch-failure]</function> usage</title>
+	    <programlisting>
+...
+route {
+    t_on_branch_failure("myroute");
+    t_relay();
+}
+
+event_route[tm:branch-failure:myroute] {
+    xlog("L_INFO", "Received $T_reply_code to $rm message\n");
+}
+...
+	    </programlisting>
+	</example>
+    </section>
+
+</section>
diff --git a/modules/tm/doc/functions.xml b/modules/tm/doc/functions.xml
index a5ce5a0..fba4e92 100644
--- a/modules/tm/doc/functions.xml
+++ b/modules/tm/doc/functions.xml
@@ -8,7 +8,7 @@
 
     <title>Functions</title>
 
-    <section id="t_relay">
+    <section id="tm.f.t_relay">
 	<title>
 	    <function>t_relay([host, port])</function>
 	</title>
@@ -49,7 +49,7 @@ if (!t_relay())
 	</example>
     </section>
 
-    <section id="t_relay_to_udp">
+    <section id="tm.f.t_relay_to_udp">
 	<title>
 	    <function>t_relay_to_udp([ip, port])</function>
 	</title>
@@ -90,7 +90,7 @@ else
 	</example>
     </section>
 
-    <section id="t_relay_to_tcp">
+    <section id="tm.f.t_relay_to_tcp">
 	<title>
 	    <function>t_relay_to_tcp([ip, port])</function>
 	</title>
@@ -99,7 +99,7 @@ else
 	</para>
     </section>
 
-    <section id="t_relay_to_tls">
+    <section id="tm.f.t_relay_to_tls">
 	<title>
 	    <function>t_relay_to_tls([ip, port])</function>
 	</title>
@@ -108,7 +108,7 @@ else
 	</para>
     </section>
 
-    <section id="t_relay_to_sctp">
+    <section id="tm.f.t_relay_to_sctp">
 	<title>
 	    <function>t_relay_to_sctp([ip, port])</function>
 	</title>
@@ -117,7 +117,7 @@ else
 	</para>
     </section>
 
-    <section id="t_on_failure">
+    <section id="tm.f.t_on_failure">
 	<title>
 	    <function>t_on_failure(failure_route)</function>
 	</title>
@@ -167,8 +167,52 @@ failure_route[1] {
 	    combination of serial with parallel forking.
 	</para>
     </section>
+     <section id="tm.f.t_on_branch_failure">
+	<title>
+	    <function>t_on_branch_failure(branch_failure_route)</function>
+	</title>
+	<para>
+	    Sets the branch_failure routing block, to which control is passed on each
+	    negative response to a transaction. This route is run before deciding if
+	    the transaction is complete. In the referred block, you can start a new
+	    branch which is required for failover of multiple outbound flows (RFC 5626).
+	    Note that the set of commands which are usable within a branch_failure route
+	    is limited to a subset of the failure_rotue commands including logging,
+	    rewriting URI and initiating new branches. Any other commands may generate
+	    errors or result in unpredictable behavior.
+	    Note that whenever failure_route is entered, uri is reset to
+	    value which it had on relaying. If it temporarily changed during a
+	    reply_route processing, subsequent reply_route will ignore the
+	    changed value and use again the original one.
+	</para>
+	<para>Function Parameters:</para>
+	<itemizedlist>
+	    <listitem>
+			<para><emphasis>branch_failure_route</emphasis> - Name of the branch_failure route
+			block to be called (it is prefixed internally with 'tm:branch-failure:').
+		</para>
+	    </listitem>
+	</itemizedlist>
+	<example>
+	    <title><function>t_on_branch_failure</function> usage</title>
+	    <programlisting>
+...
+route {
+    t_on_branch_failure("myroute");
+    t_relay();
+}
+
+event_route[tm:branch-failure:myroute] {
+    if (t_check_status("430|403") {
+        unregister("location", "$tu", "$T_reply_ruid");
+    }
+}
+...
+	    </programlisting>
+	</example>
+    </section>
  
-	 <section id="t_on_reply">
+	 <section id="tm.f.t_on_reply">
 	<title>
 	    <function>t_on_reply(onreply_route)</function>
 	</title>
@@ -211,7 +255,7 @@ onreply_route[1] {
 	</example>
 	</section>
 
-	<section id="t_on_branch">
+	<section id="tm.f.t_on_branch">
 	<title>
 	    <function>t_on_branch(branch_route)</function>
 	</title>
@@ -249,7 +293,7 @@ branch_route[1] {
 	</example>
 	</section>
 
-    <section id="t_newtran">
+    <section id="tm.f.t_newtran">
 	<title>
 	    <function>t_newtran()</function>
 	</title>
@@ -274,7 +318,7 @@ if (t_newtran()) {
 	</para>
     </section>
 
-    <section id="t_reply">
+    <section id="tm.f.t_reply">
 	<title>
 	    <function>t_reply(code, reason_phrase)</function>
 	</title>
@@ -303,7 +347,7 @@ t_reply("404", "Not found");
 	</example>
     </section>
 
-    <section id="t_lookup_request">
+    <section id="tm.f.t_lookup_request">
 	<title>
 	    <function>t_lookup_request()</function>
 	</title>
@@ -326,7 +370,7 @@ if (t_lookup_request()) {
 	</example>
     </section>
 
-    <section id="t_retransmit_reply">
+    <section id="tm.f.t_retransmit_reply">
 	<title>
 	    <function>t_retransmit_reply()</function>
 	</title>
@@ -343,7 +387,7 @@ t_retransmit_reply();
 	</example>
     </section>
 
-    <section id="t_release">
+    <section id="tm.f.t_release">
 	<title>
 	    <function>t_release()</function>
 	</title>
@@ -361,7 +405,7 @@ t_release();
 	</example>
     </section>
 
-    <section id="t_forward_nonack">
+    <section id="tm.f.t_forward_nonack">
 	<title>
 	    <function>t_forward_nonack([ip, port])</function>
 	</title>
@@ -390,7 +434,7 @@ t_forward_nonack("1.2.3.4", "5060");
 	</example>
     </section>
 
-   <section id="t_forward_nonack_udp">
+   <section id="tm.f.t_forward_nonack_udp">
 	<title>
 	    <function>t_forward_nonack_udp(ip, port)</function>
 	</title>
@@ -399,7 +443,7 @@ t_forward_nonack("1.2.3.4", "5060");
 	</para>
     </section>
 
-   <section id="t_forward_nonack_tcp">
+   <section id="tm.f.t_forward_nonack_tcp">
 	<title>
 	    <function>t_forward_nonack_tcp(ip, port)</function>
 	</title>
@@ -408,7 +452,7 @@ t_forward_nonack("1.2.3.4", "5060");
 	</para>
     </section>
 
-   <section id="t_forward_nonack_tls">
+   <section id="tm.f.t_forward_nonack_tls">
 	<title>
 	    <function>t_forward_nonack_tls(ip, port)</function>
 	</title>
@@ -417,7 +461,7 @@ t_forward_nonack("1.2.3.4", "5060");
 	</para>
     </section>
 
-   <section id="t_forward_nonack_sctp">
+   <section id="tm.f.t_forward_nonack_sctp">
 	<title>
 	    <function>t_forward_nonack_sctp(ip, port)</function>
 	</title>
@@ -426,7 +470,7 @@ t_forward_nonack("1.2.3.4", "5060");
 	</para>
     </section>
 
-	<section id="t_set_fr">
+	<section id="tm.f.t_set_fr">
 	<title>
 	    <function>t_set_fr(fr_inv_timeout [, fr_timeout])</function>
 	</title>
@@ -480,7 +524,7 @@ branch_route[1] {
 	</example>
 	</section>
 
-	<section id="t_reset_fr">
+	<section id="tm.f.t_reset_fr">
 	<title>
 	    <function>t_reset_fr()</function>
 	</title>
@@ -513,7 +557,7 @@ route {
 	</section>
 
 
-	<section id="t_set_max_lifetime">
+	<section id="tm.f.t_set_max_lifetime">
 	<title>
 	    <function>t_set_max_lifetime(inv_lifetime, noninv_lifetime)</function>
 	</title>
@@ -563,7 +607,7 @@ route {
 	</example>
 	</section>
 
-	<section id="t_reset_max_lifetime">
+	<section id="tm.f.t_reset_max_lifetime">
 	<title>
 	    <function>t_reset_max_lifetime()</function>
 	</title>
@@ -595,7 +639,7 @@ route {
 	</example>
 	</section>
 
-	<section id="t_set_retr">
+	<section id="tm.f.t_set_retr">
 	<title>
 	    <function>t_set_retr(retr_t1_interval, retr_t2_interval)</function>
 	</title>
@@ -665,7 +709,7 @@ branch_route[1] {
 	</section>
 
 
-	<section id="t_reset_retr">
+	<section id="tm.f.t_reset_retr">
 	<title>
 	    <function>t_reset_retr()</function>
 	</title>
@@ -697,7 +741,7 @@ route {
 	</example>
 	</section>
 
-	<section id="t_set_auto_inv_100">
+	<section id="tm.f.t_set_auto_inv_100">
 	<title>
 	    <function>t_set_auto_inv_100(0|1)</function>
 	</title>
@@ -723,14 +767,15 @@ route {
 	</example>
 	</section>
 
-	<section id="t_branch_timeout">
+	<section id="tm.f.t_branch_timeout">
 	<title>
 	    <function>t_branch_timeout()</function>
 	</title>
 	<para>
 		Returns true if the failure route is executed for a branch that did
-		timeout. It can be used only from the 
-		<emphasis>failure_route</emphasis>.
+		timeout. It can be used from 
+		<emphasis>failure_route</emphasis> and
+		<emphasis>branch-failure</emphasis> event route.
 	</para>
 	<example>
 	    <title><function>t_branch_timeout</function> usage</title>
@@ -746,15 +791,16 @@ failure_route[0]{
 	</example>
 	</section>
 
-<section id="t_branch_replied">
+<section id="tm.f.t_branch_replied">
 	<title>
 	    <function>t_branch_replied()</function>
 	</title>
 	<para>
 		Returns true if the failure route is executed for a branch that did
 		receive at least one reply in the past (the "current" reply is not 
-		taken into account). It can be used only from the 
-		<emphasis>failure_route</emphasis>.
+		taken into account). It can be used from
+		<emphasis>failure_route</emphasis>  and
+		<emphasis>branch-failure</emphasis> event route.
 	</para>
 	<example>
 	    <title><function>t_branch_replied</function> usage</title>
@@ -773,7 +819,7 @@ failure_route[0]{
 	</example>
 	</section>
 
-<section id="t_any_timeout">
+<section id="tm.f.t_any_timeout">
 	<title>
 	    <function>t_any_timeout()</function>
 	</title>
@@ -797,7 +843,7 @@ failure_route[0]{
 	</example>
 	</section>
 
-<section id="t_any_replied">
+<section id="tm.f.t_any_replied">
 	<title>
 	    <function>t_any_replied()</function>
 	</title>
@@ -820,7 +866,7 @@ onreply_route[0]{
 	</example>
 </section>
 
-<section id="t_grep_status">
+<section id="tm.f.t_grep_status">
 	<title>
 	    <function>t_grep_status("code")</function>
 	</title>
@@ -842,7 +888,7 @@ onreply_route[0]{
 	</example>
 </section>
 
-<section id="t_is_canceled">
+<section id="tm.f.t_is_canceled">
 	<title>
 	    <function>t_is_canceled()</function>
 	</title>
@@ -863,7 +909,7 @@ failure_route[0]{
 	</example>
 	</section>
 
-	<section id="t_is_expired">
+	<section id="tm.f.t_is_expired">
 	<title>
 	    <function>t_is_expired()</function>
 	</title>
@@ -886,7 +932,7 @@ failure_route[0]{
 	</example>
 	</section>
 
-    <section id="t_relay_cancel">
+    <section id="tm.f.t_relay_cancel">
 	<title>
 	    <function>t_relay_cancel()</function>
 	</title>
@@ -922,7 +968,7 @@ if (method == CANCEL) {
 	</example>
     </section>
 
-    <section id="t_lookup_cancel">
+    <section id="tm.f.t_lookup_cancel">
 	<title>
 	    <function>t_lookup_cancel([1])</function>
 	</title>
@@ -965,7 +1011,7 @@ if (method == CANCEL) {
 	</example>
     </section>
 
-    <section id="t_drop_replies">
+    <section id="tm.f.t_drop_replies">
 	<title>
 	    <function>t_drop_replies([mode])</function>
 	</title>
@@ -1003,7 +1049,7 @@ failure_route[0]{
 	</example>
     </section>
 
-    <section id="t_save_lumps">
+    <section id="tm.f.t_save_lumps">
 	<title>
 	    <function>t_save_lumps()</function>
 	</title>
@@ -1054,7 +1100,7 @@ failure_route[1] {
 	</example>
     </section>
 
-	<section>
+	<section id="tm.f.t_load_contacts">
 		<title>
 		<function moreinfo="none">t_load_contacts()</function>
 		</title>
@@ -1096,7 +1142,7 @@ failure_route[1] {
 		<para>
 		  After calling <function>t_load_contacts()</function>, function
 		  <function>t_next_contacts()</function> and possibly
-		  also <function>t_next_contact_flows()</function> need
+		  also <function>t_next_contact_flow()</function> need
 		  to be called
 		  one or more times in order to retrieve the branches based
 		  on their q value.
@@ -1122,7 +1168,7 @@ if (!t_load_contacts()) {
 		</example>
 	</section>
 
-	<section>
+	<section id="tm.f.t_next_contacts">
 		<title>
 		<function moreinfo="none">t_next_contacts()</function>
 		</title>
@@ -1139,7 +1185,7 @@ if (!t_load_contacts()) {
 		  but only one contact with the same +sip.instance value is
 		  included.  Duplicate contacts are added to contact_flows_avp
 		  for later consumption by function 
-		  <function>next_contact_flows()</function>.
+		  <function>next_contact_flow()</function>.
 		  Upon each call, Request URI is rewritten with
 		  the first contact and the remaining contacts (if any) are
 		  added as branches. Then all highest priority contacts
@@ -1202,25 +1248,22 @@ if (!t_next_contacts()) {
 		</example>
 	</section>
 
-	<section>
+	<section id="tm.f.t_next_contact_flow">
 		<title>
-		<function moreinfo="none">t_next_contact_flows()</function>
+		<function moreinfo="none">t_next_contact_flow()</function>
 		</title>
 		<para>
-		  Function <function>t_next_contact_flows()</function> 
+		  Function <function>t_next_contact_flow()</function>
 		  is the last of the three functions that can be used to
-		  implement serial/parallel
-		  forking based on the q value of the individual branches
-		  in a destination set.
+		  implement serial/parallel forking based on the q value
+		  and instance value of individual branches in a destination set.
 		</para>
 		<para>
-		  Function adds to request a new destination set that
-		  includes contacts from <varname>contact_flows_avp</varname>,
-		  but only one contact with same +sip.instance value is
-		  included.  Upon each call, Request URI is rewritten with
-		  first contact (if any) and the remaining contacts (if any) are
-		added as branches. Then the used contacts
-		are removed from <varname>contact_flows_avp</varname>.
+		  Function adds a new branch to the request that includes
+		  the first contact from <varname>contact_flows_avp</varname>
+		  that matches the +sip.instance value of the flow that has failed.
+		  Upon each call, Request URI is rewritten with the contact. The
+		  used contact is removed from <varname>contact_flows_avp</varname>.
 		</para>
 		<para>
 		  Function does nothing if there are
@@ -1228,20 +1271,25 @@ if (!t_next_contacts()) {
 		</para>
 		<para>
 		Function returns 1 if <varname>contact_flows_avp</varname>
-		was not empty and a
-		destination set was successfully added,
+		was not empty and a destination set was successfully added,
 		returns -2 if <varname>contacts_avp</varname>
 		was empty and thus there was
 		nothing to do, and returns -1 in case of an error (see
 		syslog).
-          	This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.
+		This function can be used from a BRANCH_FAILURE event route.
 		</para>
 		<example>
-		<title><function>t_next_contact_flows</function> usage</title>
+		<title><function>t_next_contact_flow</function> usage</title>
 		<programlisting format="linespecific">
 ...
-if (!t_next_contact_flows())
-    t_next_contacts();
+event_route[tm:branch-failure:outbound]
+{
+	if (t_next_contact_flow())
+	{
+		t_relay();
+	} else {
+		xlog("L_INFO", "No more flows\n");
+	}
 ...
 </programlisting>
 		</example>
@@ -1365,7 +1413,7 @@ if ( method == "CANCEL" && !t_check_trans())
 	</example>
 	</section>
 
-	<section id="t_set_disable_6xx">
+	<section id="tm.f.t_set_disable_6xx">
 	<title>
 		<function>t_set_disable_6xx(0|1)</function>
 	</title>
@@ -1396,7 +1444,7 @@ route {
 	</example>
 	</section>
 
-	<section id="t_set_disable_failover">
+	<section id="tm.f.t_set_disable_failover">
 	<title>
 		<function>t_set_disable_failover(0|1)</function>
 	</title>
@@ -1424,10 +1472,10 @@ route {
 	<title>
 		<function>t_set_disable_internal_reply(0|1)</function>
 	</title>
-		<para>
+	<para>
 		Turn off/on sending internally a SIP reply in case of relay errors.
-		</para>
-		<example>
+	</para>
+	<example>
 		<title><function>t_set_disable_internal_reply</function> usage</title>
 		<programlisting>
 ...
@@ -1437,10 +1485,10 @@ if(!t_relay()) {
 }
 ...
 		</programlisting>
-		</example>
+	</example>
 	</section>
 
-	<section id="t_replicate">
+	<section id="tm.f.t_replicate">
 	<title>
 	    <function>t_replicate(params)</function>
 	</title>
@@ -1515,7 +1563,7 @@ t_replicate_to_udp("1.2.3.4", "5060");
 	    </programlisting>
 	</example>
     </section>
-	<section id="t_relay_to">
+	<section id="tm.f.t_relay_to">
 	<title>
 	    <function>t_relay_to(proxy, flags)</function>
 	</title>
@@ -1587,7 +1635,7 @@ t_relay_to("0x01");
     </section>
 
 
-	<section id="t_set_no_e2e_cancel_reason">
+	<section id="tm.f.t_set_no_e2e_cancel_reason">
 	<title>
 		<function>t_set_no_e2e_cancel_reason(0|1)</function>
 	</title>
@@ -1617,7 +1665,7 @@ route {
 	</example>
 	</section>
 
-	<section id="t_is_set">
+	<section id="tm.f.t_is_set">
 	<title>
 	    <function>t_is_set(target)</function>
 	</title>
@@ -1653,4 +1701,24 @@ if(!t_is_set("failure_route"))
 	</example>
     </section>
 
+	<section id="tm.f.t_use_uac_headers">
+	<title>
+	    <function>t_use_uac_headers()</function>
+	</title>
+	<para>
+	Set internal flags to tell tm to use UAC side for building headers for
+	local generated requests (ACK, CANCEL) - useful when changing From/To
+	headers using other functions than uac_replace_[from|to]().
+	</para>
+	<para>It returns true.</para>
+	<example>
+	    <title><function>t_use_uac_headers</function> usage</title>
+	    <programlisting>
+...
+t_use_uac_headers();
+...
+	    </programlisting>
+	</example>
+    </section>
+
 </section>
diff --git a/modules/tm/doc/params.xml b/modules/tm/doc/params.xml
index 3f09467..4d3bf26 100644
--- a/modules/tm/doc/params.xml
+++ b/modules/tm/doc/params.xml
@@ -1357,4 +1357,55 @@ modparam("tm", "remap_503_500", 0)
 		</example>
 	</section>
 
+	<section id="tm.p.failure_exec_mode">
+		<title><varname>failure_exec_mode</varname> (boolean)</title>
+		<para>
+			Add local failed branches in timer to be cosidered for failure
+			routing blocks. If disabled, relay functions will return false
+			in case the branch could not be forwarded (default behaviour
+			before v4.1.0).
+		</para>
+		<para>
+			Default value is 0 (disabled).
+		</para>
+		<example>
+			<title>Set <varname>failure_exec_mode</varname> parameter</title>
+			<programlisting>
+...
+modparam("tm", "failure_exec_mode", 1)
+...
+			</programlisting>
+		</example>
+	</section>
+
+
+	<section id="tm.p.dns_reuse_rcv_socket">
+		<title><varname>dns_reuse_rcv_socket</varname> (boolean)</title>
+		<para>
+			Control reuse of the receive socket for additional branches added
+			by dns failover. If set to 1, the receive socket is used for
+			sending out the new branches, unless the socket is forced
+			explicitely in configuration file. If set to 0, selected socket
+			is done depending on value of global parameter mhomed (if mhomed=0,
+			then the first listen socket is used, otherwise the socket is
+			selected based on routing rules).
+		</para>
+		<para>
+			Do enable it with caution, it might create troubles on dns results
+			with different transport layer. Better let it disabled and enable
+			mhomed.
+		</para>
+		<para>
+			Default value is 0 (disabled).
+		</para>
+		<example>
+			<title>Set <varname>dns_reuse_rcv_socket</varname> parameter</title>
+			<programlisting>
+...
+modparam("tm", "dns_reuse_rcv_socket", 1)
+...
+			</programlisting>
+		</example>
+	</section>
+
 </section>
diff --git a/modules/tm/doc/tm.xml b/modules/tm/doc/tm.xml
index bd5f9ce..3ecb80a 100644
--- a/modules/tm/doc/tm.xml
+++ b/modules/tm/doc/tm.xml
@@ -350,5 +350,6 @@ failure_route["serial"]
     <xi:include href="params.xml"/>
     <xi:include href="functions.xml"/>
     <xi:include href="api.xml"/>
+    <xi:include href="event_routes.xml"/>
     </chapter>
 </book>
diff --git a/modules/tm/h_table.c b/modules/tm/h_table.c
index 663b0ea..26ca3e3 100644
--- a/modules/tm/h_table.c
+++ b/modules/tm/h_table.c
@@ -256,27 +256,25 @@ static inline void init_synonym_id( struct cell *t )
 	char *c;
 	unsigned int myrand;
 
-	if (!syn_branch) {
-		p_msg=t->uas.request;
-		if (p_msg) {
-			/* char value of a proxied transaction is
-			   calculated out of header-fields forming
-			   transaction key
-			*/
-			char_msg_val( p_msg, t->md5 );
-		} else {
-			/* char value for a UAC transaction is created
-			   randomly -- UAC is an originating stateful element 
-			   which cannot be refreshed, so the value can be
-			   anything
-			*/
-			/* HACK : not long enough */
-			myrand=rand();
-			c=t->md5;
-			size=MD5_LEN;
-			memset(c, '0', size );
-			int2reverse_hex( &c, &size, myrand );
-		}
+	p_msg=t->uas.request;
+	if (p_msg) {
+		/* char value of a proxied transaction is
+		   calculated out of header-fields forming
+		   transaction key
+		*/
+		char_msg_val( p_msg, t->md5 );
+	} else {
+		/* char value for a UAC transaction is created
+		   randomly -- UAC is an originating stateful element
+		   which cannot be refreshed, so the value can be
+		   anything
+		*/
+		/* HACK : not long enough */
+		myrand=rand();
+		c=t->md5;
+		size=MD5_LEN;
+		memset(c, '0', size );
+		int2reverse_hex( &c, &size, myrand );
 	}
 }
 
@@ -309,10 +307,9 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 	sr_xavp_t** xold;
 #endif
 
-	/* allocs a new cell */
-	/* if syn_branch==0 add space for md5 (MD5_LEN -sizeof(struct cell.md5)) */
+	/* allocs a new cell, add space for md5 (MD5_LEN - sizeof(struct cell.md5)) */
 	new_cell = (struct cell*)shm_malloc( sizeof( struct cell )+
-			((MD5_LEN-sizeof(((struct cell*)0)->md5))&((syn_branch!=0)-1)) );
+			MD5_LEN-sizeof(((struct cell*)0)->md5) );
 	if  ( !new_cell ) {
 		ser_error=E_OUT_OF_MEM;
 		return NULL;
@@ -383,6 +380,7 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 
 	init_synonym_id(new_cell);
 	init_cell_lock(  new_cell );
+	init_async_lock( new_cell );
 	t_stats_created();
 	return new_cell;
 
diff --git a/modules/tm/h_table.h b/modules/tm/h_table.h
index d13cd9b..5790935 100644
--- a/modules/tm/h_table.h
+++ b/modules/tm/h_table.h
@@ -91,6 +91,7 @@ struct cell;
 struct timer;
 struct retr_buf;
 struct ua_client;
+struct async_state;
 
 #include "../../mem/shm_mem.h"
 #include "lock.h"
@@ -214,6 +215,7 @@ typedef struct ua_client
 {
 	/* if we store a reply (branch picking), this is where it is */
 	struct sip_msg  *reply;
+	char *end_reply;	/* pointer to end of sip_msg so we know the shm blocked used in clone...(used in async replies) */
 	struct retr_buf  request;
 	/* we maintain a separate copy of cancel rather than
 	   reuse the structure for original request; the 
@@ -229,6 +231,9 @@ typedef struct ua_client
 #endif
 	str uri;
 	str path;
+	str instance;
+	str ruid;
+	str location_ua;
 	/* if we don't store, we at least want to know the status */
 	int             last_received;
 
@@ -236,7 +241,11 @@ typedef struct ua_client
 	/* internal flags per tm uac */
 	unsigned int flags;
 #endif
+	/* per branch flags */
 	flag_t branch_flags;
+	/* internal processing code - (mapping over sip warning codes)
+	 * - storing the code giving a clue of what happened internally */
+	int icode;
 #ifdef WITH_AS_SUPPORT
 	/**
 	 * Resent for every rcvd 2xx reply.
@@ -249,8 +258,12 @@ typedef struct ua_client
 #endif
 	/* the route to take if no final positive reply arrived */
 	unsigned short on_failure;
+	/* the route to take for all failure replies */
+	unsigned short on_branch_failure;
 	/* the onreply_route to be processed if registered to do so */
 	unsigned short on_reply;
+	/* unused - keep the structure aligned to 32b */
+	unsigned short on_unused;
 }ua_client_type;
 
 
@@ -260,7 +273,13 @@ struct totag_elem {
 	volatile int acked;
 };
 
-
+/* structure for storing transaction state prior to suspending of async transactions */
+typedef struct async_state {
+	unsigned int backup_route;
+	unsigned int backup_branch;
+	unsigned int blind_uac;
+	unsigned int ruri_new;
+} async_state_type;
 
 /* transaction's flags */
 /* is the transaction's request an INVITE? */
@@ -298,8 +317,9 @@ struct totag_elem {
 #	define T_PASS_PROVISIONAL_FLAG (1<<11)
 #	define pass_provisional(_t_)	((_t_)->flags&T_PASS_PROVISIONAL_FLAG)
 #endif
+#define T_ASYNC_CONTINUE (1<<12) /* Is this transaction in a continuation after being suspended */
 
-#define T_DISABLE_INTERNAL_REPLY (1<<12) /* don't send internal negative reply */
+#define T_DISABLE_INTERNAL_REPLY (1<<13) /* don't send internal negative reply */
 
 /* unsigned short should be enough for a retr. timer: max. 65535 ms =>
  * max retr. = 65 s which should be enough and saves us 2*2 bytes */
@@ -406,6 +426,9 @@ typedef struct cell
 	/* UA Clients */
 	struct ua_client  uac[ MAX_BRANCHES ];
 	
+	/* store transaction state to be used for async transactions */
+	struct async_state async_backup;
+	
 	/* to-tags of 200/INVITEs which were received from downstream and 
 	 * forwarded or passed to UAC; note that there can be arbitrarily 
 	 * many due to downstream forking; */
@@ -424,7 +447,9 @@ typedef struct cell
 
 	/* protection against concurrent reply processing */
 	ser_lock_t   reply_mutex;
-	
+	/* protect against concurrent async continues */
+	ser_lock_t   async_mutex;
+		
 	ticks_t fr_timeout;     /* final response interval for retr_bufs */
 	ticks_t fr_inv_timeout; /* final inv. response interval for retr_bufs */
 #ifdef TM_DIFF_RT_TIMEOUT
@@ -439,13 +464,15 @@ typedef struct cell
 
 	/* the route to take if no final positive reply arrived */
 	unsigned short on_failure;
+	/* the route to take for all failure replies */
+	unsigned short on_branch_failure;
 	/* the onreply_route to be processed if registered to do so */
 	unsigned short on_reply;
 	 /* The route to take for each downstream branch separately */
 	unsigned short on_branch;
 
-	/* place holder for MD5checksum  (meaningful only if syn_branch=0) */
-	char md5[0]; /* if syn_branch==0 then MD5_LEN bytes are extra alloc'ed*/
+	/* place holder for MD5checksum, MD5_LEN bytes are extra alloc'ed */
+	char md5[0];
 
 } tm_cell_t;
 
diff --git a/modules/tm/lock.c b/modules/tm/lock.c
index 461f58e..bcd7192 100644
--- a/modules/tm/lock.c
+++ b/modules/tm/lock.c
@@ -71,6 +71,7 @@
 static int sem_nr;
 gen_lock_set_t* entry_semaphore=0;
 gen_lock_set_t* reply_semaphore=0;
+gen_lock_set_t* async_semaphore=0;
 #endif
 
 
@@ -100,6 +101,10 @@ again:
 			lock_set_destroy(reply_semaphore);
 			lock_set_dealloc(reply_semaphore);
 		}
+		if (async_semaphore!=0){
+			lock_set_destroy(async_semaphore);
+			lock_set_dealloc(async_semaphore);
+		}
 		
 		if (i==0){
 			LOG(L_CRIT, "lock_initialize: could not allocate semaphore"
@@ -154,6 +159,20 @@ again:
 			i--;
 			goto again;
 	}
+	i++;
+	if (((async_semaphore=lock_set_alloc(i))==0)||
+		(lock_set_init(async_semaphore)==0)){
+			if (async_semaphore){
+				lock_set_dealloc(async_semaphore);
+				async_semaphore=0;
+			}
+			DBG("DEBUG:lock_initialize: async semaphore initialization"
+				" failure: %s\n", strerror(errno));
+			probe_run=1;
+			i--;
+			goto again;
+	}
+	
 
 	/* return success */
 	LOG(L_INFO, "INFO: semaphore arrays of size %d allocated\n", sem_nr );
@@ -193,7 +212,11 @@ void lock_cleanup()
 		lock_set_destroy(reply_semaphore);
 		lock_set_dealloc(reply_semaphore);
 	};
-	entry_semaphore =  reply_semaphore = 0;
+	if (async_semaphore !=0) {
+		lock_set_destroy(async_semaphore);
+		lock_set_dealloc(async_semaphore);
+	};
+	entry_semaphore =  reply_semaphore = async_semaphore = 0;
 
 }
 #endif /*GEN_LOCK_T_PREFERED*/
@@ -229,7 +252,16 @@ int init_entry_lock( struct s_table* ht, struct entry *entry )
 	return 0;
 }
 
-
+int init_async_lock( struct cell *cell )
+{
+#ifdef GEN_LOCK_T_PREFERED
+	lock_init(&cell->async_mutex);
+#else
+	cell->async_mutex.semaphore_set=async_semaphore;
+	cell->async_mutex.semaphore_index = cell->hash_index % sem_nr;
+#endif /* GEN_LOCK_T_PREFERED */
+	return 0;
+}
 
 int release_cell_lock( struct cell *cell )
 {
diff --git a/modules/tm/lock.h b/modules/tm/lock.h
index ee06cab..90c76b3 100644
--- a/modules/tm/lock.h
+++ b/modules/tm/lock.h
@@ -76,6 +76,7 @@ void lock_cleanup(void);
 
 int init_cell_lock( struct cell *cell );
 int init_entry_lock( struct s_table* ht, struct entry *entry );
+int init_async_lock( struct cell *cell );
 
 
 int release_cell_lock( struct cell *cell );
diff --git a/modules/tm/t_cancel.c b/modules/tm/t_cancel.c
index ccd2212..1b39648 100644
--- a/modules/tm/t_cancel.c
+++ b/modules/tm/t_cancel.c
@@ -285,7 +285,7 @@ int cancel_branch( struct cell *t, int branch,
 			(t->uas.request && t->uas.request->msg_flags&(FL_USE_UAC_FROM|FL_USE_UAC_TO))) {
 		/* build the CANCEL from the INVITE which was sent out */
 		cancel = build_local_reparse(t, branch, &len, CANCEL, CANCEL_LEN,
-									 (t->uas.request->msg_flags&FL_USE_UAC_TO)?0:&t->to
+									 (t->uas.request && t->uas.request->msg_flags&FL_USE_UAC_TO)?0:&t->to
 	#ifdef CANCEL_REASON_SUPPORT
 									 , reason
 	#endif /* CANCEL_REASON_SUPPORT */
diff --git a/modules/tm/t_funcs.c b/modules/tm/t_funcs.c
index 729b537..531f4bd 100644
--- a/modules/tm/t_funcs.c
+++ b/modules/tm/t_funcs.c
@@ -373,6 +373,7 @@ handle_ret:
 			set_kr(REQ_ERR_DELAYED);
 			DBG("%d error reply generation delayed \n", ser_error);
 #else
+
 			reply_ret=kill_transaction( t, ser_error );
 			if (reply_ret>0) {
 				/* we have taken care of all -- do nothing in
diff --git a/modules/tm/t_fwd.c b/modules/tm/t_fwd.c
index 9659f6f..af4952b 100644
--- a/modules/tm/t_fwd.c
+++ b/modules/tm/t_fwd.c
@@ -126,6 +126,9 @@
 #include "../../atomic_ops.h" /* membar_depends() */
 
 
+extern int tm_failure_exec_mode;
+extern int tm_dns_reuse_rcv_socket;
+
 static int goto_on_branch = 0, branch_route = 0;
 
 void t_on_branch( unsigned int go_to )
@@ -187,7 +190,9 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 									str* next_hop,
 									struct socket_info* fsocket,
 									snd_flags_t snd_flags,
-									int fproto, int flags)
+									int fproto, int flags,
+									str *instance, str *ruid,
+									str *location_ua)
 {
 	char *shbuf;
 	struct lump* add_rm_backup, *body_lumps_backup;
@@ -200,6 +205,12 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 	int dst_uri_backed_up;
 	str path_bak;
 	int free_path;
+	str instance_bak;
+	int free_instance;
+	str ruid_bak;
+	int free_ruid;
+	str ua_bak;
+	int free_ua;
 	int backup_route_type;
 	snd_flags_t fwd_snd_flags_bak;
 	snd_flags_t rpl_snd_flags_bak;
@@ -219,6 +230,15 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 	path_bak.s=0;
 	path_bak.len=0;
 	free_path=0;
+	instance_bak.s=0;
+	instance_bak.len=0;
+	free_instance=0;
+	ruid_bak.s=0;
+	ruid_bak.len=0;
+	free_ruid=0;
+	ua_bak.s=0;
+	ua_bak.len=0;
+	free_ua=0;
 	dst=&t->uac[branch].request.dst;
 
 	/* ... we calculate branch ... */	
@@ -259,6 +279,9 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 	parsed_uri_bak=i_req->parsed_uri;
 	parsed_uri_ok_bak=i_req->parsed_uri_ok;
 	path_bak=i_req->path_vec;
+	instance_bak=i_req->instance;
+	ruid_bak=i_req->ruid;
+	ua_bak=i_req->location_ua;
 	
 	if (unlikely(branch_route || has_tran_tmcbs(t, TMCB_REQUEST_FWDED))){
 		/* dup uris, path a.s.o. if we have a branch route or callback */
@@ -292,6 +315,53 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 			}
 			free_path=1;
 		}
+		/* update instance */
+		/* if instance points to msg instance, it needs to be "fixed" so that we 
+		   can change/update msg->instance */
+		if (instance==&i_req->instance)
+			instance=&instance_bak;
+		/* zero it first so that set_instance will work */
+		i_req->instance.s=0;
+		i_req->instance.len=0;
+		if (unlikely(instance)){
+			if (unlikely(set_instance(i_req, instance)<0)){
+				ret=E_OUT_OF_MEM;
+				goto error03;
+			}
+			free_instance=1;
+		}
+
+		/* update ruid */
+		/* if ruid points to msg ruid, it needs to be "fixed" so that we 
+		   can change/update msg->ruid */
+		if (ruid==&i_req->ruid)
+			ruid=&ruid_bak;
+		/* zero it first so that set_ruid will work */
+		i_req->ruid.s=0;
+		i_req->ruid.len=0;
+		if (unlikely(ruid)){
+			if (unlikely(set_ruid(i_req, ruid)<0)){
+				ret=E_OUT_OF_MEM;
+				goto error03;
+			}
+			free_ruid=1;
+		}
+
+		/* update location_ua */
+		/* if location_ua points to msg location_ua, it needs to be "fixed" so that we 
+		   can change/update msg->location_ua */
+		if (location_ua==&i_req->location_ua)
+			location_ua=&ua_bak;
+		/* zero it first so that set_ua will work */
+		i_req->location_ua.s=0;
+		i_req->location_ua.len=0;
+		if (unlikely(location_ua)){
+			if (unlikely(set_ua(i_req, location_ua)<0)){
+				ret=E_OUT_OF_MEM;
+				goto error03;
+			}
+			free_ua=1;
+		}
 	
 		/* backup dst uri  & zero it*/
 		dst_uri_bak=i_req->dst_uri;
@@ -397,6 +467,27 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 			i_req->path_vec.s=0;
 			i_req->path_vec.len=0;
 		}
+		if (unlikely(instance && (i_req->instance.s!=instance->s ||
+							  i_req->instance.len!=instance->len))){
+			i_req->instance=*instance;
+		}else if (unlikely(instance==0 && i_req->instance.len!=0)){
+			i_req->instance.s=0;
+			i_req->instance.len=0;
+		}
+		if (unlikely(ruid && (i_req->ruid.s!=ruid->s ||
+							  i_req->ruid.len!=ruid->len))){
+			i_req->ruid=*ruid;
+		}else if (unlikely(ruid==0 && i_req->ruid.len!=0)){
+			i_req->ruid.s=0;
+			i_req->ruid.len=0;
+		}
+		if (unlikely(location_ua && (i_req->location_ua.s!=location_ua->s ||
+							  i_req->location_ua.len!=location_ua->len))){
+			i_req->location_ua=*location_ua;
+		}else if (unlikely(location_ua==0 && i_req->location_ua.len!=0)){
+			i_req->location_ua.s=0;
+			i_req->location_ua.len=0;
+		}
 	}
 	
 	if (likely(next_hop!=0 || (flags & UAC_DNS_FAILOVER_F))){
@@ -420,6 +511,7 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 	/* Set on_reply and on_negative handlers for this branch to the handlers in the transaction */
 	t->uac[branch].on_reply = t->on_reply;
 	t->uac[branch].on_failure = t->on_failure;
+	t->uac[branch].on_branch_failure = t->on_branch_failure;
 
 	/* check if send_sock is ok */
 	if (t->uac[branch].request.dst.send_sock==0) {
@@ -463,6 +555,51 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 		t->uac[branch].path.s[i_req->path_vec.len]=0;
 		memcpy( t->uac[branch].path.s, i_req->path_vec.s, i_req->path_vec.len);
 	}
+	if (unlikely(i_req->instance.s && i_req->instance.len)){
+		t->uac[branch].instance.s=shm_malloc(i_req->instance.len+1);
+		if (unlikely(t->uac[branch].instance.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=E_OUT_OF_MEM;
+			goto error01;
+		}
+		t->uac[branch].instance.len=i_req->instance.len;
+		t->uac[branch].instance.s[i_req->instance.len]=0;
+		memcpy( t->uac[branch].instance.s, i_req->instance.s, i_req->instance.len);
+	}
+	if (unlikely(i_req->ruid.s && i_req->ruid.len)){
+		t->uac[branch].ruid.s=shm_malloc(i_req->ruid.len+1);
+		if (unlikely(t->uac[branch].ruid.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=E_OUT_OF_MEM;
+			goto error01;
+		}
+		t->uac[branch].ruid.len=i_req->ruid.len;
+		t->uac[branch].ruid.s[i_req->ruid.len]=0;
+		memcpy( t->uac[branch].ruid.s, i_req->ruid.s, i_req->ruid.len);
+	}
+	if (unlikely(i_req->location_ua.s && i_req->location_ua.len)){
+		t->uac[branch].location_ua.s=shm_malloc(i_req->location_ua.len+1);
+		if (unlikely(t->uac[branch].location_ua.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=E_OUT_OF_MEM;
+			goto error01;
+		}
+		t->uac[branch].location_ua.len=i_req->location_ua.len;
+		t->uac[branch].location_ua.s[i_req->location_ua.len]=0;
+		memcpy( t->uac[branch].location_ua.s, i_req->location_ua.s, i_req->location_ua.len);
+	}
 	ret=0;
 
 error01:
@@ -474,6 +611,15 @@ error03:
 	if (unlikely(free_path)){
 		reset_path_vector(i_req);
 	}
+	if (unlikely(free_instance)){
+		reset_instance(i_req);
+	}
+	if (unlikely(free_ruid)){
+		reset_ruid(i_req);
+	}
+	if (unlikely(free_ua)){
+		reset_ua(i_req);
+	}
 	if (dst_uri_backed_up){
 		reset_dst_uri(i_req); /* free dst_uri */
 		i_req->dst_uri=dst_uri_bak;
@@ -483,6 +629,9 @@ error03:
 	i_req->parsed_uri=parsed_uri_bak;
 	i_req->parsed_uri_ok=parsed_uri_ok_bak;
 	i_req->path_vec=path_bak;
+	i_req->instance=instance_bak;
+	i_req->ruid=ruid_bak;
+	i_req->location_ua=ua_bak;
 	
 	/* Delete the duplicated lump lists, this will also delete
 	 * all lumps created here, such as lumps created in per-branch
@@ -607,6 +756,11 @@ int add_blind_uac( /*struct cell *t*/ )
 	membar_write(); /* to allow lockless prepare_to_cancel() we want to be sure
 					   all the writes finished before updating branch number*/
 	t->nr_of_outgoings=(branch+1);
+	t->async_backup.blind_uac = branch; /* whenever we create a blind UAC, lets save the current branch
+					 * this is used in async tm processing specifically to be able to route replies
+					 * that were possibly in response to a request forwarded on this blind UAC......
+					 * we still want replies to be processed as if it were a normal UAC */
+	
 	/* start FR timer -- protocol set by default to PROTO_NONE,
        which means retransmission timer will not be started
     */
@@ -646,7 +800,8 @@ int add_blind_uac( /*struct cell *t*/ )
 static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
 					str* next_hop, str* path, struct proxy_l *proxy,
 					struct socket_info* fsocket, snd_flags_t snd_flags,
-					int proto, int flags)
+					int proto, int flags, str *instance, str *ruid,
+					str *location_ua)
 {
 
 	int ret;
@@ -691,7 +846,8 @@ static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
 	/* now message printing starts ... */
 	if (unlikely( (ret=prepare_new_uac(t, request, branch, uri, path,
 										next_hop, fsocket, snd_flags,
-										proto, flags)) < 0)){
+										proto, flags, instance, ruid,
+										location_ua)) < 0)){
 		ser_error=ret;
 		goto error01;
 	}
@@ -731,7 +887,9 @@ static int add_uac_from_buf( struct cell *t, struct sip_msg *request,
 								struct socket_info* fsocket,
 								snd_flags_t send_flags,
 								int proto,
-								char *buf, short buf_len)
+								char *buf, short buf_len,
+								str *instance, str *ruid,
+								str *location_ua)
 {
 
 	int ret;
@@ -802,6 +960,59 @@ static int add_uac_from_buf( struct cell *t, struct sip_msg *request,
 		t->uac[branch].path.s[path->len]=0;
 		memcpy( t->uac[branch].path.s, path->s, path->len);
 	}
+	/* copy the instance */
+	if (unlikely(instance && instance->s)){
+		t->uac[branch].instance.s=shm_malloc(instance->len+1);
+		if (unlikely(t->uac[branch].instance.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=ser_error=E_OUT_OF_MEM;
+			goto error;
+		}
+		t->uac[branch].instance.len=instance->len;
+		t->uac[branch].instance.s[instance->len]=0;
+		memcpy( t->uac[branch].instance.s, instance->s, instance->len);
+	}
+	/* copy the ruid */
+	if (unlikely(ruid && ruid->s)){
+		t->uac[branch].ruid.s=shm_malloc(ruid->len+1);
+		if (unlikely(t->uac[branch].ruid.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=ser_error=E_OUT_OF_MEM;
+			goto error;
+		}
+		t->uac[branch].ruid.len=ruid->len;
+		t->uac[branch].ruid.s[ruid->len]=0;
+		memcpy( t->uac[branch].ruid.s, ruid->s, ruid->len);
+	}
+	/* copy the location_ua */
+	if (unlikely(location_ua && location_ua->s)){
+		t->uac[branch].location_ua.s=shm_malloc(location_ua->len+1);
+		if (unlikely(t->uac[branch].location_ua.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=ser_error=E_OUT_OF_MEM;
+			goto error;
+		}
+		t->uac[branch].location_ua.len=location_ua->len;
+		t->uac[branch].location_ua.s[location_ua->len]=0;
+		memcpy( t->uac[branch].location_ua.s, location_ua->s, location_ua->len);
+	}
+
+	t->uac[branch].on_reply = t->on_reply;
+	t->uac[branch].on_failure = t->on_failure;
+	t->uac[branch].on_branch_failure = t->on_branch_failure;
+
 	membar_write(); /* to allow lockless ops (e.g. prepare_to_cancel()) we want
 					   to be sure everything above is fully written before
 					   updating branches no. */
@@ -869,12 +1080,16 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 							&old_uac->path,
 							 (old_uac->request.dst.send_flags.f &
 								SND_F_FORCE_SOCKET)?
-									old_uac->request.dst.send_sock:0,
+									old_uac->request.dst.send_sock:
+									((tm_dns_reuse_rcv_socket)
+											?msg->rcv.bind_address:0),
 							old_uac->request.dst.send_flags,
 							old_uac->request.dst.proto,
 							old_uac->request.buffer,
-							old_uac->request.buffer_len);
-			}else
+							old_uac->request.buffer_len,
+							&old_uac->instance, &old_uac->ruid,
+							&old_uac->location_ua);
+			} else {
 				/* add_uac will use dns_h => next_hop will be ignored.
 				 * Unfortunately we can't reuse the old buffer, the branch id
 				 *  must be changed and the send_socket might be different =>
@@ -882,9 +1097,14 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 				ret=add_uac(t,  msg, &old_uac->uri, 0, &old_uac->path, 0,
 							 (old_uac->request.dst.send_flags.f &
 								SND_F_FORCE_SOCKET)?
-									old_uac->request.dst.send_sock:0,
+									old_uac->request.dst.send_sock:
+									((tm_dns_reuse_rcv_socket)
+											?msg->rcv.bind_address:0),
 							old_uac->request.dst.send_flags,
-							old_uac->request.dst.proto, UAC_DNS_FAILOVER_F);
+							old_uac->request.dst.proto, UAC_DNS_FAILOVER_F,
+							&old_uac->instance, &old_uac->ruid,
+							&old_uac->location_ua);
+			}
 
 			if (ret<0){
 				/* failed, delete the copied dns_h */
@@ -959,7 +1179,8 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 		if (unlikely((ret=prepare_new_uac( t_cancel, cancel_msg, branch,
 									&t_invite->uac[branch].uri,
 									&t_invite->uac[branch].path,
-									0, 0, snd_flags, PROTO_NONE, 0)) <0)){
+									0, 0, snd_flags, PROTO_NONE, 0,
+									NULL, NULL, NULL)) <0)){
 			ser_error=ret;
 			goto error;
 		}
@@ -1383,9 +1604,25 @@ int t_send_branch( struct cell *t, int branch, struct sip_msg* p_msg ,
 			}
 		}
 #endif
+		uac->icode = 908; /* internal code set to delivery failure */
 		LOG(L_ERR, "ERROR: t_send_branch: sending request on branch %d "
 				"failed\n", branch);
 		if (proxy) { proxy->errors++; proxy->ok=0; }
+		if(tm_failure_exec_mode==1) {
+			LM_DBG("putting branch %d on hold \n", branch);
+			/* put on retransmission timer,
+			 * but set proto to NONE, so actually it is not trying to resend */
+			uac->request.dst.proto = PROTO_NONE;
+			/* reset last_received, 408 reply is faked by timer */
+			uac->last_received=0;
+			/* add to retransmission timer */
+			if (start_retr( &uac->request )!=0){
+				LM_CRIT("retransmission already started for %p\n",
+					&uac->request);
+				return -2;
+			}
+			return branch;
+		}
 		return -2;
 	} else {
 		if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_SENT)))
@@ -1418,7 +1655,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	int success_branch;
 	int try_new;
 	int lock_replies;
-	str dst_uri, path;
+	str dst_uri, path, instance, ruid, location_ua;
 	struct socket_info* si;
 	flag_t backup_bflags = 0;
 	flag_t bflags = 0;
@@ -1484,7 +1721,8 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 		branch_ret=add_uac( t, p_msg, GET_RURI(p_msg), GET_NEXT_HOP(p_msg),
 							&p_msg->path_vec, proxy, p_msg->force_send_socket,
 							p_msg->fwd_send_flags, proto,
-							(p_msg->dst_uri.len)?0:UAC_SKIP_BR_DST_F);
+							(p_msg->dst_uri.len)?0:UAC_SKIP_BR_DST_F, &p_msg->instance,
+							&p_msg->ruid, &p_msg->location_ua);
 		if (branch_ret>=0) 
 			added_branches |= 1<<branch_ret;
 		else
@@ -1493,14 +1731,15 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 
 	init_branch_iterator();
 	while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri, &path,
-										&bflags, &si))) {
+										&bflags, &si, &ruid, &instance, &location_ua))) {
 		try_new++;
 		setbflagsval(0, bflags);
 
 		branch_ret=add_uac( t, p_msg, &current_uri,
 							(dst_uri.len) ? (&dst_uri) : &current_uri,
 							&path, proxy, si, p_msg->fwd_send_flags,
-							proto, (dst_uri.len)?0:UAC_SKIP_BR_DST_F);
+							proto, (dst_uri.len)?0:UAC_SKIP_BR_DST_F, &instance,
+							&ruid, &location_ua);
 		/* pick some of the errors in case things go wrong;
 		   note that picking lowest error is just as good as
 		   any other algorithm which picks any other negative
diff --git a/modules/tm/t_hooks.h b/modules/tm/t_hooks.h
index 9646c11..e94d2df 100644
--- a/modules/tm/t_hooks.h
+++ b/modules/tm/t_hooks.h
@@ -82,7 +82,9 @@ struct cell;
 #endif
 #define TMCB_REQUEST_SENT_N     22
 #define TMCB_RESPONSE_SENT_N    23
-#define TMCB_MAX_N              23
+#define TMCB_ON_BRANCH_FAILURE_RO_N 24
+#define TMCB_ON_BRANCH_FAILURE_N 25
+#define TMCB_MAX_N              25
 
 
 #define TMCB_REQUEST_IN       (1<<TMCB_REQUEST_IN_N)
@@ -111,6 +113,8 @@ struct cell;
 #endif
 #define TMCB_REQUEST_SENT      (1<<TMCB_REQUEST_SENT_N)
 #define TMCB_RESPONSE_SENT     (1<<TMCB_RESPONSE_SENT_N)
+#define TMCB_ON_BRANCH_FAILURE (1<<TMCB_ON_BRANCH_FAILURE_N)
+#define TMCB_ON_BRANCH_FAILURE_RO (1<<TMCB_ON_BRANCH_FAILURE_RO_N)
 #define TMCB_MAX              ((1<<(TMCB_MAX_N+1))-1)
 
 
diff --git a/modules/tm/t_lookup.c b/modules/tm/t_lookup.c
index fec6e8b..fbc624b 100644
--- a/modules/tm/t_lookup.c
+++ b/modules/tm/t_lookup.c
@@ -13,15 +13,8 @@
  * reply and both  of them are constructed by different software.
  * 
  * As for reply matching, we match based on branch value -- that is
- * faster too. There are two versions .. with SYNONYMs #define
- * enabled, the branch includes ordinal number of a transaction
- * in a synonym list in hash table and is somewhat faster but
- * not reboot-resilient. SYNONYMs turned off are little slower
- * but work across reboots as well.
- *
- * The branch parameter is formed as follows:
- * SYNONYMS  on: hash.synonym.branch
- * SYNONYMS off: hash.md5.branch
+ * faster too.
+ * The branch parameter is formed as follows: hash.md5.branch
  *
  * -jiri
  *
@@ -892,16 +885,12 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
 
 	char *loopi;
 	int loopl;
-	char *syni;
-	int synl;
 	
 	short is_cancel;
 
 	/* make compiler warnings happy */
 	loopi=0;
 	loopl=0;
-	syni=0;
-	synl=0;
 
 	/* split the branch into pieces: loop_detection_check(ignored),
 	 hash_table_id, synonym_id, branch_id */
@@ -928,25 +917,14 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
 	hashi=p;
 	p=n+1;scan_space--;
 
-	if (!syn_branch) {
-		/* md5 value */
-		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
-		loopl = n-p;
-		scan_space-= loopl;
-		if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) 
-			goto nomatch2;
-		loopi=p;
-		p=n+1; scan_space--;
-	} else {
-		/* synonym id */
-		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
-		synl=n-p;
-		scan_space-=synl;
-		if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) 
-			goto nomatch2;
-		syni=p;
-		p=n+1;scan_space--;
-	}
+	/* md5 value */
+	n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
+	loopl = n-p;
+	scan_space-= loopl;
+	if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR)
+		goto nomatch2;
+	loopi=p;
+	p=n+1; scan_space--;
 
 	/* branch id  -  should exceed the scan_space */
 	n=eat_token_end( p, p+scan_space );
@@ -959,8 +937,7 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
 		||hash_index>=TABLE_ENTRIES
 		|| reverse_hex2int(branchi, branchl, &branch_id)<0
 		||branch_id>=MAX_BRANCHES
-		|| (syn_branch ? (reverse_hex2int(syni, synl, &entry_label))<0 
-			: loopl!=MD5_LEN ))
+		|| loopl!=MD5_LEN)
 	) {
 		DBG("DEBUG: t_reply_matching: poor reply labels %d label %d "
 			"branch %d\n", hash_index, entry_label, branch_id );
@@ -983,14 +960,8 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
 	/* all the transactions from the entry are compared */
 	clist_foreach(hash_bucket, p_cell, next_c){
 		prefetch_loc_r(p_cell->next_c, 1);
-		/* first look if branch matches */
-		if (likely(syn_branch)) {
-			if (p_cell->label != entry_label) 
-				continue;
-		} else {
-			if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
+		if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
 					continue;
-		}
 
 		/* sanity check ... too high branch ? */
 		if (unlikely(branch_id>=p_cell->nr_of_outgoings))
@@ -1291,6 +1262,7 @@ static inline void init_new_t(struct cell *new_cell, struct sip_msg *p_msg)
 			lifetime=cfg_get(tm, tm_cfg, tm_max_noninv_lifetime);
 	}
 	new_cell->on_failure=get_on_failure();
+	new_cell->on_branch_failure=get_on_branch_failure();
 	new_cell->on_reply=get_on_reply();
 	new_cell->end_of_life=get_ticks_raw()+lifetime;;
 	new_cell->fr_timeout=(ticks_t)get_msgid_val(user_fr_timeout,
diff --git a/modules/tm/t_lookup.h b/modules/tm/t_lookup.h
index 32a9e8a..cced995 100644
--- a/modules/tm/t_lookup.h
+++ b/modules/tm/t_lookup.h
@@ -86,10 +86,13 @@ int t_check_msg(struct sip_msg* , int *branch );
 
 typedef struct cell * (*tgett_f)(void);
 struct cell *get_t(void);
+
+typedef int (*tgett_branch_f)(void);
 int get_t_branch(void);
 
 /* use carefully or better not at all -- current transaction is 
  * primarily set by lookup functions */
+typedef void (*tsett_f)(struct cell *t, int branch);
 void set_t(struct cell *t, int branch);
 
 
diff --git a/modules/tm/t_msgbuilder.c b/modules/tm/t_msgbuilder.c
index aa0144c..666d3bf 100644
--- a/modules/tm/t_msgbuilder.c
+++ b/modules/tm/t_msgbuilder.c
@@ -815,9 +815,7 @@ static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset,
 		return F_RB_NH_STRICT;
 	/* if 1st route contains an IP address, comparing it against .dst */
 	if ((uri_ia = str2ip(&topr_uri.host))
-#ifdef USE_IPV6
 			|| (uri_ia = str2ip6(&topr_uri.host))
-#endif
 			) {
 		/* we have an IP address in route -> comparison can go swiftly */
 		if (init_su(&uri_sau, uri_ia, uri_port) < 0)
@@ -1398,10 +1396,13 @@ static inline char* print_request_uri(char* w, str* method, dlg_t* dialog, struc
 static inline char* print_to(char* w, dlg_t* dialog, struct cell* t)
 {
 	t->to.s = w;
-	t->to.len = TO_LEN + dialog->rem_uri.len + CRLF_LEN;
+	t->to.len = TO_LEN + dialog->rem_uri.len + CRLF_LEN
+		+ ((dialog->rem_uri.s[0]!='<')?2:0);
 
 	memapp(w, TO, TO_LEN);
+	if(dialog->rem_uri.s[0]!='<') memapp(w, "<", 1);
 	memapp(w, dialog->rem_uri.s, dialog->rem_uri.len);
+	if(dialog->rem_uri.s[0]!='<') memapp(w, ">", 1);
 
 	if (dialog->id.rem_tag.len) {
 		t->to.len += TOTAG_LEN + dialog->id.rem_tag.len ;
@@ -1420,10 +1421,13 @@ static inline char* print_to(char* w, dlg_t* dialog, struct cell* t)
 static inline char* print_from(char* w, dlg_t* dialog, struct cell* t)
 {
 	t->from.s = w;
-	t->from.len = FROM_LEN + dialog->loc_uri.len + CRLF_LEN;
+	t->from.len = FROM_LEN + dialog->loc_uri.len + CRLF_LEN
+		+ ((dialog->loc_uri.s[0]!='<')?2:0);
 
 	memapp(w, FROM, FROM_LEN);
+	if(dialog->loc_uri.s[0]!='<') memapp(w, "<", 1);
 	memapp(w, dialog->loc_uri.s, dialog->loc_uri.len);
+	if(dialog->loc_uri.s[0]!='<') memapp(w, ">", 1);
 
 	if (dialog->id.loc_tag.len) {
 		t->from.len += FROMTAG_LEN + dialog->id.loc_tag.len;
@@ -1544,8 +1548,10 @@ char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int bra
 
 	*len += TO_LEN + dialog->rem_uri.len
 		+ (dialog->id.rem_tag.len ? (TOTAG_LEN + dialog->id.rem_tag.len) : 0) + CRLF_LEN;    /* To */
+	if(dialog->rem_uri.s[0]!='<') *len += 2; /* To-URI < > */
 	*len += FROM_LEN + dialog->loc_uri.len
 		+ (dialog->id.loc_tag.len ? (FROMTAG_LEN + dialog->id.loc_tag.len) : 0) + CRLF_LEN;  /* From */
+	if(dialog->loc_uri.s[0]!='<') *len += 2; /* From-URI < > */
 	*len += CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;                                      /* Call-ID */
 	*len += CSEQ_LEN + cseq.len + 1 + method->len + CRLF_LEN;                                    /* CSeq */
 	*len += calculate_routeset_length(dialog);                                                   /* Route set */
@@ -1606,11 +1612,7 @@ char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int bra
 int t_calc_branch(struct cell *t, 
 	int b, char *branch, int *branch_len)
 {
-	return syn_branch ?
-		branch_builder( t->hash_index,
-			t->label, 0,
-			b, branch, branch_len )
-		: branch_builder( t->hash_index,
+	return branch_builder( t->hash_index,
 			0, t->md5,
 			b, branch, branch_len );
 }
diff --git a/modules/tm/t_reply.c b/modules/tm/t_reply.c
index c36daf6..562b583 100644
--- a/modules/tm/t_reply.c
+++ b/modules/tm/t_reply.c
@@ -172,6 +172,8 @@ char *tm_tag_suffix;
 
 /* where to go if there is no positive reply (>=300) */
 static int goto_on_failure=0;
+/* where to go if a failure is returned on a branch */
+static int goto_on_branch_failure=0;
 /* where to go on receipt of reply */
 static int goto_on_reply=0;
 /* where to go on receipt of reply without transaction context */
@@ -262,6 +264,20 @@ void t_on_failure( unsigned int go_to )
 }
 
 
+void t_on_branch_failure( unsigned int go_to )
+{
+	struct cell *t = get_t();
+
+	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
+	 * in REQUEST_ROUTE T will be set only if the transaction was already
+	 * created; if not -> use the static variable */
+	if (!t || t==T_UNDEFINED )
+		goto_on_branch_failure=go_to;
+	else
+		t->on_branch_failure = go_to;
+}
+
+
 void t_on_reply( unsigned int go_to )
 {
 	struct cell *t = get_t();
@@ -280,6 +296,12 @@ unsigned int get_on_failure()
 {
 	return goto_on_failure;
 }
+
+unsigned int get_on_branch_failure()
+{
+	return goto_on_branch_failure;
+}
+
 unsigned int get_on_reply()
 {
 	return goto_on_reply;
@@ -784,13 +806,13 @@ static int _reply( struct cell *trans, struct sip_msg* p_msg,
 	}
 }
 
-/** create or restore a "fake environment" for running a failure_route.
- *if msg is set -> it will fake the env. vars conforming with the msg; if NULL
+/** create or restore a "fake environment" for running a failure_route, 
+ * OR an "async environment" depending on is_async_value (0=std failure-faked, 1=async)
+ * if msg is set -> it will fake the env. vars conforming with the msg; if NULL
  * the env. will be restore to original.
- * Side-effect: mark_ruri_consumed().
+ * Side-effect: mark_ruri_consumed() for faked env only.
  */
-void faked_env( struct cell *t, struct sip_msg *msg)
-{
+void faked_env(struct cell *t, struct sip_msg *msg, int is_async_env) {
 	static int backup_route_type;
 	static struct cell *backup_t;
 	static int backup_branch;
@@ -813,64 +835,83 @@ void faked_env( struct cell *t, struct sip_msg *msg)
 		 * a shmem-ed replica of the request; advertise it in route type;
 		 * for example t_reply needs to know that
 		 */
-		backup_route_type=get_route_type();
-		set_route_type(FAILURE_ROUTE);
-		/* don't bother backing up ruri state, since failure route
-		   is called either on reply or on timer and in both cases
-		   the ruri should not be used again for forking */
-		ruri_mark_consumed(); /* in failure route we assume ruri
-								 should not be used again for forking */
+		backup_route_type = get_route_type();
+
+		if (is_async_env) {
+			set_route_type(t->async_backup.backup_route);
+			if (t->async_backup.ruri_new) {
+				ruri_mark_new();
+			}
+		} else {
+			set_route_type(FAILURE_ROUTE);
+			/* don't bother backing up ruri state, since failure route
+			   is called either on reply or on timer and in both cases
+			   the ruri should not be used again for forking */
+			ruri_mark_consumed(); /* in failure route we assume ruri
+								     should not be used again for forking */
+		}
 		/* also, tm actions look in beginning whether transaction is
 		 * set -- whether we are called from a reply-processing
 		 * or a timer process, we need to set current transaction;
 		 * otherwise the actions would attempt to look the transaction
 		 * up (unnecessary overhead, refcounting)
 		 */
-		/* backup */
-		backup_t=get_t();
-		backup_branch=get_t_branch();
-		backup_msgid=global_msg_id;
-		/* fake transaction and message id */
-		global_msg_id=msg->id;
-		set_t(t, T_BR_UNDEFINED);
-		/* make available the avp list from transaction */
-
-		backup_uri_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from );
-		backup_uri_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to );
-		backup_user_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from );
-		backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
-		backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
-		backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
+		if (!is_async_env) {
+			/* backup */
+			backup_t = get_t();
+			backup_branch = get_t_branch();
+			backup_msgid = global_msg_id;
+			/* fake transaction and message id */
+			global_msg_id = msg->id;
+			set_t(t, T_BR_UNDEFINED);
+
+			/* make available the avp list from transaction */
+			backup_uri_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
+			backup_uri_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
+			backup_user_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
+			backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
+			backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
+			backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
 #ifdef WITH_XAVP
-		backup_xavps = xavp_set_list(&t->xavps_list);
+			backup_xavps = xavp_set_list(&t->xavps_list);
 #endif
-		/* set default send address to the saved value */
-		backup_si=bind_address;
-		bind_address=t->uac[0].request.dst.send_sock;
-		/* backup lump lists */
-		backup_add_rm = t->uas.request->add_rm;
-		backup_body_lumps = t->uas.request->body_lumps;
-		backup_reply_lump = t->uas.request->reply_lump;
+			/* set default send address to the saved value */
+			backup_si = bind_address;
+			bind_address = t->uac[0].request.dst.send_sock;
+			/* backup lump lists */
+			backup_add_rm = t->uas.request->add_rm;
+			backup_body_lumps = t->uas.request->body_lumps;
+			backup_reply_lump = t->uas.request->reply_lump;
+		} else {
+			global_msg_id = msg->id;
+			set_t(t, t->async_backup.backup_branch);
+		}
 	} else {
-		/* restore original environment */
-		set_t(backup_t, backup_branch);
-		global_msg_id=backup_msgid;
-		set_route_type(backup_route_type);
-		/* restore original avp list */
-		set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, backup_user_from );
-		set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, backup_user_to );
-		set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, backup_domain_from );
-		set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to );
-		set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, backup_uri_from );
-		set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, backup_uri_to );
+		if (!is_async_env) {
+			/* restore original environment */
+			set_t(backup_t, backup_branch);
+			global_msg_id = backup_msgid;
+			set_route_type(backup_route_type);
+			/* restore original avp list */
+			set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, backup_user_from);
+			set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, backup_user_to);
+			set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, backup_domain_from);
+			set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to);
+			set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, backup_uri_from);
+			set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, backup_uri_to);
 #ifdef WITH_XAVP
-		xavp_set_list(backup_xavps);
+			xavp_set_list(backup_xavps);
 #endif
-		bind_address=backup_si;
-		/* restore lump lists */
-		t->uas.request->add_rm = backup_add_rm;
-		t->uas.request->body_lumps = backup_body_lumps;
-		t->uas.request->reply_lump = backup_reply_lump;
+			bind_address = backup_si;
+			/* restore lump lists */
+			t->uas.request->add_rm = backup_add_rm;
+			t->uas.request->body_lumps = backup_body_lumps;
+			t->uas.request->reply_lump = backup_reply_lump;
+		} else {
+			/*we don't need to restore anything as there was no "environment" prior 
+						    to continuing (we are in a different process)*/
+			LOG(L_DBG, "nothing to restore in async continue, useless call\n");
+		}
 	}
 }
 
@@ -942,15 +983,8 @@ void free_faked_req(struct sip_msg *faked_req, struct cell *t)
 {
 	struct hdr_field *hdr;
 
-	if (faked_req->new_uri.s) {
-		pkg_free(faked_req->new_uri.s);
-		faked_req->new_uri.s = 0;
-	}
-
-	if (faked_req->dst_uri.s) {
-		pkg_free(faked_req->dst_uri.s);
-		faked_req->dst_uri.s = 0;
-	}
+	reset_new_uri(faked_req);
+	reset_dst_uri(faked_req);
 
 	/* free all types of lump that were added in failure handlers */
 	del_nonshm_lump( &(faked_req->add_rm) );
@@ -976,9 +1010,13 @@ void free_faked_req(struct sip_msg *faked_req, struct cell *t)
 			faked_req->body->free(&faked_req->body);
 		faked_req->body = 0;
 	}
+
 	/* free sip_msg_t fileds that can be set in pkg */
 	reset_path_vector(faked_req);
 	reset_instance(faked_req);
+	reset_ruid(faked_req);
+	reset_ua(faked_req);
+	msg_ldata_reset(faked_req);
 }
 
 
@@ -1012,7 +1050,7 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 		return 0;
 	}
 	/* fake also the env. conforming to the fake msg */
-	faked_env( t, &faked_req);
+	faked_env( t, &faked_req, 0);
 	/* DONE with faking ;-) -> run the failure handlers */
 
 	if (unlikely(has_tran_tmcbs( t, TMCB_ON_FAILURE)) ) {
@@ -1034,7 +1072,7 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 	}
 
 	/* restore original environment and free the fake msg */
-	faked_env( t, 0);
+	faked_env( t, 0, 0);
 	free_faked_req(&faked_req,t);
 
 	/* if failure handler changed flag, update transaction context */
@@ -1043,6 +1081,66 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 }
 
 
+/* return 1 if a failure_route processes */
+int run_branch_failure_handlers(struct cell *t, struct sip_msg *rpl,
+					int code, int extra_flags)
+{
+	static struct sip_msg faked_req;
+	struct sip_msg *shmem_msg = t->uas.request;
+	int on_branch_failure;
+
+	on_branch_failure = t->uac[picked_branch].on_branch_failure;
+
+	/* failure_route for a local UAC? */
+	if (!shmem_msg) {
+		LOG(L_WARN,"Warning: run_branch_failure_handlers: no UAC support (%d, %d) \n",
+			on_branch_failure, t->tmcb_hl.reg_types);
+		return 0;
+	}
+
+	/* don't start faking anything if we don't have to */
+	if (unlikely((on_branch_failure < 0) && !has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE))) {
+		LOG(L_WARN,
+			"Warning: run_failure_handlers: no branch_failure handler (%d, %d)\n",
+			on_branch_failure, t->tmcb_hl.reg_types);
+		return 1;
+	}
+
+	if (!fake_req(&faked_req, shmem_msg, extra_flags, &t->uac[picked_branch])) {
+		LOG(L_ERR, "ERROR: run_branch_failure_handlers: fake_req failed\n");
+		return 0;
+	}
+	/* fake also the env. conforming to the fake msg */
+	faked_env( t, &faked_req, 0);
+	set_route_type(BRANCH_FAILURE_ROUTE);
+	set_t(t, picked_branch);
+	/* DONE with faking ;-) -> run the branch_failure handlers */
+
+	if (unlikely(has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE)) ) {
+		run_trans_callbacks( TMCB_ON_BRANCH_FAILURE, t, &faked_req, rpl, code);
+	}
+	if (on_branch_failure >= 0) {
+		t->on_branch_failure = 0;
+		if (exec_pre_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE)>0) {
+			/* run a branch_failure_route action if some was marked */
+			if (run_top_route(event_rt.rlist[on_branch_failure], &faked_req, 0)<0)
+				LOG(L_ERR, "ERROR: run_branch_failure_handlers: Error in run_top_route\n");
+			exec_post_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE);
+		}
+		/* update message flags, if changed in branch_failure route */
+		t->uas.request->flags = faked_req.flags;
+	}
+
+	/* restore original environment and free the fake msg */
+	faked_env( t, 0, 0);
+	free_faked_req(&faked_req,t);
+
+	/* if branch_failure handler changed flag, update transaction context */
+	shmem_msg->flags = faked_req.flags;
+	return 1;
+}
+
+
 
 /* 401, 407, 415, 420, and 484 have priority over the other 4xx*/
 inline static short int get_4xx_prio(unsigned char xx)
@@ -1124,8 +1222,8 @@ int t_pick_branch(int inc_branch, int inc_code, struct cell *t, int *res_code)
 		 * to be a pending, incomplete branch. */
 		if ((!t->uac[b].request.buffer) && (t->uac[b].last_received>=200))
 			continue;
-		/* there is still an unfinished UAC transaction; wait now! */
-		if ( t->uac[b].last_received<200 )
+		/* there is still an unfinished UAC transaction (we ignore unfinished blind UACs) wait now! */
+		if ( t->uac[b].last_received<200 && !((t->flags&T_ASYNC_CONTINUE) && b==t->async_backup.blind_uac))
 			return -2;
 		/* if reply is null => t_send_branch "faked" reply, skip over it */
 		if ( rpl && 
@@ -1256,6 +1354,24 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 
 		Trans->uac[branch].last_received=new_code;
 
+		/* also append the current reply to the transaction to
+		 * make it available in failure routes - a kind of "fake"
+		 * save of the final reply per branch */
+		Trans->uac[branch].reply = reply;
+		if (unlikely(has_tran_tmcbs( Trans, TMCB_ON_BRANCH_FAILURE_RO|TMCB_ON_BRANCH_FAILURE)
+						|| (Trans->uac[picked_branch].on_branch_failure) )) {
+			extra_flags=
+				((Trans->uac[branch].request.flags & F_RB_TIMEOUT)?
+							FL_TIMEOUT:0) | 
+				((Trans->uac[branch].request.flags & F_RB_REPLIED)?
+						 	FL_REPLIED:0);
+			tm_ctx_set_branch_index(branch);
+			picked_branch = branch;
+			run_branch_failure_handlers( Trans, Trans->uac[branch].reply,
+									new_code, extra_flags);
+		}
+
+
 		/* if all_final return lowest */
 		picked_branch=t_pick_branch(branch,new_code, Trans, &picked_code);
 		if (picked_branch==-2) { /* branches open yet */
@@ -1706,8 +1822,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
 	/* *** store and relay message as needed *** */
 	reply_status = t_should_relay_response(t, msg_status, branch,
 		&save_clone, &relay, cancel_data, p_msg );
-	DBG("DEBUG: relay_reply: branch=%d, save=%d, relay=%d\n",
-		branch, save_clone, relay );
+	DBG("DEBUG: relay_reply: branch=%d, save=%d, relay=%d icode=%d\n",
+		branch, save_clone, relay, t->uac[branch].icode);
 
 	/* store the message if needed */
 	if (save_clone) /* save for later use, typically branch picking */
@@ -2350,6 +2466,11 @@ int reply_received( struct sip_msg  *p_msg )
 			}
 		}
 #endif
+        
+	if (unlikely(p_msg->msg_flags&FL_RPL_SUSPENDED)) {
+		goto skip_send_reply;
+		/* suspend the reply (async), no error */
+	}
 	if (unlikely(!replies_locked)){
 		LOCK_REPLIES( t );
 		replies_locked=1;
@@ -2406,6 +2527,13 @@ int reply_received( struct sip_msg  *p_msg )
 		restart_rb_fr(& uac->request, t->fr_inv_timeout);
 		uac->request.flags|=F_RB_FR_INV; /* mark fr_inv */
 	} /* provisional replies */
+        
+skip_send_reply:
+
+	if (likely(replies_locked)){
+		UNLOCK_REPLIES(t); /* unlock replies  - this would be unlocked by send function*/
+		replies_locked=0;
+	}
 
 done:
 	tm_ctx_set_branch_index(T_BR_UNDEFINED);
@@ -2534,6 +2662,58 @@ void t_drop_replies(int v)
 	drop_replies = v;
 }
 
+int t_get_this_branch_instance(struct sip_msg *msg, str *instance)
+{
+	struct cell *t;
+	if (!msg || !instance)
+	{
+		LM_ERR("Invalid params\n");
+		return -1;
+	}
+	if (get_route_type() != BRANCH_FAILURE_ROUTE)
+	{
+		LM_ERR("Called t_get_this_branch_instance not in a branch_failure_route\n");
+		return -1;
+	}
+
+	t = 0;
+	/* first get the transaction */
+	if (t_check(msg, 0 ) == -1) return -1;
+	if ((t = get_t()) == 0) {
+		LOG(L_ERR, "ERROR: t_check_status: cannot check status for a reply "
+			"which has no T-state established\n");
+		return -1;
+	}
+	*instance = t->uac[get_t_branch()].instance;
+	return 1;
+}
+
+int t_get_this_branch_ruid(struct sip_msg *msg, str *ruid)
+{
+	struct cell *t;
+	if (!msg || !ruid)
+	{
+		LM_ERR("Invalid params\n");
+		return -1;
+	}
+	if (get_route_type() != BRANCH_FAILURE_ROUTE)
+	{
+		LM_ERR("Called t_get_this_branch_ruid not in a branch_failure_route\n");
+		return -1;
+	}
+
+	t = 0;
+	/* first get the transaction */
+	if (t_check(msg, 0 ) == -1) return -1;
+	if ((t = get_t()) == 0) {
+		LOG(L_ERR, "ERROR: t_check_status: cannot check status for a reply "
+			"which has no T-state established\n");
+		return -1;
+	}
+	*ruid = t->uac[get_t_branch()].ruid;
+	return 1;
+}
+
 #if 0
 static int send_reply(struct cell *trans, unsigned int code, str* text, str* body, str* headers, str* to_tag)
 {
diff --git a/modules/tm/t_reply.h b/modules/tm/t_reply.h
index 560ca23..a98473f 100644
--- a/modules/tm/t_reply.h
+++ b/modules/tm/t_reply.h
@@ -161,6 +161,11 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 					int code, int extra_flags);
 typedef int (*run_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
 
+/* return 1 if a branch_failure_route processes */
+int run_branch_failure_handlers(struct cell *t, struct sip_msg *rpl,
+					int code, int extra_flags);
+typedef int (*run_branch_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
+
 
 /* Retransmits the last sent inbound reply.
  * Returns  -1 - error
@@ -209,6 +214,8 @@ void on_failure_reply( struct cell* t, struct sip_msg* msg,
 */
 void t_on_failure( unsigned int go_to );
 unsigned int get_on_failure(void);
+void t_on_branch_failure( unsigned int go_to );
+unsigned int get_on_branch_failure(void);
 void t_on_reply( unsigned int go_to );
 unsigned int get_on_reply(void);
 
@@ -228,7 +235,7 @@ void t_drop_replies(int v);
 
 void rpc_reply(rpc_t* rpc, void* c);
 
-void faked_env( struct cell *t,struct sip_msg *msg);
+void faked_env( struct cell *t,struct sip_msg *msg, int is_async_env);
 int fake_req(struct sip_msg *faked_req,
 		struct sip_msg *shmem_msg, int extra_flags, struct ua_client *uac);
 
@@ -237,4 +244,7 @@ void free_faked_req(struct sip_msg *faked_req, struct cell *t);
 typedef int (*tget_picked_f)(void);
 int t_get_picked_branch(void);
 
+int t_get_this_branch_instance(struct sip_msg *msg, str *instance);
+int t_get_this_branch_ruid(struct sip_msg *msg, str *ruid);
+
 #endif
diff --git a/modules/tm/t_serial.c b/modules/tm/t_serial.c
index 1eb722a..93c7480 100644
--- a/modules/tm/t_serial.c
+++ b/modules/tm/t_serial.c
@@ -44,45 +44,47 @@
 
 /* Struture where information regarding contacts is stored */
 struct contact {
-    str uri;
-    qvalue_t q;
-    str dst_uri;
-    str path;
-    struct socket_info* sock;
-    str instance;
-    unsigned int flags;
-    unsigned short q_flag;
-    struct contact *next;
+	str uri;
+	qvalue_t q;
+	str dst_uri;
+	str path;
+	struct socket_info* sock;
+	str instance;
+	str ruid;
+	str location_ua;
+	unsigned int flags;
+	unsigned short q_flag;
+	struct contact *next;
 };
 
 struct instance_list {
-    str instance;
-    struct instance_list *next;
+	str instance;
+	struct instance_list *next;
 };
 
 /* 
  * Frees contact list used by load_contacts function
  */
 static inline void free_contact_list(struct contact *curr) {
-    struct contact *prev;
-    while (curr) {
+	struct contact *prev;
+	while (curr) {
 		prev = curr;
 		curr = curr->next;
 		pkg_free(prev);
-    }
+	}
 }
 
 /* 
  * Frees instance list used by next_contacts function
  */
 static inline void free_instance_list(struct instance_list *curr) {
-    struct instance_list *prev;
-    while (curr) {
-	pkg_free(curr->instance.s);
-	prev = curr;
-	curr = curr->next;
-	pkg_free(prev);
-    }
+	struct instance_list *prev;
+	while (curr) {
+		pkg_free(curr->instance.s);
+		prev = curr;
+		curr = curr->next;
+		pkg_free(prev);
+	}
 }
 
 static str uri_name = {"uri", 3};
@@ -92,53 +94,68 @@ static str sock_name = {"sock", 4};
 static str instance_name = {"instance", 8};
 static str flags_name = {"flags", 5};
 static str q_flag_name = {"q_flag", 6};
+static str ruid_name = {"ruid", 4};
+static str ua_name = {"ua", 2};
 
 void add_contacts_avp(str *uri, str *dst_uri, str *path, str *sock_str,
-		      unsigned int flags, unsigned int q_flag, str *instance)
+		unsigned int flags, unsigned int q_flag, str *instance,
+		str *ruid, str *location_ua)
 {
-    sr_xavp_t *record;
-    sr_xval_t val;
+	sr_xavp_t *record;
+	sr_xval_t val;
 
-    record = NULL;
+	record = NULL;
 
-    val.type = SR_XTYPE_STR;
-    val.v.s = *uri;
-    xavp_add_value(&uri_name, &val, &record);
-
-    if (dst_uri->len > 0) {
 	val.type = SR_XTYPE_STR;
-	val.v.s = *dst_uri;
-	xavp_add_value(&dst_uri_name, &val, &record);
-    }
+	val.v.s = *uri;
+	xavp_add_value(&uri_name, &val, &record);
 
-    if (path->len > 0) {
-	val.type = SR_XTYPE_STR;
-	val.v.s = *path;
-	xavp_add_value(&path_name, &val, &record);
-    }
+	if (dst_uri->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *dst_uri;
+		xavp_add_value(&dst_uri_name, &val, &record);
+	}
 
-    if (sock_str->len > 0) {
-	val.v.s = *sock_str;
-	xavp_add_value(&sock_name, &val, &record);
-    }
+	if (path->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *path;
+		xavp_add_value(&path_name, &val, &record);
+	}
 
-    val.type = SR_XTYPE_INT;
-    val.v.i = flags;
-    xavp_add_value(&flags_name, &val, &record);
+	if (sock_str->len > 0) {
+		val.v.s = *sock_str;
+		xavp_add_value(&sock_name, &val, &record);
+	}
 
-    val.type = SR_XTYPE_INT;
-    val.v.i = q_flag;
-    xavp_add_value(&q_flag_name, &val, &record);
+	val.type = SR_XTYPE_INT;
+	val.v.i = flags;
+	xavp_add_value(&flags_name, &val, &record);
 
-    if (instance->len > 0) {
-	val.type = SR_XTYPE_STR;
-	val.v.s = *instance;
-	xavp_add_value(&instance_name, &val, &record);
-    }
+	val.type = SR_XTYPE_INT;
+	val.v.i = q_flag;
+	xavp_add_value(&q_flag_name, &val, &record);
+
+	if (instance->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *instance;
+		xavp_add_value(&instance_name, &val, &record);
+	}
+
+	if (ruid->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *ruid;
+		xavp_add_value(&ruid_name, &val, &record);
+	}
 
-    val.type = SR_XTYPE_XAVP;
-    val.v.xavp = record;
-    xavp_add_value(&contacts_avp, &val, NULL);
+	if (location_ua->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *location_ua;
+		xavp_add_value(&ua_name, &val, &record);
+	}
+
+	val.type = SR_XTYPE_XAVP;
+	val.v.xavp = record;
+	xavp_add_value(&contacts_avp, &val, NULL);
 }
 
 /* 
@@ -149,203 +166,231 @@ void add_contacts_avp(str *uri, str *dst_uri, str *path, str *sock_str,
  */
 int t_load_contacts(struct sip_msg* msg, char* key, char* value)
 {
-    branch_t *branch;
-    str *ruri, sock_str;
-    struct contact *contacts, *next, *prev, *curr;
-    int first_idx, idx, len;
-    char sock_buf[MAX_SOCKET_STR];
-
-    /* Check if contacts_avp has been defined */
-    if (contacts_avp.len == 0) {
-	LM_ERR("feature has been disabled - "
-	       "to enable define contacts_avp module parameter");
-	return -1;
-    }
+	branch_t *branch;
+	str *ruri, sock_str;
+	struct contact *contacts, *next, *prev, *curr;
+	int first_idx, idx, len;
+	char sock_buf[MAX_SOCKET_STR];
+
+	/* Check if contacts_avp has been defined */
+	if (contacts_avp.len == 0) {
+		LM_ERR("feature has been disabled - "
+				"to enable define contacts_avp module parameter");
+		return -1;
+	}
 
-    /* Check if anything needs to be done */
-    LM_DBG("nr_branches is %d\n", nr_branches);
+	/* Check if anything needs to be done */
+	LM_DBG("nr_branches is %d\n", nr_branches);
 
-    if ((nr_branches == 0) || ((nr_branches == 1) && !ruri_is_new)) {
-	LM_DBG("nothing to do - only one contact!\n");
-	return 1;
-    }
+	if ((nr_branches == 0) || ((nr_branches == 1) && !ruri_is_new)) {
+		LM_DBG("nothing to do - only one contact!\n");
+		return 1;
+	}
 
-    /* Allocate memory for first contact */
-    contacts = (struct contact *)pkg_malloc(sizeof(struct contact));
-    if (!contacts) {
-	LM_ERR("no memory for contact info\n");
-	return -1;
-    }
-
-    if (ruri_is_new) {
-	ruri = GET_RURI(msg);
-	if (!ruri) {
-	    LM_ERR("no Request-URI found\n");
-	    return -1;
-	}	
-	/* Insert Request-URI branch to first contact */
-	contacts->uri.s = ruri->s;
-	contacts->uri.len = ruri->len;
-	contacts->dst_uri = msg->dst_uri;
-	contacts->sock = msg->force_send_socket;
-	getbflagsval(0, &contacts->flags);
-	contacts->path = msg->path_vec;
-	contacts->q = get_ruri_q();
-	contacts->instance = msg->instance;
-	first_idx = 0;
-    } else {
-	/* Insert first branch to first contact */
-	branch = get_sip_branch(0);
-	contacts->uri.s = branch->uri;
-	contacts->uri.len = branch->len;
-	contacts->dst_uri.s = branch->dst_uri;
-	contacts->dst_uri.len = branch->dst_uri_len;
-	contacts->sock = branch->force_send_socket;
-	contacts->flags = branch->flags;
-	contacts->path.s = branch->path;
-	contacts->path.len = branch->path_len;
-	contacts->q = branch->q;
-	contacts->instance.s = branch->instance;
-	contacts->instance.len = branch->instance_len;
-	first_idx = 1;
-    }
-
-    contacts->next = (struct contact *)0;
-
-    /* Insert (remaining) branches to contact list in increasing q order */
-    for (idx = first_idx; (branch = get_sip_branch(idx)) != 0; idx++) {
-
-	next = (struct contact *)pkg_malloc(sizeof(struct contact));
-	if (!next) {
-	    LM_ERR("no memory for contact info\n");
-	    free_contact_list(contacts);
-	    return -1;
-	}
-
-	next->uri.s = branch->uri;
-	next->uri.len = branch->len;
-	next->dst_uri.s = branch->dst_uri;
-	next->dst_uri.len = branch->dst_uri_len;
-	next->sock = branch->force_send_socket;
-	next->flags = branch->flags;
-	next->path.s = branch->path;
-	next->path.len = branch->path_len;
-	next->q = branch->q;
-	next->instance.s = branch->instance;
-	next->instance.len = branch->instance_len;
-	next->next = (struct contact *)0;
-
-	prev = (struct contact *)0;
-	curr = contacts;
-	while (curr && (curr->q < branch->q)) {
-	    prev = curr;
-	    curr = curr->next;
+	/* Allocate memory for first contact */
+	contacts = (struct contact *)pkg_malloc(sizeof(struct contact));
+	if (!contacts) {
+		LM_ERR("no memory for contact info\n");
+		return -1;
 	}
-	if (!curr) {
-	    next->next = (struct contact *)0;
-	    prev->next = next;
-	} else {
-	    next->next = curr;
-	    if (prev) {
-		prev->next = next;
-	    } else {
-		contacts = next;
-	    }
-	}    
-    }
-
-    /* Assign values for q_flags */
-    curr = contacts;
-    curr->q_flag = 0;
-    while (curr->next) {
-	if (curr->q < curr->next->q) {
-	    curr->next->q_flag = Q_FLAG;
+
+	if (ruri_is_new) {
+		ruri = GET_RURI(msg);
+		if (!ruri) {
+			LM_ERR("no Request-URI found\n");
+			return -1;
+		}
+		/* Insert Request-URI branch to first contact */
+		contacts->uri.s = ruri->s;
+		contacts->uri.len = ruri->len;
+		contacts->dst_uri = msg->dst_uri;
+		contacts->sock = msg->force_send_socket;
+		getbflagsval(0, &contacts->flags);
+		contacts->path = msg->path_vec;
+		contacts->q = get_ruri_q();
+		contacts->instance = msg->instance;
+		contacts->ruid = msg->ruid;
+		contacts->location_ua = msg->location_ua;
+		first_idx = 0;
 	} else {
-	    curr->next->q_flag = 0;
+		/* Insert first branch to first contact */
+		branch = get_sip_branch(0);
+		contacts->uri.s = branch->uri;
+		contacts->uri.len = branch->len;
+		contacts->dst_uri.s = branch->dst_uri;
+		contacts->dst_uri.len = branch->dst_uri_len;
+		contacts->sock = branch->force_send_socket;
+		contacts->flags = branch->flags;
+		contacts->path.s = branch->path;
+		contacts->path.len = branch->path_len;
+		contacts->q = branch->q;
+		contacts->instance.s = branch->instance;
+		contacts->instance.len = branch->instance_len;
+		contacts->ruid.s = branch->ruid;
+		contacts->ruid.len = branch->ruid_len;
+		contacts->location_ua.s = branch->location_ua;
+		contacts->location_ua.len = branch->location_ua_len;
+		first_idx = 1;
 	}
-	curr = curr->next;
-    }
 
-    /* Add contacts to contacts_avp */
-    curr = contacts;
-    while (curr) {
+	contacts->next = (struct contact *)0;
 
-	if (curr->sock) {
-	    len = MAX_SOCKET_STR - 1;
-	    if (socket2str(sock_buf, &len, curr->sock) < 0) {
-		LM_ERR("failed to convert socket to str\n");
-		return -1;
-	    }
-	    sock_buf[len] = 0;
-	    sock_str.s = sock_buf;
-	    sock_str.len = len + 1;
+	/* Insert (remaining) branches to contact list in increasing q order */
+	for (idx = first_idx; (branch = get_sip_branch(idx)) != 0; idx++) {
+
+		next = (struct contact *)pkg_malloc(sizeof(struct contact));
+		if (!next) {
+			LM_ERR("no memory for contact info\n");
+			free_contact_list(contacts);
+			return -1;
+		}
+
+		next->uri.s = branch->uri;
+		next->uri.len = branch->len;
+		next->dst_uri.s = branch->dst_uri;
+		next->dst_uri.len = branch->dst_uri_len;
+		next->sock = branch->force_send_socket;
+		next->flags = branch->flags;
+		next->path.s = branch->path;
+		next->path.len = branch->path_len;
+		next->q = branch->q;
+		next->instance.s = branch->instance;
+		next->instance.len = branch->instance_len;
+		next->ruid.s = branch->ruid;
+		next->ruid.len = branch->ruid_len;
+		next->location_ua.s = branch->location_ua;
+		next->location_ua.len = branch->location_ua_len;
+		next->next = (struct contact *)0;
+
+		prev = (struct contact *)0;
+		curr = contacts;
+		while (curr &&
+				((curr->q < next->q) ||
+				 ((curr->q == next->q) && (next->path.len == 0)))) {
+			prev = curr;
+			curr = curr->next;
+		}
+		if (!curr) {
+			next->next = (struct contact *)0;
+			prev->next = next;
+		} else {
+			next->next = curr;
+			if (prev) {
+				prev->next = next;
+			} else {
+				contacts = next;
+			}
+		}
 	}
 
-	add_contacts_avp(&(curr->uri), &(curr->dst_uri), &(curr->path),
-			 &sock_str, curr->flags, curr->q_flag,
-			 &(curr->instance));
+	/* Assign values for q_flags */
+	curr = contacts;
+	curr->q_flag = 0;
+	while (curr->next) {
+		if (curr->q < curr->next->q) {
+			curr->next->q_flag = Q_FLAG;
+		} else {
+			curr->next->q_flag = 0;
+		}
+		curr = curr->next;
+	}
 
-	curr = curr->next;
-    }
+	/* Add contacts to contacts_avp */
+	curr = contacts;
+	while (curr) {
+
+		if (curr->sock) {
+			len = MAX_SOCKET_STR - 1;
+			if (socket2str(sock_buf, &len, curr->sock) < 0) {
+				LM_ERR("failed to convert socket to str\n");
+				return -1;
+			}
+			sock_buf[len] = 0;
+			sock_str.s = sock_buf;
+			sock_str.len = len + 1;
+		} else {
+			sock_str.s = 0;
+			sock_str.len = 0;
+		}
 
-    /* Clear all branches */
-    clear_branches();
+		add_contacts_avp(&(curr->uri), &(curr->dst_uri), &(curr->path),
+				&sock_str, curr->flags, curr->q_flag,
+				&(curr->instance), &(curr->ruid), &(curr->location_ua));
 
-    /* Free contact list */
-    free_contact_list(contacts);
+		curr = curr->next;
+	}
 
-    return 1;
+	/* Clear all branches */
+	clear_branches();
+
+	/* Free contact list */
+	free_contact_list(contacts);
+
+	return 1;
 }
 
 void add_contact_flows_avp(str *uri, str *dst_uri, str *path, str *sock_str,
-			   unsigned int flags, str *instance)
+		unsigned int flags, str *instance, str *ruid,
+		str *location_ua)
 {
-    sr_xavp_t *record;
-    sr_xval_t val;
-
-    record = NULL;
+	sr_xavp_t *record;
+	sr_xval_t val;
 
-    val.type = SR_XTYPE_STR;
-    val.v.s = *uri;
-    xavp_add_value(&uri_name, &val, &record);
+	record = NULL;
 
-    if (dst_uri->len > 0) {
 	val.type = SR_XTYPE_STR;
-	val.v.s = *dst_uri;
-	xavp_add_value(&dst_uri_name, &val, &record);
-    }
+	val.v.s = *uri;
+	xavp_add_value(&uri_name, &val, &record);
 
-    if (path->len > 0) {
-	val.type = SR_XTYPE_STR;
-	val.v.s = *path;
-	xavp_add_value(&path_name, &val, &record);
-    }
+	if (dst_uri->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *dst_uri;
+		xavp_add_value(&dst_uri_name, &val, &record);
+	}
 
-    if (sock_str->len > 0) {
-	val.v.s = *sock_str;
-	xavp_add_value(&sock_name, &val, &record);
-    }
+	if (path->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *path;
+		xavp_add_value(&path_name, &val, &record);
+	}
 
-    if (instance->len > 0) {
-	val.type = SR_XTYPE_STR;
-	val.v.s = *instance;
-	xavp_add_value(&instance_name, &val, &record);
-    }
+	if (sock_str->len > 0) {
+		val.v.s = *sock_str;
+		xavp_add_value(&sock_name, &val, &record);
+	}
+
+	if (instance->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *instance;
+		xavp_add_value(&instance_name, &val, &record);
+	}
+
+	if (ruid->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *ruid;
+		xavp_add_value(&ruid_name, &val, &record);
+	}
 
-    val.type = SR_XTYPE_INT;
-    val.v.i = flags;
-    xavp_add_value(&flags_name, &val, &record);
+	if (location_ua->len > 0) {
+		val.type = SR_XTYPE_STR;
+		val.v.s = *location_ua;
+		xavp_add_value(&ua_name, &val, &record);
+	}
+
+	val.type = SR_XTYPE_INT;
+	val.v.i = flags;
+	xavp_add_value(&flags_name, &val, &record);
 
-    val.type = SR_XTYPE_XAVP;
-    val.v.xavp = record;
-    xavp_add_value(&contact_flows_avp, &val, NULL);
+	val.type = SR_XTYPE_XAVP;
+	val.v.xavp = record;
+	xavp_add_value(&contact_flows_avp, &val, NULL);
 }
 
 /*
  * Adds to request a new destination set that includes highest
  * priority class contacts in contacts_avp, but only one contact with same
  * +sip.instance value is included.  Others are added to contact_flows_avp
- * for later consumption by next_contact_flows().
+ * for later consumption by next_contact_flow().
  * Request URI is rewritten with first contact and the remaining contacts
  * (if any) are added as branches. Removes all highest priority contacts
  * from contacts_avp.
@@ -354,234 +399,262 @@ void add_contact_flows_avp(str *uri, str *dst_uri, str *path, str *sock_str,
  * there was nothing to do. Returns -1 in case of an error. */
 int t_next_contacts(struct sip_msg* msg, char* key, char* value)
 {
-    str uri, dst_uri, path, instance, host, sock_str;
-    struct socket_info *sock;
-    unsigned int flags, q_flag;
-    sr_xavp_t *xavp_list, *xavp, *prev_xavp, *vavp;
-    int port, proto;
-    struct instance_list *il, *ilp;
-
-    /* Check if contacts_avp has been defined */
-    if (contacts_avp.len == 0) {
-	LM_ERR("feature has been disabled - "
-	       "to enable define contacts_avp module parameter");
-	return -1;
-    }
-
-    /* Load Request-URI and branches */
-
-    /* Find first contacts_avp value */
-    xavp_list = xavp_get(&contacts_avp, NULL);
-    if (!xavp_list) {
-	LM_DBG("no contacts in contacts_avp - we are done!\n");
-	return -2;
-    }
-
-    xavp = xavp_list;
-
-    vavp = xavp_get(&uri_name, xavp->val.v.xavp);
-    uri = vavp->val.v.s;
-
-    vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	dst_uri = vavp->val.v.s;
-    } else {
-	dst_uri.s = 0;
-	dst_uri.len = 0;
-    }
-
-    vavp = xavp_get(&path_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	path = vavp->val.v.s;
-    } else {
-	path.s = 0;
-	path.len = 0;
-    }
-
-    vavp = xavp_get(&sock_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	sock_str.s = vavp->val.v.s.s;
-	if (parse_phostport(sock_str.s, &host.s, &host.len, &port, &proto)
-	    != 0) {
-	    LM_ERR("parsing of socket info <%s> failed\n", sock_str.s);
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
-	}
-	sock = grep_sock_info(&host, (unsigned short)port,
-			      (unsigned short)proto);
-	if (sock == 0) {
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
-	}
-    } else {
-	sock = NULL;
-    }
-
-    vavp = xavp_get(&flags_name, xavp->val.v.xavp);
-    flags = vavp->val.v.i;
-
-    vavp = xavp_get(&q_flag_name, xavp->val.v.xavp);
-    q_flag = vavp->val.v.i;
-
-    vavp = xavp_get(&instance_name, xavp->val.v.xavp);
-    il = (struct instance_list *)0;
-    if ((vavp != NULL) && !q_flag) {
-	instance = vavp->val.v.s;
-	il = (struct instance_list *)pkg_malloc(sizeof(struct instance_list));
-	if (!il) {
-	    LM_ERR("no memory for instance list entry\n");
-	    return -1;
-	}
-	il->instance.s = pkg_malloc(instance.len);
-	if (!il->instance.s) {
-	    pkg_free(il);
-	    LM_ERR("no memory for instance list instance\n");
-	    return -1;
-	}
-	il->instance.len = instance.len;
-	memcpy(il->instance.s, instance.s, instance.len);
-	il->next = (struct instance_list *)0;
-    }
-
-    /* Rewrite Request-URI */
-    rewrite_uri(msg, &uri);
-
-    if (dst_uri.len) {
-	set_dst_uri(msg, &dst_uri);
-    } else {
-	reset_dst_uri(msg);
-    }
-
-    if (path.len) {
-	set_path_vector(msg, &path);
-    } else {
-	reset_path_vector(msg);
-    }
-
-    set_force_socket(msg, sock);
-
-    setbflagsval(0, flags);
-
-    /* Check if there was only one contact at this priority */
-    if (q_flag) {
-	xavp_rm(xavp, NULL);
-	return 1;
-    }
-		
-    /* Append branches until out of branches or Q_FLAG is set */
-    /* If a branch has same instance value as some previous branch, */
-    /* instead of appending it, add it to contact_flows_avp */
-
-    xavp_rm_by_name(&contact_flows_avp, 1, NULL);
-    prev_xavp = xavp;
+	str uri, dst_uri, path, instance, host, sock_str, ruid, location_ua;
+	struct socket_info *sock;
+	unsigned int flags, q_flag;
+	sr_xavp_t *xavp_list, *xavp, *prev_xavp, *vavp;
+	int port, proto;
+	struct instance_list *il, *ilp;
+
+	/* Check if contacts_avp has been defined */
+	if (contacts_avp.len == 0) {
+		LM_ERR("feature has been disabled - "
+				"to enable define contacts_avp module parameter");
+		return -1;
+	}
 
-    while ((xavp = xavp_get_next(prev_xavp)) != NULL) {
+	/* Load Request-URI and branches */
 
-	xavp_rm(prev_xavp, NULL);
+	/* Find first contacts_avp value */
+	xavp_list = xavp_get(&contacts_avp, NULL);
+	if (!xavp_list) {
+		LM_DBG("no contacts in contacts_avp - we are done!\n");
+		return -2;
+	}
 
-	vavp = xavp_get(&q_flag_name, xavp->val.v.xavp);
-	q_flag = vavp->val.v.i;
+	xavp = xavp_list;
 
 	vavp = xavp_get(&uri_name, xavp->val.v.xavp);
 	uri = vavp->val.v.s;
 
 	vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
 	if (vavp != NULL) {
-	    dst_uri = vavp->val.v.s;
+		dst_uri = vavp->val.v.s;
 	} else {
-	    dst_uri.len = 0;
+		dst_uri.s = 0;
+		dst_uri.len = 0;
 	}
 
 	vavp = xavp_get(&path_name, xavp->val.v.xavp);
 	if (vavp != NULL) {
-	    path = vavp->val.v.s;
+		path = vavp->val.v.s;
 	} else {
-	    path.len = 0;
+		path.s = 0;
+		path.len = 0;
 	}
 
 	vavp = xavp_get(&sock_name, xavp->val.v.xavp);
 	if (vavp != NULL) {
-	    sock_str = vavp->val.v.s;
-	    if (parse_phostport(sock_str.s, &host.s, &host.len, &port, &proto)
-		!= 0) {
-		LM_ERR("parsing of socket info <%s> failed\n", sock_str.s);
-		free_instance_list(il);
-		xavp_destroy_list(&xavp_list);
-		return -1;
-	    }
-	    sock = grep_sock_info(&host, (unsigned short)port,
-				  (unsigned short)proto);
-	    if (sock == 0) {
-		free_instance_list(il);
-		xavp_destroy_list(&xavp_list);
-		return -1;
-	    }
+		sock_str.s = vavp->val.v.s.s;
+		if (parse_phostport(sock_str.s, &host.s, &host.len, &port, &proto)
+				!= 0) {
+			LM_ERR("parsing of socket info <%s> failed\n", sock_str.s);
+			xavp_destroy_list(&xavp_list);
+			return -1;
+		}
+		sock = grep_sock_info(&host, (unsigned short)port,
+				(unsigned short)proto);
+		if (sock == 0) {
+			xavp_destroy_list(&xavp_list);
+			return -1;
+		}
 	} else {
-	    sock = NULL;
+		sock = NULL;
 	}
 
 	vavp = xavp_get(&flags_name, xavp->val.v.xavp);
 	flags = vavp->val.v.i;
 
+	vavp = xavp_get(&q_flag_name, xavp->val.v.xavp);
+	q_flag = vavp->val.v.i;
+
 	vavp = xavp_get(&instance_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    instance = vavp->val.v.s;
-	    ilp = il;
-	    while (ilp) {
-		if ((instance.len == ilp->instance.len) &&
-		    (strncmp(instance.s, ilp->instance.s, instance.len) == 0))
-		    break;
-		ilp = ilp->next;
-	    }
-	    if (ilp) {
-		add_contact_flows_avp(&uri, &dst_uri, &path, &sock_str,
-				      flags, &instance);
-		goto check_q_flag;
-	    }
-	    if (!q_flag) {
-		ilp = (struct instance_list *)
-		    pkg_malloc(sizeof(struct instance_list));
-		if (!ilp) {
-		    LM_ERR("no memory for instance list element\n");
-		    free_instance_list(il);
-		    return -1;
+	il = (struct instance_list *)0;
+	if ((vavp != NULL) && !q_flag) {
+		instance = vavp->val.v.s;
+		il = (struct instance_list *)pkg_malloc(sizeof(struct instance_list));
+		if (!il) {
+			LM_ERR("no memory for instance list entry\n");
+			return -1;
 		}
-		ilp->instance.s = pkg_malloc(instance.len);
-		if (!ilp->instance.s) {
-		    LM_ERR("no memory for instance list instance\n");
-		    pkg_free(ilp);
-		    free_instance_list(il);
-		    return -1;
+		il->instance.s = pkg_malloc(instance.len);
+		if (!il->instance.s) {
+			pkg_free(il);
+			LM_ERR("no memory for instance list instance\n");
+			return -1;
 		}
-		ilp->instance.len = instance.len;
-		memcpy(ilp->instance.s, instance.s, instance.len);
-		ilp->next = il;
-		il = ilp;
-	    }
+		il->instance.len = instance.len;
+		memcpy(il->instance.s, instance.s, instance.len);
+		il->next = (struct instance_list *)0;
+		set_instance(msg, &instance);
+	} else {
+		instance.len = 0;
 	}
 
-	if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, 0, 0)
-	    != 1) {
-	    LM_ERR("appending branch failed\n");
-	    free_instance_list(il);
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
+	vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
+	ruid = vavp->val.v.s;
+
+	vavp = xavp_get(&ua_name, xavp->val.v.xavp);
+	location_ua = vavp->val.v.s;
+
+	/* Rewrite Request-URI */
+	rewrite_uri(msg, &uri);
+
+	if (dst_uri.len) {
+		set_dst_uri(msg, &dst_uri);
+	} else {
+		reset_dst_uri(msg);
+	}
+
+	if (path.len) {
+		set_path_vector(msg, &path);
+	} else {
+		reset_path_vector(msg);
 	}
 
-    check_q_flag:
+	set_force_socket(msg, sock);
+
+	setbflagsval(0, flags);
+
+	set_ruid(msg, &ruid);
+
+	set_ua(msg, &location_ua);
+
+	/* Check if there was only one contact at this priority */
 	if (q_flag) {
-	    free_instance_list(il);
-	    xavp_rm(xavp, NULL);
-	    return 1;
+		xavp_rm(xavp, NULL);
+		return 1;
 	}
 
+	/* Append branches until out of branches or Q_FLAG is set */
+	/* If a branch has same instance value as some previous branch, */
+	/* instead of appending it, add it to contact_flows_avp */
+
+	xavp_rm_by_name(&contact_flows_avp, 1, NULL);
 	prev_xavp = xavp;
-    }
 
-    free_instance_list(il);
-    xavp_rm(prev_xavp, NULL);
+	while ((xavp = xavp_get_next(prev_xavp)) != NULL) {
+
+		xavp_rm(prev_xavp, NULL);
+
+		vavp = xavp_get(&q_flag_name, xavp->val.v.xavp);
+		q_flag = vavp->val.v.i;
+
+		vavp = xavp_get(&uri_name, xavp->val.v.xavp);
+		uri = vavp->val.v.s;
+
+		vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			dst_uri = vavp->val.v.s;
+		} else {
+			dst_uri.len = 0;
+		}
+
+		vavp = xavp_get(&path_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			path = vavp->val.v.s;
+		} else {
+			path.len = 0;
+		}
+
+		vavp = xavp_get(&sock_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			sock_str = vavp->val.v.s;
+			if (parse_phostport(sock_str.s, &host.s, &host.len, &port, &proto)
+					!= 0) {
+				LM_ERR("parsing of socket info <%s> failed\n", sock_str.s);
+				free_instance_list(il);
+				xavp_destroy_list(&xavp_list);
+				return -1;
+			}
+			sock = grep_sock_info(&host, (unsigned short)port,
+					(unsigned short)proto);
+			if (sock == 0) {
+				free_instance_list(il);
+				xavp_destroy_list(&xavp_list);
+				return -1;
+			}
+		} else {
+			sock = NULL;
+		}
+
+		vavp = xavp_get(&flags_name, xavp->val.v.xavp);
+		flags = vavp->val.v.i;
+
+		vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
+		ruid = vavp->val.v.s;
+
+		vavp = xavp_get(&ua_name, xavp->val.v.xavp);
+		location_ua = vavp->val.v.s;
+
+		vavp = xavp_get(&instance_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			instance = vavp->val.v.s;
+			ilp = il;
+			while (ilp) {
+				if ((instance.len == ilp->instance.len) &&
+						(strncmp(instance.s, ilp->instance.s, instance.len) == 0))
+					break;
+				ilp = ilp->next;
+			}
+			if (ilp) {
+				add_contact_flows_avp(&uri, &dst_uri, &path, &sock_str,
+						flags, &instance, &ruid, &location_ua);
+				goto check_q_flag;
+			}
+			if (!q_flag) {
+				ilp = (struct instance_list *)
+					pkg_malloc(sizeof(struct instance_list));
+				if (!ilp) {
+					LM_ERR("no memory for instance list element\n");
+					free_instance_list(il);
+					return -1;
+				}
+				ilp->instance.s = pkg_malloc(instance.len);
+				if (!ilp->instance.s) {
+					LM_ERR("no memory for instance list instance\n");
+					pkg_free(ilp);
+					free_instance_list(il);
+					return -1;
+				}
+				ilp->instance.len = instance.len;
+				memcpy(ilp->instance.s, instance.s, instance.len);
+				ilp->next = il;
+				il = ilp;
+			}
+		} else {
+			instance.len = 0;
+		}
+
+		LM_DBG("Appending branch uri-'%.*s' dst-'%.*s' path-'%.*s' inst-'%.*s'"
+				" ruid-'%.*s' location_ua-'%.*s'\n",
+				uri.len, uri.s,
+				dst_uri.len, (dst_uri.len > 0)?dst_uri.s:"",
+				path.len, (path.len>0)?path.s:"",
+				instance.len, (instance.len>0)?instance.s:"",
+				ruid.len, ruid.s, location_ua.len, location_ua.s);
+		if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, &instance, 0,
+					&ruid, &location_ua) != 1) {
+			LM_ERR("appending branch failed\n");
+			free_instance_list(il);
+			xavp_destroy_list(&xavp_list);
+			return -1;
+		}
 
-    return 1;
+check_q_flag:
+		if (q_flag) {
+			free_instance_list(il);
+			xavp_rm(xavp, NULL);
+			return 1;
+		}
+
+		prev_xavp = xavp;
+	}
+
+	free_instance_list(il);
+	xavp_rm(prev_xavp, NULL);
+
+	return 1;
 }
 
 /*
@@ -594,218 +667,121 @@ int t_next_contacts(struct sip_msg* msg, char* key, char* value)
  * Returns 1, if contact_flows_avp was not empty and a destination set was
  * successfully added.  Returns -2, if contact_flows_avp was empty and thus
  * there was nothing to do. Returns -1 in case of an error. */
-int t_next_contact_flows(struct sip_msg* msg, char* key, char* value)
+int t_next_contact_flow(struct sip_msg* msg, char* key, char* value)
 {
-    str uri, dst_uri, path, instance, host;
-    struct socket_info *sock;
-    unsigned int flags;
-    sr_xavp_t *xavp_list, *xavp, *next_xavp, *vavp;
-    char *tmp;
-    int port, proto;
-    struct instance_list *il, *ilp;
-
-    /* Check if contact_flows_avp has been defined */
-    if (contact_flows_avp.len == 0) {
-	LM_ERR("feature has been disabled - "
-	       "to enable define contact_flows_avp module parameter");
-	return -1;
-    }
-
-    /* Load Request-URI and branches */
-
-    /* Find first contact_flows_avp value */
-    xavp_list = xavp_get(&contact_flows_avp, NULL);
-    if (!xavp_list) {
-	LM_DBG("no contacts in contact_flows_avp - we are done!\n");
-	return -2;
-    }
-
-    xavp = xavp_list;
-    next_xavp = xavp_get_next(xavp);
-
-    vavp = xavp_get(&uri_name, xavp->val.v.xavp);
-    uri = vavp->val.v.s;
-
-    vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	dst_uri = vavp->val.v.s;
-    } else {
-	dst_uri.s = 0;
-	dst_uri.len = 0;
-    }
-
-    vavp = xavp_get(&path_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	path = vavp->val.v.s;
-    } else {
-	path.s = 0;
-	path.len = 0;
-    }
-
-    vavp = xavp_get(&sock_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	tmp = vavp->val.v.s.s;
-	if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
-	    LM_ERR("parsing of socket info <%s> failed\n", tmp);
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
-	}
-	sock = grep_sock_info(&host, (unsigned short)port,
-			      (unsigned short)proto);
-	if (sock == 0) {
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
-	}
-    } else {
-	sock = NULL;
-    }
-
-    vavp = xavp_get(&flags_name, xavp->val.v.xavp);
-    flags = vavp->val.v.i;
-
-    vavp = xavp_get(&instance_name, xavp->val.v.xavp);
-    il = (struct instance_list *)0;
-    if ((vavp != NULL) && next_xavp) {
-	instance = vavp->val.v.s;
-	il = (struct instance_list *)pkg_malloc(sizeof(struct instance_list));
-	if (!il) {
-	    LM_ERR("no memory for instance list entry\n");
-	    return -1;
-	}
-	il->instance.s = pkg_malloc(instance.len);
-	if (!il->instance.s) {
-	    pkg_free(il);
-	    LM_ERR("no memory for instance list instance\n");
-	    return -1;
-	}
-	il->instance.len = instance.len;
-	memcpy(il->instance.s, instance.s, instance.len);
-	il->next = (struct instance_list *)0;
-    }
-
-    /* Rewrite Request-URI */
-    rewrite_uri(msg, &uri);
-
-    if (dst_uri.len) {
-	set_dst_uri(msg, &dst_uri);
-    } else {
-	reset_dst_uri(msg);
-    }
-
-    if (path.len) {
-	set_path_vector(msg, &path);
-    } else {
-	reset_path_vector(msg);
-    }
-
-    set_force_socket(msg, sock);
-
-    setbflagsval(0, flags);
-
-    /* Append branches until out of branches. */
-    /* Do not include a branch that has same instance value as some */
-    /* previous branch. */
-
-    xavp_rm(xavp, NULL);
-    xavp = next_xavp;
-
-    while (xavp) {
-	
-	next_xavp = xavp_get_next(xavp);
-
-	vavp = xavp_get(&instance_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    instance = vavp->val.v.s;
-	    ilp = il;
-	    while (ilp) {
-		if ((instance.len == ilp->instance.len) &&
-		    (strncmp(instance.s, ilp->instance.s, instance.len) == 0))
-		    break;
-		ilp = ilp->next;
-	    }
-	    if (ilp) {
-		/* skip already appended instance */
-		xavp = next_xavp;
-		continue;
-	    }
-	    if (next_xavp) {
-		ilp = (struct instance_list *)
-		pkg_malloc(sizeof(struct instance_list));
-		if (!ilp) {
-		    LM_ERR("no memory for new instance list entry\n");
-		    free_instance_list(il);
-		    return -1;
-		}
-		ilp->instance.s = pkg_malloc(instance.len);
-		if (!ilp->instance.s) {
-		    pkg_free(il);
-		    LM_ERR("no memory for instance list instance\n");
-		    return -1;
-		}
-		ilp->instance.len = instance.len;
-		memcpy(ilp->instance.s, instance.s, instance.len);
-		ilp->next = il;
-		il = ilp;
-	    } else {
-		LM_ERR("instance missing from contact_flow_avp contact\n");
-		free_instance_list(il);
+	str uri, dst_uri, path, instance, host, ruid, location_ua;
+	str this_instance;
+	struct socket_info *sock;
+	unsigned int flags;
+	sr_xavp_t *xavp_list, *xavp, *next_xavp, *vavp;
+	char *tmp;
+	int port, proto;
+
+	/* Check if contact_flows_avp has been defined */
+	if (contact_flows_avp.len == 0) {
+		LM_ERR("feature has been disabled - "
+				"to enable define contact_flows_avp module parameter");
 		return -1;
-	    }
 	}
 
-	vavp = xavp_get(&uri_name, xavp->val.v.xavp);
-	uri = vavp->val.v.s;
+	/* Load Request-URI and branches */
+	t_get_this_branch_instance(msg, &this_instance);
 
-	vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    dst_uri = vavp->val.v.s;
-	} else {
-	    dst_uri.len = 0;
+	if (this_instance.len == 0)
+	{
+		LM_DBG("No instance on this branch\n");
+		return -2;
 	}
-
-	vavp = xavp_get(&path_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    path = vavp->val.v.s;
-	} else {
-	    path.len = 0;
+	/* Find first contact_flows_avp value */
+	xavp_list = xavp_get(&contact_flows_avp, NULL);
+	if (!xavp_list) {
+		LM_DBG("no contacts in contact_flows_avp - we are done!\n");
+		return -2;
 	}
 
-	vavp = xavp_get(&sock_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    tmp = vavp->val.v.s.s;
-	    if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
-		LM_ERR("parsing of socket info <%s> failed\n", tmp);
-		free_instance_list(il);
-		xavp_destroy_list(&xavp_list);
-		return -1;
-	    }
-	    sock = grep_sock_info(&host, (unsigned short)port,
-				  (unsigned short)proto);
-	    if (sock == 0) {
-		free_instance_list(il);
-		xavp_destroy_list(&xavp_list);
-		return -1;
-	    }
-	} else {
-	    sock = NULL;
-	}
+	xavp = xavp_list;
 
-	vavp = xavp_get(&flags_name, xavp->val.v.xavp);
-	flags = vavp->val.v.i;
+	while (xavp) {
+		next_xavp = xavp_get_next(xavp);
 
-	if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, 0, 0)
-	    != 1) {
-	    LM_ERR("appending branch failed\n");
-	    free_instance_list(il);
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
-	}
+		vavp = xavp_get(&instance_name, xavp->val.v.xavp);
+		if (vavp == NULL)
+		{
+			/* Does not match this instance */
+			goto next_xavp;
+		}
+		else
+		{
+			instance = vavp->val.v.s;
+			if ((instance.len != this_instance.len) ||
+					(strncmp(instance.s, this_instance.s, instance.len) != 0))
+				/* Does not match this instance */
+				goto next_xavp;
+		}
+
+		vavp = xavp_get(&uri_name, xavp->val.v.xavp);
+		uri = vavp->val.v.s;
+
+		vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			dst_uri = vavp->val.v.s;
+		} else {
+			dst_uri.len = 0;
+		}
 
-	xavp_rm(xavp, NULL);
-	xavp = next_xavp;
-    }
+		vavp = xavp_get(&path_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			path = vavp->val.v.s;
+		} else {
+			path.len = 0;
+		}
 
-    free_instance_list(il);
+		vavp = xavp_get(&sock_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			tmp = vavp->val.v.s.s;
+			if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
+				LM_ERR("parsing of socket info <%s> failed\n", tmp);
+				xavp_rm(xavp, NULL);
+				return -1;
+			}
+			sock = grep_sock_info(&host, (unsigned short)port,
+					(unsigned short)proto);
+			if (sock == 0) {
+				xavp_rm(xavp, NULL);
+				return -1;
+			}
+		} else {
+			sock = NULL;
+		}
+
+		vavp = xavp_get(&flags_name, xavp->val.v.xavp);
+		flags = vavp->val.v.i;
+
+		vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
+		ruid = vavp->val.v.s;
+
+		vavp = xavp_get(&ua_name, xavp->val.v.xavp);
+		location_ua = vavp->val.v.s;
+
+		LM_DBG("Appending branch uri-'%.*s' dst-'%.*s' path-'%.*s'"
+				" inst-'%.*s' ruid-'%.*s' location_ua-'%.*s'\n",
+				uri.len, uri.s,
+				dst_uri.len, (dst_uri.len > 0)?dst_uri.s:"",
+				path.len, (path.len>0)?path.s:"",
+				instance.len, (instance.len>0)?instance.s:"",
+				ruid.len, ruid.s, location_ua.len, location_ua.s);
+		if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, &instance, 0,
+					&ruid, &location_ua) != 1) {
+			LM_ERR("appending branch failed\n");
+			xavp_destroy_list(&xavp_list);
+			return -1;
+		}
 
-    return 1;
+		xavp_rm(xavp, NULL);
+		return 1;
+next_xavp:
+		xavp = next_xavp;
+	}
+
+	return -1;
 }
diff --git a/modules/tm/t_serial.h b/modules/tm/t_serial.h
index b1c8181..0794e31 100644
--- a/modules/tm/t_serial.h
+++ b/modules/tm/t_serial.h
@@ -34,4 +34,4 @@ int t_load_contacts(struct sip_msg* msg, char* key, char* value);
 
 int t_next_contacts(struct sip_msg* msg, char* key, char* value);
 
-int t_next_contact_flows(struct sip_msg* msg, char* key, char* value);
+int t_next_contact_flow(struct sip_msg* msg, char* key, char* value);
diff --git a/modules/tm/t_suspend.c b/modules/tm/t_suspend.c
index 35adcb1..789d25a 100644
--- a/modules/tm/t_suspend.c
+++ b/modules/tm/t_suspend.c
@@ -33,6 +33,7 @@
 
 #include "../../action.h"
 #include "../../script_cb.h"
+#include "../../dset.h"
 
 #include "config.h"
 #include "sip_msg.h"
@@ -42,8 +43,13 @@
 #include "t_fwd.h"
 #include "t_funcs.h"
 #include "timer.h"
+#include "t_cancel.h"
+
 #include "t_suspend.h"
 
+#include "../../data_lump.h"
+#include "../../data_lump_rpl.h"
+
 /* Suspends the transaction for later use.
  * Save the returned hash_index and label to get
  * back to the SIP request processing, see the readme.
@@ -56,6 +62,7 @@ int t_suspend(struct sip_msg *msg,
 		unsigned int *hash_index, unsigned int *label)
 {
 	struct cell	*t;
+	int branch;
 
 	t = get_t();
 	if (!t || t == T_UNDEFINED) {
@@ -72,37 +79,72 @@ int t_suspend(struct sip_msg *msg,
 		return 1;
 	}
 
-	/* send a 100 Trying reply, because the INVITE processing
-	will probably take a long time */
-	if (msg->REQ_METHOD==METHOD_INVITE && (t->flags&T_AUTO_INV_100)
-		&& (t->uas.status < 100)
-	) {
-		if (!t_reply( t, msg , 100 ,
-			cfg_get(tm, tm_cfg, tm_auto_inv_100_r)))
+	if (msg->first_line.type != SIP_REPLY) {
+		/* send a 100 Trying reply, because the INVITE processing
+		will probably take a long time */
+		if (msg->REQ_METHOD==METHOD_INVITE && (t->flags&T_AUTO_INV_100)
+			&& (t->uas.status < 100)
+		) {
+			if (!t_reply( t, msg , 100 ,
+				cfg_get(tm, tm_cfg, tm_auto_inv_100_r)))
 				DBG("SER: ERROR: t_suspend (100)\n");
-	}
+		}
 
-	if ((t->nr_of_outgoings==0) && /* if there had already been
-				an UAC created, then the lumps were
-				saved as well */
-		save_msg_lumps(t->uas.request, msg)
-	) {
-		LOG(L_ERR, "ERROR: t_suspend: " \
-			"failed to save the message lumps\n");
-		return -1;
+		if ((t->nr_of_outgoings==0) && /* if there had already been
+			an UAC created, then the lumps were
+			saved as well */
+			save_msg_lumps(t->uas.request, msg)
+		) {
+			LOG(L_ERR, "ERROR: t_suspend: " \
+				"failed to save the message lumps\n");
+			return -1;
+		}
+		/* save the message flags */
+		t->uas.request->flags = msg->flags;
+
+		/* add a blind UAC to let the fr timer running */
+		if (add_blind_uac() < 0) {
+			LOG(L_ERR, "ERROR: t_suspend: " \
+				"failed to add the blind UAC\n");
+			return -1;
+		}
+	}else{
+		LOG(L_DBG,"DEBUG: t_suspend_reply: This is a suspend on reply - setting msg flag to SUSPEND\n");
+		msg->msg_flags |= FL_RPL_SUSPENDED;
+		/* this is a reply suspend find which branch */
+
+		if (t_check( msg  , &branch )==-1){
+			LOG(L_ERR, "ERROR: t_suspend_reply: " \
+				"failed find UAC branch\n");
+			return -1; 
+		}
+		LOG(L_DBG,"DEBUG: t_suspend_reply:Found a a match with branch id [%d]\n", branch);
+
+		LOG(L_DBG,"DEBUG: t_suspend_reply:Cloning reply message to t->uac[branch].reply\n");
+
+		int sip_msg_len = 0;
+		t->uac[branch].reply = sip_msg_cloner( msg, &sip_msg_len );
+
+		if (! t->uac[branch].reply ) {
+			LOG(L_ERR, "ERROR: t_suspend_reply: can't alloc' clone memory\n");
+			return -1;
+		}
+		t->uac[branch].end_reply = ((char*)t->uac[branch].reply) + sip_msg_len;
+
+		LOG(L_DBG,"DEBUG: t_suspend_reply: Saving transaction data\n");
+		t->uac[branch].reply->flags = msg->flags;
 	}
-	/* save the message flags */
-	t->uas.request->flags = msg->flags;
 
-	*hash_index = t->hash_index;
+        *hash_index = t->hash_index;
 	*label = t->label;
 
-	/* add a bling UAC to let the fr timer running */
-	if (add_blind_uac() < 0) {
-		LOG(L_ERR, "ERROR: t_suspend: " \
-			"failed to add the blind UAC\n");
-		return -1;
-	}
+
+
+	/* backup some extra info that can be used in continuation logic */
+	t->async_backup.backup_route = get_route_type();
+	t->async_backup.backup_branch = get_t_branch();
+	t->async_backup.ruri_new = ruri_get_forking_state();
+
 
 	return 0;
 }
@@ -120,6 +162,7 @@ int t_continue(unsigned int hash_index, unsigned int label,
 {
 	struct cell	*t;
 	struct sip_msg	faked_req;
+	struct cancel_info cancel_data;
 	int	branch;
 	struct ua_client *uac =NULL;
 	int	ret;
@@ -140,95 +183,247 @@ int t_continue(unsigned int hash_index, unsigned int label,
 
 	/* The transaction has to be locked to protect it
 	 * form calling t_continue() multiple times simultaneously */
-	LOCK_REPLIES(t);
-
-	/* Try to find the blind UAC, and cancel its fr timer.
-	 * We assume that the last blind uac called t_continue(). */
-	for (	branch = t->nr_of_outgoings-1;
-		branch >= 0 && t->uac[branch].request.buffer;
-		branch--);
-
-	if (branch >= 0) {
-		stop_rb_timers(&t->uac[branch].request);
-
-		if (t->uac[branch].last_received != 0) {
-			/* Either t_continue() has already been
-			 * called or the branch has already timed out.
-			 * Needless to continue. */
-			UNLOCK_REPLIES(t);
-			UNREF(t); /* t_unref would kill the transaction */
-			return 1;
-		}
+	LOCK_ASYNC_CONTINUE(t);
 
-		/* Set last_received to something >= 200,
-		 * the actual value does not matter, the branch
-		 * will never be picked up for response forwarding.
-		 * If last_received is lower than 200,
-		 * then the branch may tried to be cancelled later,
-		 * for example when t_reply() is called from
-		 * a failure route => deadlock, because both
-		 * of them need the reply lock to be held. */
-		t->uac[branch].last_received=500;
-		uac = &t->uac[branch];
+	t->flags |= T_ASYNC_CONTINUE;   /* we can now know anywhere in kamailio 
+					 * that we are executing post a suspend */
+	
+	/* which route block type were we in when we were suspended */
+	int cb_type = REQUEST_CB_TYPE;
+	switch (t->async_backup.backup_route) {
+		case REQUEST_ROUTE:
+			cb_type = REQUEST_CB_TYPE;
+			break;
+		case FAILURE_ROUTE:
+			cb_type = FAILURE_CB_TYPE;
+			break;
+		case TM_ONREPLY_ROUTE:
+			cb_type = ONREPLY_CB_TYPE;
+			break;
+		case BRANCH_ROUTE:
+			cb_type = BRANCH_CB_TYPE;
+			break;
 	}
-	/* else
-		Not a huge problem, fr timer will fire, but CANCEL
-		will not be sent. last_received will be set to 408. */
 
-	reset_kr();
+	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
+		branch = t->async_backup.blind_uac;	/* get the branch of the blind UAC setup 
+			* during suspend */
+		if (branch >= 0) {
+			stop_rb_timers(&t->uac[branch].request);
+ 
+			if (t->uac[branch].last_received != 0) {
+				/* Either t_continue() has already been
+				* called or the branch has already timed out.
+				* Needless to continue. */
+				UNLOCK_ASYNC_CONTINUE(t);
+				UNREF(t); /* t_unref would kill the transaction */
+				return 1;
+			}
+
+			/*we really don't need this next line anymore otherwise we will 
+			never be able to forward replies after a (t_relay) on this branch.
+			We want to try and treat this branch as 'normal' (as if it were a normal req, not async)' */
+			//t->uac[branch].last_received=500;
+			uac = &t->uac[branch];
+		}
+		/* else
+			Not a huge problem, fr timer will fire, but CANCEL
+			will not be sent. last_received will be set to 408. */
 
-	/* fake the request and the environment, like in failure_route */
-	if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */, uac)) {
-		LOG(L_ERR, "ERROR: t_continue: fake_req failed\n");
-		ret = -1;
-		goto kill_trans;
-	}
-	faked_env( t, &faked_req);
-
-	/* The sip msg is a faked msg just like in failure route
-	 * therefore execute the pre- and post-script callbacks
-	 * of failure route (Miklos)
-	 */
-	if (exec_pre_script_cb(&faked_req, FAILURE_CB_TYPE)>0) {
-		if (run_top_route(route, &faked_req, 0)<0)
-			LOG(L_ERR, "ERROR: t_continue: Error in run_top_route\n");
-		exec_post_script_cb(&faked_req, FAILURE_CB_TYPE);
-	}
+		reset_kr();
 
-	/* TODO: save_msg_lumps should clone the lumps to shm mem */
+		/* fake the request and the environment, like in failure_route */
+		if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */, uac)) {
+			LOG(L_ERR, "ERROR: t_continue: fake_req failed\n");
+			ret = -1;
+			goto kill_trans;
+		}
+		faked_env( t, &faked_req, 1);
 
-	/* restore original environment and free the fake msg */
-	faked_env( t, 0);
-	free_faked_req(&faked_req, t);
+		/* execute the pre/post -script callbacks based on original route block */
+		if (exec_pre_script_cb(&faked_req, cb_type)>0) {
+			if (run_top_route(route, &faked_req, 0)<0)
+				LOG(L_ERR, "ERROR: t_continue: Error in run_top_route\n");
+			exec_post_script_cb(&faked_req, cb_type);
+		}
 
-	/* update the flags */
-	t->uas.request->flags = faked_req.flags;
+		/* TODO: save_msg_lumps should clone the lumps to shm mem */
 
-	if (t->uas.status < 200) {
-		/* No final reply has been sent yet.
-		 * Check whether or not there is any pending branch.
-		 */
-		for (	branch = 0;
-			branch < t->nr_of_outgoings;
-			branch++
-		) {
-			if (t->uac[branch].last_received < 200)
-				break;
-		}
+		/* restore original environment and free the fake msg */
+		faked_env( t, 0, 1);
+		free_faked_req(&faked_req, t);
+
+		/* update the flags */
+		t->uas.request->flags = faked_req.flags;
 
-		if (branch == t->nr_of_outgoings) {
+		if (t->uas.status < 200) {
+			/* No final reply has been sent yet.
+			* Check whether or not there is any pending branch.
+			*/
+			for (	branch = 0;
+				branch < t->nr_of_outgoings;
+				branch++
+			) {
+				if (t->uac[branch].last_received < 200)
+					break;
+			}
+
+			if (branch == t->nr_of_outgoings) {
 			/* There is not any open branch so there is
-			 * no chance that a final response will be received. */
-			ret = 0;
-			goto kill_trans;
+			* no chance that a final response will be received. */
+				ret = 0;
+				goto kill_trans;
+			}
 		}
-	}
 
-	UNLOCK_REPLIES(t);
+	}else{
+		branch = t->async_backup.backup_branch;
+
+		init_cancel_info(&cancel_data);
+
+		LOG(L_DBG,"DEBUG: t_continue_reply: This a continue from a reply suspend\n");
+		/* this is a continue from a reply suspend */
+
+		LOG(L_DBG,"DEBUG: t_continue_reply: Disabling suspend branch");
+		t->uac[branch].reply->msg_flags &= ~FL_RPL_SUSPENDED;
+		if (t->uas.request) t->uas.request->msg_flags&= ~FL_RPL_SUSPENDED;
+
+		faked_env( t, t->uac[branch].reply, 1);
+
+		LOG(L_DBG,"DEBUG: Running pre script\n");
+		if (exec_pre_script_cb(t->uac[branch].reply, cb_type)>0) {
+			if (run_top_route(route, t->uac[branch].reply, 0)<0){
+				LOG(L_ERR, "ERROR: t_continue_reply: Error in run_top_route\n");
+			}
+			LOG(L_DBG,"DEBUG: t_continue_reply: Running exec post script\n");
+			exec_post_script_cb(t->uac[branch].reply, cb_type);
+		}
+
+		LOG(L_DBG,"DEBUG: t_continue_reply: Restoring previous environment");
+		faked_env( t, 0, 1);
+
+		int reply_status;
+
+		/*lock transaction replies - will be unlocked when reply is relayed*/
+		LOCK_REPLIES( t );
+		if ( is_local(t) ) {
+			LOG(L_DBG,"DEBUG: t_continue_reply: t is local sending local reply with status code: [%d]\n", t->uac[branch].reply->first_line.u.reply.statuscode);
+			reply_status = local_reply( t, t->uac[branch].reply, branch, t->uac[branch].reply->first_line.u.reply.statuscode, &cancel_data );
+			if (reply_status == RPS_COMPLETED) {
+				/* no more UAC FR/RETR (if I received a 2xx, there may
+				* be still pending branches ...
+				*/
+				cleanup_uac_timers( t );
+				if (is_invite(t)) cancel_uacs(t, &cancel_data, F_CANCEL_B_KILL);
+				/* There is no need to call set_final_timer because we know
+				* that the transaction is local */
+				put_on_wait(t);
+			}else if (unlikely(cancel_data.cancel_bitmap)){
+				/* cancel everything, even non-INVITEs (e.g in case of 6xx), use
+				* cancel_b_method for canceling unreplied branches */
+				cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags));
+			}
+
+		} else {
+			LOG(L_DBG,"DEBUG: t_continue_reply: t is NOT local sending relaying reply with status code: [%d]\n", t->uac[branch].reply->first_line.u.reply.statuscode);
+			int do_put_on_wait = 0;
+			if(t->uac[branch].reply->first_line.u.reply.statuscode>=200){
+				do_put_on_wait = 1;
+			}
+			reply_status=relay_reply( t, t->uac[branch].reply, branch, t->uac[branch].reply->first_line.u.reply.statuscode, &cancel_data, do_put_on_wait );
+			if (reply_status == RPS_COMPLETED) {
+				/* no more UAC FR/RETR (if I received a 2xx, there may
+				be still pending branches ...
+				*/
+				cleanup_uac_timers( t );
+				/* 2xx is a special case: we can have a COMPLETED request
+				* with branches still open => we have to cancel them */
+				if (is_invite(t) && cancel_data.cancel_bitmap) 
+					cancel_uacs( t, &cancel_data,  F_CANCEL_B_KILL);
+				/* FR for negative INVITES, WAIT anything else */
+				/* Call to set_final_timer is embedded in relay_reply to avoid
+				* race conditions when reply is sent out and an ACK to stop
+				* retransmissions comes before retransmission timer is set.*/
+			}else if (unlikely(cancel_data.cancel_bitmap)){
+				/* cancel everything, even non-INVITEs (e.g in case of 6xx), use
+				* cancel_b_method for canceling unreplied branches */
+				cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags));
+			}
+
+		}
+		t->uac[branch].request.flags|=F_RB_REPLIED;
+
+		if (reply_status==RPS_ERROR){
+			goto done;
+		}
+
+		/* update FR/RETR timers on provisional replies */
+
+		int msg_status=t->uac[branch].reply->REPLY_STATUS;
+		int last_uac_status=t->uac[branch].last_received;
+
+		if (is_invite(t) && msg_status<200 &&
+			( cfg_get(tm, tm_cfg, restart_fr_on_each_reply) ||
+			( (last_uac_status<msg_status) &&
+			((msg_status>=180) || (last_uac_status==0)) )
+		) ) { /* provisional now */
+			restart_rb_fr(& t->uac[branch].request, t->fr_inv_timeout);
+			t->uac[branch].request.flags|=F_RB_FR_INV; /* mark fr_inv */
+		}
+            
+	}
 
-	/* unref the transaction */
-	t_unref(t->uas.request);
+done:
+	UNLOCK_ASYNC_CONTINUE(t);
+
+	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
+		/* unref the transaction */
+		t_unref(t->uas.request);
+	}else{
+		struct hdr_field *hdr, *prev = 0, *tmp = 0;
+
+		tm_ctx_set_branch_index(T_BR_UNDEFINED);        
+		/* unref the transaction */
+		t_unref(t->uac[branch].reply);
+		LOG(L_DBG,"DEBUG: t_continue_reply: Freeing earlier cloned reply\n");
+
+		/* free lumps that were added during reply processing */
+		del_nonshm_lump( &(t->uac[branch].reply->add_rm) );
+		del_nonshm_lump( &(t->uac[branch].reply->body_lumps) );
+		del_nonshm_lump_rpl( &(t->uac[branch].reply->reply_lump) );
+
+		/* free header's parsed structures that were added */
+		for( hdr=t->uac[branch].reply->headers ; hdr ; hdr=hdr->next ) {
+			if ( hdr->parsed && hdr_allocs_parse(hdr) &&
+				(hdr->parsed<(void*)t->uac[branch].reply ||
+				hdr->parsed>=(void*)t->uac[branch].end_reply)) {
+				clean_hdr_field(hdr);
+				hdr->parsed = 0;
+			}
+		}
 
+		/* now go through hdr_fields themselves and remove the pkg allocated space */
+		hdr = t->uac[branch].reply->headers;
+		while (hdr) {
+			if ( hdr && ((void*)hdr<(void*)t->uac[branch].reply ||
+				(void*)hdr>=(void*)t->uac[branch].end_reply)) {
+				//this header needs to be freed and removed form the list.
+				if (!prev) {
+					t->uac[branch].reply->headers = hdr->next;
+				} else {
+					prev->next = hdr->next;
+				}
+				tmp = hdr;
+				hdr = hdr->next;
+				pkg_free(tmp);
+			} else {
+				prev = hdr;
+				hdr = hdr->next;
+			}
+		}
+		sip_msg_free(t->uac[branch].reply);
+		t->uac[branch].reply = 0;
+	}
 	return 0;
 
 kill_trans:
@@ -241,13 +436,18 @@ kill_trans:
 			"reply generation failed\n");
 		/* The transaction must be explicitely released,
 		 * no more timer is running */
-		UNLOCK_REPLIES(t);
+		UNLOCK_ASYNC_CONTINUE(t);
 		t_release_transaction(t);
 	} else {
-		UNLOCK_REPLIES(t);
+		UNLOCK_ASYNC_CONTINUE(t);
 	}
 
-	t_unref(t->uas.request);
+	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
+		t_unref(t->uas.request);
+	}else{
+		/* unref the transaction */
+		t_unref(t->uac[branch].reply);
+	}
 	return ret;
 }
 
@@ -281,34 +481,45 @@ int t_cancel_suspend(unsigned int hash_index, unsigned int label)
 			"transaction id mismatch\n");
 		return -1;
 	}
-	/* The transaction does not need to be locked because this
-	 * function is either executed from the original route block
-	 * or from failure route which already locks */
-
-	reset_kr(); /* the blind UAC of t_suspend has set kr */
-
-	/* Try to find the blind UAC, and cancel its fr timer.
-	 * We assume that the last blind uac called this function. */
-	for (	branch = t->nr_of_outgoings-1;
-		branch >= 0 && t->uac[branch].request.buffer;
-		branch--);
-
-	if (branch >= 0) {
-		stop_rb_timers(&t->uac[branch].request);
-		/* Set last_received to something >= 200,
-		 * the actual value does not matter, the branch
-		 * will never be picked up for response forwarding.
-		 * If last_received is lower than 200,
-		 * then the branch may tried to be cancelled later,
-		 * for example when t_reply() is called from
-		 * a failure rute => deadlock, because both
-		 * of them need the reply lock to be held. */
-		t->uac[branch].last_received=500;
-	} else {
-		/* Not a huge problem, fr timer will fire, but CANCEL
-		will not be sent. last_received will be set to 408. */
-		return -1;
-	}
+        
+	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
+		/* The transaction does not need to be locked because this
+		* function is either executed from the original route block
+		* or from failure route which already locks */
+
+		reset_kr(); /* the blind UAC of t_suspend has set kr */
+
+		/* Try to find the blind UAC, and cancel its fr timer.
+		* We assume that the last blind uac called this function. */
+		for (	branch = t->nr_of_outgoings-1;
+			branch >= 0 && t->uac[branch].request.buffer;
+			branch--);
+
+		if (branch >= 0) {
+			stop_rb_timers(&t->uac[branch].request);
+			/* Set last_received to something >= 200,
+			* the actual value does not matter, the branch
+			* will never be picked up for response forwarding.
+			* If last_received is lower than 200,
+			* then the branch may tried to be cancelled later,
+			* for example when t_reply() is called from
+			* a failure rute => deadlock, because both
+			* of them need the reply lock to be held. */
+			t->uac[branch].last_received=500;
+		} else {
+			/* Not a huge problem, fr timer will fire, but CANCEL
+			will not be sent. last_received will be set to 408. */
+			return -1;
+		}
+	}else{
+		branch = t->async_backup.backup_branch;
+
+		LOG(L_DBG,"DEBUG: t_cancel_suspend_reply: This is a cancel suspend for a response\n");
 
+		t->uac[branch].reply->msg_flags &= ~FL_RPL_SUSPENDED;
+		if (t->uas.request) t->uas.request->msg_flags&= ~FL_RPL_SUSPENDED;
+        }
+	
 	return 0;
 }
+
diff --git a/modules/tm/t_suspend.h b/modules/tm/t_suspend.h
index 1c19be1..3721f73 100644
--- a/modules/tm/t_suspend.h
+++ b/modules/tm/t_suspend.h
@@ -29,6 +29,9 @@
 #ifndef _T_SUSPEND_H
 #define _T_SUSPEND_H
 
+#define LOCK_ASYNC_CONTINUE(_t) lock(&(_t)->async_mutex )
+#define UNLOCK_ASYNC_CONTINUE(_t) unlock(&(_t)->async_mutex )
+
 int t_suspend(struct sip_msg *msg,
 		unsigned int *hash_index, unsigned int *label);
 typedef int (*t_suspend_f)(struct sip_msg *msg,
diff --git a/modules/tm/tm.c b/modules/tm/tm.c
index 6b03081..3bdc7fb 100644
--- a/modules/tm/tm.c
+++ b/modules/tm/tm.c
@@ -190,6 +190,7 @@ MODULE_VERSION
 static int fixup_hostport2proxy(void** param, int param_no);
 static int fixup_proto_hostport2proxy(void** param, int param_no);
 static int fixup_on_failure(void** param, int param_no);
+static int fixup_on_branch_failure(void** param, int param_no);
 static int fixup_on_reply(void** param, int param_no);
 static int fixup_on_branch(void** param, int param_no);
 static int fixup_t_reply(void** param, int param_no);
@@ -272,6 +273,7 @@ inline static int w_t_forward_nonack_sctp(struct sip_msg*, char* str,char*);
 inline static int w_t_forward_nonack_to(struct sip_msg* msg, char* str,char*);
 inline static int w_t_relay_cancel(struct sip_msg *p_msg, char *_foo, char *_bar);
 inline static int w_t_on_failure(struct sip_msg* msg, char *go_to, char *foo);
+inline static int w_t_on_branch_failure(struct sip_msg* msg, char *go_to, char *foo);
 inline static int w_t_on_branch(struct sip_msg* msg, char *go_to, char *foo);
 inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
 inline static int t_check_status(struct sip_msg* msg, char *match, char *foo);
@@ -301,6 +303,7 @@ static int w_t_drop_replies(struct sip_msg* msg, char* foo, char* bar);
 static int w_t_save_lumps(struct sip_msg* msg, char* foo, char* bar);
 static int w_t_check_trans(struct sip_msg* msg, char* foo, char* bar);
 static int w_t_is_set(struct sip_msg* msg, char* target, char* bar);
+static int w_t_use_uac_headers(sip_msg_t* msg, char* foo, char* bar);
 
 
 /* by default the fr timers avps are not set, so that the avps won't be
@@ -313,6 +316,10 @@ str contact_flows_avp = {0, 0};
 
 int tm_remap_503_500 = 1;
 
+int tm_failure_exec_mode = 0;
+
+int tm_dns_reuse_rcv_socket = 0;
+
 static rpc_export_t tm_rpc[];
 
 static int fixup_t_check_status(void** param, int param_no);
@@ -410,12 +417,14 @@ static cmd_export_t cmds[]={
 			REQUEST_ROUTE},
 	{"t_on_failure",       w_t_on_failure,         1, fixup_on_failure,
 			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
+	{"t_on_branch_failure",w_t_on_branch_failure,  1, fixup_on_branch_failure,
+			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
 	{"t_on_reply",         w_t_on_reply,            1, fixup_on_reply,
 			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
 	{"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"t_check_status",     t_check_status,          1, fixup_t_check_status,
-			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
 	{"t_write_req",       t_write_req,              2, fixup_t_write,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"t_write_unix",      t_write_unix,             2, fixup_t_write,
@@ -451,8 +460,10 @@ static cmd_export_t cmds[]={
 #endif /* CANCEL_REASON_SUPPORT */
 	{"t_set_disable_internal_reply", t_set_disable_internal_reply, 1, fixup_var_int_1,
 			REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
-	{"t_branch_timeout",  t_branch_timeout,         0, 0,  FAILURE_ROUTE},
-	{"t_branch_replied",  t_branch_replied,         0, 0,  FAILURE_ROUTE},
+	{"t_branch_timeout",  t_branch_timeout,         0, 0,
+	                FAILURE_ROUTE|EVENT_ROUTE},
+	{"t_branch_replied",  t_branch_replied,         0, 0,
+	                FAILURE_ROUTE|EVENT_ROUTE},
 	{"t_any_timeout",     t_any_timeout,            0, 0, 
 			REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
 	{"t_any_replied",     t_any_replied,            0, 0, 
@@ -473,13 +484,15 @@ static cmd_export_t cmds[]={
 			REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE },
 	{"t_is_set",	      w_t_is_set,				1, fixup_t_is_set,
 			ANY_ROUTE },
+	{"t_use_uac_headers",  w_t_use_uac_headers,		0, 0,
+			ANY_ROUTE },
 
 	{"t_load_contacts", t_load_contacts,            0, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE},
 	{"t_next_contacts", t_next_contacts,            0, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE},
-	{"t_next_contact_flows", t_next_contact_flows,            0, 0,
-			REQUEST_ROUTE | FAILURE_ROUTE},
+	{"t_next_contact_flow", t_next_contact_flow,            0, 0,
+			REQUEST_ROUTE },
 
 	/* not applicable from the script */
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,   0, 0},
@@ -534,6 +547,8 @@ static param_export_t params[]={
 	{"failure_reply_mode",  PARAM_INT, &failure_reply_mode                   },
 	{"faked_reply_prio",    PARAM_INT, &faked_reply_prio                     },
 	{"remap_503_500",       PARAM_INT, &tm_remap_503_500                     },
+	{"failure_exec_mode",   PARAM_INT, &tm_failure_exec_mode                 },
+	{"dns_reuse_rcv_socket",PARAM_INT, &tm_dns_reuse_rcv_socket              },
 #ifdef CANCEL_REASON_SUPPORT
 	{"local_cancel_reason", PARAM_INT, &default_tm_cfg.local_cancel_reason   },
 	{"e2e_cancel_reason",   PARAM_INT, &default_tm_cfg.e2e_cancel_reason     },
@@ -603,6 +618,31 @@ static int fixup_on_failure(void** param, int param_no)
 	return 0;
 }
 
+#define BRANCH_FAILURE_ROUTE_PREFIX "tm:branch-failure"
+static int fixup_on_branch_failure(void** param, int param_no)
+{
+	char *full_route_name = NULL;
+	int len;
+	int ret = 0;
+	if (param_no==1){
+		if((len = strlen((char*)*param))<=1
+				&& (*(char*)(*param)==0 || *(char*)(*param)=='0')) {
+			*param = (void*)0;
+			return 0;
+		}
+		len += strlen(BRANCH_FAILURE_ROUTE_PREFIX) + 1;
+		if ((full_route_name = pkg_malloc(len+1)) == NULL)
+		{
+			LM_ERR("No memory left in branch_failure fixup\n");
+			return -1;
+		}
+		sprintf(full_route_name, "%s:%s", BRANCH_FAILURE_ROUTE_PREFIX, (char*)*param);
+		*param=(void*)full_route_name;
+		ret = fixup_routes("t_on_branch_failure", &event_rt, param);
+		pkg_free(full_route_name);
+	}
+	return ret;
+}
 
 
 static int fixup_on_reply(void** param, int param_no)
@@ -736,6 +776,7 @@ static int script_init( struct sip_msg *foo, unsigned int flags, void *bar)
 		message's t_on_failure value
 	*/
 	t_on_failure( 0 );
+	t_on_branch_failure(0);
 	t_on_reply(0);
 	t_on_branch(0);
 	/* reset the kr status */
@@ -897,8 +938,6 @@ static int child_init(int rank)
 
 
 
-
-
 /**************************** wrapper functions ***************************/
 static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
 {
@@ -982,7 +1021,9 @@ static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
 		}
 		status = int2str( lowest_status , 0);
 		break;
-
+	case BRANCH_FAILURE_ROUTE:
+		status = int2str(t->uac[get_t_branch()].last_received, 0);
+		break;
 	default:
 		LOG(L_ERR,"ERROR:t_check_status: unsupported route type %d\n",
 				get_route_type());
@@ -1371,6 +1412,14 @@ inline static int w_t_on_failure( struct sip_msg* msg, char *go_to, char *foo)
 	return 1;
 }
 
+
+inline static int w_t_on_branch_failure( struct sip_msg* msg, char *go_to, char *foo)
+{
+	t_on_branch_failure( (unsigned int )(long) go_to );
+	return 1;
+}
+
+
 inline static int w_t_on_branch( struct sip_msg* msg, char *go_to, char *foo)
 {
 	t_on_branch( (unsigned int )(long) go_to );
@@ -1441,7 +1490,7 @@ inline static int _w_t_relay_to(struct sip_msg  *p_msg ,
 	struct cell *t;
 	int res;
 
-	if (is_route_type(FAILURE_ROUTE)) {
+	if (is_route_type(FAILURE_ROUTE|BRANCH_FAILURE_ROUTE)) {
 		t=get_t();
 		if (!t || t==T_UNDEFINED) {
 			LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
@@ -1834,21 +1883,37 @@ T_SET_FLAG_GEN_FUNC(t_set_no_e2e_cancel_reason, T_NO_E2E_CANCEL_REASON)
 T_SET_FLAG_GEN_FUNC(t_set_disable_internal_reply, T_DISABLE_INTERNAL_REPLY)
 
 
-/* script function, FAILURE_ROUTE only, returns true if the 
- * choosed "failure" branch failed because of a timeout, 
+/* script function, FAILURE_ROUTE and BRANCH_FAILURE_ROUTE only,
+ * returns true if the choosed "failure" branch failed because of a timeout, 
  * -1 otherwise */
 int t_branch_timeout(struct sip_msg* msg, char* foo, char* bar)
 {
+    switch(get_route_type()) {
+    case FAILURE_ROUTE:
+    case BRANCH_FAILURE_ROUTE:
 	return (msg->msg_flags & FL_TIMEOUT)?1:-1;
+    default:
+	LOG(L_ERR, "ERROR:t_check_status: unsupported route type %d\n",
+	    get_route_type());
+    }
+    return -1;
 }
 
 
-
-/* script function, FAILURE_ROUTE only, returns true if the 
- * choosed "failure" branch ever received a reply, -1 otherwise */
+/* script function, FAILURE_ROUTE and BRANCH_FAILURE_ROUTE only,
+ * returns true if the choosed "failure" branch ever received a reply,
+ * -1 otherwise */
 int t_branch_replied(struct sip_msg* msg, char* foo, char* bar)
 {
+    switch(get_route_type()) {
+    case FAILURE_ROUTE:
+    case BRANCH_FAILURE_ROUTE:
 	return (msg->msg_flags & FL_REPLIED)?1:-1;
+    default:
+	LOG(L_ERR, "ERROR:t_check_status: unsupported route type %d\n",
+	    get_route_type());
+    }
+    return -1;
 }
 
 
@@ -2242,6 +2307,18 @@ inline static int w_t_relay_to(struct sip_msg *msg, char *proxy, char *flags)
 }
 
 
+static int w_t_use_uac_headers(sip_msg_t* msg, char* foo, char* bar)
+{
+	tm_cell_t *t;
+
+	t=get_t();
+	if (t!=NULL && t!=T_UNDEFINED) {
+		t->uas.request->msg_flags |= FL_USE_UAC_FROM|FL_USE_UAC_TO;
+	}
+	msg->msg_flags |= FL_USE_UAC_FROM|FL_USE_UAC_TO;
+
+	return 1;
+}
 
 /* rpc docs */
 
diff --git a/modules/tm/tm_load.c b/modules/tm/tm_load.c
index 5a0c936..285120a 100644
--- a/modules/tm/tm_load.c
+++ b/modules/tm/tm_load.c
@@ -105,11 +105,14 @@ int load_tm( struct tm_binds *tmb)
 	tmb->free_dlg = free_dlg;
 	tmb->print_dlg = print_dlg;
 	tmb->t_gett = get_t;
+	tmb->t_gett_branch = get_t_branch;
+	tmb->t_sett = set_t;
 	tmb->calculate_hooks = w_calculate_hooks;
 	tmb->t_uac = t_uac;
 	tmb->t_uac_with_ids = t_uac_with_ids;
 	tmb->t_unref = t_unref;
 	tmb->run_failure_handlers = run_failure_handlers;
+	tmb->run_branch_failure_handlers = run_branch_failure_handlers;
 	tmb->cancel_uacs = cancel_uacs;
 	tmb->cancel_all_uacs = cancel_all_uacs;
 	tmb->prepare_request_within = prepare_req_within;
diff --git a/modules/tm/tm_load.h b/modules/tm/tm_load.h
index 1c43d41..3d1a3f5 100644
--- a/modules/tm/tm_load.h
+++ b/modules/tm/tm_load.h
@@ -82,12 +82,15 @@ struct tm_binds {
 	free_dlg_f         free_dlg;
 	print_dlg_f        print_dlg;
 	tgett_f            t_gett;
+	tgett_branch_f     t_gett_branch;
+	tsett_f            t_sett;
 	calculate_hooks_f  calculate_hooks;
 	t_uac_t            t_uac;
 	t_uac_with_ids_t   t_uac_with_ids;
 	trelease_f         t_release;
 	tunref_f           t_unref;
 	run_failure_handlers_f run_failure_handlers;
+	run_branch_failure_handlers_f run_branch_failure_handlers;
 	cancel_uacs_f      cancel_uacs;
 	cancel_all_uacs_f  cancel_all_uacs;
 	prepare_request_within_f  prepare_request_within;
diff --git a/modules/tm/uac.c b/modules/tm/uac.c
index c1f8256..ecdc357 100644
--- a/modules/tm/uac.c
+++ b/modules/tm/uac.c
@@ -426,6 +426,9 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
 	}
 #endif
 
+	new_cell->uac[0].on_reply = new_cell->on_reply;
+	new_cell->uac[0].on_failure = new_cell->on_failure;
+
 	new_cell->method.s = buf;
 	new_cell->method.len = uac_r->method->len;
 
@@ -701,6 +704,12 @@ int req_within(uac_req_t *uac_r)
 		goto err;
 	}
 
+	if(uac_r->ssock!=NULL && uac_r->ssock->len>0
+			&& uac_r->dialog->send_sock==NULL) {
+		/* set local send socket */
+		uac_r->dialog->send_sock = lookup_local_socket(uac_r->ssock);
+	}
+
 	if ((uac_r->method->len == 3) && (!memcmp("ACK", uac_r->method->s, 3))) goto send;
 	if ((uac_r->method->len == 6) && (!memcmp("CANCEL", uac_r->method->s, 6))) goto send;
 	uac_r->dialog->loc_seq.value++; /* Increment CSeq */
@@ -741,6 +750,12 @@ int req_outside(uac_req_t *uac_r, str* ruri, str* to, str* from, str *next_hop)
 	if (next_hop) uac_r->dialog->dst_uri = *next_hop;
 	w_calculate_hooks(uac_r->dialog);
 
+	if(uac_r->ssock!=NULL && uac_r->ssock->len>0
+			&& uac_r->dialog->send_sock==NULL) {
+		/* set local send socket */
+		uac_r->dialog->send_sock = lookup_local_socket(uac_r->ssock);
+	}
+
 	return t_uac(uac_r);
 
  err:
@@ -762,7 +777,10 @@ int request(uac_req_t *uac_r, str* ruri, str* to, str* from, str *next_hop)
 
 	if (check_params(uac_r, to, from) < 0) goto err;
 
-	generate_callid(&callid);
+	if (uac_r->callid == NULL || uac_r->callid->len <= 0)
+	    generate_callid(&callid);
+	else
+	    callid = *uac_r->callid;
 	generate_fromtag(&fromtag, &callid);
 
 	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
@@ -791,6 +809,13 @@ int request(uac_req_t *uac_r, str* ruri, str* to, str* from, str *next_hop)
 	 * before freeing dialog here must be removed
 	 */
 	uac_r->dialog = dialog;
+
+	if(uac_r->ssock!=NULL && uac_r->ssock->len>0
+			&& uac_r->dialog->send_sock==NULL) {
+		/* set local send socket */
+		uac_r->dialog->send_sock = lookup_local_socket(uac_r->ssock);
+	}
+
 	res = t_uac(uac_r);
 	dialog->rem_target.s = 0;
 	dialog->dst_uri.s = 0;
diff --git a/modules/tm/uac.h b/modules/tm/uac.h
index 619d43e..b466426 100644
--- a/modules/tm/uac.h
+++ b/modules/tm/uac.h
@@ -54,16 +54,19 @@ typedef struct uac_req {
 	str	*method;
 	str	*headers;
 	str	*body;
+	str *ssock;
 	dlg_t	*dialog;
 	int	cb_flags;
 	transaction_cb	*cb;
 	void	*cbp;
+	str	*callid;
 } uac_req_t;
 
 /* macro for setting the values of uac_req_t struct */
 #define set_uac_req(_req, \
 		_m, _h, _b, _dlg, _cb_flags, _cb, _cbp) \
 	do { \
+		memset((_req), 0, sizeof(uac_req_t)); \
 		(_req)->method = (_m); \
 		(_req)->headers = (_h); \
 		(_req)->body = (_b); \
diff --git a/modules/tmrec/README b/modules/tmrec/README
index a9b331f..6cffee0 100644
--- a/modules/tmrec/README
+++ b/modules/tmrec/README
@@ -298,7 +298,7 @@ if(is_leap_year("2010"))
 
    Example 1.4. time_period_match usage
 ...
-if(time_period_match("wd{2-6} hr{8-16}, wd{1-5} hr{17} min{0-29}"))
+if(time_period_match("wd{1-5} hr{8-16}, wd{1-5} hr{17} min{0-29}"))
         xdbg("Monday to Friday, 8:00 to 17:30\n");
 
 if(time_period_match("weekday { sat sun }, weekday {mo-fr} hr {17-8},wd{mo-wed}h
diff --git a/modules/tmx/README b/modules/tmx/README
index 6eee7fd..0208c62 100644
--- a/modules/tmx/README
+++ b/modules/tmx/README
@@ -1,3 +1,4 @@
+
 TMX Module
 
 Daniel-Constantin Mierla
@@ -12,7 +13,7 @@ Daniel-Constantin Mierla
    <miconda at gmail.com>
 
    Copyright � 2009 Daniel-Constantin Mierla
-     __________________________________________________________________
+     _________________________________________________________________
 
    Table of Contents
 
@@ -26,24 +27,24 @@ Daniel-Constantin Mierla
 
         3. Functions
 
-              3.1. t_cancel_branches(which)
-              3.2. t_cancel_callid(callid, cseq, flag)
-              3.3. t_reply_callid(callid, cseq, code, reason)
-              3.4. t_flush_flags()
-              3.5. t_is_failure_route()
-              3.6. t_is_branch_route()
-              3.7. t_is_reply_route()
-              3.8. t_suspend()
-              3.9. t_continue(tindex, tlabel, rtname)
+              3.1. t_cancel_branches(which) 
+              3.2. t_cancel_callid(callid, cseq, flag) 
+              3.3. t_reply_callid(callid, cseq, code, reason) 
+              3.4. t_flush_flags() 
+              3.5. t_is_failure_route() 
+              3.6. t_is_branch_route() 
+              3.7. t_is_reply_route() 
+              3.8. t_suspend() 
+              3.9. t_continue(tindex, tlabel, rtname) 
 
         4. Exported pseudo-variables
         5. MI Commands
 
-              5.1. t_uac_dlg
-              5.2. t_uac_cancel
-              5.3. t_hash
-              5.4. t_reply
-              5.5. t_reply_callid
+              5.1. t_uac_dlg 
+              5.2. t_uac_cancel 
+              5.3. t_hash 
+              5.4. t_reply 
+              5.5. t_reply_callid 
 
         6. Statistics
 
@@ -83,24 +84,24 @@ Chapter 1. Admin Guide
 
    3. Functions
 
-        3.1. t_cancel_branches(which)
-        3.2. t_cancel_callid(callid, cseq, flag)
-        3.3. t_reply_callid(callid, cseq, code, reason)
-        3.4. t_flush_flags()
-        3.5. t_is_failure_route()
-        3.6. t_is_branch_route()
-        3.7. t_is_reply_route()
-        3.8. t_suspend()
-        3.9. t_continue(tindex, tlabel, rtname)
+        3.1. t_cancel_branches(which) 
+        3.2. t_cancel_callid(callid, cseq, flag) 
+        3.3. t_reply_callid(callid, cseq, code, reason) 
+        3.4. t_flush_flags() 
+        3.5. t_is_failure_route() 
+        3.6. t_is_branch_route() 
+        3.7. t_is_reply_route() 
+        3.8. t_suspend() 
+        3.9. t_continue(tindex, tlabel, rtname) 
 
    4. Exported pseudo-variables
    5. MI Commands
 
-        5.1. t_uac_dlg
-        5.2. t_uac_cancel
-        5.3. t_hash
-        5.4. t_reply
-        5.5. t_reply_callid
+        5.1. t_uac_dlg 
+        5.2. t_uac_cancel 
+        5.3. t_hash 
+        5.4. t_reply 
+        5.5. t_reply_callid 
 
    6. Statistics
 
@@ -135,25 +136,25 @@ Chapter 1. Admin Guide
 
 2.2. External Libraries or Applications
 
-   The following libraries or applications must be installed before
+   The  following  libraries  or  applications  must  be installed before
    running Kamailio with this module loaded:
      * None.
 
 3. Functions
 
-   3.1. t_cancel_branches(which)
-   3.2. t_cancel_callid(callid, cseq, flag)
-   3.3. t_reply_callid(callid, cseq, code, reason)
-   3.4. t_flush_flags()
-   3.5. t_is_failure_route()
-   3.6. t_is_branch_route()
-   3.7. t_is_reply_route()
-   3.8. t_suspend()
-   3.9. t_continue(tindex, tlabel, rtname)
+   3.1. t_cancel_branches(which) 
+   3.2. t_cancel_callid(callid, cseq, flag) 
+   3.3. t_reply_callid(callid, cseq, code, reason) 
+   3.4. t_flush_flags() 
+   3.5. t_is_failure_route() 
+   3.6. t_is_branch_route() 
+   3.7. t_is_reply_route() 
+   3.8. t_suspend() 
+   3.9. t_continue(tindex, tlabel, rtname) 
 
-3.1. t_cancel_branches(which)
+3.1.  t_cancel_branches(which)
 
-   Cancel branches of an active SIP transaction. The function can be
+   Cancel  branches  of  an  active  SIP transaction. The function can be
    called for a SIP reply that will identify the current branch.
 
    Parameter can be:.
@@ -170,7 +171,7 @@ if (t_cancel_branches("all")) {
 }
 ...
 
-3.2. t_cancel_callid(callid, cseq, flag)
+3.2.  t_cancel_callid(callid, cseq, flag)
 
    Cancel first INVITE transaction identified by callid and cseq. It sets
    the flag if the value is greater than zero
@@ -189,7 +190,7 @@ if (t_cancel_callid("123qaz", "5", "22")) {
 }
 ...
 
-3.3. t_reply_callid(callid, cseq, code, reason)
+3.3.  t_reply_callid(callid, cseq, code, reason)
 
    Send reply to first INVITE transaction identified by callid and cseq.
 
@@ -208,11 +209,11 @@ if (t_reply_callid("123qaz", "5", "458", "Replied remotely")) {
 }
 ...
 
-3.4. t_flush_flags()
+3.4.  t_flush_flags()
 
-   Flush the flags from current SIP message into the already created
-   transaction. It make sense only in routing block if the transaction was
-   created via t_newtran() and the flags have been altered since.
+   Flush  the  flags  from  current  SIP message into the already created
+   transaction.  It  make  sense only in routing block if the transaction
+   was created via t_newtran() and the flags have been altered since.
 
    This function can be used from ANY_ROUTE .
 
@@ -221,7 +222,7 @@ if (t_reply_callid("123qaz", "5", "458", "Replied remotely")) {
 t_flush_flags();
 ...
 
-3.5. t_is_failure_route()
+3.5.  t_is_failure_route()
 
    Returns true if the top-executed route block is failure_route.
 
@@ -238,7 +239,7 @@ route[abc] {
 }
 ...
 
-3.6. t_is_branch_route()
+3.6.  t_is_branch_route()
 
    Returns true if the top-executed route block is branch_route.
 
@@ -255,7 +256,7 @@ route[abc] {
 }
 ...
 
-3.7. t_is_reply_route()
+3.7.  t_is_reply_route()
 
    Returns true if the top-executed route block is reply_route.
 
@@ -272,10 +273,10 @@ route[abc] {
 }
 ...
 
-3.8. t_suspend()
+3.8.  t_suspend()
 
-   Suspend the execution of SIP request in a transaction. If transaction
-   was not created yet, it is created by this function. Returns true in
+   Suspend  the execution of SIP request in a transaction. If transaction
+   was  not  created yet, it is created by this function. Returns true in
    case of success and internal transaction index and label are available
    via $T(id_index) and $T(id_label).
 
@@ -290,17 +291,17 @@ if(t_suspend())
 }
 ...
 
-3.9. t_continue(tindex, tlabel, rtname)
+3.9.  t_continue(tindex, tlabel, rtname)
 
-   Continue the execution of the transaction identified by tindex and
+   Continue  the  execution  of  the transaction identified by tindex and
    tlabel with the actions defined in route[rtname].
 
    Parameters:.
-     * tindex - internal index of transaction. Can be an integer or a
+     * tindex  -  internal  index  of transaction. Can be an integer or a
        pseudo-variable.
-     * tlabel - internal label of transaction. Can be an integer or a
+     * tlabel  -  internal  label  of transaction. Can be an integer or a
        pseudo-variable.
-     * rtname - the name of the route block to execute. Can be a static
+     * rtname  -  the name of the route block to execute. Can be a static
        string value or a dynamic string with pseudo-variables.
 
    This function can be used in ANY_ROUTE.
@@ -318,19 +319,20 @@ tcontinue('123', '456', 'MYROUTE');
      * $T_reply_last
      * $T_req(pv)
      * $T_rpl(pv)
+     * $T_reply_ruid
 
    Exported pseudo-variables are documented at
-   http://www.kamailio.org/wiki/.
+   http://www.kamailio.org/dokuwiki/.
 
 5. MI Commands
 
-   5.1. t_uac_dlg
-   5.2. t_uac_cancel
-   5.3. t_hash
-   5.4. t_reply
-   5.5. t_reply_callid
+   5.1. t_uac_dlg 
+   5.2. t_uac_cancel 
+   5.3. t_hash 
+   5.4. t_reply 
+   5.5. t_reply_callid 
 
-5.1. t_uac_dlg
+5.1.  t_uac_dlg
 
    Generates and sends a local SIP request.
 
@@ -338,14 +340,14 @@ tcontinue('123', '456', 'MYROUTE');
      * method - request method
      * RURI - request SIP URI
      * NEXT HOP - next hop SIP URI (OBP); use "." if no value.
-     * socket - local socket to be used for sending the request; use "."
+     * socket  - local socket to be used for sending the request; use "."
        if no value.
      * headers - set of additional headers to be added to the request; at
        least "From" and "To" headers must be specify)
-     * body - (optional, may not be present) request body (if present,
+     * body  -  (optional,  may not be present) request body (if present,
        requires the "Content-Type" and "Content-length" headers)
 
-5.2. t_uac_cancel
+5.2.  t_uac_cancel
 
    Generates and sends a CANCEL for an existing local SIP request.
 
@@ -353,28 +355,29 @@ tcontinue('123', '456', 'MYROUTE');
      * callid - callid of the INVITE request to be cancelled.
      * cseq - cseq of the INVITE request to be cancelled.
 
-5.3. t_hash
+5.3.  t_hash
 
    Gets information about the load of TM internal hash table.
 
    Parameters:
      * none
 
-5.4. t_reply
+5.4.  t_reply
 
    Generates and sends a reply for an existing inbound SIP transaction.
 
    Parameters:
      * code - reply code
      * reason - reason phrase.
-     * trans_id - transaction identifier (has the hash_entry:label format)
+     * trans_id   -  transaction  identifier  (has  the  hash_entry:label
+       format)
      * to_tag - To tag to be added to TO header
      * new_headers - extra headers to be appended to the reply; use a dot
        (".") char only if there are no headers;
-     * body - (optional, may not be present) reply body (if present,
+     * body  -  (optional,  may  not  be present) reply body (if present,
        requires the "Content-Type" and "Content-length" headers)
 
-5.5. t_reply_callid
+5.5.  t_reply_callid
 
    Generates and sends a reply for an existing inbound SIP transaction.
 
@@ -386,7 +389,7 @@ tcontinue('123', '456', 'MYROUTE');
      * to_tag - To tag to be added to TO header
      * new_headers - extra headers to be appended to the reply; use a dot
        (".") char only if there are no headers;
-     * body - (optional, may not be present) reply body (if present,
+     * body  -  (optional,  may  not  be present) reply body (if present,
        requires the "Content-Type" and "Content-length" headers)
 
 6. Statistics
@@ -403,7 +406,7 @@ tcontinue('123', '456', 'MYROUTE');
    6.10. 6xx_transactions
    6.11. inuse_transactions
 
-   Exported statistics are listed in the next sections. All statistics
+   Exported  statistics  are  listed in the next sections. All statistics
    except "inuse_transactions" can be reset.
 
 6.1. received_replies
diff --git a/modules/tmx/doc/tmx_admin.xml b/modules/tmx/doc/tmx_admin.xml
index a8b2e32..a644010 100644
--- a/modules/tmx/doc/tmx_admin.xml
+++ b/modules/tmx/doc/tmx_admin.xml
@@ -355,6 +355,9 @@ tcontinue('123', '456', 'MYROUTE');
 			<listitem><para>
 				<emphasis>$T_rpl(pv)</emphasis>
 			</para></listitem>
+			<listitem><para>
+				<emphasis>$T_reply_ruid</emphasis>
+			</para></listitem>
 		</itemizedlist>
 		<para>
 		Exported pseudo-variables are documented at &kamwikilink;.
diff --git a/modules/tmx/t_var.c b/modules/tmx/t_var.c
index 11e3229..a52927a 100644
--- a/modules/tmx/t_var.c
+++ b/modules/tmx/t_var.c
@@ -417,6 +417,42 @@ int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
 	return 0;
 }
 
+int pv_get_tm_reply_ruid(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	struct cell *t;
+	int branch;
+
+	if(msg==NULL || res==NULL)
+		return -1;
+
+	/* first get the transaction */
+	if (_tmx_tmb.t_check( msg , 0 )==-1) return -1;
+	if ( (t=_tmx_tmb.t_gett())==0) {
+		/* no T */
+		res->rs = _empty_str;
+	} else {
+		switch (get_route_type()) {
+			case FAILURE_ROUTE:
+			case BRANCH_FAILURE_ROUTE:
+				/* use the reason of the winning reply */
+				if ( (branch=_tmx_tmb.t_get_picked_branch())<0 ) {
+					LM_CRIT("no picked branch (%d) for a final response"
+							" in MODE_ONFAILURE\n", branch);
+					return -1;
+				}
+				res->rs = t->uac[branch].ruid;
+				break;
+			default:
+				LM_ERR("unsupported route_type %d\n", get_route_type());
+				return -1;
+		}
+	}
+	LM_DBG("reply ruid is [%.*s]\n", res->rs.len, res->rs.s);
+	res->flags = PV_VAL_STR;
+	return 0;
+}
+
 int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 {
@@ -449,6 +485,7 @@ int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 				code = msg->first_line.u.reply.statuscode;
 				break;
 			case FAILURE_ROUTE:
+			case BRANCH_FAILURE_ROUTE:
 				/* use the status of the winning reply */
 				if ( (branch=_tmx_tmb.t_get_picked_branch())<0 ) {
 					LM_CRIT("no picked branch (%d) for a final response"
diff --git a/modules/tmx/t_var.h b/modules/tmx/t_var.h
index dbfd559..46e8a50 100644
--- a/modules/tmx/t_var.h
+++ b/modules/tmx/t_var.h
@@ -38,6 +38,8 @@ int pv_parse_t_var_name(pv_spec_p sp, str *in);
 
 int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
+int pv_get_tm_reply_ruid(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
 int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 int pv_get_tm_reply_reason(struct sip_msg *msg, pv_param_t *param,
diff --git a/modules/tmx/tmx_mod.c b/modules/tmx/tmx_mod.c
index c559f40..89f5e65 100644
--- a/modules/tmx/tmx_mod.c
+++ b/modules/tmx/tmx_mod.c
@@ -123,6 +123,9 @@ static pv_export_t mod_pvs[] = {
 	{ {"T_branch_idx", sizeof("T_branch_idx")-1}, PVT_OTHER,
 		pv_get_tm_branch_idx, 0,
 		 0, 0, 0, 0 },
+	{ {"T_reply_ruid", sizeof("T_reply_ruid")-1}, PVT_OTHER,
+		pv_get_tm_reply_ruid, 0,
+		 0, 0, 0, 0 },
 	{ {"T_reply_code", sizeof("T_reply_code")-1}, PVT_OTHER,
 		pv_get_tm_reply_code, 0,
 		 0, 0, 0, 0 },
@@ -331,6 +334,8 @@ static int fixup_cancel_callid(void** param, int param_no)
 static int t_cancel_callid(struct sip_msg* msg, char *cid, char *cseq, char *flag)
 {
 	struct cell *trans;
+	struct cell *bkt;
+	int bkb;
 	struct cancel_info cancel_data;
 	str cseq_s;
 	str callid_s;
@@ -356,6 +361,8 @@ static int t_cancel_callid(struct sip_msg* msg, char *cid, char *cseq, char *fla
 		return -1;
 	}
 
+	bkt = _tmx_tmb.t_gett();
+	bkb = _tmx_tmb.t_gett_branch();
 	if( _tmx_tmb.t_lookup_callid(&trans, callid_s, cseq_s) < 0 ) {
 		DBG("Lookup failed - no transaction\n");
 		return -1;
@@ -370,6 +377,7 @@ static int t_cancel_callid(struct sip_msg* msg, char *cid, char *cseq, char *fla
 	_tmx_tmb.cancel_uacs(trans, &cancel_data, 0);
 
 	//_tmx_tmb.unref_cell(trans);
+	_tmx_tmb.t_sett(bkt, bkb);
 
 	return 1;
 }
diff --git a/modules/uac/README b/modules/uac/README
index cd5cf5c..fc3846d 100644
--- a/modules/uac/README
+++ b/modules/uac/README
@@ -605,6 +605,7 @@ $uac_req(method)="OPTIONS";
 $uac_req(ruri)="sip:kamailio.org";
 $uac_req(furi)="sip:kamailio.org";
 $uac_req(turi)="sip:kamailio.org";
+$uac_req(callid)=$(mb{s.md5});
 uac_req_send();
 ...
 
diff --git a/modules/uac/doc/uac_admin.xml b/modules/uac/doc/uac_admin.xml
index 05dc713..d3a3c54 100644
--- a/modules/uac/doc/uac_admin.xml
+++ b/modules/uac/doc/uac_admin.xml
@@ -103,7 +103,7 @@
 
 	<section>
 		<title>Parameters</title>
-		<section>
+		<section id="uac.p.rr_from_store_param">
 			<title><varname>rr_from_store_param</varname> (string)</title>
 			<para>
 			Name of Record-Route header parameter that will be used to store 
@@ -124,7 +124,7 @@ modparam("uac","rr_from_store_param","my_param")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.p.rr_to_store_param">
 			<title><varname>rr_to_store_param</varname> (string)</title>
 			<para>
 			Name of Record-Route header parameter that will be used to store 
@@ -145,7 +145,7 @@ modparam("uac","rr_to_store_param","my_param")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.p.restore_mode">
 			<title><varname>restore_mode</varname> (string)</title>
 			<para>
 			There are 3 modes of restoring the original FROM URI and the original TO URI:
@@ -188,7 +188,7 @@ modparam("uac","restore_mode","auto")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.p.restore_dlg">
 			<title><varname>restore_dlg</varname> (int)</title>
 			<para>
 			If set to 1, the module uses dialog variables to store initial and
@@ -209,7 +209,7 @@ modparam("uac", "restore_dlg", 1)
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.p.restore_passwd">
 			<title><varname>restore_passwd</varname> (string)</title>
 			<para>
 			String password to be used to encrypt the RR storing parameters. If
@@ -229,7 +229,7 @@ modparam("uac","restore_passwd","my_secret_passwd")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.p.restore_from_avp">
 			<title><varname>restore_from_avp</varname> (string)</title>
 			<para>
 			If defined and restore_mode is manual or auto, the avp is used to save
@@ -255,7 +255,7 @@ modparam("uac","restore_from_avp","$avp(original_uri_from)")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.p.restore_to_avp">
 			<title><varname>restore_to_avp</varname> (string)</title>
 			<para>
 			If defined and restore_mode is manual or auto, the avp is used to save
@@ -280,7 +280,7 @@ modparam("uac","restore_to_avp","$avp(original_uri_to)")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.p.credential">
 			<title><varname>credential</varname> (string)</title>
 			<para>
 			Contains a multiple definition of credentials used to perform
@@ -300,7 +300,7 @@ modparam("uac","credential","username:domain:password")
 				</programlisting>
 			</example>
 		</section>
-		<section id="auth-realm-avp-id">
+		<section id="uac.p.auth-realm-avp-id">
 			<title><varname>auth_realm_avp</varname> (string)</title>
 			<para>
 			The definition of an PV that might contain the realm to be used
@@ -314,9 +314,9 @@ modparam("uac","credential","username:domain:password")
 			<para><emphasis>
 				If you define it, you also need to define 
 				<quote>auth_username_avp</quote> 
-				(<xref linkend="auth-username-avp-id"/>) and 
+				(<xref linkend="uac.p.auth-username-avp-id"/>) and 
 				<quote>auth_username_avp</quote> 
-				(<xref linkend="auth-password-avp-id"/>).
+				(<xref linkend="uac.p.auth-password-avp-id"/>).
 			</emphasis></para>
 			<example>
 				<title>Set <varname>auth_realm_avp</varname> parameter</title>
@@ -327,7 +327,7 @@ modparam("uac","auth_realm_avp","$avp(i:10)")
 				</programlisting>
 			</example>
 		</section>
-		<section id="auth-username-avp-id">
+		<section id="uac.p.auth-username-avp-id">
 			<title><varname>auth_username_avp</varname> (string)</title>
 			<para>
 			The definition of an AVP that might contain the username to be used
@@ -336,9 +336,9 @@ modparam("uac","auth_realm_avp","$avp(i:10)")
 			<para><emphasis>
 				If you define it, you also need to define 
 				<quote>auth_realm_avp</quote> 
-				(<xref linkend="auth-realm-avp-id"/>) and 
+				(<xref linkend="uac.p.auth-realm-avp-id"/>) and 
 				<quote>auth_username_avp</quote> 
-				(<xref linkend="auth-password-avp-id"/>).
+				(<xref linkend="uac.p.auth-password-avp-id"/>).
 			</emphasis></para>
 			<example>
 				<title>Set <varname>auth_username_avp</varname> parameter</title>
@@ -349,7 +349,7 @@ modparam("uac","auth_username_avp","$avp(i:11)")
 				</programlisting>
 			</example>
 		</section>
-		<section id="auth-password-avp-id">
+		<section id="uac.p.auth-password-avp-id">
 			<title><varname>auth_password_avp</varname> (string)</title>
 			<para>
 			The definition of an AVP that might contain the password to be used
@@ -358,9 +358,9 @@ modparam("uac","auth_username_avp","$avp(i:11)")
 			<para><emphasis>
 				If you define it, you also need to define 
 				<quote>auth_password_avp</quote> 
-				(<xref linkend="auth-password-avp-id"/>) and 
+				(<xref linkend="uac.p.auth-password-avp-id"/>) and 
 				<quote>auth_username_avp</quote> 
-				(<xref linkend="auth-password-avp-id"/>).
+				(<xref linkend="uac.p.auth-password-avp-id"/>).
 			</emphasis></para>
 			<example>
 				<title>Set <varname>auth_password_avp</varname> parameter</title>
@@ -371,7 +371,7 @@ modparam("uac","auth_password_avp","$avp(i:12)")
 				</programlisting>
 			</example>
 		</section>
-		<section id="reg-db-url-id">
+		<section id="uac.p.reg-db-url-id">
 			<title><varname>reg_db_url</varname> (string)</title>
 			<para>
 			DB URL to fetch account profiles for registration.
@@ -387,7 +387,7 @@ modparam("uac", "reg_db_url",
 			</example>
 		</section>
 
-		<section id="reg-timer-interval-id">
+		<section id="uac.p.reg-timer-interval-id">
 			<title><varname>reg_timer_interval</varname> (string)</title>
 			<para>
 			Timer interval (in seconds) at which registrations are managed, e.g. renewed as needed.  
@@ -408,7 +408,7 @@ modparam("uac", "reg_timer_interval", 60)
 			</example>
 		</section>
 
-		<section id="reg-retry-interval-id">
+		<section id="uac.p.reg-retry-interval-id">
 			<title><varname>reg_retry_interval</varname> (int)</title>
 			<para>
 			Failed registration attempts will be retried after this interval
@@ -427,7 +427,7 @@ modparam("uac", "reg_retry_interval", 300)
 			</example>
 		</section>
 
-		<section id="reg-db-table-id">
+		<section id="uac.p.reg-db-table-id">
 			<title><varname>reg_db_table</varname> (string)</title>
 			<para>
 			DB table name to fetch user profiles for registration.
@@ -448,7 +448,7 @@ modparam("uac", "reg_db_table", "uacreg")
 			</example>
 		</section>
 
-		<section id="reg-contact-addr-id">
+		<section id="uac.p.reg-contact-addr-id">
 			<title><varname>reg_contact_addr</varname> (string)</title>
 			<para>
 			Address to be used to build contact address. Must be at least
@@ -469,7 +469,7 @@ modparam("uac", "reg_contact_addr", "192.168.1.2:5080")
 
 	<section>
 		<title>Functions</title>
-		<section>
+		<section id="uac.f.uac_replace_from">
 			<title>
 				<function moreinfo="none">uac_replace_from(display,uri)</function>
 			</title>
@@ -526,7 +526,7 @@ uac_replace_from("","");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_replace_from(uri)">
 			<title>
 				<function moreinfo="none">uac_replace_from(uri)</function>
 			</title>
@@ -549,7 +549,7 @@ uac_replace_from("sip:batman at gotham.org");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_restore_from()">
 			<title>
 				<function moreinfo="none">uac_restore_from()</function>
 			</title>
@@ -570,7 +570,7 @@ uac_restore_from();
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_replace_to(display,uri)">
 		<title>
 				<function moreinfo="none">uac_replace_to(display,uri)</function>
 			</title>
@@ -606,7 +606,7 @@ uac_replace_to("","");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_replace_to(uri)">
 			<title>
 				<function moreinfo="none">uac_replace_to(uri)</function>
 			</title>
@@ -651,7 +651,7 @@ uac_replace_to("sip:batman at gotham.org");
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_restore_to()">
 			<title>
 				<function moreinfo="none">uac_restore_to()</function>
 			</title>
@@ -672,7 +672,7 @@ uac_restore_to();
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_auth()">
 			<title>
 				<function moreinfo="none">uac_auth()</function>
 			</title>
@@ -693,7 +693,7 @@ uac_auth();
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_req_send()">
 			<title>
 				<function moreinfo="none">uac_req_send()</function>
 			</title>
@@ -713,12 +713,13 @@ $uac_req(method)="OPTIONS";
 $uac_req(ruri)="sip:kamailio.org";
 $uac_req(furi)="sip:kamailio.org";
 $uac_req(turi)="sip:kamailio.org";
+$uac_req(callid)=$(mb{s.md5});
 uac_req_send();
 ...
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_reg_lookup(uuid, dst)">
 			<title>
 				<function moreinfo="none">uac_reg_lookup(uuid, dst)</function>
 			</title>
@@ -742,7 +743,7 @@ if(uac_reg_lookup("$rU", "$ru"))
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="uac.f.uac_reg_request_to(user, mode)">
 			<title>
 				<function moreinfo="none">uac_reg_request_to(user, mode)</function>
 			</title>
diff --git a/modules/uac/uac_reg.c b/modules/uac/uac_reg.c
index ff7fed2..537ba82 100644
--- a/modules/uac/uac_reg.c
+++ b/modules/uac/uac_reg.c
@@ -646,7 +646,7 @@ error:
 		ri->flags |= UAC_REG_DISABLED;
 done:
 	if(ri)
-		ri->flags &= ~UAC_REG_ONGOING|UAC_REG_AUTHSENT;
+		ri->flags &= ~(UAC_REG_ONGOING|UAC_REG_AUTHSENT);
 	shm_free(uuid);
 }
 
diff --git a/modules/uac/uac_send.c b/modules/uac/uac_send.c
index 47744cd..153c3bb 100644
--- a/modules/uac/uac_send.c
+++ b/modules/uac/uac_send.c
@@ -21,9 +21,17 @@
  */
 
 #include "../../dprint.h"
+#include "../../trim.h"
 
 #include "../../modules/tm/tm_load.h"
 
+#include "../../parser/parse_uri.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
+#include "../../parser/contact/parse_contact.h"
+
+#include "auth.h"
+#include "auth_hdr.h"
 #include "uac_send.h"
 
 #define MAX_UACH_SIZE 2048
@@ -32,7 +40,7 @@
 /** TM bind */
 struct tm_binds tmb;
 
-struct _uac_send_info {
+typedef struct _uac_send_info {
 	unsigned int flags;
 	char  b_method[32];
 	str   s_method;
@@ -42,17 +50,50 @@ struct _uac_send_info {
 	str   s_turi;
 	char  b_furi[MAX_URI_SIZE];
 	str   s_furi;
+	char  b_callid[128];
+	str   s_callid;
 	char  b_hdrs[MAX_UACH_SIZE];
 	str   s_hdrs;
 	char  b_body[MAX_UACB_SIZE];
 	str   s_body;
 	char  b_ouri[MAX_URI_SIZE];
 	str   s_ouri;
+	char  b_sock[MAX_URI_SIZE];
+	str   s_sock;
+	char  b_auser[128];
+	str   s_auser;
+	char  b_apasswd[64];
+	str   s_apasswd;
 	unsigned int onreply;
-};
+} uac_send_info_t;
 
 static struct _uac_send_info _uac_req;
 
+uac_send_info_t *uac_send_info_clone(uac_send_info_t *ur)
+{
+	uac_send_info_t *tp = NULL;
+	tp = (uac_send_info_t*)shm_malloc(sizeof(uac_send_info_t));
+	if(tp==NULL)
+	{
+		LM_ERR("no more shm memory\n");
+		return NULL;
+	}
+	memcpy(tp, ur, sizeof(uac_send_info_t));
+	tp->s_method.s  = tp->b_method;
+	tp->s_ruri.s    = tp->b_ruri;
+	tp->s_turi.s    = tp->b_turi;
+	tp->s_furi.s    = tp->b_furi;
+	tp->s_hdrs.s    = tp->b_hdrs;
+	tp->s_body.s    = tp->b_body;
+	tp->s_ouri.s    = tp->b_ouri;
+	tp->s_auser.s   = tp->b_auser;
+	tp->s_apasswd.s = tp->b_apasswd;
+	tp->s_callid.s  = tp->b_callid;
+	tp->s_sock.s    = tp->b_sock;
+
+	return tp;
+}
+
 int pv_get_uac_req(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 {
@@ -91,6 +132,22 @@ int pv_get_uac_req(struct sip_msg *msg, pv_param_t *param,
 			if(_uac_req.s_method.len<=0)
 				return pv_get_null(msg, param, res);
 			return pv_get_strval(msg, param, res, &_uac_req.s_method);
+		case 9:
+			if(_uac_req.s_auser.len<=0)
+				return pv_get_null(msg, param, res);
+			return pv_get_strval(msg, param, res, &_uac_req.s_auser);
+		case 10:
+			if(_uac_req.s_apasswd.len<=0)
+				return pv_get_null(msg, param, res);
+			return pv_get_strval(msg, param, res, &_uac_req.s_apasswd);
+		case 11:
+			if(_uac_req.s_callid.len<=0)
+				return pv_get_null(msg, param, res);
+			return pv_get_strval(msg, param, res, &_uac_req.s_callid);
+		case 12:
+			if(_uac_req.s_sock.len<=0)
+				return pv_get_null(msg, param, res);
+			return pv_get_strval(msg, param, res, &_uac_req.s_sock);
 		default:
 			return pv_get_uintval(msg, param, res, _uac_req.flags);
 	}
@@ -117,6 +174,7 @@ int pv_set_uac_req(struct sip_msg* msg, pv_param_t *param,
 				_uac_req.s_body.len = 0;
 				_uac_req.s_method.len = 0;
 				_uac_req.onreply = 0;
+				_uac_req.s_callid.len = 0;
 			}
 			break;
 		case 1:
@@ -277,6 +335,81 @@ int pv_set_uac_req(struct sip_msg* msg, pv_param_t *param,
 			}
 			_uac_req.onreply = val->ri;
 			break;
+		case 9:
+			if(val==NULL)
+			{
+				_uac_req.s_auser.len = 0;
+				return 0;
+			}
+			if(!(val->flags&PV_VAL_STR))
+			{
+				LM_ERR("Invalid auth user type\n");
+				return -1;
+			}
+			if(val->rs.len>=128)
+			{
+				LM_ERR("Value size too big\n");
+				return -1;
+			}
+			memcpy(_uac_req.s_auser.s, val->rs.s, val->rs.len);
+			_uac_req.s_auser.s[val->rs.len] = '\0';
+			_uac_req.s_auser.len = val->rs.len;
+			break;
+		case 10:
+			if(val==NULL)
+			{
+				_uac_req.s_apasswd.len = 0;
+				return 0;
+			}
+			if(!(val->flags&PV_VAL_STR))
+			{
+				LM_ERR("Invalid auth password type\n");
+				return -1;
+			}
+			if(val->rs.len>=64)
+			{
+				LM_ERR("Value size too big\n");
+				return -1;
+			}
+			memcpy(_uac_req.s_apasswd.s, val->rs.s, val->rs.len);
+			_uac_req.s_apasswd.s[val->rs.len] = '\0';
+			_uac_req.s_apasswd.len = val->rs.len;
+			break;
+		case 11:
+			if(val==NULL)
+			{
+				_uac_req.s_callid.len = 0;
+				return 0;
+			}
+			if(!(val->flags&PV_VAL_STR))
+			{
+				LM_ERR("Invalid value type\n");
+				return -1;
+			}
+			memcpy(_uac_req.s_callid.s, val->rs.s, val->rs.len);
+			_uac_req.s_callid.s[val->rs.len] = '\0';
+			_uac_req.s_callid.len = val->rs.len;
+			break;
+		case 12:
+			if(val==NULL)
+			{
+				_uac_req.s_apasswd.len = 0;
+				return 0;
+			}
+			if(!(val->flags&PV_VAL_STR))
+			{
+				LM_ERR("Invalid socket pv type\n");
+				return -1;
+			}
+			if(val->rs.len>=MAX_URI_SIZE)
+			{
+				LM_ERR("Value size too big\n");
+				return -1;
+			}
+			memcpy(_uac_req.s_sock.s, val->rs.s, val->rs.len);
+			_uac_req.s_sock.s[val->rs.len] = '\0';
+			_uac_req.s_sock.len = val->rs.len;
+			break;
 	}
 	return 0;
 }
@@ -306,16 +439,27 @@ int pv_parse_uac_req_name(pv_spec_p sp, str *in)
 				sp->pvp.pvn.u.isname.name.n = 5;
 			else if(strncmp(in->s, "ouri", 4)==0)
 				sp->pvp.pvn.u.isname.name.n = 6;
+			else if(strncmp(in->s, "sock", 4)==0)
+				sp->pvp.pvn.u.isname.name.n = 12;
+			else goto error;
+		break;
+		case 5:
+			if(strncmp(in->s, "auser", 5)==0)
+				sp->pvp.pvn.u.isname.name.n = 9;
 			else goto error;
 		break;
 		case 6: 
 			if(strncmp(in->s, "method", 6)==0)
 				sp->pvp.pvn.u.isname.name.n = 7;
+			else if(strncmp(in->s, "callid", 6)==0)
+				sp->pvp.pvn.u.isname.name.n = 11;
 			else goto error;
 		break;
 		case 7: 
 			if(strncmp(in->s, "onreply", 7)==0)
 				sp->pvp.pvn.u.isname.name.n = 8;
+			else if(strncmp(in->s, "apasswd", 7)==0)
+				sp->pvp.pvn.u.isname.name.n = 10;
 			else goto error;
 		break;
 		default:
@@ -347,25 +491,151 @@ void uac_req_init(void)
 	_uac_req.s_hdrs.s = _uac_req.b_hdrs;
 	_uac_req.s_body.s = _uac_req.b_body;
 	_uac_req.s_method.s = _uac_req.b_method;
+	_uac_req.s_auser.s  = _uac_req.b_auser;
+	_uac_req.s_apasswd.s  = _uac_req.b_apasswd;
+	_uac_req.s_callid.s   = _uac_req.b_callid;
+	_uac_req.s_sock.s     = _uac_req.b_sock;
 	return;
 }
 
+int uac_send_tmdlg(dlg_t *tmdlg, sip_msg_t *rpl)
+{
+	if(tmdlg==NULL || rpl==NULL)
+		return -1;
+
+	if (parse_headers(rpl, HDR_EOH_F, 0) < 0) {
+		LM_ERR("error while parsing all headers in the reply\n");
+		return -1;
+	}
+	if(parse_to_header(rpl)<0 || parse_from_header(rpl)<0) {
+		LM_ERR("error while parsing From/To headers in the reply\n");
+		return -1;
+	}
+	memset(tmdlg, 0, sizeof(dlg_t));
+
+	str2int(&(get_cseq(rpl)->number), &tmdlg->loc_seq.value);
+	tmdlg->loc_seq.is_set = 1;
+
+	tmdlg->id.call_id = rpl->callid->body;
+	trim(&tmdlg->id.call_id);
+
+	if (get_from(rpl)->tag_value.len) {
+		tmdlg->id.loc_tag = get_from(rpl)->tag_value;
+	}
+#if 0
+	if (get_to(rpl)->tag_value.len) {
+		tmdlg->id.rem_tag = get_to(rpl)->tag_value;
+	}
+#endif
+	tmdlg->loc_uri = get_from(rpl)->uri;
+	tmdlg->rem_uri = get_to(rpl)->uri;
+	tmdlg->state= DLG_CONFIRMED;
+	return 0;
+}
+
+#define MAX_UACH_SIZE 2048
+
 /** 
  * TM callback function
  */
-void uac_send_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
+void uac_send_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
 {
-	unsigned int onreply;
+	int ret;
+	struct hdr_field *hdr;
+	HASHHEX response;
+	str *new_auth_hdr = NULL;
+	static struct authenticate_body auth;
+	struct uac_credential cred;
+	char  b_hdrs[MAX_UACH_SIZE];
+	str   s_hdrs;
+	uac_req_t uac_r;
+	dlg_t tmdlg;
+	uac_send_info_t *tp = NULL;
+
 	if(ps->param==NULL || *ps->param==0)
 	{
 		LM_DBG("message id not received\n");
 		goto done;
 	}
-	onreply = *((unsigned int*)ps->param);
-	LM_DBG("completed with status %d [onreply: %u]\n",
-		ps->code, onreply);
+	tp = (uac_send_info_t*)(*ps->param);
+	if(ps->code != 401 && ps->code != 407)
+	{
+		LM_DBG("completed with status %d\n", ps->code);
+		goto done;
+	}
+
+	LM_DBG("completed with status %d\n", ps->code);
+
+	hdr = get_autenticate_hdr(ps->rpl, ps->code);
+	if (hdr==0)
+	{
+		LM_ERR("failed to extract authenticate hdr\n");
+		goto error;
+	}
+
+	LM_DBG("auth header body [%.*s]\n",
+		hdr->body.len, hdr->body.s);
+
+	if (parse_authenticate_body(&hdr->body, &auth)<0)
+	{
+		LM_ERR("failed to parse auth hdr body\n");
+		goto error;
+	}
+
+	cred.realm  = auth.realm;
+	cred.user   = tp->s_auser;
+	cred.passwd = tp->s_apasswd;
+	cred.next   = NULL;
+
+	do_uac_auth(&tp->s_method, &tp->s_ruri, &cred, &auth, response);
+	new_auth_hdr=build_authorization_hdr(ps->code, &tp->s_ruri, &cred,
+						&auth, response);
+	if (new_auth_hdr==0)
+	{
+		LM_ERR("failed to build authorization hdr\n");
+		goto error;
+	}
+
+	if(tp->s_hdrs.len <= 0) {
+		snprintf(b_hdrs, MAX_UACH_SIZE,
+				"%.*s",
+				new_auth_hdr->len, new_auth_hdr->s);
+	} else {
+		snprintf(b_hdrs, MAX_UACH_SIZE,
+				"%.*s%.*s",
+				tp->s_hdrs.len, tp->s_hdrs.s,
+				new_auth_hdr->len, new_auth_hdr->s);
+	}
+
+	s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
+	pkg_free(new_auth_hdr->s);
+
+	memset(&uac_r, 0, sizeof(uac_r));
+	if(uac_send_tmdlg(&tmdlg, ps->rpl)<0)
+	{
+		LM_ERR("failed to build tm dialog\n");
+		goto error;
+	}
+	tmdlg.rem_target = tp->s_ruri;
+	if(tp->s_ouri.len>0)
+		tmdlg.dst_uri = tp->s_ouri;
+	uac_r.method = &tp->s_method;
+	uac_r.headers = &s_hdrs;
+	uac_r.body = (tp->s_body.len <= 0) ? NULL : &tp->s_body;
+	uac_r.ssock = (tp->s_sock.len <= 0) ? NULL : &tp->s_sock;
+	uac_r.dialog = &tmdlg;
+	uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
+	ret = tmb.t_request_within(&uac_r);
+
+	if(ret<0) {
+		LM_ERR("failed to send request with authentication\n");
+		goto error;
+	}
 
 done:
+error:
+	if(tp!=NULL)
+		shm_free(tp);
 	return;
 }
 
@@ -374,6 +644,7 @@ int uac_req_send(struct sip_msg *msg, char *s1, char *s2)
 {
 	int ret;
 	uac_req_t uac_r;
+	uac_send_info_t *tp = NULL;
 
 	if(_uac_req.s_ruri.len<=0 || _uac_req.s_method.len == 0
 			|| tmb.t_request==NULL)
@@ -383,14 +654,23 @@ int uac_req_send(struct sip_msg *msg, char *s1, char *s2)
 	uac_r.method = &_uac_req.s_method;
 	uac_r.headers = (_uac_req.s_hdrs.len <= 0) ? NULL : &_uac_req.s_hdrs;
 	uac_r.body = (_uac_req.s_body.len <= 0) ? NULL : &_uac_req.s_body;
-	if(_uac_req.onreply > 0)
+	uac_r.ssock = (_uac_req.s_sock.len <= 0) ? NULL : &_uac_req.s_sock;
+	if(_uac_req.s_auser.len > 0 && _uac_req.s_apasswd.len>0)
 	{
+		tp = uac_send_info_clone(&_uac_req);
+		if(tp==NULL)
+		{
+			LM_ERR("cannot clone the uac structure\n");
+			return -1;
+		}
+
 		uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
 		/* Callback function */
 		uac_r.cb  = uac_send_tm_callback;
 		/* Callback parameter */
-		uac_r.cbp = (void*)(long)_uac_req.onreply;
+		uac_r.cbp = (void*)tp;
 	}
+	uac_r.callid = (_uac_req.s_callid.len <= 0) ? NULL : &_uac_req.s_callid;
 	ret = tmb.t_request(&uac_r,  /* UAC Req */
 						&_uac_req.s_ruri,        /* Request-URI */
 						(_uac_req.s_turi.len<=0)?&_uac_req.s_ruri:&_uac_req.s_turi, /* To */
@@ -398,8 +678,11 @@ int uac_req_send(struct sip_msg *msg, char *s1, char *s2)
 						(_uac_req.s_ouri.len<=0)?NULL:&_uac_req.s_ouri /* outbound uri */
 		);
 
-	if(ret<0)
+	if(ret<0) {
+		if(tp!=NULL)
+			shm_free(tp);
 		return -1;
+	}
 	return 1;
 }
 
diff --git a/modules/uac_redirect/rd_funcs.c b/modules/uac_redirect/rd_funcs.c
index d1e4d46..aa8dbd0 100644
--- a/modules/uac_redirect/rd_funcs.c
+++ b/modules/uac_redirect/rd_funcs.c
@@ -297,7 +297,8 @@ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl,
 				scontacts[i]->uri.s);
 		if(sruid_next(&_redirect_sruid)==0) {
 			if(append_branch( 0, &scontacts[i]->uri, 0, 0, sqvalues[i],
-						bflags, 0, &_redirect_sruid.uid, 0)<0) {
+						bflags, 0, &_redirect_sruid.uid, 0,
+						&_redirect_sruid.uid, &_redirect_sruid.uid)<0) {
 				LM_ERR("failed to add contact to dset\n");
 			} else {
 				added++;
diff --git a/modules/uid_avp_db/uid_avp_db.c b/modules/uid_avp_db/uid_avp_db.c
index 5d3b5e4..7970740 100644
--- a/modules/uid_avp_db/uid_avp_db.c
+++ b/modules/uid_avp_db/uid_avp_db.c
@@ -285,7 +285,7 @@ static int load_uri_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp
     uri_type_to_str(puri.type, &(load_uri_attrs_cmd->match[2].v.lstr));
 
 	if (db_exec(&res, load_uri_attrs_cmd) < 0) {
-		ERR("Error while quering database\n");
+		ERR("Error while querying database\n");
 		return -1;
     }
     
@@ -307,7 +307,7 @@ static int load_user_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* f
 	}
 
 	if (db_exec(&res, load_user_attrs_cmd) < 0) {
-		ERR("Error while quering database\n");
+		ERR("Error while querying database\n");
 		return -1;
     }
     
diff --git a/modules/uri_db/README b/modules/uri_db/README
index a16de47..1bf2cc2 100644
--- a/modules/uri_db/README
+++ b/modules/uri_db/README
@@ -118,7 +118,7 @@ Chapter 1. Admin Guide
 
    If the db_url string is empty, the default database URL will be used.
 
-   Default value is "mysql://kamailioro:kamailioro@localhost/kamailio".
+   Default value is "mysql://openserro:openserro@localhost/openser".
 
    Example 1.1. Set db_url parameter
 ...
diff --git a/modules/userblacklist/README b/modules/userblacklist/README
index f338b9e..833e7b4 100644
--- a/modules/userblacklist/README
+++ b/modules/userblacklist/README
@@ -352,7 +352,7 @@ Chapter 2. Module parameter for database access.
 
    URL to the database containing the data.
 
-   Default value is "mysql://kamailioro:kamailioro@localhost/kamailio".
+   Default value is "mysql://openserro:openserro@localhost/openser".
 
    Example 2.1. Set db_url parameter
 ...
diff --git a/modules/usrloc/README b/modules/usrloc/README
index 2c1ffef..2a3767d 100644
--- a/modules/usrloc/README
+++ b/modules/usrloc/README
@@ -68,6 +68,7 @@ Bogdan-Andrei Iancu
               3.30. timer_procs (string)
               3.31. xavp_contact (string)
               3.32. db_ops_ruid (int)
+              3.33. handle_lost_tcp (int)
 
         4. Functions
         5. MI Commands
@@ -83,6 +84,13 @@ Bogdan-Andrei Iancu
 
               6.1. ul.dump
               6.2. ul.lookup table AOR
+              6.3. ul.rm table AOR
+              6.4. ul.rm_contact table AOR contact
+              6.5. ul.flush
+              6.6. ul.add
+              6.7. ul.db_users
+              6.8. ul.db_contacts
+              6.9. ul.db_expired_contacts
 
         7. Statistics
 
@@ -98,22 +106,23 @@ Bogdan-Andrei Iancu
               1.1. ul_register_domain(name)
               1.2. ul_insert_urecord(domain, aor, rec)
               1.3. ul_delete_urecord(domain, aor)
-              1.4. ul_get_urecord(domain, aor)
-              1.5. ul_lock_udomain(domain)
-              1.6. ul_unlock_udomain(domain)
-              1.7. ul_release_urecord(record)
-              1.8. ul_insert_ucontact(record, contact, expires, q, callid,
+              1.4. ul_delete_urecord_by_ruid(domain, ruid)
+              1.5. ul_get_urecord(domain, aor)
+              1.6. ul_lock_udomain(domain)
+              1.7. ul_unlock_udomain(domain)
+              1.8. ul_release_urecord(record)
+              1.9. ul_insert_ucontact(record, contact, expires, q, callid,
                       cseq, flags, cont, ua, sock)
 
-              1.9. ul_delete_ucontact (record, contact)
-              1.10. ul_get_ucontact(record, contact)
-              1.11. ul_get_all_ucontacts (buf, len, flags)
-              1.12. ul_update_ucontact(contact, expires, q, callid, cseq,
+              1.10. ul_delete_ucontact (record, contact)
+              1.11. ul_get_ucontact(record, contact)
+              1.12. ul_get_all_ucontacts (buf, len, flags)
+              1.13. ul_update_ucontact(contact, expires, q, callid, cseq,
                       set, res, ua, sock)
 
-              1.13. ul_bind_ursloc( api )
-              1.14. ul_register_ulcb(type ,callback, param)
-              1.15. ul_get_num_users()
+              1.14. ul_bind_ursloc( api )
+              1.15. ul_register_ulcb(type ,callback, param)
+              1.16. ul_get_num_users()
 
    List of Examples
 
@@ -149,6 +158,7 @@ Bogdan-Andrei Iancu
    1.30. Set timer_procs parameter
    1.31. Set xavp_contact parameter
    1.32. Set db_ops_ruid parameter
+   1.33. Set handle_lost_tcp parameter
 
 Chapter 1. Admin Guide
 
@@ -197,6 +207,7 @@ Chapter 1. Admin Guide
         3.30. timer_procs (string)
         3.31. xavp_contact (string)
         3.32. db_ops_ruid (int)
+        3.33. handle_lost_tcp (int)
 
    4. Functions
    5. MI Commands
@@ -212,6 +223,13 @@ Chapter 1. Admin Guide
 
         6.1. ul.dump
         6.2. ul.lookup table AOR
+        6.3. ul.rm table AOR
+        6.4. ul.rm_contact table AOR contact
+        6.5. ul.flush
+        6.6. ul.add
+        6.7. ul.db_users
+        6.8. ul.db_contacts
+        6.9. ul.db_expired_contacts
 
    7. Statistics
 
@@ -310,6 +328,7 @@ Chapter 1. Admin Guide
    3.30. timer_procs (string)
    3.31. xavp_contact (string)
    3.32. db_ops_ruid (int)
+   3.33. handle_lost_tcp (int)
 
 3.1. nat_bflag (integer)
 
@@ -584,6 +603,11 @@ modparam("usrloc", "db_url", "dbdriver://username:password@dbhost/dbname")
        For example NAT pinging is a killer since during each ping cycle
        all nated contact are loaded from the DB; The lack of memory
        caching also disable the statistics exports.
+     * 4 - This uses database to load records at startup but uses only
+       memory during the runtime. Records are not written back at all, not
+       even at shutdown. Useful for scenarios when registrations are
+       replicated to a node that does the storage in database during
+       runtime.
 
 Warning
 
@@ -744,6 +768,18 @@ modparam("usrloc", "xavp_contact", "ulattrs")
 modparam("usrloc", "db_ops_ruid", 1)
 ...
 
+3.33. handle_lost_tcp (int)
+
+   If set to 1, Kamailio will remove location records made via
+   TCP/TLS/WS/WSS transports when it looses corresponding tcp connections.
+
+   Default value is "0".
+
+   Example 1.33. Set handle_lost_tcp parameter
+...
+modparam("usrloc", "handle_lost_tcp", 1)
+...
+
 4. Functions
 
    There are no exported functions that could be used in scripts.
@@ -800,7 +836,7 @@ modparam("usrloc", "db_ops_ruid", 1)
      * contact - contact string to be added
      * expires - expires value of the contact
      * Q - Q value of the contact
-     * unused - unused attribute (kept for backword compatibility)
+     * path value of the contact
      * flags - internal USRLOC flags of the contact
      * cflags - per branch flags of the contact
      * methods - mask with supported requests of the contact
@@ -818,6 +854,13 @@ modparam("usrloc", "db_ops_ruid", 1)
 
    6.1. ul.dump
    6.2. ul.lookup table AOR
+   6.3. ul.rm table AOR
+   6.4. ul.rm_contact table AOR contact
+   6.5. ul.flush
+   6.6. ul.add
+   6.7. ul.db_users
+   6.8. ul.db_contacts
+   6.9. ul.db_expired_contacts
 
 6.1. ul.dump
 
@@ -835,6 +878,70 @@ modparam("usrloc", "db_ops_ruid", 1)
      * AOR - user AOR in username[@domain] format (domain must be supplied
        only if use_domain option is on).
 
+6.3. ul.rm table AOR
+
+   Deletes an entire AOR record (including its contacts).
+
+   Parameters:
+     * table name - table where the AOR resides (Ex: location).
+     * AOR - user AOR in username[@domain] format (domain must be supplied
+       only if use_domain option is on).
+
+6.4. ul.rm_contact table AOR contact
+
+   Deletes a contact from an AOR record.
+
+   Parameters:
+     * table name - table where the AOR is removed from (Ex: location).
+     * AOR - user AOR in username[@domain] format (domain must be supplied
+       only if use_domain option is on).
+     * contact - exact contact to be removed
+
+6.5. ul.flush
+
+   Triggers the flush of USRLOC memory cache into DB.
+
+6.6. ul.add
+
+   Adds a new contact for an user AOR.
+
+   Parameters:
+     * table name - table where the contact will be added (Ex: location).
+     * AOR - user AOR in username[@domain] format (domain must be supplied
+       only if use_domain option is on).
+     * contact - contact string to be added
+     * expires - expires value of the contact
+     * Q - Q value of the contact
+     * path value of the contact
+     * flags - internal USRLOC flags of the contact
+     * cflags - per branch flags of the contact
+     * methods - mask with supported requests of the contact
+
+6.7. ul.db_users
+
+   Tell number of different users (AoRs) in a location table that have
+   unexpired contacts.
+
+   Parameters:
+     * table name - location table where the users are looked for, for
+       example, location.
+
+6.8. ul.db_contacts
+
+   Tell number of unexpired contacts in a location table.
+
+   Parameters:
+     * table name - location table where the contacts are looked for, for
+       example, location.
+
+6.9. ul.db_expired_contacts
+
+   Tell number of expired contacts in a location table.
+
+   Parameters:
+     * table name - location table where the contacts are looked for, for
+       example, location.
+
 7. Statistics
 
    7.1. users
@@ -875,44 +982,46 @@ Chapter 2. Developer Guide
         1.1. ul_register_domain(name)
         1.2. ul_insert_urecord(domain, aor, rec)
         1.3. ul_delete_urecord(domain, aor)
-        1.4. ul_get_urecord(domain, aor)
-        1.5. ul_lock_udomain(domain)
-        1.6. ul_unlock_udomain(domain)
-        1.7. ul_release_urecord(record)
-        1.8. ul_insert_ucontact(record, contact, expires, q, callid, cseq,
+        1.4. ul_delete_urecord_by_ruid(domain, ruid)
+        1.5. ul_get_urecord(domain, aor)
+        1.6. ul_lock_udomain(domain)
+        1.7. ul_unlock_udomain(domain)
+        1.8. ul_release_urecord(record)
+        1.9. ul_insert_ucontact(record, contact, expires, q, callid, cseq,
                 flags, cont, ua, sock)
 
-        1.9. ul_delete_ucontact (record, contact)
-        1.10. ul_get_ucontact(record, contact)
-        1.11. ul_get_all_ucontacts (buf, len, flags)
-        1.12. ul_update_ucontact(contact, expires, q, callid, cseq, set,
+        1.10. ul_delete_ucontact (record, contact)
+        1.11. ul_get_ucontact(record, contact)
+        1.12. ul_get_all_ucontacts (buf, len, flags)
+        1.13. ul_update_ucontact(contact, expires, q, callid, cseq, set,
                 res, ua, sock)
 
-        1.13. ul_bind_ursloc( api )
-        1.14. ul_register_ulcb(type ,callback, param)
-        1.15. ul_get_num_users()
+        1.14. ul_bind_ursloc( api )
+        1.15. ul_register_ulcb(type ,callback, param)
+        1.16. ul_get_num_users()
 
 1. Available Functions
 
    1.1. ul_register_domain(name)
    1.2. ul_insert_urecord(domain, aor, rec)
    1.3. ul_delete_urecord(domain, aor)
-   1.4. ul_get_urecord(domain, aor)
-   1.5. ul_lock_udomain(domain)
-   1.6. ul_unlock_udomain(domain)
-   1.7. ul_release_urecord(record)
-   1.8. ul_insert_ucontact(record, contact, expires, q, callid, cseq,
+   1.4. ul_delete_urecord_by_ruid(domain, ruid)
+   1.5. ul_get_urecord(domain, aor)
+   1.6. ul_lock_udomain(domain)
+   1.7. ul_unlock_udomain(domain)
+   1.8. ul_release_urecord(record)
+   1.9. ul_insert_ucontact(record, contact, expires, q, callid, cseq,
           flags, cont, ua, sock)
 
-   1.9. ul_delete_ucontact (record, contact)
-   1.10. ul_get_ucontact(record, contact)
-   1.11. ul_get_all_ucontacts (buf, len, flags)
-   1.12. ul_update_ucontact(contact, expires, q, callid, cseq, set, res,
+   1.10. ul_delete_ucontact (record, contact)
+   1.11. ul_get_ucontact(record, contact)
+   1.12. ul_get_all_ucontacts (buf, len, flags)
+   1.13. ul_update_ucontact(contact, expires, q, callid, cseq, set, res,
           ua, sock)
 
-   1.13. ul_bind_ursloc( api )
-   1.14. ul_register_ulcb(type ,callback, param)
-   1.15. ul_get_num_users()
+   1.14. ul_bind_ursloc( api )
+   1.15. ul_register_ulcb(type ,callback, param)
+   1.16. ul_get_num_users()
 
 1.1. ul_register_domain(name)
 
@@ -956,7 +1065,17 @@ Chapter 2. Developer Guide
      * str* aor - Address of record (aka username) of the record, that
        should be deleted.
 
-1.4. ul_get_urecord(domain, aor)
+1.4. ul_delete_urecord_by_ruid(domain, ruid)
+
+   The function deletes from given domain a contact with given ruid.
+
+   Meaning of the parameters is as follows:
+     * udomain_t* domain - Pointer to domain returned by
+       ul_register_udomain.
+
+     * str* ruid - ruid of contact that should be deleted.
+
+1.5. ul_get_urecord(domain, aor)
 
    The function returns pointer to record with given Address of Record.
 
@@ -966,7 +1085,7 @@ Chapter 2. Developer Guide
 
      * str* aor - Address of Record of request record.
 
-1.5. ul_lock_udomain(domain)
+1.6. ul_lock_udomain(domain)
 
    The function lock the specified domain, it means, that no other
    processes will be able to access during the time. This prevents race
@@ -977,14 +1096,14 @@ Chapter 2. Developer Guide
    Meaning of the parameters is as follows:
      * udomain_t* domain - Domain to be locked.
 
-1.6. ul_unlock_udomain(domain)
+1.7. ul_unlock_udomain(domain)
 
    Unlock the specified domain previously locked by ul_lock_udomain.
 
    Meaning of the parameters is as follows:
      * udomain_t* domain - Domain to be unlocked.
 
-1.7. ul_release_urecord(record)
+1.8. ul_release_urecord(record)
 
    Do some sanity checks - if all contacts have been removed, delete the
    entire record structure.
@@ -992,7 +1111,7 @@ Chapter 2. Developer Guide
    Meaning of the parameters is as follows:
      * urecord_t* record - Record to be released.
 
-1.8. ul_insert_ucontact(record, contact, expires, q, callid, cseq, flags,
+1.9. ul_insert_ucontact(record, contact, expires, q, callid, cseq, flags,
 cont, ua, sock)
 
    The function inserts a new contact in the given record with specified
@@ -1013,7 +1132,7 @@ cont, ua, sock)
      * struct socket_info *sock - socket on which the REGISTER message was
        received on.
 
-1.9. ul_delete_ucontact (record, contact)
+1.10. ul_delete_ucontact (record, contact)
 
    The function deletes given contact from record.
 
@@ -1023,7 +1142,7 @@ cont, ua, sock)
 
      * ucontact_t* contact - Contact to be deleted.
 
-1.10. ul_get_ucontact(record, contact)
+1.11. ul_get_ucontact(record, contact)
 
    The function tries to find contact with given Contact URI and returns
    pointer to structure representing the contact.
@@ -1033,7 +1152,7 @@ cont, ua, sock)
 
      * str_t* contact - URI of the request contact.
 
-1.11. ul_get_all_ucontacts (buf, len, flags)
+1.12. ul_get_all_ucontacts (buf, len, flags)
 
    The function retrieves all contacts of all registered users and returns
    them in the caller-supplied buffer. If the buffer is too small, the
@@ -1054,7 +1173,7 @@ cont, ua, sock)
 
      * unsigned int flags - Flags that must be set.
 
-1.12. ul_update_ucontact(contact, expires, q, callid, cseq, set, res, ua,
+1.13. ul_update_ucontact(contact, expires, q, callid, cseq, set, res, ua,
 sock)
 
    The function updates contact with new values.
@@ -1073,7 +1192,7 @@ sock)
      * struct socket_info *sock - socket on which the REGISTER message was
        received on.
 
-1.13. ul_bind_ursloc( api )
+1.14. ul_bind_ursloc( api )
 
    The function imports all functions that are exported by the USRLOC
    module. Overs for other modules which want to user the internal USRLOC
@@ -1082,7 +1201,7 @@ sock)
    Meaning of the parameters is as follows:
      * usrloc_api_t* api - USRLOC API
 
-1.14. ul_register_ulcb(type ,callback, param)
+1.15. ul_register_ulcb(type ,callback, param)
 
    The function register with USRLOC a callback function to be called when
    some event occures inside USRLOC.
@@ -1095,6 +1214,6 @@ sock)
      * void *param - some parameter to be passed to the callback each time
        when it is called.
 
-1.15. ul_get_num_users()
+1.16. ul_get_num_users()
 
    The function loops through all domains summing up the number of users.
diff --git a/modules/usrloc/doc/usrloc_admin.xml b/modules/usrloc/doc/usrloc_admin.xml
index 9f389ad..1de1c31 100644
--- a/modules/usrloc/doc/usrloc_admin.xml
+++ b/modules/usrloc/doc/usrloc_admin.xml
@@ -104,7 +104,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="usrloc.p.nat_bflag">
 		<title><varname>nat_bflag</varname> (integer)</title>
 		<para>
 		The index of the branch flag to be used as NAT marker (if the contact 
@@ -126,7 +126,7 @@ modparam("usrloc", "nat_bflag", 3)
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.user_column">
 		<title><varname>user_column</varname> (string)</title>
 		<para>
 		Name of database column containing usernames.
@@ -146,7 +146,7 @@ modparam("usrloc", "user_column", "username")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.domain_column">
 		<title><varname>domain_column</varname> (string)</title>
 		<para>
 		Name of database column containing domains.
@@ -166,7 +166,7 @@ modparam("usrloc", "domain_column", "domain")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.contact_column">
 		<title><varname>contact_column</varname> (string)</title>
 		<para>
 		Name of database column containing contacts.
@@ -186,7 +186,7 @@ modparam("usrloc", "contact_column", "contact")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.expires_column">
 		<title><varname>expires_column</varname> (string)</title>
 		<para>
 		Name of database column containing expires value.
@@ -206,7 +206,7 @@ modparam("usrloc", "expires_column", "expires")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.q_column">
 		<title><varname>q_column</varname> (string)</title>
 		<para>
 		Name of database column containing q values.
@@ -226,7 +226,7 @@ modparam("usrloc", "q_column", "q")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.callid_column">
 		<title><varname>callid_column</varname> (string)</title>
 		<para>
 		Name of database column containing Call-ID values.
@@ -246,7 +246,7 @@ modparam("usrloc", "callid_column", "callid")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.cseq_column">
 		<title><varname>cseq_column</varname> (string)</title>
 		<para>
 		Name of database column containing Cseq.
@@ -266,7 +266,7 @@ modparam("usrloc", "cseq_column", "cseq")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.methods_column">
 		<title><varname>methods_column</varname> (string)</title>
 		<para>
 		Name of database column containing supported methods.
@@ -286,7 +286,7 @@ modparam("usrloc", "methods_column", "methods")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.flags_column">
 		<title><varname>flags_column</varname> (string)</title>
 		<para>
 		Name of database column to save the internal flags of the record.
@@ -306,7 +306,7 @@ modparam("usrloc", "flags_column", "flags")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.cflags_column">
 		<title><varname>cflags_column</varname> (string)</title>
 		<para>
 		Name of database column to save the branch/contact flags of the record.
@@ -326,7 +326,7 @@ modparam("usrloc", "cflags_column", "cflags")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.user_agent_column">
 		<title><varname>user_agent_column</varname> (string)</title>
 		<para>
 		Name of database column containing user-agent values.
@@ -346,7 +346,7 @@ modparam("usrloc", "user_agent_column", "user_agent")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.received_column">
 		<title><varname>received_column</varname> (string)</title>
 		<para>
 		Name of database column containing the source IP, port, and protocol from the REGISTER
@@ -367,7 +367,7 @@ modparam("usrloc", "received_column", "received")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.socket_column">
 		<title><varname>socket_column</varname> (string)</title>
 		<para>
 		Name of database column containing the received socket information (IP:port)
@@ -388,7 +388,7 @@ modparam("usrloc", "socket_column", "socket")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.path_column">
 		<title><varname>path_column</varname> (string)</title>
 		<para>
 		Name of database column containing the Path header.
@@ -408,7 +408,7 @@ modparam("usrloc", "path_column", "path")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.ruid_column">
 		<title><varname>ruid_column</varname> (string)</title>
 		<para>
 		Name of database column containing the Kamailio record unique id.
@@ -428,7 +428,7 @@ modparam("usrloc", "ruid_column", "myruid")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.instance_column">
 		<title><varname>instance_column</varname> (string)</title>
 		<para>
 		Name of database column containing the SIP instance ID (GRUU - RFC5627).
@@ -449,7 +449,7 @@ modparam("usrloc", "instance_column", "myinstance")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.use_domain">
 		<title><varname>use_domain</varname> (integer)</title>
 		<para>
 		If the domain part of the user should be also saved and used for
@@ -471,7 +471,7 @@ modparam("usrloc", "use_domain", 1)
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.desc_time_order">
 		<title><varname>desc_time_order</varname> (integer)</title>
 		<para>
 		If the user's contacts should be kept timestamp ordered; otherwise the
@@ -493,7 +493,7 @@ modparam("usrloc", "desc_time_order", 1)
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.timer_interval">
 		<title><varname>timer_interval</varname> (integer)</title>
 		<para>
 		Number of seconds between two timer runs. The module uses a timer to 
@@ -515,7 +515,7 @@ modparam("usrloc", "timer_interval", 120)
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.db_url">
 		<title><varname>db_url</varname> (string)</title>
 		<para>
 		&url; of the database that should be used.
@@ -535,7 +535,7 @@ modparam("usrloc", "db_url", "&exampledb;")
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.db_mode">
 		<title><varname>db_mode</varname> (integer)</title>
 		<para>
 		The usrloc module can utilize a database for persistent contact storage.
@@ -588,6 +588,15 @@ modparam("usrloc", "db_url", "&exampledb;")
 			caching also disable the statistics exports.
 			</para>
 		</listitem>
+		<listitem>
+			<para>
+			4 - This uses database to load records at startup but uses only
+			memory during the runtime. Records are not written back at all,
+			not even at shutdown. Useful for scenarios when registrations are
+			replicated to a node that does the storage in database during
+			runtime.
+			</para>
+		</listitem>
 		</itemizedlist>
 		<warning>
 		<para>
@@ -611,7 +620,7 @@ modparam("usrloc", "db_mode", 2)
 		</example>
 	</section>
 
-	<section id="matching-mode">
+	<section id="usrloc.p.matching_mode">
 		<title><varname>matching_mode</varname> (integer)</title>
 		<para>
 		What contact matching algorithm to be used. Refer to section 
@@ -655,7 +664,7 @@ modparam("usrloc", "matching_mode", 1)
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.cseq_delay">
 		<title><varname>cseq_delay</varname> (integer)</title>
 		<para>
 		Delay (in seconds) for accepting as retransmissions register requests
@@ -685,7 +694,7 @@ modparam("usrloc", "cseq_delay", 5)
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.fetch_rows">
 		<title><varname>fetch_rows</varname> (integer)</title>
 		<para>
 		The number of the rows to be fetched at once from database
@@ -709,7 +718,7 @@ modparam("usrloc", "fetch_rows", 3000)
 		</example>
 	</section>
 
-	<section>
+	<section id="usrloc.p.hash_size">
 		<title><varname>hash_size</varname> (integer)</title>
 		<para>
 		The number of entries of the hash table used by usrloc to store the
@@ -731,7 +740,7 @@ modparam("usrloc", "hash_size", 10)
 		</example>
 	</section>
 
-	<section id="preload">
+	<section id="usrloc.p.preload">
 		<title><varname>preload</varname> (string)</title>
 		<para>
 		Preload location table given as value. A location table is loaded
@@ -754,7 +763,7 @@ modparam("usrloc", "preload", "location")
 		</example>
 	</section>
 
-	<section id="db_update_as_insert">
+	<section id="usrloc.p.db_update_as_insert">
 		<title><varname>db_update_as_insert</varname> (string)</title>
 		<para>
 			Set this parameter if you want to do INSERT DB operations
@@ -776,7 +785,7 @@ modparam("usrloc", "db_update_as_insert", 1)
 		</example>
 	</section>
 
-	<section id="db_check_update">
+	<section id="usrloc.p.db_check_update">
 		<title><varname>db_check_update</varname> (string)</title>
 		<para>
 			Set this parameter to 1 if you want to do DB INSERT if the number
@@ -800,7 +809,7 @@ modparam("usrloc", "db_check_update", 1)
 		</example>
 	</section>
 
-	<section id="timer_procs">
+	<section id="usrloc.p.timer_procs">
 		<title><varname>timer_procs</varname> (string)</title>
 		<para>
 			Number of timer processes to be started by module. Timer processes
@@ -823,7 +832,7 @@ modparam("usrloc", "timer_procs", 4)
 		</example>
 	</section>
 
-	<section id="xavp_contact">
+	<section id="usrloc.p.xavp_contact">
 		<title><varname>xavp_contact</varname> (string)</title>
 		<para>
 		The name of XAVP storring the attributes per contact. They are saved
@@ -866,6 +875,27 @@ modparam("usrloc", "db_ops_ruid", 1)
 		</example>
 	</section>
 
+	<section id="usrloc.p.handle_lost_tcp">
+		<title><varname>handle_lost_tcp</varname> (int)</title>
+		<para>
+			If set to 1, Kamailio will remove location records made via
+			TCP/TLS/WS/WSS transports when it looses corresponding tcp connections.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>0</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>handle_lost_tcp</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("usrloc", "handle_lost_tcp", 1)
+...
+</programlisting>
+		</example>
+	</section>
+
 	</section>
 
 	<section>
@@ -878,7 +908,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 	<section>
 	<title>MI Commands</title>
 
-	<section>
+	<section id="usrloc.m.ul_rm">
 		<title>
 		<function moreinfo="none">ul_rm</function>
 		</title>
@@ -899,7 +929,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 		</itemizedlist>
 	</section>
 
-	<section>
+	<section id="usrloc.m.ul_rm_contact">
 		<title>
 		<function moreinfo="none">ul_rm_contact</function>
 		</title>
@@ -923,7 +953,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 		</itemizedlist>
 	</section>
 
-	<section>
+	<section id="usrloc.m.ul_dump">
 		<title>
 		<function moreinfo="none">ul_dump</function>
 		</title>
@@ -940,7 +970,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 		</itemizedlist>
 	</section>
 
-	<section>
+	<section id="usrloc.m.ul_flush">
 		<title>
 		<function moreinfo="none">ul_flush</function>
 		</title>
@@ -949,7 +979,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 		</para>
 	</section>
 
-	<section>
+	<section id="usrloc.m.ul_add">
 		<title>
 		<function moreinfo="none">ul_add</function>
 		</title>
@@ -977,8 +1007,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 				<emphasis>Q</emphasis> - Q value of the contact
 			</para></listitem>
 			<listitem><para>
-				<emphasis>unused</emphasis> - unused attribute (kept for
-				backword compatibility)
+				<emphasis>path</emphasis> value of the contact
 			</para></listitem>
 			<listitem><para>
 				<emphasis>flags</emphasis> - internal USRLOC flags of the 
@@ -995,7 +1024,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 		</itemizedlist>
 	</section>
 
-	<section>
+	<section id="usrloc.m.ul_show_contact">
 		<title>
 		<function moreinfo="none">ul_show_contact</function>
 		</title>
@@ -1020,7 +1049,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 	<section>
 	<title>RPC Commands</title>
 
-	<section>
+	<section id="usrloc.r.dump">
 		<title>
 		<function moreinfo="none">ul.dump</function>
 		</title>
@@ -1034,7 +1063,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 			</para></listitem>
 		</itemizedlist>
 	</section>
-	<section>
+	<section id="usrloc.r.lookup">
 		<title>
 		<function moreinfo="none">ul.lookup table AOR</function>
 		</title>
@@ -1054,6 +1083,147 @@ modparam("usrloc", "db_ops_ruid", 1)
 			</para></listitem>
 		</itemizedlist>
 	</section>
+	<section id="usrloc.r.rm">
+		<title>
+		<function moreinfo="none">ul.rm table AOR</function>
+		</title>
+		<para>
+		Deletes an entire AOR record (including its contacts).
+		</para>
+		<para>Parameters: </para>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>table name</emphasis> - table where the AOR
+				resides (Ex: location).
+			</para></listitem>
+			<listitem><para>
+				<emphasis>AOR</emphasis> - user AOR in username[@domain]
+				format (domain must be supplied only if use_domain option
+				is on).
+			</para></listitem>
+		</itemizedlist>
+	</section>
+	<section id="usrloc.r.rm_contact">
+		<title>
+		<function moreinfo="none">ul.rm_contact table AOR contact</function>
+		</title>
+		<para>
+		Deletes a contact from an AOR record.
+		</para>
+		<para>Parameters: </para>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>table name</emphasis> - table where the AOR
+				is removed from (Ex: location).
+			</para></listitem>
+			<listitem><para>
+				<emphasis>AOR</emphasis> - user AOR in username[@domain]
+				format (domain must be supplied only if use_domain option
+				is on).
+			</para></listitem>
+			<listitem><para>
+				<emphasis>contact</emphasis> - exact contact to be removed
+			</para></listitem>
+		</itemizedlist>
+	</section>
+	<section id="usrloc.r.flush">
+		<title>
+		<function moreinfo="none">ul.flush</function>
+		</title>
+		<para>
+		Triggers the flush of USRLOC memory cache into DB.
+		</para>
+	</section>
+	<section id="usrloc.r.add">
+		<title>
+		<function moreinfo="none">ul.add</function>
+		</title>
+		<para>
+		Adds a new contact for an user AOR.
+		</para>
+		<para>Parameters: </para>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>table name</emphasis> - table where the contact
+				will be added (Ex: location).
+			</para></listitem>
+			<listitem><para>
+				<emphasis>AOR</emphasis> - user AOR in username[@domain]
+				format (domain must be supplied only if use_domain option
+				is on).
+			</para></listitem>
+			<listitem><para>
+				<emphasis>contact</emphasis> - contact string to be added
+			</para></listitem>
+			<listitem><para>
+				<emphasis>expires</emphasis> - expires value of the contact
+			</para></listitem>
+			<listitem><para>
+				<emphasis>Q</emphasis> - Q value of the contact
+			</para></listitem>
+			<listitem><para>
+				<emphasis>path</emphasis> value of the contact
+			</para></listitem>
+			<listitem><para>
+				<emphasis>flags</emphasis> - internal USRLOC flags of the
+				contact
+			</para></listitem>
+			<listitem><para>
+				<emphasis>cflags</emphasis> - per branch flags of the
+				contact
+			</para></listitem>
+			<listitem><para>
+				<emphasis>methods</emphasis> - mask with supported requests
+				of the contact
+			</para></listitem>
+		</itemizedlist>
+	</section>
+
+	<section id="usrloc.r.db_users">
+		<title>
+		<function moreinfo="none">ul.db_users</function>
+		</title>
+		<para>
+		Tell number of different users (AoRs) in a location table that have unexpired contacts.
+		</para>
+		<para>Parameters: </para>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>table name</emphasis> - location table where the users are looked for, for example, location.
+			</para></listitem>
+		</itemizedlist>
+	</section>
+
+	<section id="usrloc.r.db_contacts">
+		<title>
+		<function moreinfo="none">ul.db_contacts</function>
+		</title>
+		<para>
+		Tell number of unexpired contacts in a location table.
+		</para>
+		<para>Parameters: </para>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>table name</emphasis> - location table where the contacts are looked for, for example, location.
+			</para></listitem>
+		</itemizedlist>
+	</section>
+
+	<section id="usrloc.r.db_expired_contacts">
+		<title>
+		<function moreinfo="none">ul.db_expired_contacts</function>
+		</title>
+		<para>
+		Tell number of expired contacts in a location table.
+		</para>
+		<para>Parameters: </para>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>table name</emphasis> - location table where the contacts are looked for, for example, location.
+			</para></listitem>
+		</itemizedlist>
+	</section>
+
 	</section><!-- RPC commands -->
 
 
@@ -1062,7 +1232,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 		<para>
 		Exported statistics are listed in the next sections.
 		</para>
-		<section>
+		<section id="usrloc.s.users">
 		<title>users</title>
 			<para>
 			Number of AOR existing in the USRLOC memory cache for that domain
@@ -1070,7 +1240,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 			used domain (Ex: location).
 			</para>
 		</section>
-		<section>
+		<section id="usrloc.s.contacts">
 		<title>contacts</title>
 			<para>
 			Number of contacts existing in the USRLOC memory cache for that 
@@ -1078,7 +1248,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 			each used domain (Ex: location).
 			</para>
 		</section>
-		<section>
+		<section id="usrloc.s.expires">
 		<title>expires</title>
 			<para>
 			Total number of expired contacts for that domain - can be resetted;
@@ -1086,7 +1256,7 @@ modparam("usrloc", "db_ops_ruid", 1)
 			(Ex: location).
 			</para>
 		</section>
-		<section>
+		<section id="usrloc.s.registered_users">
 		<title>registered_users</title>
 			<para>
 			Total number of AOR existing in the USRLOC memory cache for all
diff --git a/modules/usrloc/doc/usrloc_devel.xml b/modules/usrloc/doc/usrloc_devel.xml
index 7cb1961..4e3ba75 100644
--- a/modules/usrloc/doc/usrloc_devel.xml
+++ b/modules/usrloc/doc/usrloc_devel.xml
@@ -100,6 +100,31 @@
 
 	<section>
 		<title>
+		<function moreinfo="none">ul_delete_urecord_by_ruid(domain, ruid)</function>
+		</title>
+		<para>
+		The function deletes from given domain a contact with
+		given ruid.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>udomain_t* domain</emphasis> - Pointer
+			to domain returned by ul_register_udomain.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>str* ruid</emphasis> - ruid of contact
+			that should be deleted.
+			</para>
+		</listitem>
+		</itemizedlist>
+	</section>
+
+	<section>
+		<title>
 		<function moreinfo="none">ul_get_urecord(domain, aor)</function>
 		</title>
 		<para>
diff --git a/modules/usrloc/ucontact.c b/modules/usrloc/ucontact.c
index 996e8d5..4877c7f 100644
--- a/modules/usrloc/ucontact.c
+++ b/modules/usrloc/ucontact.c
@@ -135,6 +135,7 @@ ucontact_t* new_ucontact(str* _dom, str* _aor, str* _contact, ucontact_info_t* _
 	c->reg_id = _ci->reg_id;
 	c->last_modified = _ci->last_modified;
 	c->last_keepalive = _ci->last_modified;
+	c->tcpconn_id = _ci->tcpconn_id;
 #ifdef WITH_XAVP
 	ucontact_xavp_store(c);
 #endif
@@ -306,6 +307,7 @@ int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci)
 	_c->last_keepalive = _ci->last_modified;
 	_c->flags = _ci->flags;
 	_c->cflags = _ci->cflags;
+	_c->tcpconn_id = _ci->tcpconn_id;
 
 	return 0;
 }
@@ -626,8 +628,11 @@ int db_insert_ucontact(ucontact_t* _c)
 		return -1;
 	}
 
-	uldb_insert_attrs(_c->domain, &vals[0].val.str_val, &vals[nr_cols-1].val.str_val,
-		&_c->ruid, _c->xavp);
+	if (ul_xavp_contact_name.s) {
+		uldb_insert_attrs(_c->domain, &vals[0].val.str_val,
+				  &vals[nr_cols-1].val.str_val,
+				  &_c->ruid, _c->xavp);
+	}
 
 	return 0;
 }
@@ -645,8 +650,8 @@ int db_update_ucontact_addr(ucontact_t* _c)
 	db_val_t vals1[4];
 	int n1;
 
-	db_key_t keys2[14];
-	db_val_t vals2[14];
+	db_key_t keys2[15];
+	db_val_t vals2[15];
 	int nr_cols2;
 
 
@@ -674,18 +679,21 @@ int db_update_ucontact_addr(ucontact_t* _c)
 	vals1[n1].type = DB1_STR;
 	vals1[n1].nul = 0;
 	vals1[n1].val.str_val = *_c->aor;
+	LM_DBG("aor:%.*s\n", vals1[n1].val.str_val.len, vals1[n1].val.str_val.s);
 	n1++;
 
 	keys1[n1] = &contact_col;
 	vals1[n1].type = DB1_STR;
 	vals1[n1].nul = 0;
 	vals1[n1].val.str_val = _c->c;
+	LM_DBG("contact:%.*s\n", vals1[n1].val.str_val.len, vals1[n1].val.str_val.s);
 	n1++;
 
 	keys1[n1] = &callid_col;
 	vals1[n1].type = DB1_STR;
 	vals1[n1].nul = 0;
 	vals1[n1].val.str_val = _c->callid;
+	LM_DBG("callid:%.*s\n", vals1[n1].val.str_val.len, vals1[n1].val.str_val.s);
 	n1++;
 
 	vals2[0].type = DB1_DATETIME;
@@ -774,6 +782,13 @@ int db_update_ucontact_addr(ucontact_t* _c)
 	vals2[nr_cols2].val.int_val = (int)_c->reg_id;
 	nr_cols2++;
 
+	keys2[nr_cols2] = &contact_col;
+	vals2[nr_cols2].type = DB1_STR;
+	vals2[nr_cols2].nul = 0;
+	vals2[nr_cols2].val.str_val = _c->c;
+	LM_DBG("contact:%.*s\n", vals2[nr_cols2].val.str_val.len, vals2[nr_cols2].val.str_val.s);
+	nr_cols2++;
+
 	if (use_domain) {
 		keys1[n1] = &domain_col;
 		vals1[n1].type = DB1_STR;
@@ -811,16 +826,19 @@ int db_update_ucontact_addr(ucontact_t* _c)
 		}
 	}
 	/* delete old db attrs and add the current list */
-	if (use_domain) {
-		uldb_delete_attrs(_c->domain, &vals1[0].val.str_val,
-				&vals1[n1-1].val.str_val, &_c->ruid);
-		uldb_insert_attrs(_c->domain, &vals1[0].val.str_val,
-				&vals1[n1-1].val.str_val, &_c->ruid, _c->xavp);
-	} else {
-		uldb_delete_attrs(_c->domain, &vals1[0].val.str_val,
-				NULL, &_c->ruid);
-		uldb_insert_attrs(_c->domain, &vals1[0].val.str_val,
-				NULL, &_c->ruid, _c->xavp);
+	if (ul_xavp_contact_name.s) {
+		if (use_domain) {
+			uldb_delete_attrs(_c->domain, &vals1[0].val.str_val,
+					  &vals1[n1-1].val.str_val, &_c->ruid);
+			uldb_insert_attrs(_c->domain, &vals1[0].val.str_val,
+					  &vals1[n1-1].val.str_val,
+					  &_c->ruid, _c->xavp);
+		} else {
+			uldb_delete_attrs(_c->domain, &vals1[0].val.str_val,
+					  NULL, &_c->ruid);
+			uldb_insert_attrs(_c->domain, &vals1[0].val.str_val,
+					  NULL, &_c->ruid, _c->xavp);
+		}
 	}
 
 	return 0;
@@ -839,8 +857,8 @@ int db_update_ucontact_ruid(ucontact_t* _c)
 	db_val_t vals1[1];
 	int n1;
 
-	db_key_t keys2[14];
-	db_val_t vals2[14];
+	db_key_t keys2[15];
+	db_val_t vals2[15];
 	int n2;
 
 
@@ -858,6 +876,7 @@ int db_update_ucontact_ruid(ucontact_t* _c)
 	vals1[n1].type = DB1_STR;
 	vals1[n1].nul = 0;
 	vals1[n1].val.str_val = _c->ruid;
+	LM_DBG("ruid:%.*s\n", vals1[n1].val.str_val.len, vals1[n1].val.str_val.s);
 	n1++;
 
 	n2 = 0;
@@ -966,6 +985,13 @@ int db_update_ucontact_ruid(ucontact_t* _c)
 	vals2[n2].val.int_val = (int)_c->reg_id;
 	n2++;
 
+	keys2[n2] = &contact_col;
+	vals2[n2].type = DB1_STR;
+	vals2[n2].nul = 0;
+	vals2[n2].val.str_val = _c->c;
+	LM_DBG("contact:%.*s\n", vals2[n2].val.str_val.len, vals2[n2].val.str_val.s);
+	n2++;
+
 	if (ul_dbf.use_table(ul_dbh, _c->domain) < 0) {
 		LM_ERR("sql use_table failed\n");
 		return -1;
@@ -987,27 +1013,220 @@ int db_update_ucontact_ruid(ucontact_t* _c)
 	}
 
 	/* delete old db attrs and add the current list */
-	auser = *_c->aor;
-	if (use_domain) {
-		adomain.s = memchr(_c->aor->s, '@', _c->aor->len);
-		if (adomain.s==0) {
-			auser.len = 0;
-			adomain = *_c->aor;
+	if (ul_xavp_contact_name.s) {
+	        auser = *_c->aor;
+	        if (use_domain) {
+			adomain.s = memchr(_c->aor->s, '@', _c->aor->len);
+			if (adomain.s==0) {
+				auser.len = 0;
+				adomain = *_c->aor;
+			} else {
+				auser.len = adomain.s - _c->aor->s;
+				adomain.s++;
+				adomain.len = _c->aor->s +
+					_c->aor->len - adomain.s;
+			}
+
+			uldb_delete_attrs(_c->domain, &auser,
+					  &adomain, &_c->ruid);
+			uldb_insert_attrs(_c->domain, &auser,
+					  &adomain, &_c->ruid, _c->xavp);
 		} else {
-			auser.len = adomain.s - _c->aor->s;
-			adomain.s++;
-			adomain.len = _c->aor->s + _c->aor->len - adomain.s;
+			uldb_delete_attrs(_c->domain, &auser,
+					  NULL, &_c->ruid);
+			uldb_insert_attrs(_c->domain, &auser,
+					  NULL, &_c->ruid, _c->xavp);
 		}
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Update contact in the database by instance reg_id
+ * \param _c updated contact
+ * \return 0 on success, -1 on failure
+ */
+int db_update_ucontact_instance(ucontact_t* _c)
+{
+	str auser;
+	str adomain;
+	db_key_t keys1[2];
+	db_val_t vals1[2];
+	int n1;
+
+	db_key_t keys2[13];
+	db_val_t vals2[13];
+	int n2;
+
+
+	if (_c->flags & FL_MEM) {
+		return 0;
+	}
+
+	if(_c->instance.len<=0) {
+		LM_ERR("updating record in database failed - empty instance\n");
+		return -1;
+	}
+
+	n1 = 0;
+	keys1[n1] = &instance_col;
+	vals1[n1].type = DB1_STR;
+	vals1[n1].nul = 0;
+	vals1[n1].val.str_val = _c->instance;
+	LM_DBG("instance:%.*s\n", vals1[n1].val.str_val.len, vals1[n1].val.str_val.s);
+	n1++;
 
-		uldb_delete_attrs(_c->domain, &auser,
-				&adomain, &_c->ruid);
-		uldb_insert_attrs(_c->domain, &auser,
-				&adomain, &_c->ruid, _c->xavp);
+	keys1[n1] = &reg_id_col;
+	vals1[n1].type = DB1_INT;
+	vals1[n1].nul = 0;
+	vals1[n1].val.int_val = (int)_c->reg_id;
+	LM_DBG("reg-id:%d\n", vals1[n1].val.int_val);
+	n1++;
+
+	n2 = 0;
+	keys2[n2] = &expires_col;
+	vals2[n2].type = DB1_DATETIME;
+	vals2[n2].nul = 0;
+	vals2[n2].val.time_val = _c->expires;
+	n2++;
+
+	keys2[n2] = &q_col;
+	vals2[n2].type = DB1_DOUBLE;
+	vals2[n2].nul = 0;
+	vals2[n2].val.double_val = q2double(_c->q);
+	n2++;
+
+	keys2[n2] = &cseq_col;
+	vals2[n2].type = DB1_INT;
+	vals2[n2].nul = 0;
+	vals2[n2].val.int_val = _c->cseq;
+	n2++;
+
+	keys2[n2] = &flags_col;
+	vals2[n2].type = DB1_INT;
+	vals2[n2].nul = 0;
+	vals2[n2].val.bitmap_val = _c->flags;
+	n2++;
+
+	keys2[n2] = &cflags_col;
+	vals2[n2].type = DB1_INT;
+	vals2[n2].nul = 0;
+	vals2[n2].val.bitmap_val = _c->cflags;
+	n2++;
+
+	keys2[n2] = &user_agent_col;
+	vals2[n2].type = DB1_STR;
+	vals2[n2].nul = 0;
+	vals2[n2].val.str_val = _c->user_agent;
+	n2++;
+
+	keys2[n2] = &received_col;
+	vals2[n2].type = DB1_STR;
+	if (_c->received.s == 0) {
+		vals2[n2].nul = 1;
+	} else {
+		vals2[n2].nul = 0;
+		vals2[n2].val.str_val = _c->received;
+	}
+	n2++;
+
+	keys2[n2] = &path_col;
+	vals2[n2].type = DB1_STR;
+	if (_c->path.s == 0) {
+		vals2[n2].nul = 1;
+	} else {
+		vals2[n2].nul = 0;
+		vals2[n2].val.str_val = _c->path;
+	}
+	n2++;
+
+	keys2[n2] = &sock_col;
+	vals2[n2].type = DB1_STR;
+	if (_c->sock) {
+		vals2[n2].val.str_val = _c->sock->sock_str;
+		vals2[n2].nul = 0;
 	} else {
-		uldb_delete_attrs(_c->domain, &auser,
-				NULL, &_c->ruid);
-		uldb_insert_attrs(_c->domain, &auser,
-				NULL, &_c->ruid, _c->xavp);
+		vals2[n2].nul = 1;
+	}
+	n2++;
+
+	keys2[n2] = &methods_col;
+	vals2[n2].type = DB1_BITMAP;
+	if (_c->methods == 0xFFFFFFFF) {
+		vals2[n2].nul = 1;
+	} else {
+		vals2[n2].val.bitmap_val = _c->methods;
+		vals2[n2].nul = 0;
+	}
+	n2++;
+
+	keys2[n2] = &last_mod_col;
+	vals2[n2].type = DB1_DATETIME;
+	vals2[n2].nul = 0;
+	vals2[n2].val.time_val = _c->last_modified;
+	n2++;
+
+	keys2[n2] = &callid_col;
+	vals2[n2].type = DB1_STR;
+	vals2[n2].nul = 0;
+	vals2[n2].val.str_val = _c->callid;
+	n2++;
+
+	keys2[n2] = &contact_col;
+	vals2[n2].type = DB1_STR;
+	vals2[n2].nul = 0;
+	vals2[n2].val.str_val.s = _c->c.s;
+	vals2[n2].val.str_val.len = _c->c.len;
+	LM_DBG("contact:%.*s\n", vals2[n2].val.str_val.len, vals2[n2].val.str_val.s);
+	n2++;
+
+	if (ul_dbf.use_table(ul_dbh, _c->domain) < 0) {
+		LM_ERR("sql use_table failed\n");
+		return -1;
+	}
+
+	if (ul_dbf.update(ul_dbh, keys1, 0, vals1, keys2, vals2, n1, n2) < 0) {
+		LM_ERR("updating database failed\n");
+		return -1;
+	}
+
+	if (ul_db_check_update==1 && ul_dbf.affected_rows) {
+		LM_DBG("update affected_rows 0\n");
+		/* supposed to be an UPDATE, but if affected rows is 0, then try
+		 * to do an INSERT */
+		if(ul_dbf.affected_rows(ul_dbh)==0) {
+			LM_DBG("affected rows by UPDATE was 0, doing an INSERT\n");
+			if(db_insert_ucontact(_c)<0)
+				return -1;
+		}
+	}
+
+	/* delete old db attrs and add the current list */
+	if (ul_xavp_contact_name.s) {
+	        auser = *_c->aor;
+	        if (use_domain) {
+			adomain.s = memchr(_c->aor->s, '@', _c->aor->len);
+			if (adomain.s==0) {
+				auser.len = 0;
+				adomain = *_c->aor;
+			} else {
+				auser.len = adomain.s - _c->aor->s;
+				adomain.s++;
+				adomain.len = _c->aor->s +
+					_c->aor->len - adomain.s;
+			}
+
+			uldb_delete_attrs(_c->domain, &auser,
+					  &adomain, &_c->ruid);
+			uldb_insert_attrs(_c->domain, &auser,
+					  &adomain, &_c->ruid, _c->xavp);
+		} else {
+			uldb_delete_attrs(_c->domain, &auser,
+					  NULL, &_c->ruid);
+			uldb_insert_attrs(_c->domain, &auser,
+					  NULL, &_c->ruid, _c->xavp);
+		}
 	}
 
 	return 0;
@@ -1021,7 +1240,12 @@ int db_update_ucontact_ruid(ucontact_t* _c)
 int db_update_ucontact(ucontact_t* _c)
 {
 	if(ul_db_ops_ruid==0)
-		return db_update_ucontact_addr(_c);
+		if (_c->instance.len<=0) {
+			return db_update_ucontact_addr(_c);
+		}
+		else {
+			return db_update_ucontact_instance(_c);
+		}
 	else
 		return db_update_ucontact_ruid(_c);
 }
@@ -1063,24 +1287,25 @@ int db_delete_ucontact_addr(ucontact_t* _c)
 	n++;
 
 	if (use_domain) {
-		keys[n] = &domain_col;
-		vals[n].type = DB1_STR;
-		vals[n].nul = 0;
-		dom = memchr(_c->aor->s, '@', _c->aor->len);
-		if (dom==0) {
-			vals[0].val.str_val.len = 0;
-			vals[n].val.str_val = *_c->aor;
-		} else {
-			vals[0].val.str_val.len = dom - _c->aor->s;
-			vals[n].val.str_val.s = dom + 1;
-			vals[n].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1;
-		}
-		uldb_delete_attrs(_c->domain, &vals[0].val.str_val,
-				&vals[n].val.str_val, &_c->ruid);
-		n++;
+	    keys[n] = &domain_col;
+	    vals[n].type = DB1_STR;
+	    vals[n].nul = 0;
+	    dom = memchr(_c->aor->s, '@', _c->aor->len);
+	    if (dom==0) {
+		vals[0].val.str_val.len = 0;
+		vals[n].val.str_val = *_c->aor;
+	    } else {
+		vals[0].val.str_val.len = dom - _c->aor->s;
+		vals[n].val.str_val.s = dom + 1;
+		vals[n].val.str_val.len = _c->aor->s +
+		    _c->aor->len - dom - 1;
+	    }
+	    uldb_delete_attrs(_c->domain, &vals[0].val.str_val,
+			      &vals[n].val.str_val, &_c->ruid);
+	    n++;
 	} else {
-		uldb_delete_attrs(_c->domain, &vals[0].val.str_val,
-				NULL, &_c->ruid);
+	    uldb_delete_attrs(_c->domain, &vals[0].val.str_val,
+			      NULL, &_c->ruid);
 	}
 
 	if (ul_dbf.use_table(ul_dbh, _c->domain) < 0) {
diff --git a/modules/usrloc/udomain.c b/modules/usrloc/udomain.c
index 13632d2..244f8e7 100644
--- a/modules/usrloc/udomain.c
+++ b/modules/usrloc/udomain.c
@@ -351,6 +351,9 @@ static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact)
 		ci.reg_id = VAL_UINT(vals+15);
 	}
 
+	/* tcp connection id */
+	ci.tcpconn_id = -1;
+
 	return &ci;
 }
 
@@ -648,7 +651,7 @@ urecord_t* db_load_urecord_by_ruid(db1_con_t* _c, udomain_t* _d, str *_ruid)
 	db_row_t *row;
 	str contact;
 	str aor;
-	char aorbuf[512];
+	static char aorbuf[512];
 	str domain;
 
 	urecord_t* r;
@@ -1031,7 +1034,7 @@ int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
  * \param _ruid record internal unique id
  * \param _r store pointer to location record
  * \param _c store pointer to contact structure
- * \return 0 if a record was found, 1 if nothing could be found
+ * \return 0 if a record was found, -1 if nothing could be found
  */
 int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
 		str *_ruid, struct urecord** _r, struct ucontact** _c)
@@ -1057,6 +1060,7 @@ int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
 						*_c = c;
 						return 0;
 					}
+					c = c->next;
 				}
 			}
 			r = r->next;
@@ -1074,6 +1078,7 @@ int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
 						*_c = c;
 						return 0;
 					}
+					c = c->next;
 				}
 			}
 		}
diff --git a/modules/usrloc/ul_mi.c b/modules/usrloc/ul_mi.c
index 3f88a71..3e12bf1 100644
--- a/modules/usrloc/ul_mi.c
+++ b/modules/usrloc/ul_mi.c
@@ -491,8 +491,8 @@ struct mi_root* mi_usrloc_flush(struct mi_root *cmd, void *param)
  * \brief Add a new contact for an address of record
  * \param cmd mi_root containing the parameter
  * \param param not used
- * \note Expects 7 nodes: table name, AOR, contact, expires, Q,
- * useless - backward compatible, flags, cflags, methods
+ * \note Expects 9 nodes: table name, AOR, contact, expires, Q,
+ * path, flags, cflags, methods
  * \return mi_root with the result
  */
 struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param)
@@ -540,8 +540,10 @@ struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param)
 	if (str2q( &ci.q, node->value.s, node->value.len) < 0)
 		goto bad_syntax;
 
-	/* unused value (param 6) FIXME */
+	/* path value (param 6) */
 	node = node->next;
+	if(strncmp(node->value.s, "0", 1) != 0 && node->value.len > 1)
+		ci.path = &node->value;
 
 	/* flags value (param 7) */
 	node = node->next;
diff --git a/modules/usrloc/ul_mod.c b/modules/usrloc/ul_mod.c
index 77a2a40..b1be56b 100644
--- a/modules/usrloc/ul_mod.c
+++ b/modules/usrloc/ul_mod.c
@@ -161,6 +161,7 @@ int timer_interval  = 60;				/*!< Timer interval in seconds */
 int db_mode         = 0;				/*!< Database sync scheme: 0-no db, 1-write through, 2-write back, 3-only db */
 int use_domain      = 0;				/*!< Whether usrloc should use domain part of aor */
 int desc_time_order = 0;				/*!< By default do not enable timestamp ordering */
+int handle_lost_tcp = 0;				/*!< By default do not remove contacts before expiration time */
 
 int ul_fetch_rows = 2000;				/*!< number of rows to fetch from result */
 int ul_hash_size = 9;
@@ -214,6 +215,7 @@ static param_export_t params[] = {
 	{"fetch_rows",          INT_PARAM, &ul_fetch_rows   },
 	{"hash_size",           INT_PARAM, &ul_hash_size    },
 	{"nat_bflag",           INT_PARAM, &nat_bflag       },
+	{"handle_lost_tcp",     INT_PARAM, &handle_lost_tcp },
 	{"preload",             STR_PARAM|USE_FUNC_PARAM, (void*)ul_preload_param},
 	{"db_update_as_insert", INT_PARAM, &ul_db_update_as_insert},
 	{"timer_procs",         INT_PARAM, &ul_timer_procs},
@@ -387,6 +389,10 @@ static int mod_init(void)
 			return -1;
 		}
 	}
+
+	if (handle_lost_tcp && db_mode == DB_ONLY)
+		LM_WARN("handle_lost_tcp option makes nothing in DB_ONLY mode\n");
+
 	init_flag = 1;
 
 	return 0;
@@ -419,15 +425,19 @@ static int child_init(int _rank)
 			return 0;
 		case DB_ONLY:
 		case WRITE_THROUGH:
-			/* we need connection from working SIP and TIMER and MAIN
-			 * processes only */
+			/* connect to db only from SIP workers, TIMER and MAIN processes */
 			if (_rank<=0 && _rank!=PROC_TIMER && _rank!=PROC_MAIN)
 				return 0;
 			break;
 		case WRITE_BACK:
-			/* connect only from TIMER (for flush), from MAIN (for
+			/* connect to db only from TIMER (for flush), from MAIN (for
 			 * final flush() and from child 1 for preload */
-			if (_rank!=PROC_TIMER && _rank!=PROC_MAIN && _rank!=1)
+			if (_rank!=PROC_TIMER && _rank!=PROC_MAIN && _rank!=PROC_SIPINIT)
+				return 0;
+			break;
+		case DB_READONLY:
+			/* connect to db only from child 1 for preload */
+			if(_rank!=PROC_SIPINIT)
 				return 0;
 			break;
 	}
@@ -438,7 +448,7 @@ static int child_init(int _rank)
 		return -1;
 	}
 	/* _rank==PROC_SIPINIT is used even when fork is disabled */
-	if (_rank==PROC_SIPINIT && db_mode!= DB_ONLY) {
+	if (_rank==PROC_SIPINIT && db_mode!=DB_ONLY) {
 		/* if cache is used, populate domains from DB */
 		for( ptr=root ; ptr ; ptr=ptr->next) {
 			if (preload_udomain(ul_dbh, ptr->d) < 0) {
diff --git a/modules/usrloc/ul_mod.h b/modules/usrloc/ul_mod.h
index 2435b5e..0e61924 100644
--- a/modules/usrloc/ul_mod.h
+++ b/modules/usrloc/ul_mod.h
@@ -84,6 +84,7 @@ extern int ul_hash_size;
 extern int ul_db_update_as_insert;
 extern int ul_db_check_update;
 extern int ul_keepalive_timeout;
+extern int handle_lost_tcp;
 
 /*! nat branch flag */
 extern unsigned int nat_bflag;
diff --git a/modules/usrloc/ul_rpc.c b/modules/usrloc/ul_rpc.c
index 042ef81..077b035 100644
--- a/modules/usrloc/ul_rpc.c
+++ b/modules/usrloc/ul_rpc.c
@@ -20,6 +20,7 @@
 
 #include "../../ip_addr.h"
 #include "../../dprint.h"
+#include "../../lib/srutils/sruid.h"
 
 #include "ul_rpc.h"
 #include "dlist.h"
@@ -28,6 +29,17 @@
 #include "ul_mod.h"
 #include "utime.h"
 
+/*! CSEQ nr used */
+#define RPC_UL_CSEQ 1
+/*! call-id used for ul_add and ul_rm_contact */
+static str rpc_ul_cid = str_init("dfjrewr12386fd6-343 at kamailio.mi");
+/*! path used for ul_add and ul_rm_contact */
+static str rpc_ul_path = str_init("dummypath");
+/*! user agent used for ul_add */
+static str rpc_ul_ua  = str_init("SIP Router MI Server");
+
+extern sruid_t _ul_sruid;
+
 static const char* ul_rpc_dump_doc[2] = {
 	"Dump user location tables",
 	0
@@ -95,7 +107,7 @@ int rpc_dump_contact(rpc_t* rpc, void* ctx, void *ih, ucontact_t* c)
 		socket_str.s = c->sock->sock_str.s;
 		socket_str.len = c->sock->sock_str.len;
 	}
-	if(rpc->struct_add(vh, "f", "Q", c->q)<0)
+	if(rpc->struct_add(vh, "f", "Q", q2double(c->q))<0)
 	{
 		rpc->fault(ctx, 500, "Internal error adding q");
 		return -1;
@@ -393,9 +405,409 @@ static void ul_rpc_lookup(rpc_t* rpc, void* ctx)
 	return;
 }
 
+static void ul_rpc_rm_aor(rpc_t* rpc, void* ctx)
+{
+	udomain_t* dom;
+	str table = {0, 0};
+	str aor = {0, 0};
+
+	if (rpc->scan(ctx, "SS", &table, &aor) != 2) {
+		rpc->fault(ctx, 500, "Not enough parameters (table and AOR to lookup)");
+		return;
+	}
+
+	/* look for table */
+	dom = rpc_find_domain( &table );
+	if (dom == NULL) {
+		rpc->fault(ctx, 500, "Domain not found");
+		return;
+	}
+
+	/* process the aor */
+	if ( rpc_fix_aor(&aor) != 0 ) {
+		rpc->fault(ctx, 500, "Domain missing in AOR");
+		return;
+	}
+
+	lock_udomain( dom, &aor);
+	if (delete_urecord( dom, &aor, 0) < 0) {
+		unlock_udomain( dom, &aor);
+		rpc->fault(ctx, 500, "Failed to delete AOR");
+		return;
+	}
+
+	unlock_udomain( dom, &aor);
+	return;
+}
+
+static const char* ul_rpc_rm_aor_doc[2] = {
+	"Delete a address of record including its contacts",
+	0
+};
+
+static void ul_rpc_rm_contact(rpc_t* rpc, void* ctx)
+{
+	udomain_t* dom;
+	str table = {0, 0};
+	str aor = {0, 0};
+	str contact = {0, 0};
+	urecord_t *rec;
+	ucontact_t* con;
+	int ret;
+
+	if (rpc->scan(ctx, "SSS", &table, &aor, &contact) != 3) {
+		rpc->fault(ctx, 500, "Not enough parameters (table, AOR and contact)");
+		return;
+	}
+
+	/* look for table */
+	dom = rpc_find_domain( &table );
+	if (dom == NULL) {
+		rpc->fault(ctx, 500, "Domain not found");
+		return;
+	}
+
+	/* process the aor */
+	if ( rpc_fix_aor(&aor) != 0 ) {
+		rpc->fault(ctx, 500, "Domain missing in AOR");
+		return;
+	}
+
+	lock_udomain( dom, &aor);
+
+	ret = get_urecord( dom, &aor, &rec);
+	if (ret == 1) {
+		unlock_udomain( dom, &aor);
+		rpc->fault(ctx, 404, "AOR not found");
+		return;
+	}
+
+	ret = get_ucontact( rec, &contact, &rpc_ul_cid, &rpc_ul_path, RPC_UL_CSEQ+1, &con);
+	if (ret < 0) {
+		unlock_udomain( dom, &aor);
+		rpc->fault(ctx, 500, "Internal error (can't get contact)");
+		return;
+	}
+	if (ret > 0) {
+		unlock_udomain( dom, &aor);
+		rpc->fault(ctx, 404, "Contact not found");
+		return;
+	}
+
+	if (delete_ucontact(rec, con) < 0) {
+		unlock_udomain( dom, &aor);
+		rpc->fault(ctx, 500, "Internal error (can't delete contact)");
+		return;
+	}
+
+	release_urecord(rec);
+	unlock_udomain( dom, &aor);
+	return;
+}
+
+static const char* ul_rpc_rm_contact_doc[2] = {
+	"Delete a contact from an AOR record",
+	0
+};
+
+static void ul_rpc_flush(rpc_t* rpc, void* ctx)
+{
+	synchronize_all_udomains(0, 1);
+	return;
+}
+
+static const char* ul_rpc_flush_doc[2] = {
+	"Flush the usrloc memory cache to DB",
+	0
+};
+
+/*!
+ * \brief Add a new contact for an address of record
+ * \note Expects 9 parameters: table name, AOR, contact, expires, Q,
+ * path, flags, cflags, methods
+ */
+static void ul_rpc_add(rpc_t* rpc, void* ctx)
+{
+	str table = {0, 0};
+	str aor = {0, 0};
+	str contact = {0, 0};
+	str path = {0, 0};
+	str temp = {0, 0};
+	double dtemp;
+	ucontact_info_t ci;
+	urecord_t* r;
+	ucontact_t* c;
+	udomain_t *dom;
+	int ret;
+
+	memset( &ci, 0, sizeof(ucontact_info_t));
+
+	ret = rpc->scan(ctx, "SSSdfSddd", &table, &aor, &contact, &ci.expires,
+		&dtemp, &path, &ci.flags, &ci.cflags, &ci.methods);
+	if(path.len==1 && (strncmp(temp.s, "0", 1)==0))	{
+		LM_DBG("path == 0 -> unset\n");
+	}
+	else {
+		ci.path = &path;
+	}
+	LM_DBG("ret: %d table:%.*s aor:%.*s contact:%.*s expires:%d dtemp:%f path:%.*s flags:%d bflags:%d methods:%d\n",
+		ret, table.len, table.s, aor.len, aor.s, contact.len, contact.s,
+		(int) ci.expires, dtemp, ci.path->len, ci.path->s, ci.flags, ci.cflags, (int) ci.methods);
+	if ( ret != 9) {
+		rpc->fault(ctx, 500, "Not enough parameters or wrong format");
+		return;
+	}
+	ci.q = double2q(dtemp);
+	temp.s = q2str(ci.q, (unsigned int*)&temp.len);
+	LM_DBG("q:%.*s\n", temp.len, temp.s);
+	/* look for table */
+	dom = rpc_find_domain( &table );
+	if (dom == NULL) {
+		rpc->fault(ctx, 500, "Domain not found");
+		return;
+	}
+
+	/* process the aor */
+	if ( rpc_fix_aor(&aor) != 0 ) {
+		rpc->fault(ctx, 500, "Domain missing in AOR");
+		return;
+	}
+
+	if(sruid_next(&_ul_sruid)<0)
+	{
+		rpc->fault(ctx, 500, "Can't obtain next uid");
+		return;
+	}
+	ci.ruid = _ul_sruid.uid;
+
+	lock_udomain( dom, &aor);
+
+	ret = get_urecord( dom, &aor, &r);
+	if(ret==1) {
+		if (insert_urecord( dom, &aor, &r) < 0)
+		{
+			unlock_udomain( dom, &aor);
+			rpc->fault(ctx, 500, "Can't insert record");
+			return;
+		}
+		c = 0;
+	} else {
+		if (get_ucontact( r, &contact, &rpc_ul_cid, &rpc_ul_path, RPC_UL_CSEQ+1, &c) < 0)
+		{
+			unlock_udomain( dom, &aor);
+			rpc->fault(ctx, 500, "Can't get record");
+			return;
+		}
+	}
+
+	get_act_time();
+
+	ci.callid = &rpc_ul_cid;
+	ci.user_agent = &rpc_ul_ua;
+	ci.cseq = RPC_UL_CSEQ;
+	/* 0 expires means permanent contact */
+	if (ci.expires!=0)
+		ci.expires += act_time;
+
+	if (c) {
+		if (update_ucontact( r, c, &ci) < 0)
+		{
+			release_urecord(r);
+			unlock_udomain( dom, &aor);
+			rpc->fault(ctx, 500, "Can't update contact");
+			return;
+		}
+	} else {
+		if ( insert_ucontact( r, &contact, &ci, &c) < 0 )
+		{
+			release_urecord(r);
+			unlock_udomain( dom, &aor);
+			rpc->fault(ctx, 500, "Can't insert contact");
+			return;
+		}
+	}
+
+	release_urecord(r);
+	unlock_udomain( dom, &aor);
+	return;
+}
+
+static const char* ul_rpc_add_doc[2] = {
+	"Add a new contact for an address of record",
+	0
+};
+
+#define QUERY_LEN 256
+
+static void ul_rpc_db_users(rpc_t* rpc, void* ctx)
+{
+    str table = {0, 0};
+    char query[QUERY_LEN];
+    str query_str;
+    db1_res_t* res;
+    int count;
+
+    if (db_mode == NO_DB) {
+	rpc->fault(ctx, 500, "Command is not supported in db_mode=0");
+	return;
+    }
+
+    if (rpc->scan(ctx, "S", &table) != 1) {
+	rpc->fault(ctx, 500, "Not enough parameters (table to lookup)");
+	return;
+    }
+
+    if (user_col.len + domain_col.len + table.len + 32 > QUERY_LEN) {
+	rpc->fault(ctx, 500, "Too long database query");
+	return;
+    }
+
+    if (!DB_CAPABILITY(ul_dbf, DB_CAP_RAW_QUERY)) {
+	rpc->fault(ctx, 500, "Database does not support raw queries");
+	return;
+    }
+    if (ul_dbf.use_table(ul_dbh, &table) < 0) {
+	rpc->fault(ctx, 500, "Failed to use table");
+	return;
+    }
+	
+    memset(query, 0, QUERY_LEN);
+    query_str.len = snprintf(query, QUERY_LEN,
+			     "SELECT COUNT(DISTINCT %.*s, %.*s) FROM %.*s WHERE (UNIX_TIMESTAMP(expires) = 0) OR (expires > NOW())",
+			     user_col.len, user_col.s,
+			     domain_col.len, domain_col.s,
+			     table.len, table.s);
+    query_str.s = query;
+    if (ul_dbf.raw_query(ul_dbh, &query_str, &res) < 0) {
+	rpc->fault(ctx, 500, "Failed to query AoR count");
+	return;
+    }
+
+    count = (int)VAL_INT(ROW_VALUES(RES_ROWS(res)));
+    ul_dbf.free_result(ul_dbh, res);
+
+    rpc->add(ctx, "d", count);
+}
+
+static const char* ul_rpc_db_users_doc[2] = {
+	"Tell number of different unexpired users (AoRs) in database table (db_mode!=0 only)",
+	0
+};
+
+static void ul_rpc_db_contacts(rpc_t* rpc, void* ctx)
+{
+    str table = {0, 0};
+    char query[QUERY_LEN];
+    str query_str;
+    db1_res_t* res;
+    int count;
+
+    if (db_mode == NO_DB) {
+	rpc->fault(ctx, 500, "Command is not supported in db_mode=0");
+	return;
+    }
+
+    if (rpc->scan(ctx, "S", &table) != 1) {
+	rpc->fault(ctx, 500, "Not enough parameters (table to lookup)");
+	return;
+    }
+
+    if (table.len + 22 > QUERY_LEN) {
+	rpc->fault(ctx, 500, "Too long database query");
+	return;
+    }
+
+    if (!DB_CAPABILITY(ul_dbf, DB_CAP_RAW_QUERY)) {
+	rpc->fault(ctx, 500, "Database does not support raw queries");
+	return;
+    }
+    if (ul_dbf.use_table(ul_dbh, &table) < 0) {
+	rpc->fault(ctx, 500, "Failed to use table");
+	return;
+    }
+	
+    memset(query, 0, QUERY_LEN);
+    query_str.len = snprintf(query, QUERY_LEN, "SELECT COUNT(*) FROM %.*s WHERE (UNIX_TIMESTAMP(expires) = 0) OR (expires > NOW())",
+			     table.len, table.s);
+    query_str.s = query;
+    if (ul_dbf.raw_query(ul_dbh, &query_str, &res) < 0) {
+	rpc->fault(ctx, 500, "Failed to query contact count");
+	return;
+    }
+
+    count = (int)VAL_INT(ROW_VALUES(RES_ROWS(res)));
+    ul_dbf.free_result(ul_dbh, res);
+
+    rpc->add(ctx, "d", count);
+}
+
+static const char* ul_rpc_db_contacts_doc[2] = {
+	"Tell number of unexpired contacts in database table (db_mode=3 only)",
+	0
+};
+
+static void ul_rpc_db_expired_contacts(rpc_t* rpc, void* ctx)
+{
+    str table = {0, 0};
+    char query[QUERY_LEN];
+    str query_str;
+    db1_res_t* res;
+    int count;
+
+    if (db_mode == NO_DB) {
+	rpc->fault(ctx, 500, "Command is not supported in db_mode=0");
+	return;
+    }
+
+    if (rpc->scan(ctx, "S", &table) != 1) {
+	rpc->fault(ctx, 500, "Not enough parameters (table to lookup)");
+	return;
+    }
+
+    if (table.len + 22 > QUERY_LEN) {
+	rpc->fault(ctx, 500, "Too long database query");
+	return;
+    }
+
+    if (!DB_CAPABILITY(ul_dbf, DB_CAP_RAW_QUERY)) {
+	rpc->fault(ctx, 500, "Database does not support raw queries");
+	return;
+    }
+    if (ul_dbf.use_table(ul_dbh, &table) < 0) {
+	rpc->fault(ctx, 500, "Failed to use table");
+	return;
+    }
+	
+    memset(query, 0, QUERY_LEN);
+    query_str.len = snprintf(query, QUERY_LEN, "SELECT COUNT(*) FROM %.*s WHERE (UNIX_TIMESTAMP(expires) > 0) AND (expires <= NOW())",
+			     table.len, table.s);
+    query_str.s = query;
+    if (ul_dbf.raw_query(ul_dbh, &query_str, &res) < 0) {
+	rpc->fault(ctx, 500, "Failed to query contact count");
+	return;
+    }
+
+    count = (int)VAL_INT(ROW_VALUES(RES_ROWS(res)));
+    ul_dbf.free_result(ul_dbh, res);
+
+    rpc->add(ctx, "d", count);
+}
+
+static const char* ul_rpc_db_expired_contacts_doc[2] = {
+	"Tell number of expired contacts in database table (db_mode=3 only)",
+	0
+};
+
 rpc_export_t ul_rpc[] = {
 	{"ul.dump",   ul_rpc_dump,   ul_rpc_dump_doc,   0},
 	{"ul.lookup",   ul_rpc_lookup,   ul_rpc_lookup_doc,   0},
+	{"ul.rm", ul_rpc_rm_aor, ul_rpc_rm_aor_doc, 0},
+	{"ul.rm_contact", ul_rpc_rm_contact, ul_rpc_rm_contact_doc, 0},
+	{"ul.flush", ul_rpc_flush, ul_rpc_flush_doc, 0},
+	{"ul.add", ul_rpc_add, ul_rpc_add_doc, 0},
+	{"ul.db_users", ul_rpc_db_users, ul_rpc_db_users_doc, 0},
+	{"ul.db_contacts", ul_rpc_db_contacts, ul_rpc_db_contacts_doc, 0},
+	{"ul.db_expired_contacts", ul_rpc_db_expired_contacts, ul_rpc_db_expired_contacts_doc, 0},
 	{0, 0, 0, 0}
 };
 
diff --git a/modules/usrloc/urecord.c b/modules/usrloc/urecord.c
index 75ddd1a..b9722d9 100644
--- a/modules/usrloc/urecord.c
+++ b/modules/usrloc/urecord.c
@@ -40,6 +40,7 @@
 #include "../../dprint.h"
 #include "../../ut.h"
 #include "../../hashes.h"
+#include "../../tcp_conn.h"
 #include "ul_mod.h"
 #include "usrloc.h"
 #include "utime.h"
@@ -221,6 +222,26 @@ void mem_delete_ucontact(urecord_t* _r, ucontact_t* _c)
 	free_ucontact(_c);
 }
 
+static inline int is_valid_tcpconn(ucontact_t *c)
+{
+	if (c->tcpconn_id == -1)
+		return 0; /* tcpconn_id is not present */
+	else
+		return 1; /* valid tcpconn_id */
+}
+
+static inline int is_tcp_alive(ucontact_t *c)
+{
+	struct tcp_connection *con = NULL;
+	int rc = 0;
+
+	if ((con = tcpconn_get(c->tcpconn_id, 0, 0, 0, 0))) {
+		tcpconn_put(con); /* refcnt-- */
+		rc = 1;
+	}
+
+	return rc;
+}
 
 /*!
  * \brief Expires timer for NO_DB db_mode
@@ -236,6 +257,11 @@ static inline void nodb_timer(urecord_t* _r)
 	ptr = _r->contacts;
 
 	while(ptr) {
+		if (handle_lost_tcp && is_valid_tcpconn(ptr) && !is_tcp_alive(ptr)) {
+			LM_DBG("tcp connection has been lost, expiring contact %.*s\n", ptr->c.len, ptr->c.s);
+			ptr->expires = UL_EXPIRED_TIME;
+		}
+
 		if (!VALID_CONTACT(ptr, act_time)) {
 			/* run callbacks for EXPIRE event */
 			if (exists_ulcb_type(UL_CONTACT_EXPIRE))
@@ -296,7 +322,6 @@ static inline void wt_timer(urecord_t* _r)
 	}
 }
 
-
 /*!
  * \brief Write-back timer, used for WRITE_BACK db_mode
  *
@@ -316,6 +341,11 @@ static inline void wb_timer(urecord_t* _r)
 	ptr = _r->contacts;
 
 	while(ptr) {
+		if (handle_lost_tcp && is_valid_tcpconn(ptr) && !is_tcp_alive(ptr)) {
+			LM_DBG("tcp connection has been lost, expiring contact %.*s\n", ptr->c.len, ptr->c.s);
+			ptr->expires = UL_EXPIRED_TIME;
+		}
+
 		if (!VALID_CONTACT(ptr, act_time)) {
 			/* run callbacks for EXPIRE event */
 			if (exists_ulcb_type(UL_CONTACT_EXPIRE)) {
@@ -335,7 +365,7 @@ static inline void wb_timer(urecord_t* _r)
 				if (db_delete_ucontact(t) < 0) {
 					LM_ERR("failed to delete contact from the database"
 							" (aor: %.*s)\n",
-							ptr->aor->len, ZSW(ptr->aor->s));
+							t->aor->len, ZSW(t->aor->s));
 				}
 			}
 
@@ -387,6 +417,7 @@ static inline void wb_timer(urecord_t* _r)
 void timer_urecord(urecord_t* _r)
 {
 	switch(db_mode) {
+	case DB_READONLY:
 	case NO_DB:         nodb_timer(_r);
 						break;
 	/* use also the write_back timer routine to handle the failed
@@ -442,6 +473,39 @@ int db_delete_urecord(urecord_t* _r)
 
 
 /*!
+ * \brief Delete a record from the database based on ruid
+ * \return 0 on success, -1 on failure
+ */
+int db_delete_urecord_by_ruid(str *_table, str *_ruid)
+{
+	db_key_t keys[1];
+	db_val_t vals[1];
+
+	keys[0] = &ruid_col;
+	vals[0].type = DB1_STR;
+	vals[0].nul = 0;
+	vals[0].val.str_val.s = _ruid->s;
+	vals[0].val.str_val.len = _ruid->len;
+
+	if (ul_dbf.use_table(ul_dbh, _table) < 0) {
+		LM_ERR("use_table failed\n");
+		return -1;
+	}
+
+	if (ul_dbf.delete(ul_dbh, keys, 0, vals, 1) < 0) {
+		LM_ERR("failed to delete from database\n");
+		return -1;
+	}
+
+	if (ul_dbf.affected_rows(ul_dbh) == 0) {
+	        return -2;
+	}
+
+	return 0;
+}
+
+
+/*!
  * \brief Release urecord previously obtained through get_urecord
  * \warning Failing to calls this function after get_urecord will
  * result in a memory leak when the DB_ONLY mode is used. When
@@ -521,6 +585,17 @@ int delete_ucontact(urecord_t* _r, struct ucontact* _c)
 }
 
 
+int delete_urecord_by_ruid(udomain_t* _d, str *_ruid)
+{
+    if (db_mode != DB_ONLY) {
+	LM_ERR("delete_urecord_by_ruid currently available only in db_mode=3\n");
+	return -1;
+    }
+
+    return db_delete_urecord_by_ruid(_d->name, _ruid);
+}
+
+
 /*!
  * \brief Match a contact record to a contact string
  * \param ptr contact record
diff --git a/modules/usrloc/urecord.h b/modules/usrloc/urecord.h
index 776d897..d1303d0 100644
--- a/modules/usrloc/urecord.h
+++ b/modules/usrloc/urecord.h
@@ -119,6 +119,16 @@ void timer_urecord(urecord_t* _r);
 int db_delete_urecord(urecord_t* _r);
 
 
+/*!
+ * \brief Delete a record from the database based on ruid
+ * \param _d pointer to domain from which record is deleted
+ * \param _ruid pointer to ruid of the record which is deleted
+ * \return 0 on success, -1 on failure, and -2 if record was
+ * not found
+ */
+int delete_urecord_by_ruid(udomain_t* _d, str *_ruid);
+
+
 /* ===== Module interface ======== */
 
 
diff --git a/modules/usrloc/usrloc.c b/modules/usrloc/usrloc.c
index ba0ec1a..e901512 100644
--- a/modules/usrloc/usrloc.c
+++ b/modules/usrloc/usrloc.c
@@ -64,6 +64,7 @@ int bind_usrloc(usrloc_api_t* api)
 	api->get_all_ucontacts  = get_all_ucontacts;
 	api->insert_urecord     = insert_urecord;
 	api->delete_urecord     = delete_urecord;
+	api->delete_urecord_by_ruid     = delete_urecord_by_ruid;
 	api->get_urecord        = get_urecord;
 	api->lock_udomain       = lock_udomain;
 	api->unlock_udomain     = unlock_udomain;
diff --git a/modules/usrloc/usrloc.h b/modules/usrloc/usrloc.h
index 8b96d90..30cf354 100644
--- a/modules/usrloc/usrloc.h
+++ b/modules/usrloc/usrloc.h
@@ -40,6 +40,7 @@
 #define WRITE_THROUGH 1
 #define WRITE_BACK    2
 #define DB_ONLY       3
+#define DB_READONLY   4
 
 /*forward declaration necessary for udomain*/
 
@@ -90,6 +91,7 @@ typedef struct ucontact {
 	unsigned int methods;   /*!< Supported methods */
 	str instance;           /*!< SIP instance value - gruu */
 	unsigned int reg_id;    /*!< reg-id parameters */
+	int tcpconn_id;          /* unique tcp connection id */
 #ifdef WITH_XAVP
 	sr_xavp_t * xavp;       /*!< per contact xavps */
 #endif
@@ -115,6 +117,7 @@ typedef struct ucontact_info {
 	unsigned int methods;     /*!< supported methods */
 	str instance;             /*!< SIP instance value - gruu */
 	unsigned int reg_id;      /*!< reg-id parameters */
+	int tcpconn_id;
 #ifdef WITH_XAVP
 	sr_xavp_t * xavp;         /*!< per contact xavps */
 #endif
@@ -150,6 +153,8 @@ typedef int (*get_urecord_by_ruid_t)(udomain_t* _d, unsigned int _aorhash,
 
 typedef int  (*delete_urecord_t)(struct udomain* _d, str* _aor, struct urecord* _r);
 
+typedef int  (*delete_urecord_by_ruid_t)(struct udomain* _d, str* _ruid);
+
 typedef int (*update_ucontact_t)(struct urecord* _r, struct ucontact* _c,
 		struct ucontact_info* _ci);
 typedef void (*release_urecord_t)(struct urecord* _r);
@@ -198,6 +203,7 @@ typedef struct usrloc_api {
 
 	insert_urecord_t     insert_urecord;
 	delete_urecord_t     delete_urecord;
+	delete_urecord_by_ruid_t     delete_urecord_by_ruid;
 	get_urecord_t        get_urecord;
 	lock_udomain_t       lock_udomain;
 	unlock_udomain_t     unlock_udomain;
diff --git a/modules/utils/README b/modules/utils/README
index 44fff00..61d4276 100644
--- a/modules/utils/README
+++ b/modules/utils/README
@@ -177,7 +177,7 @@ modparam("utils", "xcap_table", "pres_xcap")
    4.1. http_query(url, result)
    4.2. xcap_auth_status(watcher_uri, presentity_uri)
 
-4.1.  http_query(url, result)
+4.1. http_query(url, result)
 
    Sends HTTP GET request according to URL given in "url" parameter, which
    is a string that may contain pseudo variables.
@@ -202,7 +202,7 @@ switch ($retcode) {
 }
 ...
 
-4.2.  xcap_auth_status(watcher_uri, presentity_uri)
+4.2. xcap_auth_status(watcher_uri, presentity_uri)
 
    Function checks in the presence server database if a watcher is
    authorized to subscribe to event "presence" of presentity. Sphere
diff --git a/modules/utils/doc/utils.xml b/modules/utils/doc/utils.xml
index dfdb290..49b2cbb 100644
--- a/modules/utils/doc/utils.xml
+++ b/modules/utils/doc/utils.xml
@@ -21,11 +21,23 @@
 			<email>jh at tutpro.com</email>
 		</address>
 		</author>
+		<author>
+		<firstname>Carsten</firstname>
+		<surname>Bock</surname>
+		<affiliation><orgname>ng-voice GmbH</orgname></affiliation>
+		<address>
+			<email>carsten at ng-voice.com</email>
+		</address>
+		</author>
 	</authorgroup>
 	<copyright>
 		<year>2008-2009</year>
 		<holder>Juha Heinanen</holder>
 	</copyright>
+	<copyright>
+		<year>2013</year>
+		<holder>Carsten Bock, ng-voice GmbH</holder>
+	</copyright>
 	</bookinfo>
 	<toc></toc>
 	
diff --git a/modules/utils/doc/utils_admin.xml b/modules/utils/doc/utils_admin.xml
index 697d0ea..3600f7d 100644
--- a/modules/utils/doc/utils_admin.xml
+++ b/modules/utils/doc/utils_admin.xml
@@ -72,7 +72,7 @@
 	
 	<section>
 		<title>Parameters</title>
-		<section>
+		<section id="utils.p.http_query_timeout">
 			<title><varname>http_query_timeout</varname> (int)</title>
 			<para>
 			Defines in seconds how long &kamailio; waits for response
@@ -93,7 +93,7 @@ modparam("utils", "http_query_timeout", 2)
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="utils.p.forward_active">
 			<title><varname>forward_active</varname> (int)</title>
 			<para>
 				Defines if the forwarding callback should be installed.
@@ -112,7 +112,7 @@ modparam("utils", "http_query_timeout", 2)
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="utils.p.pres_db_url">
 			<title><varname>pres_db_url</varname> (string)</title>
 			<para>
 			Defines presence server database URL. If not
@@ -132,7 +132,7 @@ modparam("utils", "pres_db_url", "mysql://foo:secret@localhost/pres")
 				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="utils.p.xcap_table">
 			<title><varname>xcap_table</varname> (string)</title>
 			<para>
 			Defines the name of the xcap table in the presence server database.
@@ -156,15 +156,20 @@ modparam("utils", "xcap_table", "pres_xcap")
 
 	<section>
 	<title>Functions</title>
-		<section>
+		<section id="utils.f.http_query">
 			<title>
-				<function moreinfo="none">http_query(url, result)</function>
+				<function moreinfo="none">http_query(url, [post-data], result)</function>
 			</title>
 			<para>
-			Sends HTTP GET request according to URL given in
+			Sends HTTP GET or POST request according to URL given in
 			<quote>url</quote> parameter, which is a string that may
 			contain pseudo variables.
 	    	        </para>
+			<para>
+			If you want to make a POST-Request, you have to define
+			the <quote>post</quote>-data, that should be submitted
+			in that request as the second parameter.
+	    	        </para>
 		        <para>
 			If HTTP server returns a class 2xx or 3xx reply,
 			the first line of the reply's body (if any) is
@@ -183,6 +188,7 @@ modparam("utils", "xcap_table", "pres_xcap")
 				<title><function>http_query()</function> usage</title>
 				<programlisting format="linespecific">
 ...
+# GET-Request
 http_query("http://tutpro.com/index.php?r_uri=$(ru{s.escape.param})&f_uri=$(fu{s.escape.param})",
            "$var(result)")
 switch ($retcode) {
@@ -190,9 +196,19 @@ switch ($retcode) {
 }
 ...
 				</programlisting>
+				<programlisting format="linespecific">
+...
+# POST-Request
+http_query("http://tutpro.com/index.php", "r_uri=$(ru{s.escape.param})&f_uri=$(fu{s.escape.param})",
+           "$var(result)")
+switch ($retcode) {
+       ...
+}
+...
+				</programlisting>
 			</example>
 		</section>
-		<section>
+		<section id="utils.f.xcap_auth_status">
 			<title>
 				<function moreinfo="none">xcap_auth_status(watcher_uri, presentity_uri)</function>
 			</title>
@@ -235,7 +251,7 @@ if (method=="MESSAGE") {
 	<section>
 	    <title><acronym>MI</acronym> Commands</title>
 		
-		<section>
+	<section id="utils.m.forward_list">
 	    <title><function moreinfo="none">forward_list</function></title>
 	    <para>
 		List active forward rules.
@@ -253,8 +269,8 @@ id switch                         filter proxy
 ...
 		</programlisting>
 	    </example>
-		</section>
-		<section>
+	</section>
+	<section id="utils.m.forward_switch">
 	    <title><function moreinfo="none">forward_switch</function></title>
 	    <para>
 		This command can be used to activate or deactivate forwarding rules.
@@ -268,9 +284,8 @@ id switch                         filter proxy
 ...
 		</programlisting>
 	    </example>
-		</section>
-		
-		<section>
+	</section>
+	<section id="utils.m.forward_filter">
 	    <title><function moreinfo="none">forward_filter</function></title>
 	    <para>
 		Can be used to specify the filter for a certain id. Messages will only be
@@ -298,9 +313,8 @@ id switch                         filter proxy
 ...
 		</programlisting>
 	    </example>
-		</section>
-
-		<section>
+	</section>
+	<section id="utils.m.forward_proxy">
 	    <title><function moreinfo="none">forward_proxy</function></title>
 	    <para>
 		This command can be used to configure forwarding rules. Specifies
diff --git a/modules/utils/functions.c b/modules/utils/functions.c
index aadfdd5..1225ba8 100644
--- a/modules/utils/functions.c
+++ b/modules/utils/functions.c
@@ -2,6 +2,7 @@
  * script functions of utils module
  *
  * Copyright (C) 2008 Juha Heinanen
+ * Copyright (C) 2013 Carsten Bock, ng-voice GmbH
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -70,12 +71,12 @@ size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream)
  * Performs http_query and saves possible result (first body line of reply)
  * to pvar.
  */
-int http_query(struct sip_msg* _m, char* _url, char* _dst)
+int http_query(struct sip_msg* _m, char* _url, char* _dst, char* _post)
 {
     CURL *curl;
     CURLcode res;  
-    str value;
-    char *url, *at;
+    str value, post_value;
+    char *url, *at, *post;
     char* stream;
     long stat;
     pv_spec_t *dst;
@@ -103,6 +104,28 @@ int http_query(struct sip_msg* _m, char* _url, char* _dst)
     *(url + value.len) = (char)0;
     curl_easy_setopt(curl, CURLOPT_URL, url);
 
+    if (_post) {
+        /* Now specify we want to POST data */ 
+	curl_easy_setopt(curl, CURLOPT_POST, 1L);
+
+    	if (fixup_get_svalue(_m, (gparam_p)_post, &post_value) != 0) {
+		LM_ERR("cannot get post value\n");
+		pkg_free(url);
+		return -1;
+    	}
+        post = pkg_malloc(post_value.len + 1);
+        if (post == NULL) {
+		curl_easy_cleanup(curl);
+		pkg_free(url);
+        	LM_ERR("cannot allocate pkg memory for post\n");
+        	return -1;
+	}
+	memcpy(post, post_value.s, post_value.len);
+	*(post + post_value.len) = (char)0;
+ 	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post);
+    }
+       
+
     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long)1);
     curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)http_query_timeout);
 
@@ -112,6 +135,9 @@ int http_query(struct sip_msg* _m, char* _url, char* _dst)
 
     res = curl_easy_perform(curl);  
     pkg_free(url);
+    if (_post) {
+	pkg_free(post);
+    }
     curl_easy_cleanup(curl);
 
     if (res != CURLE_OK) {
diff --git a/modules/utils/functions.h b/modules/utils/functions.h
index 5e666f9..910a4d5 100644
--- a/modules/utils/functions.h
+++ b/modules/utils/functions.h
@@ -2,6 +2,7 @@
  * headers of script functions of utils module
  *
  * Copyright (C) 2008 Juha Heinanen
+ * Copyright (C) 2013 Carsten Bock, ng-voice GmbH
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -39,7 +40,7 @@
  * Performs http_query and saves possible result (first body line of reply)
  * to pvar.
  */
-int http_query(struct sip_msg* _m, char* _page, char* _params, char* _dst);
+int http_query(struct sip_msg* _m, char* _url, char* _dst, char* _post);
 
 
 #endif /* UTILS_FUNCTIONS_H */
diff --git a/modules/utils/utils.c b/modules/utils/utils.c
index b734a69..13b7f07 100644
--- a/modules/utils/utils.c
+++ b/modules/utils/utils.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2008 Juha Heinanen
  * Copyright (C) 2009 1&1 Internet AG
+ * Copyright (C) 2013 Carsten Bock, ng-voice GmbH
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -88,16 +89,25 @@ static int child_init(int);
 static void destroy(void);
 
 /* Fixup functions to be defined later */
-static int fixup_http_query(void** param, int param_no);
-static int fixup_free_http_query(void** param, int param_no);
+static int fixup_http_query_get(void** param, int param_no);
+static int fixup_free_http_query_get(void** param, int param_no);
+static int fixup_http_query_post(void** param, int param_no);
+static int fixup_free_http_query_post(void** param, int param_no);
+
+/* Wrappers for http_query to be defined later */
+static int w_http_query(struct sip_msg* _m, char* _url, char* _result);
+static int w_http_query_post(struct sip_msg* _m, char* _url, char* _post, char* _result);
 
 /* forward function */
 int utils_forward(struct sip_msg *msg, int id, int proto);
 
 /* Exported functions */
 static cmd_export_t cmds[] = {
-    {"http_query", (cmd_function)http_query, 2, fixup_http_query,
-     fixup_free_http_query,
+    {"http_query", (cmd_function)w_http_query, 2, fixup_http_query_get,
+     fixup_free_http_query_get,
+     REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
+    {"http_query", (cmd_function)w_http_query_post, 3, fixup_http_query_post,
+     fixup_free_http_query_post,
      REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
     {"xcap_auth_status", (cmd_function)xcap_auth_status, 2, fixup_pvar_pvar,
      fixup_free_pvar_pvar, REQUEST_ROUTE},
@@ -319,7 +329,7 @@ static void destroy(void)
  * Fix http_query params: url (string that may contain pvars) and
  * result (writable pvar).
  */
-static int fixup_http_query(void** param, int param_no)
+static int fixup_http_query_get(void** param, int param_no)
 {
     if (param_no == 1) {
 	return fixup_spve_null(param, 1);
@@ -344,7 +354,7 @@ static int fixup_http_query(void** param, int param_no)
 /*
  * Free http_query params.
  */
-static int fixup_free_http_query(void** param, int param_no)
+static int fixup_free_http_query_get(void** param, int param_no)
 {
     if (param_no == 1) {
 	LM_WARN("free function has not been defined for spve\n");
@@ -360,6 +370,65 @@ static int fixup_free_http_query(void** param, int param_no)
 }
 
 
+/*
+ * Fix http_query params: url (string that may contain pvars) and
+ * result (writable pvar).
+ */
+static int fixup_http_query_post(void** param, int param_no)
+{
+    if ((param_no == 1) || (param_no == 2)) {
+	return fixup_spve_null(param, 1);
+    }
+
+    if (param_no == 3) {
+	if (fixup_pvar_null(param, 1) != 0) {
+	    LM_ERR("failed to fixup result pvar\n");
+	    return -1;
+	}
+	if (((pv_spec_t *)(*param))->setf == NULL) {
+	    LM_ERR("result pvar is not writeble\n");
+	    return -1;
+	}
+	return 0;
+    }
+
+    LM_ERR("invalid parameter number <%d>\n", param_no);
+    return -1;
+}
+
+/*
+ * Free http_query params.
+ */
+static int fixup_free_http_query_post(void** param, int param_no)
+{
+    if ((param_no == 1) || (param_no == 2)) {
+	LM_WARN("free function has not been defined for spve\n");
+	return 0;
+    }
+
+    if (param_no == 3) {
+	return fixup_free_pvar_null(param, 1);
+    }
+    
+    LM_ERR("invalid parameter number <%d>\n", param_no);
+    return -1;
+}
+
+/*
+ * Wrapper for HTTP-Query (GET)
+ */
+static int w_http_query(struct sip_msg* _m, char* _url, char* _result) {
+	return http_query(_m, _url, _result, NULL);
+}
+
+
+/*
+ * Wrapper for HTTP-Query (POST-Variant)
+ */
+static int w_http_query_post(struct sip_msg* _m, char* _url, char* _post, char* _result) {
+	return http_query(_m, _url, _result, _post);
+}
+
 /*!
  * \brief checks precondition, switch, filter and forwards msg if necessary
  * \param msg the message to be forwarded
diff --git a/modules/websocket/README b/modules/websocket/README
index 0ef44d5..49d8693 100644
--- a/modules/websocket/README
+++ b/modules/websocket/README
@@ -4,7 +4,7 @@ Peter Dunkley
 
    Crocodile RCS Ltd
 
-   Copyright © 2012 Crocodile RCS Ltd
+   Copyright © 2012-2013 Crocodile RCS Ltd
      __________________________________________________________________
 
    Table of Contents
@@ -31,10 +31,12 @@ Peter Dunkley
               4.4. keepalive_interval (integer)
               4.5. ping_application_data (string)
               4.6. sub_protocols (integer)
+              4.7. cors_mode (integer)
 
         5. Functions
 
               5.1. ws_handle_handshake()
+              5.2. ws_close([status, reason[, connection_id]])
 
         6. MI Commands
 
@@ -59,7 +61,10 @@ Peter Dunkley
    1.6. Set keepalive_interval parameter
    1.7. Set ping_application_data parameter
    1.8. Set sub_protocols parameter
-   1.9. ws_handle_handshake usage
+   1.9. Set cors_mode parameter
+   1.10. ws_handle_handshake usage
+   1.11. ws_close usage
+   1.12. event_route[websocket:closed] usage
 
 Chapter 1. Admin Guide
 
@@ -85,10 +90,12 @@ Chapter 1. Admin Guide
         4.4. keepalive_interval (integer)
         4.5. ping_application_data (string)
         4.6. sub_protocols (integer)
+        4.7. cors_mode (integer)
 
    5. Functions
 
         5.1. ws_handle_handshake()
+        5.2. ws_close([status, reason[, connection_id]])
 
    6. MI Commands
 
@@ -294,8 +301,7 @@ onreply_route[WS_REPLY] {
      * sl.
 
    The following modules are required to make proper use of this module:
-     * nathelper.
-     * tm.
+     * nathelper or outbound.
      * xhttp.
 
    The following module is required to use the secure WebSocket (wss)
@@ -320,6 +326,7 @@ onreply_route[WS_REPLY] {
    4.4. keepalive_interval (integer)
    4.5. ping_application_data (string)
    4.6. sub_protocols (integer)
+   4.7. cors_mode (integer)
 
 4.1. keepalive_mechanism (integer)
 
@@ -404,9 +411,30 @@ modparam("websocket", "ping_application_data", "WebSockets rock")
 modparam("websocket", "sub_protocols", 2)
 ...
 
+4.7. cors_mode (integer)
+
+   This parameter lets you set the "Cross-origin resource sharing"
+   behaviour of the WebSocket server.
+     * 0 - Do not add an "Access-Control-Allow-Origin:" header to the
+       response accepting the WebSocket handshake.
+     * 1 - Add a "Access-Control-Allow-Origin: *" header to the response
+       accepting the WebSocket handshake.
+     * 2 - Add a "Access-Control-Allow-Origin:" header containing the same
+       body as the "Origin:" header from the request to the response
+       accepting the WebSocket handshake. If there is no "Origin:" header
+       in the request no header will be added to the response.
+
+   Default value is 0.
+
+   Example 1.9. Set cors_mode parameter
+...
+modparam("websocket", "cors_mode", 2)
+...
+
 5. Functions
 
    5.1. ws_handle_handshake()
+   5.2. ws_close([status, reason[, connection_id]])
 
 5.1.  ws_handle_handshake()
 
@@ -422,11 +450,36 @@ Note
    This function returns 0, stopping all further processing of the
    request, when there is a problem.
 
-   Example 1.9. ws_handle_handshake usage
+   Example 1.10. ws_handle_handshake usage
 ...
 ws_handle_handshake();
 ...
 
+5.2.  ws_close([status, reason[, connection_id]])
+
+   This function closes a WebSocket connection.
+
+   The function returns -1 if there is an error and 1 if it succeeds.
+
+   The meaning of the parameters is as follows:
+     * status - an integer indicating the reason for closure.
+     * reason - a string describing the reason for closure.
+     * connection_id - the connection to close. If not specified the
+       connection the current message arrived on will be closed.
+
+Note
+
+   status and reason values SHOULD correspond to the definitions in
+   section 7.4 of RFC 6455. If these parameters are not used the defaults
+   of "1000" and "Normal closure" will be used.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.11. ws_close usage
+...
+ws_close(4000, "Because I say so");
+...
+
 6. MI Commands
 
    6.1. ws.dump
@@ -533,6 +586,8 @@ Note
    When defined, the module calls event_route[websocket:closed] when a
    connection closes. The connection may be identified using the the $si
    and $sp pseudo-variables.
+
+   Example 1.12. event_route[websocket:closed] usage
 ...
 event_route[websocket:closed] {
         xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
diff --git a/modules/websocket/config.c b/modules/websocket/config.c
new file mode 100644
index 0000000..e6e6a50
--- /dev/null
+++ b/modules/websocket/config.c
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief WebSocket :: Configuration
+ * \ingroup WebSocket
+ */
+
+#include "../../cfg/cfg.h"
+#include "ws_frame.h"
+#include "config.h"
+
+struct cfg_group_websocket default_ws_cfg =
+{
+        DEFAULT_KEEPALIVE_TIMEOUT, /* keepalive_timeout */
+        1                       /* enabled */
+};
+
+void *ws_cfg = &default_ws_cfg;
+
+cfg_def_t ws_cfg_def[] =
+{
+        /* ws_frame.c */
+        { "keepalive_timeout",  CFG_VAR_INT | CFG_ATOMIC,
+          0, 0, 0, 0,
+          "Time (in seconds) after which to send a keep-alive on idle"
+          " WebSocket connections." },
+
+        /* ws_handshake.c */
+        { "enabled",            CFG_VAR_INT | CFG_ATOMIC,
+          0, 0, 0, 0,
+          "Shows whether WebSockets are enabled or not." },
+
+        { 0, 0, 0, 0, 0, 0 }
+};
diff --git a/modules/websocket/config.h b/modules/websocket/config.h
new file mode 100644
index 0000000..690649e
--- /dev/null
+++ b/modules/websocket/config.h
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief WebSocket :: Configuration Framework support
+ * \ingroup WebSocket
+ */
+
+#ifndef _WS_CONFIG_H
+#define _WS_CONFIG_H
+
+#include "../../cfg/cfg.h"
+
+struct cfg_group_websocket
+{
+	int keepalive_timeout;
+	int enabled;
+};
+extern struct cfg_group_websocket default_ws_cfg;
+extern void *ws_cfg;
+extern cfg_def_t ws_cfg_def[];
+
+#endif /* _WS_CONFIG_H */
diff --git a/modules/websocket/doc/websocket.xml b/modules/websocket/doc/websocket.xml
index 74cc28d..93aef5f 100644
--- a/modules/websocket/doc/websocket.xml
+++ b/modules/websocket/doc/websocket.xml
@@ -23,7 +23,7 @@
 		</author>
 	</authorgroup>
 	<copyright>
-		<year>2012</year>
+		<year>2012-2013</year>
 		<holder>Crocodile RCS Ltd</holder>
 	</copyright>
 	</bookinfo>
diff --git a/modules/websocket/doc/websocket_admin.xml b/modules/websocket/doc/websocket_admin.xml
index 895ed9a..fa7d300 100644
--- a/modules/websocket/doc/websocket_admin.xml
+++ b/modules/websocket/doc/websocket_admin.xml
@@ -30,11 +30,11 @@
 	<title>Initiating a connection</title>
 	<para>A WebSocket connection is initiated with an HTTP GET.  The
 	<emphasis>xhttp</emphasis> module is used to handle this GET and
-	call the <xref linkend="ws_handle_handshake"/> exported function.
+	call the <xref linkend="websocket.f.ws_handle_handshake"/> exported function.
 	</para>
 	<para><emphasis>event_route[xhttp:request]</emphasis> should perform
 	some validation of the HTTP headers before calling
-	<xref linkend="ws_handle_handshake"/>.  The event_route can also be
+	<xref linkend="websocket.f.ws_handle_handshake"/>.  The event_route can also be
 	used to make sure the HTTP GET has the correct URI, perform HTTP
 	authentication on the WebSocket connection, and check the
 	<emphasis>Origin</emphasis> header (RFC 6454) to ensure a
@@ -225,10 +225,8 @@ onreply_route[WS_REPLY] {
 		module:
 		<itemizedlist>
 		<listitem>
-		<para><emphasis>nathelper</emphasis>.</para>
-		</listitem>
-		<listitem>
-		<para><emphasis>tm</emphasis>.</para>
+		<para><emphasis>nathelper</emphasis> or
+		<emphasis>outbound</emphasis>.</para>
 		</listitem>
 		<listitem>
 		<para><emphasis>xhttp</emphasis>.</para>
@@ -275,7 +273,7 @@ onreply_route[WS_REPLY] {
 
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="websocket.p.keepalive_mechanism">
 		<title><varname>keepalive_mechanism</varname> (integer)</title>
 		<para>The keep-alive mechanism to use for WebSocket connections.
 		</para>
@@ -306,7 +304,7 @@ modparam("websocket", "keepalive_mechanism", 0)
 		</example>
 	</section>
 
-	<section>
+	<section id="websocket.p.keepalive_timeout">
 		<title><varname>keepalive_timeout</varname> (integer)</title>
 		<para>The time (in seconds) after which to send a keep-alive on
 		idle WebSocket connections.</para>
@@ -322,7 +320,7 @@ modparam("websocket", "keepalive_timeout", 30)
 		</example>
 	</section>
 
-	<section>
+	<section id="websocket.p.keepalive.processes">
 		<title><varname>keepalive_processes</varname> (integer)</title>
 		<para>The number of processes to start to perform WebSocket
 		connection keep-alives.</para>
@@ -338,7 +336,7 @@ modparam("websocket", "keepalive_processes", 2)
 		</example>
 	</section>
 
-	<section>
+	<section id="websocket.p.keepalive_interval">
 		<title><varname>keepalive_interval</varname> (integer)</title>
 		<para>The number of seconds between each keep-alice process run
 		</para>
@@ -354,7 +352,7 @@ modparam("websocket", "keepalive_interval", 2)
 		</example>
 	</section>
 
-	<section>
+	<section id="websocket.p.ping_application_data">
 		<title><varname>ping_application_data</varname> (string)</title>
 		<para>The application data to use in keep-alive Ping and Pong
 		frames.</para>
@@ -371,7 +369,7 @@ modparam("websocket", "ping_application_data", "WebSockets rock")
 		</example>
 	</section>
 
-	<section>
+	<section id="websocket.p.sub_protocols">
 		<title><varname>sub_protocols</varname> (integer)</title>
 		<para>A bitmap that allows you to control the sub-protocols
 		supported by the WebSocket server.</para>
@@ -397,11 +395,47 @@ modparam("websocket", "sub_protocols", 2)
 		</example>
 	</section>
 
+	<section id="websocket.p.cors_mode">
+		<title><varname>cors_mode</varname> (integer)</title>
+		<para>This parameter lets you set the "Cross-origin
+		resource sharing" behaviour of the WebSocket server.</para>
+		<itemizedlist>
+		<listitem><para>
+		<emphasis>0</emphasis> - Do not add an
+		"Access-Control-Allow-Origin:" header to the response
+		accepting the WebSocket handshake. 
+		</para></listitem>
+		<listitem><para>
+		<emphasis>1</emphasis> - Add a
+		"Access-Control-Allow-Origin: *" header to the
+		response accepting the WebSocket handshake.
+		</para></listitem>
+		<listitem><para>
+		<emphasis>2</emphasis> - Add a
+		"Access-Control-Allow-Origin:" header containing the
+		same body as the "Origin:" header from the request to
+		the response accepting the WebSocket handshake. If there is no
+		"Origin:" header in the request no header will be
+		added to the response.
+		</para></listitem>
+		</itemizedlist>
+		<para><emphasis>Default value is 0.</emphasis></para>
+		<example>
+		<title>Set <varname>cors_mode</varname>
+		parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("websocket", "cors_mode", 2)
+...
+</programlisting>
+		</example>
+	</section>
+
 	</section>
 
 	<section>
 	<title>Functions</title>
-	<section id="ws_handle_handshake">
+	<section id="websocket.f.ws_handle_handshake">
 		<title>
 		<function moreinfo="none">ws_handle_handshake()</function>
 		</title>
@@ -421,11 +455,47 @@ ws_handle_handshake();
 </programlisting>
 		</example>
 	</section>
+	<section id="websocket.f.ws_close">
+		<title>
+		<function moreinfo="none">ws_close([status,
+			reason[, connection_id]])</function>
+		</title>
+		<para>This function closes a WebSocket connection.</para>
+		<para>The function returns -1 if there is an error and 1 if
+		it succeeds.</para>
+		<para>The meaning of the parameters is as follows:</para>
+		<itemizedlist>
+			<listitem><para><emphasis>status</emphasis> - an
+			integer indicating the reason for closure.</para>
+			</listitem>
+			<listitem><para><emphasis>reason</emphasis> - a
+			string describing the reason for closure.</para>
+			</listitem>
+			<listitem><para><emphasis>connection_id</emphasis> - the
+			connection to close. If not specified the connection the
+			current message arrived on will be closed.</para>
+			</listitem>
+		</itemizedlist>
+		<note><para><emphasis>status</emphasis> and
+		<emphasis>reason</emphasis> values SHOULD correspond to the
+		definitions in section 7.4 of RFC 6455. If these parameters are
+		not used the defaults of "1000" and "Normal
+		closure" will be used.</para></note>
+		<para>This function can be used from ANY_ROUTE.</para>
+		<example>
+		<title><function>ws_close</function> usage</title>
+		<programlisting format="linespecific">
+...
+ws_close(4000, "Because I say so");
+...
+</programlisting>
+		</example>
+	</section>
 	</section>
 
 	<section>
 	<title>MI Commands</title>
-	<section>
+	<section id="websocket.m.ws.dump">
 		<title><function moreinfo="none">ws.dump</function></title>
 		<para>Provides the details of the first 50 WebSocket
 		connections.</para>
@@ -449,7 +519,7 @@ ws_handle_handshake();
 </programlisting>
 	</section>
 
-	<section>
+	<section id="websocket.m.ws.close">
 		<title><function moreinfo="none">ws.close</function></title>
 		<para>Starts the close handshake for the specified
 		WebSocket connection.</para>
@@ -468,7 +538,7 @@ ws_handle_handshake();
 </programlisting>
 	</section>
 
-	<section>
+	<section id="websocket.m.ping">
 		<title><function moreinfo="none">ws.ping</function></title>
 		<para>Sends a Ping frame on the specified WebSocket
 		connection.</para>
@@ -487,7 +557,7 @@ ws_handle_handshake();
 </programlisting>
 	</section>
 
-	<section>
+	<section id="websocket.m.ws.pong">
 		<title><function moreinfo="none">ws.pong</function></title>
 		<para>Sends a Pong frame on the specified WebSocket
 		connection.</para>
@@ -506,7 +576,7 @@ ws_handle_handshake();
 </programlisting>
 	</section>
 
-	<section>
+	<section id="websocket.m.ws.disable">
 		<title><function moreinfo="none">ws.disable</function></title>
 		<para>Disables WebSockets preventing new connections from
 		being established.</para>
@@ -519,7 +589,7 @@ ws_handle_handshake();
 </programlisting>
 	</section>
 
-	<section>
+	<section id="websocket.m.ws.enable">
 		<title><function moreinfo="none">ws.enable</function></title>
 		<para>Enables WebSockets allowing new connections to be
 		established.</para>
@@ -537,7 +607,7 @@ ws_handle_handshake();
 
 	<section>
 	<title>Event routes</title>
-	<section>
+	<section id="websocket.e.closed">
 		<title>
 		<function moreinfo="none">websocket:closed</function>
 		</title>
@@ -547,13 +617,16 @@ ws_handle_handshake();
 			closes.  The connection may be identified using the
 			the $si and $sp pseudo-variables.
 		</para>
-		<programlisting format="linespecific">
+		<example>
+		<title><function moreinfo="none">event_route[websocket:closed]</function> usage</title>
+			<programlisting format="linespecific">
 ...
 event_route[websocket:closed] {
 	xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
 }
 ...
-		</programlisting>
+			</programlisting>
+		</example>
 	</section>
 
 	</section>	
diff --git a/modules/websocket/ws_conn.c b/modules/websocket/ws_conn.c
index 57c2119..613f14e 100644
--- a/modules/websocket/ws_conn.c
+++ b/modules/websocket/ws_conn.c
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -48,6 +48,10 @@ ws_connection_used_list_t *wsconn_used_list = NULL;
 
 stat_var *ws_current_connections;
 stat_var *ws_max_concurrent_connections;
+stat_var *ws_sip_current_connections;
+stat_var *ws_sip_max_concurrent_connections;
+stat_var *ws_msrp_current_connections;
+stat_var *ws_msrp_max_concurrent_connections;
 
 char *wsconn_state_str[] =
 {
@@ -126,9 +130,14 @@ error:
 static inline void _wsconn_rm(ws_connection_t *wsc)
 {
 	wsconn_listrm(wsconn_id_hash[wsc->id_hash], wsc, id_next, id_prev);
-	shm_free(wsc);
-	wsc = NULL;
+
 	update_stat(ws_current_connections, -1);
+	if (wsc->sub_protocol == SUB_PROTOCOL_SIP)
+		update_stat(ws_sip_current_connections, -1);
+	else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+		update_stat(ws_msrp_current_connections, -1);
+
+	shm_free(wsc);
 }
 
 void wsconn_destroy(void)
@@ -215,11 +224,32 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol)
 
 	/* Update connection statistics */
 	lock_get(wsstat_lock);
+
 	update_stat(ws_current_connections, 1);
 	cur_cons = get_stat_val(ws_current_connections);
 	max_cons = get_stat_val(ws_max_concurrent_connections);
 	if (max_cons < cur_cons)
 		update_stat(ws_max_concurrent_connections, cur_cons - max_cons);
+
+	if (wsc->sub_protocol == SUB_PROTOCOL_SIP)
+	{
+		update_stat(ws_sip_current_connections, 1);
+		cur_cons = get_stat_val(ws_sip_current_connections);
+		max_cons = get_stat_val(ws_sip_max_concurrent_connections);
+		if (max_cons < cur_cons)
+			update_stat(ws_sip_max_concurrent_connections,
+					cur_cons - max_cons);
+	}
+	else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+	{
+		update_stat(ws_msrp_current_connections, 1);
+		cur_cons = get_stat_val(ws_msrp_current_connections);
+		max_cons = get_stat_val(ws_msrp_max_concurrent_connections);
+		if (max_cons < cur_cons)
+			update_stat(ws_msrp_max_concurrent_connections,
+					cur_cons - max_cons);
+	}
+
 	lock_release(wsstat_lock);
 
 	return 0;
@@ -353,7 +383,7 @@ ws_connection_t *wsconn_get(int id)
 static int add_node(struct mi_root *tree, ws_connection_t *wsc)
 {
 	int interval;
-	char *src_proto, *dst_proto, *pong;
+	char *src_proto, *dst_proto, *pong, *sub_protocol;
 	char src_ip[IP6_MAX_STR_SIZE + 1], dst_ip[IP6_MAX_STR_SIZE + 1];
 	struct tcp_connection *con = tcpconn_get(wsc->id, 0, 0, 0, 0);
 
@@ -370,10 +400,17 @@ static int add_node(struct mi_root *tree, ws_connection_t *wsc)
 		pong = wsc->awaiting_pong ? "awaiting Pong, " : "";
 
 		interval = (int)time(NULL) - wsc->last_used;
+		if (wsc->sub_protocol == SUB_PROTOCOL_SIP)
+			sub_protocol = "sip";
+		else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+			sub_protocol = "msrp";
+		else
+			sub_protocol = "**UNKNOWN**";
 
 		if (addf_mi_node_child(&tree->node, 0, 0, 0,
 					"%d: %s:%s:%hu -> %s:%s:%hu (state: %s"
-					", %slast used %ds ago)",
+					", %s last used %ds ago"
+					", sub-protocol: %s)",
 					wsc->id,
 					src_proto,
 					strlen(src_ip) ? src_ip : "*",
@@ -383,7 +420,8 @@ static int add_node(struct mi_root *tree, ws_connection_t *wsc)
 					con->rcv.dst_port,
 					wsconn_state_str[wsc->state],
 					pong,
-					interval) == 0)
+					interval,
+					sub_protocol) == 0)
 		{
 			tcpconn_put(con);
 			return -1;
@@ -401,10 +439,7 @@ struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param)
 	int h, connections = 0, truncated = 0, order = 0, found = 0;
 	ws_connection_t *wsc;
 	struct mi_node *node = NULL;
-	struct mi_root *rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
-	
-	if (!rpl_tree)
-		return 0;
+	struct mi_root *rpl_tree;
 
 	node = cmd->node.kids;
 	if (node != NULL)
@@ -437,6 +472,10 @@ struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param)
 		}
 	}
 
+	rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
+	if (rpl_tree == NULL)
+		return 0;
+
 	WSCONN_LOCK;
 	if (order == 0)
 	{
@@ -446,7 +485,10 @@ struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param)
 			while(wsc)
 			{
 				if ((found = add_node(rpl_tree, wsc)) < 0)
+				{
+					free_mi_tree(rpl_tree);
 					return 0;
+				}
 
 
 				connections += found;
@@ -469,7 +511,10 @@ struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param)
 		while (wsc)
 		{
 			if ((found = add_node(rpl_tree, wsc)) < 0)
+			{
+				free_mi_tree(rpl_tree);
 				return 0;
+			}
 
 			connections += found;
 			if (connections >= MAX_WS_CONNS_DUMP)
@@ -487,7 +532,10 @@ struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param)
 		while (wsc)
 		{
 			if ((found = add_node(rpl_tree, wsc)) < 0)
+			{
+				free_mi_tree(rpl_tree);
 				return 0;
+			}
 
 			connections += found;
 			if (connections >= MAX_WS_CONNS_DUMP)
@@ -505,7 +553,10 @@ struct mi_root *ws_mi_dump(struct mi_root *cmd, void *param)
 				"%d WebSocket connection%s found%s",
 				connections, connections == 1 ? "" : "s",
 				truncated == 1 ? "(truncated)" : "") == 0)
+	{
+		free_mi_tree(rpl_tree);
 		return 0;
+	}
 
 	return rpl_tree;
 }
diff --git a/modules/websocket/ws_conn.h b/modules/websocket/ws_conn.h
index de8d00e..d022d0e 100644
--- a/modules/websocket/ws_conn.h
+++ b/modules/websocket/ws_conn.h
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -72,6 +72,10 @@ extern char *wsconn_state_str[];
 
 extern stat_var *ws_current_connections;
 extern stat_var *ws_max_concurrent_connections;
+extern stat_var *ws_sip_current_connections;
+extern stat_var *ws_sip_max_concurrent_connections;
+extern stat_var *ws_msrp_current_connections;
+extern stat_var *ws_msrp_max_concurrent_connections;
 
 int wsconn_init(void);
 void wsconn_destroy(void);
diff --git a/modules/websocket/ws_frame.c b/modules/websocket/ws_frame.c
index 124a2fc..a3a4cef 100644
--- a/modules/websocket/ws_frame.c
+++ b/modules/websocket/ws_frame.c
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -37,6 +37,7 @@
 #include "ws_frame.h"
 #include "ws_mod.h"
 #include "ws_handshake.h"
+#include "config.h"
 
 /*    0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -93,8 +94,6 @@ typedef enum
 #define OPCODE_PONG		(0xa)
 /* 0xb - 0xf are reserved for further control frames */
 
-/* Time (in seconds) after which to send a keepalive on an idle connection */
-int ws_keepalive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;
 int ws_keepalive_mechanism = DEFAULT_KEEPALIVE_MECHANISM;
 str ws_ping_application_data = {0, 0};
 
@@ -103,6 +102,16 @@ stat_var *ws_local_closed_connections;
 stat_var *ws_received_frames;
 stat_var *ws_remote_closed_connections;
 stat_var *ws_transmitted_frames;
+stat_var *ws_sip_failed_connections;
+stat_var *ws_sip_local_closed_connections;
+stat_var *ws_sip_received_frames;
+stat_var *ws_sip_remote_closed_connections;
+stat_var *ws_sip_transmitted_frames;
+stat_var *ws_msrp_failed_connections;
+stat_var *ws_msrp_local_closed_connections;
+stat_var *ws_msrp_received_frames;
+stat_var *ws_msrp_remote_closed_connections;
+stat_var *ws_msrp_transmitted_frames;
 
 /* WebSocket status text */
 static str str_status_normal_closure = str_init("Normal closure");
@@ -116,6 +125,7 @@ static str str_status_too_many_params = str_init("Too many parameters");
 static str str_status_bad_param = str_init("Bad connection ID parameter");
 static str str_status_error_closing = str_init("Error closing connection");
 static str str_status_error_sending = str_init("Error sending frame");
+static str str_status_string_error = str_init("Error converting string to int");
 
 static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
 {
@@ -222,6 +232,7 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
 		pkg_free(send_buf);
 		if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
 			LM_ERR("removing WebSocket connection\n");
+		frame->wsc = NULL;
 		return -1;
 	}
 	init_dst_from_rcv(&dst, &con->rcv);
@@ -233,8 +244,10 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
 			LM_ERR("removing WebSocket connection\n");
 			tcpconn_put(con);
 			pkg_free(send_buf);
+			frame->wsc = NULL;
 			return -1;
 		}
+		frame->wsc = NULL;
 	}
 
 	if (dst.proto == PROTO_WS)
@@ -281,24 +294,46 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
 		LM_ERR("sending WebSocket frame\n");
 		pkg_free(send_buf);
 		update_stat(ws_failed_connections, 1);
+		if (frame->wsc->sub_protocol == SUB_PROTOCOL_SIP)
+			update_stat(ws_sip_failed_connections, 1);
+		else if (frame->wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+			update_stat(ws_msrp_failed_connections, 1);
 		if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
 			LM_ERR("removing WebSocket connection\n");
+		frame->wsc = NULL;
 		tcpconn_put(con);
 		return -1;
 	}
 
 	update_stat(ws_transmitted_frames, 1);
-
+	switch (frame->opcode)
+	{
+	case OPCODE_TEXT_FRAME:
+	case OPCODE_BINARY_FRAME:
+		if (frame->wsc->sub_protocol == SUB_PROTOCOL_SIP)
+			update_stat(ws_sip_transmitted_frames, 1);
+		else if (frame->wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+			update_stat(ws_msrp_transmitted_frames, 1);
+	}
+	
 	pkg_free(send_buf);
 	tcpconn_put(con);
 	return 0;
 }
 
-static int close_connection(ws_connection_t *wsc, ws_close_type_t type,
+static int close_connection(ws_connection_t **p_wsc, ws_close_type_t type,
 				short int status, str reason)
 {
 	char *data;
 	ws_frame_t frame;
+	ws_connection_t * wsc = NULL;
+	int sub_proto = -1;
+	if (!p_wsc || !(*p_wsc))
+	{
+		LM_ERR("Invalid parameters\n");
+		return -1;
+	}
+	wsc = *p_wsc;
 
 	if (wsc->state == WS_S_OPEN)
 	{
@@ -319,6 +354,7 @@ static int close_connection(ws_connection_t *wsc, ws_close_type_t type,
 		frame.payload_len = reason.len + 2;
 		frame.payload_data = data;
 		frame.wsc = wsc;
+		sub_proto = wsc->sub_protocol;
 
 		if (encode_and_send_ws_frame(&frame,
 			type ==
@@ -335,12 +371,29 @@ static int close_connection(ws_connection_t *wsc, ws_close_type_t type,
 		{
 			frame.wsc->state = WS_S_CLOSING;
 			update_stat(ws_local_closed_connections, 1);
+			if (frame.wsc->sub_protocol == SUB_PROTOCOL_SIP)
+				update_stat(ws_sip_local_closed_connections, 1);
+			else if (frame.wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+				update_stat(ws_msrp_local_closed_connections,
+						1);
 		}
 		else
+		{
 			update_stat(ws_remote_closed_connections, 1);
+			if (sub_proto == SUB_PROTOCOL_SIP)
+				update_stat(ws_sip_remote_closed_connections,
+						1);
+			else if (sub_proto == SUB_PROTOCOL_MSRP)
+				update_stat(ws_msrp_remote_closed_connections,
+						1);
+			*p_wsc = NULL;
+		}
 	}
 	else /* if (frame->wsc->state == WS_S_CLOSING) */
+	{
 		wsconn_close_now(wsc);
+		*p_wsc = NULL;
+	}
 
 	return 0;
 }
@@ -366,7 +419,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	if (len < 2)
 	{
 		LM_WARN("message is too short\n");
-		if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
 					str_status_protocol_error) < 0)
 			LM_ERR("closing connection\n");
 		return -1;
@@ -382,7 +435,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	{
 		LM_WARN("WebSocket fragmentation not supported in the sip "
 			"sub-protocol\n");
-		if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
 					str_status_protocol_error) < 0)
 			LM_ERR("closing connection\n");
 		return -1;
@@ -391,7 +444,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	if (frame->rsv1 || frame->rsv2 || frame->rsv3)
 	{
 		LM_WARN("WebSocket reserved fields with non-zero values\n");
-		if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
 					str_status_protocol_error) < 0)
 			LM_ERR("closing connection\n");
 		return -1;
@@ -415,7 +468,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	default:
 		LM_WARN("unsupported opcode: 0x%x\n",
 			(unsigned char) frame->opcode);
-		if (close_connection(frame->wsc, LOCAL_CLOSE, 1008,
+		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1008,
 					str_status_unsupported_opcode) < 0)
 			LM_ERR("closing connection\n");
 		return -1;
@@ -425,7 +478,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	{
 		LM_WARN("this is a server - all received messages must be "
 			"masked\n");
-		if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
 					str_status_protocol_error) < 0)
 			LM_ERR("closing connection\n");
 		return -1;
@@ -438,7 +491,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 		if (len < 4)
 		{
 			LM_WARN("message is too short\n");
-			if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+			if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
 						str_status_protocol_error) < 0)
 				LM_ERR("closing connection\n");
 			return -1;
@@ -453,7 +506,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 		if (len < 10)
 		{
 			LM_WARN("message is too short\n");
-			if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+			if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
 						str_status_protocol_error) < 0)
 				LM_ERR("closing connection\n");
 			return -1;
@@ -464,7 +517,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 			|| (buf[4] & 0xff) != 0 || (buf[5] & 0xff) != 0)
 		{
 			LM_WARN("message is too long\n");
-			if (close_connection(frame->wsc, LOCAL_CLOSE, 1009,
+			if (close_connection(&frame->wsc, LOCAL_CLOSE, 1009,
 						str_status_message_too_big) < 0)
 				LM_ERR("closing connection\n");
 			return -1;
@@ -492,7 +545,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
 	{
 		LM_WARN("message not complete frame size %u but received %u\n",
 			frame->payload_len + mask_start + 4, len);
-		if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+		if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
 					str_status_protocol_error) < 0)
 			LM_ERR("closing connection\n");
 		return -1;
@@ -528,7 +581,7 @@ static int handle_close(ws_frame_t *frame)
 
 	LM_DBG("Rx Close: %hu %.*s\n", code, reason.len, reason.s);
 
-	if (close_connection(frame->wsc,
+	if (close_connection(&frame->wsc,
 		frame->wsc->state == WS_S_OPEN ? REMOTE_CLOSE : LOCAL_CLOSE,
 		1000, str_status_normal_closure) < 0)
 	{
@@ -587,6 +640,7 @@ int ws_frame_receive(void *data)
 		{
 			LM_DBG("Rx SIP message:\n%.*s\n", frame.payload_len,
 				frame.payload_data);
+			update_stat(ws_sip_received_frames, 1);
 			return receive_msg(frame.payload_data,
 						frame.payload_len,
 						tcpinfo->rcv);
@@ -595,6 +649,7 @@ int ws_frame_receive(void *data)
 		{
 			LM_DBG("Rx MSRP frame:\n%.*s\n", frame.payload_len,
 				frame.payload_data);
+			update_stat(ws_msrp_received_frames, 1);
 			if (likely(sr_event_enabled(SREV_TCP_MSRP_FRAME)))
 			{
 				tcp_event_info_t tev;
@@ -689,7 +744,11 @@ struct mi_root *ws_mi_close(struct mi_root *cmd, void *param)
 
 	node = cmd->node.kids;
 	if (node == NULL)
-		return 0;
+	{
+		LM_WARN("no connection ID parameter\n");
+		return init_mi_tree(400, str_status_empty_param.s,
+					str_status_empty_param.len);
+	}
 	if (node->value.s == NULL || node->value.len == 0)
 	{
 		LM_WARN("empty connection ID parameter\n");
@@ -699,7 +758,8 @@ struct mi_root *ws_mi_close(struct mi_root *cmd, void *param)
 	if (str2int(&node->value, &id) < 0)
 	{
 		LM_ERR("converting string to int\n");
-		return 0;
+		return init_mi_tree(400, str_status_string_error.s,
+					str_status_string_error.len);
 	}
 	if (node->next != NULL)
 	{
@@ -715,7 +775,7 @@ struct mi_root *ws_mi_close(struct mi_root *cmd, void *param)
 					str_status_bad_param.len);
 	}
 
-	if (close_connection(wsc, LOCAL_CLOSE, 1000,
+	if (close_connection(&wsc, LOCAL_CLOSE, 1000,
 				str_status_normal_closure) < 0)
 	{
 		LM_WARN("closing connection\n");
@@ -735,7 +795,11 @@ static struct mi_root *mi_ping_pong(struct mi_root *cmd, void *param,
 
 	node = cmd->node.kids;
 	if (node == NULL)
-		return 0;
+	{
+		LM_WARN("no connection ID parameter\n");
+		return init_mi_tree(400, str_status_empty_param.s,
+					str_status_empty_param.len);
+	}
 	if (node->value.s == NULL || node->value.len == 0)
 	{
 		LM_WARN("empty connection ID parameter\n");
@@ -745,7 +809,8 @@ static struct mi_root *mi_ping_pong(struct mi_root *cmd, void *param,
 	if (str2int(&node->value, &id) < 0)
 	{
 		LM_ERR("converting string to int\n");
-		return 0;
+		return init_mi_tree(400, str_status_string_error.s,
+					str_status_string_error.len);
 	}
 	if (node->next != NULL)
 	{
@@ -783,7 +848,8 @@ struct mi_root *ws_mi_pong(struct mi_root *cmd, void *param)
 
 void ws_keepalive(unsigned int ticks, void *param)
 {
-	int check_time = (int) time(NULL) - ws_keepalive_timeout;
+	int check_time = (int) time(NULL)
+		- cfg_get(websocket, ws_cfg, keepalive_timeout);
 	ws_connection_t *wsc = wsconn_used_list->head;
 
 	while (wsc && wsc->last_used < check_time)
@@ -802,3 +868,70 @@ void ws_keepalive(unsigned int ticks, void *param)
 	}
 	
 }
+
+int ws_close(sip_msg_t *msg)
+{
+	ws_connection_t *wsc;
+
+	if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) {
+		LM_ERR("failed to retrieve WebSocket connection\n");
+		return -1;
+	}
+
+	return (close_connection(&wsc, LOCAL_CLOSE, 1000,
+				 str_status_normal_closure) == 0) ? 1: 0;
+}
+
+int ws_close2(sip_msg_t *msg, char *_status, char *_reason)
+{
+	int status;
+	str reason;
+	ws_connection_t *wsc;
+
+	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
+		LM_ERR("failed to get status code\n");
+		return -1;
+	}
+
+	if (get_str_fparam(&reason, msg, (fparam_t *) _reason) < 0) {
+		LM_ERR("failed to get reason string\n");
+		return -1;
+	}
+
+	if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) {
+		LM_ERR("failed to retrieve WebSocket connection\n");
+		return -1;
+	}
+
+	return (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+}
+
+int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con)
+{
+	int status;
+	str reason;
+	int con;
+	ws_connection_t *wsc;
+
+	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
+		LM_ERR("failed to get status code\n");
+		return -1;
+	}
+
+	if (get_str_fparam(&reason, msg, (fparam_t *) _reason) < 0) {
+		LM_ERR("failed to get reason string\n");
+		return -1;
+	}
+
+	if (get_int_fparam(&con, msg, (fparam_t *) _con) < 0) {
+		LM_ERR("failed to get connection ID\n");
+		return -1;
+	}
+
+	if ((wsc = wsconn_get(con)) == NULL) {
+		LM_ERR("failed to retrieve WebSocket connection\n");
+		return -1;
+	}
+
+	return (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+}
diff --git a/modules/websocket/ws_frame.h b/modules/websocket/ws_frame.h
index 6be9529..1210c6c 100644
--- a/modules/websocket/ws_frame.h
+++ b/modules/websocket/ws_frame.h
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -36,9 +36,6 @@ typedef enum
 	REMOTE_CLOSE
 } ws_close_type_t;
 
-#define DEFAULT_KEEPALIVE_TIMEOUT		180 /* seconds */
-extern int ws_keepalive_timeout;
-
 enum
 {
 	KEEPALIVE_MECHANISM_NONE = 0,
@@ -48,6 +45,8 @@ enum
 #define DEFAULT_KEEPALIVE_MECHANISM		KEEPALIVE_MECHANISM_PING
 extern int ws_keepalive_mechanism;
 
+#define DEFAULT_KEEPALIVE_TIMEOUT		180 /* seconds */
+
 extern str ws_ping_application_data;
 #define DEFAULT_PING_APPLICATION_DATA		SERVER_HDR
 #define DEFAULT_PING_APPLICATION_DATA_LEN	SERVER_HDR_LEN
@@ -57,6 +56,16 @@ extern stat_var *ws_local_closed_connections;
 extern stat_var *ws_received_frames;
 extern stat_var *ws_remote_closed_connections;
 extern stat_var *ws_transmitted_frames;
+extern stat_var *ws_sip_failed_connections;
+extern stat_var *ws_sip_local_closed_connections;
+extern stat_var *ws_sip_received_frames;
+extern stat_var *ws_sip_remote_closed_connections;
+extern stat_var *ws_sip_transmitted_frames;
+extern stat_var *ws_msrp_failed_connections;
+extern stat_var *ws_msrp_local_closed_connections;
+extern stat_var *ws_msrp_received_frames;
+extern stat_var *ws_msrp_remote_closed_connections;
+extern stat_var *ws_msrp_transmitted_frames;
 
 int ws_frame_receive(void *data);
 int ws_frame_transmit(void *data);
@@ -64,5 +73,8 @@ struct mi_root *ws_mi_close(struct mi_root *cmd, void *param);
 struct mi_root *ws_mi_ping(struct mi_root *cmd, void *param);
 struct mi_root *ws_mi_pong(struct mi_root *cmd, void *param);
 void ws_keepalive(unsigned int ticks, void *param);
+int ws_close(sip_msg_t *msg);
+int ws_close2(sip_msg_t *msg, char *_status, char *_reason);
+int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con);
 
 #endif /* _WS_FRAME_H */
diff --git a/modules/websocket/ws_handshake.c b/modules/websocket/ws_handshake.c
index 94b7280..c4e3143 100644
--- a/modules/websocket/ws_handshake.c
+++ b/modules/websocket/ws_handshake.c
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -39,13 +39,17 @@
 #include "ws_conn.h"
 #include "ws_handshake.h"
 #include "ws_mod.h"
+#include "config.h"
 
 #define WS_VERSION		(13)
 
 int ws_sub_protocols = DEFAULT_SUB_PROTOCOLS;
+int ws_cors_mode = CORS_MODE_NONE;
 
 stat_var *ws_failed_handshakes;
 stat_var *ws_successful_handshakes;
+stat_var *ws_sip_successful_handshakes;
+stat_var *ws_msrp_successful_handshakes;
 
 static str str_sip = str_init("sip");
 static str str_msrp = str_init("msrp");
@@ -60,12 +64,16 @@ static str str_hdr_sec_websocket_accept = str_init("Sec-WebSocket-Accept");
 static str str_hdr_sec_websocket_key = str_init("Sec-WebSocket-Key");
 static str str_hdr_sec_websocket_protocol = str_init("Sec-WebSocket-Protocol");
 static str str_hdr_sec_websocket_version = str_init("Sec-WebSocket-Version");
+static str str_hdr_origin = str_init("Origin");
+static str str_hdr_access_control_allow_origin
+				= str_init("Access-Control-Allow-Origin");
 #define CONNECTION		(1<<0)
 #define UPGRADE			(1<<1)
 #define SEC_WEBSOCKET_ACCEPT	(1<<2)
 #define SEC_WEBSOCKET_KEY	(1<<3)
 #define SEC_WEBSOCKET_PROTOCOL	(1<<4)
 #define SEC_WEBSOCKET_VERSION	(1<<5)
+#define ORIGIN			(1<<6)
 
 #define REQUIRED_HEADERS	(CONNECTION | UPGRADE | SEC_WEBSOCKET_KEY\
 					| SEC_WEBSOCKET_PROTOCOL\
@@ -111,10 +119,10 @@ static int ws_send_reply(sip_msg_t *msg, int code, str *reason, str *hdrs)
 
 int ws_handle_handshake(struct sip_msg *msg)
 {
-	str key = {0, 0}, headers = {0, 0}, reply_key = {0, 0};
+	str key = {0, 0}, headers = {0, 0}, reply_key = {0, 0}, origin = {0, 0};
 	unsigned char sha1[SHA_DIGEST_LENGTH];
 	unsigned int hdr_flags = 0, sub_protocol = 0;
-	int version;
+	int version = 0;
 	struct hdr_field *hdr = msg->headers;
 	struct tcp_connection *con;
 	ws_connection_t *wsc;
@@ -126,7 +134,7 @@ int ws_handle_handshake(struct sip_msg *msg)
 	msg->rpl_send_flags.f |= SND_F_CON_CLOSE;
 	msg->rpl_send_flags.f |= SND_F_FORCE_CON_REUSE;
 
-	if (*ws_enabled == 0)
+	if (cfg_get(websocket, ws_cfg, enabled) == 0)
 	{
 		LM_INFO("disabled: bouncing handshake\n");
 		ws_send_reply(msg, 503, &str_status_service_unavailable,
@@ -271,6 +279,27 @@ int ws_handle_handshake(struct sip_msg *msg)
 				hdr->body.len, hdr->body.s);
 			hdr_flags |= SEC_WEBSOCKET_VERSION;
 		}
+		/* Decode Origin */
+		else if (cmp_hdrname_strzn(&hdr->name,
+				str_hdr_origin.s,
+				str_hdr_origin.len) == 0)
+		{
+			if (hdr_flags & ORIGIN)
+			{
+				LM_WARN("%.*s found multiple times\n",
+					hdr->name.len, hdr->name.s);
+				ws_send_reply(msg, 400,
+						&str_status_bad_request,
+						NULL);
+				goto end;
+			}
+
+			LM_DBG("found %.*s: %.*s\n",
+				hdr->name.len, hdr->name.s,
+				hdr->body.len, hdr->body.s);
+			origin = hdr->body;
+			hdr_flags |= ORIGIN;
+		}
 
 		hdr = hdr->next;
 	}
@@ -346,6 +375,21 @@ int ws_handle_handshake(struct sip_msg *msg)
 	headers.s = headers_buf;
 	headers.len = 0;
 
+	if (ws_cors_mode == CORS_MODE_ANY)
+		headers.len += snprintf(headers.s + headers.len,
+					HDR_BUF_LEN - headers.len,
+					"%.*s: *\r\n",
+					str_hdr_access_control_allow_origin.len,
+					str_hdr_access_control_allow_origin.s);
+	else if (ws_cors_mode == CORS_MODE_ORIGIN && origin.len > 0)
+		headers.len += snprintf(headers.s + headers.len,
+					HDR_BUF_LEN - headers.len,
+					"%.*s: %.*s\r\n",
+					str_hdr_access_control_allow_origin.len,
+					str_hdr_access_control_allow_origin.s,
+					origin.len,
+					origin.s);
+
 	if (sub_protocol & SUB_PROTOCOL_SIP)
 		headers.len += snprintf(headers.s + headers.len,
 					HDR_BUF_LEN - headers.len,
@@ -382,6 +426,13 @@ int ws_handle_handshake(struct sip_msg *msg)
 
 		goto end;
 	}
+	else
+	{
+		if (sub_protocol & SUB_PROTOCOL_SIP)
+			update_stat(ws_sip_successful_handshakes, 1);
+		else if (sub_protocol & SUB_PROTOCOL_MSRP)
+			update_stat(ws_msrp_successful_handshakes, 1);
+	}
 
 	tcpconn_put(con);
 	return 1;
@@ -393,14 +444,14 @@ end:
 
 struct mi_root *ws_mi_disable(struct mi_root *cmd, void *param)
 {
-	*ws_enabled = 0;
+	cfg_get(websocket, ws_cfg, enabled) = 0;
 	LM_WARN("disabling websockets - new connections will be dropped\n");
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
 
 struct mi_root *ws_mi_enable(struct mi_root *cmd, void *param)
 {
-	*ws_enabled = 1;
+	cfg_get(websocket, ws_cfg, enabled) = 1;
 	LM_WARN("enabling websockets\n");
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
diff --git a/modules/websocket/ws_handshake.h b/modules/websocket/ws_handshake.h
index fa51eb0..e7ff8e0 100644
--- a/modules/websocket/ws_handshake.h
+++ b/modules/websocket/ws_handshake.h
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -26,18 +26,21 @@
 
 #include "../../sr_module.h"
 #include "../../parser/msg_parser.h"
+#include "ws_mod.h"
 
-enum
-{
-	SUB_PROTOCOL_SIP  = (1 << 0),
-	SUB_PROTOCOL_MSRP = (1 << 1)
-};
 #define DEFAULT_SUB_PROTOCOLS	(SUB_PROTOCOL_SIP | SUB_PROTOCOL_MSRP)
 #define SUB_PROTOCOL_ALL	(SUB_PROTOCOL_SIP | SUB_PROTOCOL_MSRP)
 extern int ws_sub_protocols;
 
+#define CORS_MODE_NONE		0
+#define CORS_MODE_ANY		1
+#define CORS_MODE_ORIGIN	2
+extern int ws_cors_mode;
+
 extern stat_var *ws_failed_handshakes;
 extern stat_var *ws_successful_handshakes;
+extern stat_var *ws_sip_successful_handshakes;
+extern stat_var *ws_msrp_successful_handshakes;
 
 int ws_handle_handshake(struct sip_msg *msg);
 struct mi_root *ws_mi_disable(struct mi_root *cmd, void *param);
diff --git a/modules/websocket/ws_mod.c b/modules/websocket/ws_mod.c
index 7049bfd..ec5e07c 100644
--- a/modules/websocket/ws_mod.c
+++ b/modules/websocket/ws_mod.c
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -28,14 +28,17 @@
 #include "../../sr_module.h"
 #include "../../tcp_conn.h"
 #include "../../timer_proc.h"
+#include "../../cfg/cfg.h"
 #include "../../lib/kcore/kstats_wrapper.h"
 #include "../../lib/kmi/mi.h"
 #include "../../mem/mem.h"
+#include "../../mod_fix.h"
 #include "../../parser/msg_parser.h"
 #include "ws_conn.h"
 #include "ws_handshake.h"
 #include "ws_frame.h"
 #include "ws_mod.h"
+#include "config.h"
 
 MODULE_VERSION
 
@@ -45,18 +48,31 @@ MODULE_VERSION
 static int mod_init(void);
 static int child_init(int rank);
 static void destroy(void);
+static int ws_close_fixup(void** param, int param_no);
 
 sl_api_t ws_slb;
-int *ws_enabled;
 
 #define DEFAULT_KEEPALIVE_INTERVAL	1
 static int ws_keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL;
 
+static int ws_keepalive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;
+
 #define DEFAULT_KEEPALIVE_PROCESSES	1
 static int ws_keepalive_processes = DEFAULT_KEEPALIVE_PROCESSES;
 
 static cmd_export_t cmds[]= 
 {
+	/* ws_frame.c */
+	{ "ws_close", (cmd_function) ws_close,
+	  0, 0, 0,
+	  ANY_ROUTE },
+	{ "ws_close", (cmd_function) ws_close2,
+	  2, ws_close_fixup, 0,
+	  ANY_ROUTE },
+	{ "ws_close", (cmd_function) ws_close3,
+	  3, ws_close_fixup, 0,
+	  ANY_ROUTE },
+
 	/* ws_handshake.c */
 	{ "ws_handle_handshake", (cmd_function) ws_handle_handshake,
 	  0, 0, 0,
@@ -70,10 +86,11 @@ static param_export_t params[]=
 	/* ws_frame.c */
 	{ "keepalive_mechanism",	INT_PARAM, &ws_keepalive_mechanism },
 	{ "keepalive_timeout",		INT_PARAM, &ws_keepalive_timeout },
-	{ "ping_application_data",	STR_PARAM, &ws_ping_application_data.s},
+	{ "ping_application_data",	STR_PARAM, &ws_ping_application_data.s },
 
 	/* ws_handshake.c */
-	{ "sub_protocols",		INT_PARAM, &ws_sub_protocols},
+	{ "sub_protocols",		INT_PARAM, &ws_sub_protocols },
+	{ "cors_mode",			INT_PARAM, &ws_cors_mode },
 
 	/* ws_mod.c */
 	{ "keepalive_interval",		INT_PARAM, &ws_keepalive_interval },
@@ -85,19 +102,35 @@ static param_export_t params[]=
 static stat_export_t stats[] =
 {
 	/* ws_conn.c */
-	{ "ws_current_connections",       0, &ws_current_connections },
-	{ "ws_max_concurrent_connections",0, &ws_max_concurrent_connections },
+	{ "ws_current_connections",            0, &ws_current_connections },
+	{ "ws_max_concurrent_connections",     0, &ws_max_concurrent_connections },
+	{ "ws_sip_current_connections",        0, &ws_sip_current_connections },
+        { "ws_sip_max_concurrent_connectons",  0, &ws_sip_max_concurrent_connections },
+        { "ws_msrp_current_connections",       0, &ws_msrp_current_connections },
+        { "ws_msrp_max_concurrent_connectons", 0, &ws_msrp_max_concurrent_connections },
 
 	/* ws_frame.c */
-	{ "ws_failed_connections",        0, &ws_failed_connections },
-	{ "ws_local_closed_connections",  0, &ws_local_closed_connections },
-	{ "ws_received_frames",           0, &ws_received_frames },
-	{ "ws_remote_closed_connections", 0, &ws_remote_closed_connections },
-	{ "ws_transmitted_frames",        0, &ws_transmitted_frames },
+	{ "ws_failed_connections",             0, &ws_failed_connections },
+	{ "ws_local_closed_connections",       0, &ws_local_closed_connections },
+	{ "ws_received_frames",                0, &ws_received_frames },
+	{ "ws_remote_closed_connections",      0, &ws_remote_closed_connections },
+	{ "ws_transmitted_frames",             0, &ws_transmitted_frames },
+	{ "ws_sip_failed_connections",         0, &ws_sip_failed_connections },
+	{ "ws_sip_local_closed_connections",   0, &ws_sip_local_closed_connections },
+	{ "ws_sip_received_frames",            0, &ws_sip_received_frames },
+	{ "ws_sip_remote_closed_connections",  0, &ws_sip_remote_closed_connections },
+	{ "ws_sip_transmitted_frames",         0, &ws_sip_transmitted_frames },
+	{ "ws_msrp_failed_connections",        0, &ws_msrp_failed_connections },
+	{ "ws_msrp_local_closed_connections",  0, &ws_msrp_local_closed_connections },
+	{ "ws_msrp_received_frames",           0, &ws_msrp_received_frames },
+	{ "ws_msrp_remote_closed_connections", 0, &ws_msrp_remote_closed_connections },
+	{ "ws_msrp_transmitted_frames",        0, &ws_msrp_transmitted_frames },
 
 	/* ws_handshake.c */
-	{ "ws_failed_handshakes",         0, &ws_failed_handshakes },
-	{ "ws_successful_handshakes",     0, &ws_successful_handshakes },
+	{ "ws_failed_handshakes",              0, &ws_failed_handshakes },
+	{ "ws_successful_handshakes",          0, &ws_successful_handshakes },
+	{ "ws_sip_successful_handshakes",      0, &ws_sip_successful_handshakes },
+	{ "ws_msrp_successful_handshakes",     0, &ws_msrp_successful_handshakes },
 
 	{ 0, 0, 0 }
 };
@@ -173,14 +206,6 @@ static int mod_init(void)
 		goto error;
 	}
 
-	if ((ws_enabled = (int *) shm_malloc(sizeof(int))) == NULL)
-	{
-		LM_ERR("allocating shared memory\n");
-		goto error;
-	}
-	*ws_enabled = 1;
-
-	
 	if (ws_ping_application_data.s != 0)
 		ws_ping_application_data.len =
 					strlen(ws_ping_application_data.s);
@@ -233,12 +258,39 @@ static int mod_init(void)
 		goto error;
 	}
 
+	if (ws_cors_mode < 0 || ws_cors_mode > 2)
+	{
+		LM_ERR("bad value for cors_mode\n");
+		goto error;
+	}
+
+	if (cfg_declare("websocket", ws_cfg_def, &default_ws_cfg,
+			cfg_sizeof(websocket), &ws_cfg))
+	{
+		LM_ERR("declaring configuration\n");
+		return -1;
+	}
+	cfg_get(websocket, ws_cfg, keepalive_timeout) = ws_keepalive_timeout;
+
+	if (!module_loaded("xhttp"))
+	{
+		LM_ERR("\"xhttp\" must be loaded to use WebSocket.\n");
+		return -1;
+	}
+
+	if (((ws_sub_protocols & SUB_PROTOCOL_SIP) == SUB_PROTOCOL_SIP)
+			&& !module_loaded("nathelper")
+			&& !module_loaded("outbound"))
+	{
+		LM_WARN("neither \"nathelper\" nor \"outbound\" modules are"
+			" loaded. At least one of these is required for correct"
+			" routing of SIP over WebSocket.\n");
+	}
+
 	return 0;
 
 error:
 	wsconn_destroy();
-	shm_free(ws_enabled);
-
 	return -1;
 }
 
@@ -271,5 +323,17 @@ static int child_init(int rank)
 static void destroy(void)
 {
 	wsconn_destroy();
-	shm_free(ws_enabled);
+}
+
+static int ws_close_fixup(void** param, int param_no)
+{
+	switch(param_no) {
+	case 1:
+	case 3:
+		return fixup_var_int_1(param, 1);
+	case 2:
+		return fixup_spve_null(param, 1);
+	default:
+		return 0;
+	}
 }
diff --git a/modules/websocket/ws_mod.h b/modules/websocket/ws_mod.h
index e9c3951..819d3ea 100644
--- a/modules/websocket/ws_mod.h
+++ b/modules/websocket/ws_mod.h
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) 2012 Crocodile RCS Ltd
+ * Copyright (C) 2012-2013 Crocodile RCS Ltd
  *
  * This file is part of Kamailio, a free SIP server.
  *
@@ -28,8 +28,13 @@
 #include "../../kstats_types.h"
 #include "../sl/sl.h"
 
+enum
+{
+	SUB_PROTOCOL_SIP  = (1 << 0),
+	SUB_PROTOCOL_MSRP = (1 << 1)
+};
+
 extern sl_api_t ws_slb;
-extern int *ws_enabled;
 extern gen_lock_t *ws_stats_lock;
 
 extern int ws_ping_interval;	/* time (in seconds) between sending Pings */
diff --git a/modules/xcap_client/xcap_callbacks.c b/modules/xcap_client/xcap_callbacks.c
index 58c1fc0..93d32ff 100644
--- a/modules/xcap_client/xcap_callbacks.c
+++ b/modules/xcap_client/xcap_callbacks.c
@@ -78,6 +78,6 @@ void destroy_xcapcb_list(void)
 	{
 		prev_xcb= xcb;
 		xcb= xcb->next;
-		shm_free(xcb);
+		shm_free(prev_xcb);
 	}
 }
diff --git a/modules/xcap_client/xcap_functions.c b/modules/xcap_client/xcap_functions.c
index 28d4d42..4c3eead 100644
--- a/modules/xcap_client/xcap_functions.c
+++ b/modules/xcap_client/xcap_functions.c
@@ -85,8 +85,8 @@ void xcapFreeNodeSel(xcap_node_sel_t* node)
 	{
 		m= n;
 		n= n->next;
-		pkg_free(n->value.s);
-		pkg_free(n);
+		pkg_free(m->value.s);
+		pkg_free(m);
 	}
 
 	pkg_free(node);
diff --git a/modules/xcap_server/xcap_misc.c b/modules/xcap_server/xcap_misc.c
index 7ca891e..da8bb59 100644
--- a/modules/xcap_server/xcap_misc.c
+++ b/modules/xcap_server/xcap_misc.c
@@ -334,15 +334,15 @@ int xcaps_xpath_get(str *inbuf, str *xpaths, str *outbuf)
 		LM_ERR("unable to evaluate xpath expression [%s]\n", xpaths->s);
 		goto error;
 	}
-    nodes = xpathObj->nodesetval;
-	if(nodes==NULL)
+	nodes = xpathObj->nodesetval;
+	if(nodes==NULL || nodes->nodeNr==0 || nodes->nodeTab == NULL)
 	{
 		outbuf->len = 0;
 		outbuf->s[outbuf->len] = '\0';
 		goto done;
 	}
 	size = nodes->nodeNr;
-    p = outbuf->s;
+	p = outbuf->s;
 	end = outbuf->s + outbuf->len;
 	for(i = 0; i < size; ++i)
 	{
diff --git a/modules/xcap_server/xcap_server.c b/modules/xcap_server/xcap_server.c
index 8bc14eb..372fc39 100644
--- a/modules/xcap_server/xcap_server.c
+++ b/modules/xcap_server/xcap_server.c
@@ -1070,7 +1070,8 @@ static int w_xcaps_get(sip_msg_t* msg, char* puri, char* ppath)
 	str uri;
 	str path;
 	str etag = {0, 0};
-	str body;
+	str body = {0, 0};
+	str new_body = {0, 0};
 	int ret = 0;
 	xcap_uri_t xuri;
 	str *ctype;
@@ -1170,37 +1171,77 @@ static int w_xcaps_get(sip_msg_t* msg, char* puri, char* ppath)
 			LM_ERR("could not fetch xcap document\n");
 			goto error;
 		}
-
-		if(ret==0)
+		if(ret!=0)
 		{
-			/* doc found */
-			ctype = &xcaps_str_appxml;
-			if(xuri.type==RESOURCE_LIST)
-				ctype = &xcaps_str_apprlxml;
-			else if(xuri.type==PRES_RULES)
-				ctype = &xcaps_str_appapxml;
-			else if(xuri.type==RLS_SERVICE)
-				ctype = &xcaps_str_apprsxml;
-			else if(xuri.type==USER_PROFILE)
-				ctype = &xcaps_str_appupxml;
-			else if(xuri.type==PRES_CONTENT)
-				ctype = &xcaps_str_apppcxml;
-			else if(xuri.type==PIDF_MANIPULATION)
-				ctype = &xcaps_str_apppdxml;
-			xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag,
-					ctype, &body);
-		} else {
 			/* doc not found */
 			xcaps_send_reply(msg, 404, &xcaps_str_notfound, NULL,
 					NULL, NULL);
+			break;
+		}
+
+		if(xuri.nss!=NULL && xuri.node.len>0)
+		{
+			if((new_body.s = pkg_malloc(body.len))==NULL)
+			{
+				LM_ERR("allocating package memory\n");
+				goto error;
+			}
+			new_body.len = body.len;
+			
+			if(xcaps_xpath_hack(&body, 0)<0)
+			{
+				LM_ERR("could not hack xcap document\n");
+				goto error;
+			}
+			if(xcaps_xpath_get(&body, &xuri.node, &new_body)<0)
+			{
+				LM_ERR("could not retrieve element from xcap document\n");
+				goto error;
+			}
+			if(new_body.len<=0)
+			{
+				/* element not found */
+				xcaps_send_reply(msg, 404, &xcaps_str_notfound, NULL,
+					NULL, NULL);
+				pkg_free(new_body.s);
+				new_body.s = NULL;
+				break;
+			}
+			if(xcaps_xpath_hack(&new_body, 1)<0)
+			{
+				LM_ERR("could not hack xcap document\n");
+				goto error;
+			}
+			memcpy(body.s, new_body.s, new_body.len);
+			body.len = new_body.len;
+			pkg_free(new_body.s);
+			new_body.s = NULL;
 		}
 
+		/* doc or element found */
+		ctype = &xcaps_str_appxml;
+		if(xuri.type==RESOURCE_LIST)
+			ctype = &xcaps_str_apprlxml;
+		else if(xuri.type==PRES_RULES)
+			ctype = &xcaps_str_appapxml;
+		else if(xuri.type==RLS_SERVICE)
+			ctype = &xcaps_str_apprsxml;
+		else if(xuri.type==USER_PROFILE)
+			ctype = &xcaps_str_appupxml;
+		else if(xuri.type==PRES_CONTENT)
+			ctype = &xcaps_str_apppcxml;
+		else if(xuri.type==PIDF_MANIPULATION)
+			ctype = &xcaps_str_apppdxml;
+		xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag,
+				ctype, &body);
+
 		break;
 	}
 
 	return 1;
 
 error:
+	if (new_body.s) pkg_free(new_body.s);
 	xcaps_send_reply(msg, 500, &xcaps_str_srverr, NULL,
 				NULL, NULL);
 	return -1;
diff --git a/modules/xhttp/xhttp_mod.c b/modules/xhttp/xhttp_mod.c
index 23ac3c4..9848892 100644
--- a/modules/xhttp/xhttp_mod.c
+++ b/modules/xhttp/xhttp_mod.c
@@ -45,6 +45,7 @@
 #include "../../pvar.h"
 
 #include "api.h"
+#include "xhttp_trans.h"
 
 MODULE_VERSION
 
@@ -106,6 +107,13 @@ struct module_exports exports= {
 	0           /* per-child init function */
 };
 
+static tr_export_t mod_trans[] = {
+	{ {"url", sizeof("url")-1},
+		xhttp_tr_parse_url },
+
+	{ { 0, 0 }, 0 }
+};
+
 /** 
  * 
  */
@@ -162,6 +170,11 @@ static int mod_init(void)
 	return 0;
 }
 
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+	return register_trans_mod(path, mod_trans);
+}
+
 /** 
  * 
  */
diff --git a/modules/xhttp/xhttp_trans.c b/modules/xhttp/xhttp_trans.c
new file mode 100644
index 0000000..36c5888
--- /dev/null
+++ b/modules/xhttp/xhttp_trans.c
@@ -0,0 +1,145 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "../../pvar.h"
+#include "../../str.h"
+#include "../../trim.h"
+#include "xhttp_trans.h"
+
+enum _tr_xhttp_type { TR_XHTTP_NONE = 0, TR_XHTTPURL, TR_XHTTPURLQUERYSTRING };
+enum _tr_xhttpurl_subtype { TR_XHTTPURL_NONE = 0, TR_XHTTPURL_PATH,
+	TR_XHTTPURL_QUERYSTRING};
+enum _tr_xhttpquerystring_subtype { TR_XHTTPUTLQUERYSTRING_NONE = 0,
+	TR_XHTTPURLQUERYSTRING_VALUE};
+
+static str _httpurl_str = {0, 0};
+static int _httpurl_querystring_pos = 0;
+
+int xhttp_tr_eval_xhttpurl(struct sip_msg *msg, tr_param_t *tp, int subtype,
+		pv_value_t *val)
+{
+	int pos = 0;
+
+	if (val == NULL || val->flags & PV_VAL_NULL)
+		return -1;
+
+	if (!(val->flags & PV_VAL_STR))
+	{
+		val->rs.s = int2str(val->ri, &val->rs.len);
+		val->flags = PV_VAL_STR;
+	}
+
+	if (_httpurl_str.len == 0 || _httpurl_str.len != val->rs.len
+		|| strncmp(_httpurl_str.s, val->rs.s, val->rs.len) != 0)
+	{
+		if (val->rs.len > _httpurl_str.len)
+		{
+			if (_httpurl_str.s) pkg_free(_httpurl_str.s);
+			_httpurl_str.s = (char *) pkg_malloc(
+					(val->rs.len + 1) * sizeof(char));
+			if (_httpurl_str.s == NULL)
+			{
+				LM_ERR("allocating package memory\n");
+				memset(&_httpurl_str.s, 0, sizeof(str));
+				return -1;
+			}
+		}
+		_httpurl_str.len = val->rs.len;
+		memcpy(_httpurl_str.s, val->rs.s, val->rs.len);
+
+		while (val->rs.s[pos] != '?' && pos < val->rs.len) pos++;
+		_httpurl_querystring_pos = (pos >= val->rs.len) ? 0 : pos + 1;
+	}
+
+	switch (subtype)
+	{
+	case TR_XHTTPURL_PATH:
+		val->rs.len = (_httpurl_querystring_pos == 0)
+				? val->rs.len : _httpurl_querystring_pos - 1;
+		break;
+
+	case TR_XHTTPURL_QUERYSTRING:
+		if (_httpurl_querystring_pos == 0)
+		{
+			val->rs.s[0] = '\0';
+			val->rs.len = 0;
+			break;
+		}
+
+		val->rs.s = &val->rs.s[_httpurl_querystring_pos];
+		val->rs.len = val->rs.len - _httpurl_querystring_pos;
+		break;
+
+	default:
+		LM_ERR("unknown subtype %d\n", subtype);
+		return -1;
+	}
+
+	return 0;
+}
+
+char *xhttp_tr_parse_url(str *in, trans_t *t)
+{
+	char *p;
+	str name;
+
+	if (in == NULL || in->s == NULL || t == NULL)
+		return NULL;
+
+	p = in->s;
+	name.s = in->s;
+	t->type = TR_XHTTPURL;
+	t->trf = xhttp_tr_eval_xhttpurl;
+
+        /* find next token */
+        while (is_in_str(p, in) && *p != TR_PARAM_MARKER && *p != TR_RBRACKET)
+	{
+		p++;
+	}
+
+        if (*p == '\0')
+        {
+                LM_ERR("invalid transformation: %.*s\n", in->len, in->s);
+                goto error;
+        }
+        name.len = p - name.s;
+        trim(&name);
+
+	if (name.len == 4 && strncasecmp(name.s, "path", 4) == 0)
+	{
+		t->subtype = TR_XHTTPURL_PATH;
+		goto done;
+	}
+	else if (name.len == 11 && strncasecmp(name.s, "querystring", 11) == 0)
+	{
+		t->subtype = TR_XHTTPURL_QUERYSTRING;
+		goto done;
+	}
+
+	LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s,
+			name.len, name.s, name.len);
+error:
+	return NULL;
+
+done:
+	t->name = name;
+	return p;
+}
diff --git a/modules/xhttp/xhttp_trans.h b/modules/xhttp/xhttp_trans.h
new file mode 100644
index 0000000..0f27ca8
--- /dev/null
+++ b/modules/xhttp/xhttp_trans.h
@@ -0,0 +1,30 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef XHTTP_TRANS_H_
+#define XHTTP_TRANS_H_
+
+#include "../../pvar.h"
+#include "../../str.h"
+
+char *xhttp_tr_parse_url(str *in, trans_t *t);
+
+#endif /* XHTTP_TRANS_H_ */
diff --git a/modules/xhttp_pi/xhttp_pi_fnc.c b/modules/xhttp_pi/xhttp_pi_fnc.c
index e93ac4d..761a277 100644
--- a/modules/xhttp_pi/xhttp_pi_fnc.c
+++ b/modules/xhttp_pi/xhttp_pi_fnc.c
@@ -243,6 +243,49 @@ do{								\
 }while(0)
 
 
+#define XHTTP_PI_ESC_COPY(p,str,temp_holder,temp_counter)	\
+do{	\
+	(temp_holder).s = (str).s;	\
+	(temp_holder).len = 0;	\
+	for((temp_counter)=0;(temp_counter)<(str).len;(temp_counter)++) {	\
+		switch((str).s[(temp_counter)]) {	\
+		case '<':	\
+			(temp_holder).len = (temp_counter) - (temp_holder).len;	\
+			XHTTP_PI_COPY_2(p, (temp_holder), XHTTP_PI_ESC_LT);	\
+			(temp_holder).s += (temp_counter) + 1;	\
+			(temp_holder).len = (temp_counter) + 1;	\
+			break;	\
+		case '>':	\
+			(temp_holder).len = (temp_counter) - (temp_holder).len;	\
+			XHTTP_PI_COPY_2(p, (temp_holder), XHTTP_PI_ESC_GT);	\
+			(temp_holder).s += (temp_counter) + 1;	\
+			(temp_holder).len = (temp_counter) + 1;	\
+			break;	\
+		case '&':	\
+			(temp_holder).len = (temp_counter) - (temp_holder).len;	\
+			XHTTP_PI_COPY_2(p, (temp_holder), XHTTP_PI_ESC_AMP);	\
+			(temp_holder).s += (temp_counter) + 1;	\
+			(temp_holder).len = (temp_counter) + 1;	\
+			break;	\
+		case '"':	\
+			(temp_holder).len = (temp_counter) - (temp_holder).len;	\
+			XHTTP_PI_COPY_2(p, (temp_holder), XHTTP_PI_ESC_QUOT);	\
+			(temp_holder).s += (temp_counter) + 1;	\
+			(temp_holder).len = (temp_counter) + 1;	\
+			break;	\
+		case '\'':	\
+			(temp_holder).len = (temp_counter) - (temp_holder).len;	\
+			XHTTP_PI_COPY_2(p, (temp_holder), XHTTP_PI_ESC_SQUOT);	\
+			(temp_holder).s += (temp_counter) + 1;	\
+			(temp_holder).len = (temp_counter) + 1;	\
+			break;	\
+		}	\
+	}	\
+	(temp_holder).len = (temp_counter) - (temp_holder).len;	\
+	XHTTP_PI_COPY(p, (temp_holder));	\
+}while(0)
+
+
 static const str XHTTP_PI_Response_Head_1 = str_init("<html><head><title>"\
 	"Kamailio Provisionning Interface</title>"\
 	"<style type=\"text/css\">"\
@@ -349,6 +392,12 @@ static const str XHTTP_PI_Response_Foot = str_init(\
 #define XHTTP_PI_ROWSPAN 20
 static const str XHTTP_PI_CMD_ROWSPAN = str_init("20");
 
+static const str XHTTP_PI_ESC_LT =    str_init("<");   /* < */
+static const str XHTTP_PI_ESC_GT =    str_init(">");   /* > */
+static const str XHTTP_PI_ESC_AMP =   str_init("&");  /* & */
+static const str XHTTP_PI_ESC_QUOT =  str_init("""); /* " */
+static const str XHTTP_PI_ESC_SQUOT = str_init("'");  /* ' */
+
 
 xmlAttrPtr ph_xmlNodeGetAttrByName(xmlNodePtr node, const char *name)
 {
@@ -2449,7 +2498,7 @@ int getVal(db_val_t *val, db_type_t val_type, db_key_t key, ph_db_table_t *table
 			LM_DBG("[%.*s] has flags [%d]\n", key->len, key->s, flags);
 			if(flags){
 				XHTTP_PI_BUILD_REPLY(ctx,
-					"Unkown validation [%d] for %s.",
+					"Unknown validation [%d] for %s.",
 					table->cols[i].validation, key->s);
 				goto done;
 			}
@@ -2543,7 +2592,8 @@ int ph_run_pi_cmd(pi_ctx_t* ctx)
 	str arg_url = {ctx->arg.s, ctx->arg.len};
 	str arg_name;
 	str arg_val;
-	//unsigned long i;
+	str temp_holder;
+	int temp_counter;
 	int i;
 	int j;
 	int max_page_len = ctx->reply.buf.len;
@@ -2733,8 +2783,11 @@ int ph_run_pi_cmd(pi_ctx_t* ctx)
 							values[j].val.str_val.len,
 							values[j].val.str_val.s,
 							val_str.len, val_str.s);
-					XHTTP_PI_COPY(p,
-						val_str.len?val_str:XHTTP_PI_NBSP);
+						if (val_str.len) {
+							XHTTP_PI_ESC_COPY(p, val_str, temp_holder, temp_counter);
+						} else {
+							XHTTP_PI_COPY(p, XHTTP_PI_NBSP);
+						}
 						break;
 					case DB1_INT:
 						val_str.s = p;
diff --git a/modules/xhttp_rpc/README b/modules/xhttp_rpc/README
index dca5b1e..b85f033 100644
--- a/modules/xhttp_rpc/README
+++ b/modules/xhttp_rpc/README
@@ -16,7 +16,7 @@ Alex Balashov
 
    <abalashov at evaristesys.com>
 
-   Copyright � 2011 VoIPEmbedded Inc.
+   Copyright © 2011 VoIPEmbedded Inc.
      __________________________________________________________________
 
    Table of Contents
@@ -145,7 +145,7 @@ modparam("xhttp", "xhttp_rpc_buf_size", 1024)
 
    4.1. dispatch_xhttp_rpc()
 
-4.1. dispatch_xhttp_rpc()
+4.1.  dispatch_xhttp_rpc()
 
    Handle the HTTP request and generate a response.
 
diff --git a/modules/xmlrpc/xmlrpc.c b/modules/xmlrpc/xmlrpc.c
index b840131..4fa9b15 100644
--- a/modules/xmlrpc/xmlrpc.c
+++ b/modules/xmlrpc/xmlrpc.c
@@ -1995,7 +1995,7 @@ error:
  */
 static int open_doc(rpc_ctx_t* ctx, sip_msg_t* msg)
 {
-	str doc;
+	str doc = {NULL,0};
 	xmlNodePtr root;
 	xmlNodePtr cur;
 	struct xmlrpc_reply* reply;
@@ -2396,7 +2396,7 @@ static int xmlrpc_reply(sip_msg_t* msg, char* p1, char* p2)
 static int select_method(str* res, struct select* s, sip_msg_t* msg)
 {
 	static char buf[1024];
-	str doc;
+	str doc = {NULL,0};
 	xmlDocPtr xmldoc;
 	xmlNodePtr cur;
 	char* method;
diff --git a/modules/xprint/xp_lib.c b/modules/xprint/xp_lib.c
index 2f2fba5..91cf76a 100644
--- a/modules/xprint/xp_lib.c
+++ b/modules/xprint/xp_lib.c
@@ -700,7 +700,7 @@ static int xl_get_branch(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
 
 
 	init_branch_iterator();
-	branch.s = next_branch(&branch.len, &q, 0, 0, 0, 0);
+	branch.s = next_branch(&branch.len, &q, 0, 0, 0, 0, 0, 0, 0);
 	if (!branch.s) {
 		return xl_get_null(msg, res, hp, hi, hf);
 	}
@@ -731,7 +731,7 @@ static int xl_get_branches(struct sip_msg *msg, str *res, str *hp, int hi, int h
 	cnt = len = 0;
 
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0)))
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0)))
 	{
 		cnt++;
 		len += uri.len;
@@ -756,7 +756,7 @@ static int xl_get_branches(struct sip_msg *msg, str *res, str *hp, int hi, int h
 	p = local_buf;
 
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0)))
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0)))
 	{
 		if (i)
 		{
diff --git a/msg_translator.c b/msg_translator.c
index fa7834f..b4581e7 100644
--- a/msg_translator.c
+++ b/msg_translator.c
@@ -195,9 +195,7 @@ static int check_via_address(struct ip_addr* ip, str *name,
 	struct hostent* he;
 	int i;
 	char* s;
-	#ifdef USE_IPV6
 	int len;
-	#endif
 
 	/* maybe we are lucky and name it's an ip */
 	s=ip_addr2a(ip);
@@ -205,8 +203,6 @@ static int check_via_address(struct ip_addr* ip, str *name,
 		DBG("check_via_address(%s, %.*s, %d)\n",
 			s, name->len, name->s, resolver);
 
-	#ifdef USE_IPV6
-
 		len=strlen(s);
 
 		/* check if name->s is an ipv6 address or an ipv6 address ref. */
@@ -220,7 +216,6 @@ static int check_via_address(struct ip_addr* ip, str *name,
 		   )
 			return 0;
 		else
-	#endif
 
 			if (strncmp(name->s, s, name->len)==0)
 				return 0;
@@ -1764,9 +1759,7 @@ after_local_via:
 			}
 #if 0
 			/* no longer necessary, now hots.s contains [] */
-		#ifdef USE_IPV6
 			if(send_sock->address.af==AF_INET6) size+=1; /* +1 for ']'*/
-		#endif
 #endif
 	}
 	/* if received needs to be added, add anchor after host and add it, or
@@ -1963,8 +1956,8 @@ error00:
 
 
 
-char * build_res_buf_from_sip_res( struct sip_msg* msg,
-				unsigned int *returned_len)
+char * generate_res_buf_from_sip_res( struct sip_msg* msg,
+				unsigned int *returned_len, unsigned int mode)
 {
 	unsigned int new_len, via_len, body_delta;
 	char* new_buf;
@@ -1975,13 +1968,19 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg,
 	buf=msg->buf;
 	len=msg->len;
 	new_buf=0;
-	/* we must remove the first via */
-	if (msg->via1->next) {
-		via_len=msg->via1->bsize;
-		via_offset=msg->h_via1->body.s-buf;
+
+	if(unlikely(mode&BUILD_NO_VIA1_UPDATE)) {
+		via_len = 0;
+		via_offset = 0;
 	} else {
-		via_len=msg->h_via1->len;
-		via_offset=msg->h_via1->name.s-buf;
+		/* we must remove the first via */
+		if (msg->via1->next) {
+			via_len=msg->via1->bsize;
+			via_offset=msg->h_via1->body.s-buf;
+		} else {
+			via_len=msg->h_via1->len;
+			via_offset=msg->h_via1->name.s-buf;
+		}
 	}
 
 	     /* Calculate message body difference and adjust
@@ -1990,16 +1989,16 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg,
 	body_delta = lumps_len(msg, msg->body_lumps, 0);
 	if (adjust_clen(msg, body_delta, (msg->via2? msg->via2->proto:PROTO_UDP))
 			< 0) {
-		LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: Error while adjusting"
-				" Content-Length\n");
+		LOG(L_ERR, "error while adjusting Content-Length\n");
 		goto error;
 	}
 
-	/* remove the first via*/
-	if (del_lump( msg, via_offset, via_len, HDR_VIA_T)==0){
-		LOG(L_ERR, "build_res_buf_from_sip_res: error trying to remove first"
-					"via\n");
-		goto error;
+	if(likely(!(mode&BUILD_NO_VIA1_UPDATE))) {
+		/* remove the first via*/
+		if (del_lump( msg, via_offset, via_len, HDR_VIA_T)==0){
+			LOG(L_ERR, "error trying to remove first via\n");
+			goto error;
+		}
 	}
 
 	new_len=len+body_delta+lumps_len(msg, msg->add_rm, 0); /*FIXME: we don't
@@ -2009,7 +2008,7 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg,
 	new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging
 											 (\0 to print it )*/
 	if (new_buf==0){
-		LOG(L_ERR, "ERROR: build_res_buf_from_sip_res: out of mem\n");
+		LOG(L_ERR, "out of mem\n");
 		goto error;
 	}
 	new_buf[new_len]=0; /* debug: print the message */
@@ -2022,7 +2021,7 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg,
 		buf+s_offset,
 		len-s_offset);
 	 /* send it! */
-	DBG("build_res_from_sip_res: copied size: orig:%d, new: %d, rest: %d"
+	DBG("copied size: orig:%d, new: %d, rest: %d"
 			" msg=\n%s\n", s_offset, offset, len-s_offset, new_buf);
 
 	*returned_len=new_len;
@@ -2032,6 +2031,11 @@ error:
 	return 0;
 }
 
+char * build_res_buf_from_sip_res( struct sip_msg* msg,
+				unsigned int *returned_len)
+{
+	return generate_res_buf_from_sip_res(msg, returned_len, 0);
+}
 
 char * build_res_buf_from_sip_req( unsigned int code, str *text ,str *new_tag,
 		struct sip_msg* msg, unsigned int *returned_len, struct bookmark *bmark)
@@ -2516,7 +2520,6 @@ char* via_builder( unsigned int *len,
 		LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", send_info->proto);
 		return 0;
 	}
-#	ifdef USE_IPV6
 	/* add [] only if ipv6 and outbound socket address is used;
 	 * if using pre-set no check is made */
 	if ((send_sock->address.af==AF_INET6) &&
@@ -2526,7 +2529,6 @@ char* via_builder( unsigned int *len,
 		extra_len=1;
 		via_len+=2; /* [ ]*/
 	}
-#	endif
 	memcpy(line_buf+via_prefix_len+extra_len, address_str->s,
 				address_str->len);
 	if ((send_sock->port_no!=SIP_PORT) ||
diff --git a/msg_translator.h b/msg_translator.h
index 33caa40..4848291 100644
--- a/msg_translator.h
+++ b/msg_translator.h
@@ -87,6 +87,8 @@ char * build_req_buf_from_sip_req(struct sip_msg* msg,
 char * build_res_buf_from_sip_res(struct sip_msg* msg,
 				unsigned int *returned_len);
 
+char * generate_res_buf_from_sip_res(struct sip_msg* msg,
+				unsigned int *returned_len, unsigned int mode);
 
 char * build_res_buf_from_sip_req(unsigned int code,
 				str *text,
diff --git a/name_alias.h b/name_alias.h
index d74facc..0eca031 100644
--- a/name_alias.h
+++ b/name_alias.h
@@ -59,13 +59,11 @@ static inline int grep_aliases(char* name, int len, unsigned short port,
 {
 	struct  host_alias* a;
 	
-#ifdef USE_IPV6
 	if ((len>2)&&((*name)=='[')&&(name[len-1]==']')){
 		/* ipv6 reference, skip [] */
 		name++;
 		len-=2;
 	}
-#endif
 	for(a=aliases;a;a=a->next)
 		if ((a->alias.len==len) && ((a->port==0) || (port==0) || 
 				(a->port==port)) && ((a->proto==0) || (proto==0) || 
diff --git a/obsolete/permissions/ip_set.c b/obsolete/permissions/ip_set.c
index f33297c..05d97b2 100644
--- a/obsolete/permissions/ip_set.c
+++ b/obsolete/permissions/ip_set.c
@@ -34,26 +34,20 @@ void ip_set_init(struct ip_set *ip_set, int use_shm) {
 	memset(ip_set, 0, sizeof(*ip_set));
 	ip_set->use_shm = use_shm;
 	ip_tree_init(&ip_set->ipv4_tree);
-	#ifdef USE_IPV6
 	ip_tree_init(&ip_set->ipv6_tree);
-	#endif
 }
 
 void ip_set_destroy(struct ip_set *ip_set) {
 	ip_tree_destroy(&ip_set->ipv4_tree, 0, ip_set->use_shm);
-	#ifdef USE_IPV6
 	ip_tree_destroy(&ip_set->ipv6_tree, 0, ip_set->use_shm);
-	#endif
 }
 
 int ip_set_add_ip(struct ip_set *ip_set, struct ip_addr *ip, unsigned int network_prefix) {
 	switch (ip->af) {
 		case AF_INET:
 			return ip_tree_add_ip(&ip_set->ipv4_tree, ip->u.addr, (ip->len*8<network_prefix)?ip->len*8:network_prefix, ip_set->use_shm);
-	#ifdef USE_IPV6
 		case AF_INET6:
 			return ip_tree_add_ip(&ip_set->ipv6_tree, ip->u.addr, (ip->len*8<network_prefix)?ip->len*8:network_prefix, ip_set->use_shm);
-	#endif
 		default:
 			return -1;				
 		}
@@ -64,10 +58,8 @@ int ip_set_ip_exists(struct ip_set *ip_set, struct ip_addr *ip) {
 	switch (ip->af) {
 		case AF_INET:
 			return ip_tree_find_ip(ip_set->ipv4_tree, ip->u.addr, ip->len*8, &h) > 0;
-	#ifdef USE_IPV6
 		case AF_INET6:
 			return ip_tree_find_ip(ip_set->ipv6_tree, ip->u.addr, ip->len*8, &h) > 0;
-	#endif
 		default:
 			return -1;				
 		}
@@ -76,10 +68,8 @@ int ip_set_ip_exists(struct ip_set *ip_set, struct ip_addr *ip) {
 void ip_set_print(FILE *stream, struct ip_set *ip_set) {
 	fprintf(stream, "IPv4:\n");
 	ip_tree_print(stream, ip_set->ipv4_tree, 2);
-	#ifdef USE_IPV6
 	fprintf(stream, "IPv6:\n");
 	ip_tree_print(stream, ip_set->ipv6_tree, 2);
-	#endif
 }
 
 int ip_set_add_list(struct ip_set *ip_set, str ip_set_s){
@@ -126,9 +116,7 @@ int ip_set_add_ip_s(struct ip_set *ip_set, str ip_s, str mask_s){
 	unsigned int prefix, i;
 
 	if ( ((ip = str2ip(&ip_s))==0)
-		#ifdef  USE_IPV6
 					  && ((ip = str2ip6(&ip_s))==0)
-		#endif
 									  ){
 		ERR("ip_set_add_ip_s: string to ip conversion error '%.*s'\n", ip_s.len, ip_s.s);
 		return -1;
@@ -153,9 +141,7 @@ int ip_set_add_ip_s(struct ip_set *ip_set, str ip_s, str mask_s){
 		
 		if (fl) {  /* 255.255.255.0 format */
 			if ( ((ip = str2ip(&mask_s))==0)
-				#ifdef  USE_IPV6
 					  && ((ip = str2ip6(&mask_s))==0)
-				#endif
 				  ){
 				ERR("ip_set_add_ip_s: string to ip mask conversion error '%.*s'\n", mask_s.len, mask_s.s);
 				return -1;
diff --git a/obsolete/permissions/ip_set.h b/obsolete/permissions/ip_set.h
index f363baf..e921156 100644
--- a/obsolete/permissions/ip_set.h
+++ b/obsolete/permissions/ip_set.h
@@ -37,9 +37,7 @@
 struct ip_set {
 	int use_shm;
 	struct ip_tree_leaf *ipv4_tree;
-#ifdef USE_IPV6
 	struct ip_tree_leaf *ipv6_tree;	
-#endif
 };
 
 extern void ip_set_init(struct ip_set *ip_set, int use_shm);
diff --git a/obsolete/permissions/ip_set_rpc.c b/obsolete/permissions/ip_set_rpc.c
index be40008..a1e36ce 100644
--- a/obsolete/permissions/ip_set_rpc.c
+++ b/obsolete/permissions/ip_set_rpc.c
@@ -274,10 +274,8 @@ void rpc_ip_set_print(rpc_t* rpc, void* ctx) {
 	rpc->add(ctx, "{", &c);
 	if (rpc->struct_add(c, "s", "IPv", "6") < 0) 
 		goto err;	
-#ifdef USE_IPV6
 	if (rpc_ip_tree_print(rpc, c, "", ip_set->ipv6_tree, 0) < 0) 
 		goto err;
-#endif
 
 err:		
 	if (pending)
diff --git a/obsolete/permissions/permissions.c b/obsolete/permissions/permissions.c
index 2ce457d..3a381f1 100644
--- a/obsolete/permissions/permissions.c
+++ b/obsolete/permissions/permissions.c
@@ -679,9 +679,7 @@ static int w_ip_is_trusted(struct sip_msg* msg, char* _ip_set, char* _ip) {
 			/* string -> ip */
 
 			if ( ((ip = str2ip(&ip_s))==0)
-				#ifdef  USE_IPV6
 			                  && ((ip = str2ip6(&ip_s))==0)
-				#endif
 							                  ){
 				ERR(MODULE_NAME": ip_is_trusted: string to ip conversion error '%.*s'\n", ip_s.len, ip_s.s);
 				return -1;
diff --git a/obsolete/registrar/save.c b/obsolete/registrar/save.c
index 8550d3c..86fd142 100644
--- a/obsolete/registrar/save.c
+++ b/obsolete/registrar/save.c
@@ -295,12 +295,8 @@ int parse_uri_dstip(str* received, struct ip_addr* ip, unsigned short* port,
 		goto end; /* no dst_ip param */
 	/* check if it's ipv4 or ipv6 */
 	if (
-#ifdef USE_IPV6
 			likely(((p = str2ip(&hooks.uri.dstip->body)) != 0) ||
 				((p = str2ip6(&hooks.uri.dstip->body)) != 0))
-#else /* ! USE_IPV6 */
-			likely(((p = str2ip(&hooks.uri.dstip->body)) != 0))
-#endif /* USE_IPV6 */
 				) {
 		*ip = *p;
 	} else
diff --git a/parser/hf.c b/parser/hf.c
index cd378a8..45cbe00 100644
--- a/parser/hf.c
+++ b/parser/hf.c
@@ -57,6 +57,7 @@
 #include "parse_disposition.h"
 #include "parse_allow.h"
 #include "../ut.h"
+#include "parse_ppi_pai.h"
 
 /** Frees a hdr_field structure.
  * WARNING: it frees only parsed (and not name.s, body.s)
@@ -122,11 +123,11 @@ void clean_hdr_field(struct hdr_field* const hf)
 			break;
 
 		case HDR_PAI_T:
-			free_to(hf->parsed);
+			free_pai_ppi_body(hf->parsed);
 			break;
 
 		case HDR_PPI_T:
-			free_to(hf->parsed);
+			free_pai_ppi_body(hf->parsed);
 			break;
 
 		case HDR_PROXYAUTH_T:
diff --git a/parser/keys.h b/parser/keys.h
index c62fd26..c7c934b 100644
--- a/parser/keys.h
+++ b/parser/keys.h
@@ -118,6 +118,8 @@
 #define _tity_ 0x79746974   /* "tity" */
 #define _info_ 0x6f666e69   /* "info" */
 #define _path_ 0x68746170   /* "path" */
+#define _100r_ 0x72303031   /* "100r" */
+#define _time_ 0x656d6974   /* "time" */
 
 #define _pt_l_ 0x6c2d7470   /* "pt-l" */
 #define _angu_ 0x75676e61   /* "angu" */
diff --git a/parser/msg_parser.c b/parser/msg_parser.c
index 3ea8ad7..1631401 100644
--- a/parser/msg_parser.c
+++ b/parser/msg_parser.c
@@ -723,21 +723,37 @@ void free_reply_lump( struct lump_rpl *lump)
 /*only the content*/
 void free_sip_msg(struct sip_msg* const msg)
 {
-	if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; }
-	if (msg->dst_uri.s) { pkg_free(msg->dst_uri.s); msg->dst_uri.len=0; }
-	if (msg->path_vec.s) { pkg_free(msg->path_vec.s); msg->path_vec.len=0; }
+	reset_new_uri(msg);
+	reset_dst_uri(msg);
+	reset_path_vector(msg);
 	reset_instance(msg);
+	reset_ruid(msg);
+	reset_ua(msg);
 	if (msg->headers)     free_hdr_field_lst(msg->headers);
 	if (msg->body && msg->body->free) msg->body->free(&msg->body);
 	if (msg->add_rm)      free_lump_list(msg->add_rm);
 	if (msg->body_lumps)  free_lump_list(msg->body_lumps);
 	if (msg->reply_lump)   free_reply_lump(msg->reply_lump);
+	msg_ldata_reset(msg);
 	/* don't free anymore -- now a pointer to a static buffer */
 #	ifdef DYN_BUF
 	pkg_free(msg->buf);
 #	endif
 }
 
+/**
+ * reset new uri value
+ */
+void reset_new_uri(struct sip_msg* const msg)
+{
+	if(msg->new_uri.s != 0) {
+		pkg_free(msg->new_uri.s);
+	}
+	msg->new_uri.s = 0;
+	msg->new_uri.len = 0;
+	msg->parsed_uri_ok = 0;
+}
+
 
 /*
  * Make a private copy of the string and assign it to dst_uri
@@ -860,6 +876,94 @@ void reset_instance(struct sip_msg* const msg)
 }
 
 
+int set_ruid(struct sip_msg* msg, str* ruid)
+{
+	char* ptr;
+
+	if (unlikely(!msg || !ruid)) {
+		LM_ERR("invalid ruid parameter value\n");
+		return -1;
+	}
+
+	if (unlikely(ruid->len == 0)) {
+		reset_ruid(msg);
+	} else if (msg->ruid.s && (msg->ruid.len >= ruid->len)) {
+		memcpy(msg->ruid.s, ruid->s, ruid->len);
+		msg->ruid.len = ruid->len;
+	} else {
+		ptr = (char*)pkg_malloc(ruid->len);
+		if (!ptr) {
+			LM_ERR("not enough pkg memory for ruid\n");
+			return -1;
+		}
+		memcpy(ptr, ruid->s, ruid->len);
+		if (msg->ruid.s) pkg_free(msg->ruid.s);
+		msg->ruid.s = ptr;
+		msg->ruid.len = ruid->len;
+	}
+	return 0;
+}
+
+
+void reset_ruid(struct sip_msg* const msg)
+{
+	if(msg->ruid.s != 0) {
+		pkg_free(msg->ruid.s);
+	}
+	msg->ruid.s = 0;
+	msg->ruid.len = 0;
+}
+
+
+int set_ua(struct sip_msg* msg, str* location_ua)
+{
+	char* ptr;
+
+	if (unlikely(!msg || !location_ua)) {
+		LM_ERR("invalid location_ua parameter value\n");
+		return -1;
+	}
+
+	if (unlikely(location_ua->len == 0)) {
+		reset_ua(msg);
+	} else if (msg->location_ua.s && (msg->location_ua.len >= location_ua->len)) {
+		memcpy(msg->location_ua.s, location_ua->s, location_ua->len);
+		msg->location_ua.len = location_ua->len;
+	} else {
+		ptr = (char*)pkg_malloc(location_ua->len);
+		if (!ptr) {
+			LM_ERR("not enough pkg memory for location_ua\n");
+			return -1;
+		}
+		memcpy(ptr, location_ua->s, location_ua->len);
+		if (msg->location_ua.s) pkg_free(msg->location_ua.s);
+		msg->location_ua.s = ptr;
+		msg->location_ua.len = location_ua->len;
+	}
+	return 0;
+}
+
+
+void reset_ua(struct sip_msg* const msg)
+{
+	if(msg->location_ua.s != 0) {
+		pkg_free(msg->location_ua.s);
+	}
+	msg->location_ua.s = 0;
+	msg->location_ua.len = 0;
+}
+
+/**
+ * reset content of msg->ldv (msg_ldata_t structure)
+ */
+void msg_ldata_reset(sip_msg_t *msg)
+{
+	if(msg==NULL)
+		return;
+	memset(&msg->ldv, 0, sizeof(msg_ldata_t));
+}
+
+
 hdr_field_t* get_hdr(const sip_msg_t* const msg, const enum _hdr_types_t ht)
 {
 	hdr_field_t *hdr;
diff --git a/parser/msg_parser.h b/parser/msg_parser.h
index 15d557f..724ebef 100644
--- a/parser/msg_parser.h
+++ b/parser/msg_parser.h
@@ -120,6 +120,7 @@ typedef enum request_method {
 #define FL_USE_UAC_FROM      (1<<13)  /* take FROM hdr from UAC instead of UAS*/
 #define FL_USE_UAC_TO        (1<<14)  /* take TO hdr from UAC instead of UAS */
 #define FL_TM_RPL_MATCHED    (1<<15)  /* tm matched reply already */
+#define FL_RPL_SUSPENDED     (1<<16)  /* for async reply processing */
 
 /* WARNING: Value (1 << 28) is temporarily reserved for use in kamailio call_control
  * module (flag  FL_USE_CALL_CONTROL )! */
@@ -156,6 +157,16 @@ if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \
     !strncasecmp((req)->first_line.u.request.version.s,             \
 		SIP_VERSION, SIP_VERSION_LEN))
 
+#define IS_HTTP_REPLY(rpl)                                                \
+    ((rpl)->first_line.u.reply.version.len >= HTTP_VERSION_LEN && \
+    !strncasecmp((rpl)->first_line.u.reply.version.s,             \
+		HTTP_VERSION, HTTP_VERSION_LEN))
+
+#define IS_SIP_REPLY(rpl)                                                \
+    ((rpl)->first_line.u.reply.version.len >= SIP_VERSION_LEN && \
+    !strncasecmp((rpl)->first_line.u.reply.version.s,             \
+		SIP_VERSION, SIP_VERSION_LEN))
+
 /*! \brief
  * Return a URI to which the message should be really sent (not what should
  * be in the Request URI. The following fields are tried in this order:
@@ -253,6 +264,19 @@ typedef struct msg_body {
 /* pre-declaration, to include sys/time.h in .c */
 struct timeval;
 
+/* structure for cached decoded flow for outbound */
+typedef struct ocd_flow {
+		int decoded;
+		struct receive_info rcv;
+} ocd_flow_t;
+
+/* structure holding fields that don't have to be cloned in shm
+ * - its content is memset'ed to in shm clone
+ * - add to msg_ldata_reset() if a field uses dynamic memory */
+typedef struct msg_ldata {
+	ocd_flow_t flow;
+} msg_ldata_t;
+
 /*! \brief The SIP message */
 typedef struct sip_msg {
 	unsigned int id;               /*!< message id, unique/process*/
@@ -347,25 +371,31 @@ typedef struct sip_msg {
 	struct lump_rpl *reply_lump; /*!< only for localy generated replies !!!*/
 
 	/*! \brief str add_to_branch;
-	   whatever whoever want to append to branch comes here
-	*/
+	   whatever whoever want to append to Via branch comes here */
 	char add_to_branch_s[MAX_BRANCH_PARAM_LEN];
 	int add_to_branch_len;
 
 	unsigned int  hash_index; /*!< index to TM hash table; stored in core to avoid unnecessary calculations */
-	unsigned int msg_flags; /*!< flags used by core */
-	     /* allows to set various flags on the message; may be used for
-	      *	simple inter-module communication or remembering processing state
-	      * reached
-	      */
-	flag_t flags;
+	unsigned int msg_flags; /*!< internal flags used by core */
+	flag_t flags; /*!< config flags */
 	str set_global_address;
 	str set_global_port;
-	struct socket_info* force_send_socket; /* force sending on this socket,
-											  if ser */
+	struct socket_info* force_send_socket; /*!< force sending on this socket */
 	str path_vec;
 	str instance;
 	unsigned int reg_id;
+	str ruid;
+	str location_ua;
+
+	/* structure with fields that are needed for local processing
+	 * - not cloned to shm, reset to 0 in the clone */
+	msg_ldata_t ldv;
+
+	/* IMPORTANT: when adding new fields in this structure (sip_msg_t),
+	 * be sure it is freed in free_sip_msg() and it is cloned or reset
+	 * to shm structure for transaction - see sip_msg_clone.c. In tm
+	 * module, take care of these fields for faked environemt used for
+	 * runing failure handlers - see modules/tm/t_reply.c */
 } sip_msg_t;
 
 /*! \brief pointer to a fakes message which was never received ;
@@ -431,6 +461,8 @@ inline static char* get_body(struct sip_msg* const msg)
 	return msg->unparsed + offset;
 }
 
+/*! \brief If the new_uri is set, then reset it */
+void reset_new_uri(struct sip_msg* const msg);
 
 /*! \brief
  * Make a private copy of the string and assign it to dst_uri
@@ -454,6 +486,14 @@ int set_instance(struct sip_msg* msg, str* instance);
 
 void reset_instance(struct sip_msg* const msg);
 
+int set_ruid(struct sip_msg* msg, str* ruid);
+
+void reset_ruid(struct sip_msg* const msg);
+
+int set_ua(struct sip_msg* msg, str *location_ua);
+
+void reset_ua(struct sip_msg* const msg);
+
 /** force a specific send socket for forwarding a request.
  * @param msg - sip msg.
  * @param fsocket - forced socket, pointer to struct socket_info, can be 0 (in
@@ -497,4 +537,9 @@ int msg_ctx_id_match(const sip_msg_t* const msg, const msg_ctx_id_t* const mid);
  */
 int msg_set_time(sip_msg_t* const msg);
 
+/**
+ * reset content of msg->ldv (msg_ldata_t structure)
+ */
+void msg_ldata_reset(sip_msg_t*);
+
 #endif
diff --git a/parser/parse_addr_spec.c b/parser/parse_addr_spec.c
new file mode 100644
index 0000000..1820e6c
--- /dev/null
+++ b/parser/parse_addr_spec.c
@@ -0,0 +1,927 @@
+/*
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * ---------
+ * 2003-04-26 ZSW (jiri)
+ * 2010-03-03  fix multi-token no-quotes display name (andrei)
+ */
+
+/** Parser :: Parse To: header.
+ * @file
+ * @ingroup parser
+ */
+
+#include "parse_to.h"
+#include <stdlib.h>
+#include <string.h>
+#include "../dprint.h"
+#include "msg_parser.h"
+#include "parse_uri.h"
+#include "../ut.h"
+#include "../mem/mem.h"
+
+
+enum {
+	START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN,
+	DISPLAY_TOKEN_SP, S_URI_ENCLOSED, URI_ENCLOSED, E_URI_ENCLOSED,
+	URI_OR_TOKEN, MAYBE_URI_END, END, F_CR, F_LF, F_CRLF
+};
+
+
+enum {
+	S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2,
+	TAG3, PARA_VALUE_TOKEN , PARA_VALUE_QUOTED, E_PARA_VALUE
+};
+
+
+
+#define add_param( _param , _body , _newparam ) \
+	do{\
+		DBG("DEBUG: add_param: %.*s=%.*s\n",param->name.len,ZSW(param->name.s),\
+			param->value.len,ZSW(param->value.s));\
+		if (!(_body)->param_lst)  (_body)->param_lst=(_param);\
+		else (_body)->last_param->next=(_param);\
+		(_body)->last_param =(_param);\
+		if ((_param)->type==TAG_PARAM)\
+			memcpy(&((_body)->tag_value),&((_param)->value),sizeof(str));\
+		_newparam = 0;\
+	}while(0);
+
+
+
+
+
+static char* parse_to_param(char* const buffer, const char* const end,
+					struct to_body* const to_b, const int allow_comma_sep,
+					int* const returned_status)
+{
+	struct to_param *param;
+	struct to_param *newparam;
+	int status;
+	int saved_status;
+	char  *tmp;
+
+	param=0;
+	newparam=0;
+	status=E_PARA_VALUE;
+	saved_status=E_PARA_VALUE;
+	for( tmp=buffer; tmp<end; tmp++)
+	{
+		switch(*tmp)
+		{
+			case ' ':
+			case '\t':
+				switch (status)
+				{
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						status = S_EQUAL;
+						break;
+					case PARA_VALUE_TOKEN:
+						param->value.len = tmp-param->value.s;
+						status = E_PARA_VALUE;
+						add_param(param, to_b, newparam);
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now =' '*/
+						status=saved_status;
+						break;
+				}
+				break;
+			case '\n':
+				switch (status)
+				{
+					case S_PARA_NAME:
+					case S_EQUAL:
+					case S_PARA_VALUE:
+					case E_PARA_VALUE:
+						saved_status=status;
+						status=F_LF;
+						break;
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						saved_status = S_EQUAL;
+						status = F_LF;
+						break;
+					case PARA_VALUE_TOKEN:
+						param->value.len = tmp-param->value.s;
+						saved_status = E_PARA_VALUE;
+						status = F_LF;
+						add_param(param, to_b, newparam);
+						break;
+					case F_CR:
+						status=F_CRLF;
+						break;
+					case F_CRLF:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\r':
+				switch (status)
+				{
+					case S_PARA_NAME:
+					case S_EQUAL:
+					case S_PARA_VALUE:
+					case E_PARA_VALUE:
+						saved_status=status;
+						status=F_CR;
+						break;
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						saved_status = S_EQUAL;
+						status = F_CR;
+						break;
+					case PARA_VALUE_TOKEN:
+						param->value.len = tmp-param->value.s;
+						saved_status = E_PARA_VALUE;
+						status = F_CR;
+						add_param(param, to_b, newparam);
+						break;
+					case F_CRLF:
+					case F_CR:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 0:
+				switch (status)
+				{
+					case TAG3:
+						param->type = TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						status = S_EQUAL;
+					case S_EQUAL:
+					case S_PARA_VALUE:
+						saved_status=status;
+						goto endofheader;
+					case PARA_VALUE_TOKEN:
+						status = E_PARA_VALUE;
+						param->value.len = tmp-param->value.s;
+						add_param(param , to_b, newparam);
+					case E_PARA_VALUE:
+						saved_status = status;
+						goto endofheader;
+						break;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\\':
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+						switch (*(tmp+1))
+						{
+							case '\r':
+							case '\n':
+								break;
+							default:
+								tmp++;
+						}
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '"':
+				switch (status)
+				{
+					case S_PARA_VALUE:
+						param->value.s = tmp+1;
+						status = PARA_VALUE_QUOTED;
+						break;
+					case PARA_VALUE_QUOTED:
+						param->value.len=tmp-param->value.s;
+						add_param(param, to_b, newparam);
+						status = E_PARA_VALUE;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param :"
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status,(int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case ';' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+						break;
+					case TAG3:
+						param->type = TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+					case S_EQUAL:
+						param->value.s = 0;
+						param->value.len = 0;
+						goto semicolon_add_param;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+					case PARA_VALUE_TOKEN:
+						param->value.len=tmp-param->value.s;
+semicolon_add_param:
+						add_param(param, to_b, newparam);
+					case E_PARA_VALUE:
+						param = (struct to_param*)
+							pkg_malloc(sizeof(struct to_param));
+						if (!param){
+							LOG( L_ERR , "ERROR: parse_to_param"
+							" - out of memory\n" );
+							goto error;
+						}
+						memset(param,0,sizeof(struct to_param));
+						param->type=GENERAL_PARAM;
+						status = S_PARA_NAME;
+						/* link to free mem if not added in to_body list */
+						newparam = param;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param :"
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 'T':
+			case 't' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = TAG1;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case TAG1:
+					case TAG2:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param :"
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 'A':
+			case 'a' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = PARA_NAME;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case TAG1:
+						status = TAG2;
+						break;
+					case TAG2:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 'G':
+			case 'g' :
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = PARA_NAME;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case TAG1:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case TAG2:
+						status = TAG3;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '=':
+				switch (status)
+				{
+					case PARA_VALUE_QUOTED:
+						break;
+					case TAG3:
+						param->type=TAG_PARAM;
+					case PARA_NAME:
+					case TAG1:
+					case TAG2:
+						param->name.len = tmp-param->name.s;
+						status = S_PARA_VALUE;
+						break;
+					case S_EQUAL:
+						status = S_PARA_VALUE;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to_param : "
+							"unexpected char [%c] in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case ',':
+				if (allow_comma_sep)
+				{
+					switch (status)
+					{
+						case S_PARA_NAME:
+						case S_EQUAL:
+						case S_PARA_VALUE:
+						case E_PARA_VALUE:
+							saved_status=status;
+							status=E_PARA_VALUE;
+							goto endofheader;
+						case TAG3:
+							param->type=TAG_PARAM;
+						case PARA_NAME:
+						case TAG1:
+						case TAG2:
+							param->name.len = tmp-param->name.s;
+							saved_status = S_EQUAL;
+							status = E_PARA_VALUE;
+							goto endofheader;
+						case PARA_VALUE_TOKEN:
+							param->value.len = tmp-param->value.s;
+							saved_status = E_PARA_VALUE;
+							status = E_PARA_VALUE;
+							add_param(param, to_b, newparam);
+							goto endofheader;
+						case F_CRLF:
+						case F_CR:
+						case F_LF:
+							status=saved_status;
+							goto endofheader;
+						default:
+							LOG( L_ERR , "ERROR: parse_to_param : "
+								"unexpected char [%c] in status %d: <<%.*s>> .\n",
+								*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+							goto error;
+					}
+					break;
+				}
+				else
+				{
+					LOG( L_ERR, "ERROR parse_to_param : "
+							"invalid character ',' in status %d: <<%.*s>>\n",
+							status, (int)(tmp-buffer), ZSW(buffer));
+				}
+			default:
+				switch (status)
+				{
+					case TAG1:
+					case TAG2:
+					case TAG3:
+						status = PARA_NAME;
+						break;
+					case PARA_VALUE_TOKEN:
+					case PARA_NAME:
+					case PARA_VALUE_QUOTED:
+						break;
+					case S_PARA_NAME:
+						param->name.s = tmp;
+						status = PARA_NAME;
+						break;
+					case S_PARA_VALUE:
+						param->value.s = tmp;
+						status = PARA_VALUE_TOKEN;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG(L_ERR, "ERROR: parse_to_param: "
+							"spitting out [%c] in status %d\n",*tmp,status );
+						goto error;
+				}
+		}/*switch*/
+	}/*for*/
+	if (!(status==F_CR || status==F_LF || status==F_CRLF))
+		saved_status=status;
+
+
+endofheader:
+	switch(saved_status){
+		case TAG3:
+			param->type = TAG_PARAM; /* tag at the end */
+			/* no break */
+		case PARA_NAME:
+		case TAG1:
+		case TAG2:
+			param->name.len = tmp-param->name.s;
+			/* no break */
+		case S_EQUAL:
+			/* parameter without '=', e.g. foo */
+			param->value.s=0;
+			param->value.len=0;
+			add_param(param, to_b, newparam);
+			saved_status=E_PARA_VALUE;
+			break;
+		case S_PARA_VALUE:
+			/* parameter with null value, e.g. foo= */
+			param->value.s=tmp;
+			param->value.len=0;
+			add_param(param, to_b, newparam);
+			saved_status=E_PARA_VALUE;
+			break;
+		case PARA_VALUE_TOKEN:
+			param->value.len=tmp-param->value.s;
+			add_param(param, to_b, newparam);
+			saved_status=E_PARA_VALUE;
+			break;
+		case E_PARA_VALUE:
+			break;
+		default:
+			LOG( L_ERR , "ERROR: parse_to_param : unexpected end of header,"
+						" status %d: <<%.*s>> .\n",
+						saved_status, (int)(tmp-buffer), ZSW(buffer));
+			goto error;
+	}
+	*returned_status=saved_status;
+	return tmp;
+
+error:
+	if (newparam) pkg_free(newparam);
+	to_b->error=PARSE_ERROR;
+	*returned_status = status;
+	return tmp;
+}
+
+
+
+char* parse_addr_spec(char* const buffer, const char* const end, struct to_body* const to_b, const int allow_comma_sep)
+{
+	int status;
+	int saved_status;
+	char  *tmp,*foo;
+	
+	saved_status=START_TO; /* fixes gcc 4.x warning */
+	status=START_TO;
+	memset(to_b, 0, sizeof(struct to_body));
+	to_b->error=PARSE_OK;
+	foo=0;
+
+	for( tmp=buffer; tmp<end; tmp++)
+	{
+		switch(*tmp)
+		{
+			case ' ':
+			case '\t':
+				switch (status)
+				{
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now =' '*/
+						status=saved_status;
+						break;
+					case URI_ENCLOSED:
+						to_b->uri.len = tmp - to_b->uri.s;
+						status = E_URI_ENCLOSED;
+						break;
+					case URI_OR_TOKEN:
+						foo = tmp;
+						status = MAYBE_URI_END;
+						break;
+					case DISPLAY_TOKEN:
+						foo = tmp;
+						status = DISPLAY_TOKEN_SP;
+						break;
+				}
+				break;
+			case '\n':
+				switch (status)
+				{
+					case URI_OR_TOKEN:
+						foo = tmp;
+						status = MAYBE_URI_END;
+					case MAYBE_URI_END:
+					case DISPLAY_TOKEN_SP:
+					case E_DISPLAY_QUOTED:
+					case END:
+						saved_status=status;
+						status=F_LF;
+						break;
+					case DISPLAY_TOKEN:
+						foo=tmp;
+						saved_status=DISPLAY_TOKEN_SP;
+						status=F_LF;
+						break;
+					case F_CR:
+						status=F_CRLF;
+						break;
+					case F_CRLF:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\r':
+				switch (status)
+				{
+					case URI_OR_TOKEN:
+						foo = tmp;
+						status = MAYBE_URI_END;
+					case MAYBE_URI_END:
+					case DISPLAY_TOKEN_SP:
+					case E_DISPLAY_QUOTED:
+					case END:
+						saved_status=status;
+						status=F_CR;
+						break;
+					case DISPLAY_TOKEN:
+						foo=tmp;
+						saved_status=DISPLAY_TOKEN_SP;
+						status=F_CR;
+						break;
+					case F_CRLF:
+					case F_CR:
+					case F_LF:
+						status=saved_status;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case 0:
+				switch (status)
+				{
+					case URI_OR_TOKEN:
+					case MAYBE_URI_END:
+						to_b->uri.len = tmp - to_b->uri.s;
+					case END:
+						saved_status = status = END;
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '\\':
+				switch (status)
+				{
+					case DISPLAY_QUOTED:
+						tmp++; /* jump over next char */
+						break;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '<':
+				switch (status)
+				{
+					case START_TO:
+						to_b->body.s=tmp;
+						status = S_URI_ENCLOSED;
+						break;
+					case DISPLAY_QUOTED:
+						break;
+					case E_DISPLAY_QUOTED:
+						status = S_URI_ENCLOSED;
+						break;
+					case URI_OR_TOKEN:
+					case DISPLAY_TOKEN:
+						to_b->display.len=tmp-to_b->display.s;
+						status = S_URI_ENCLOSED;
+						break;
+					case DISPLAY_TOKEN_SP:
+					case MAYBE_URI_END:
+						to_b->display.len=foo-to_b->display.s;
+						status = S_URI_ENCLOSED;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '>':
+				switch (status)
+				{
+					case DISPLAY_QUOTED:
+						break;
+					case URI_ENCLOSED:
+						to_b->uri.len = tmp - to_b->uri.s;
+					case E_URI_ENCLOSED:
+						status = END;
+						foo = 0;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
+						goto error;
+				}
+				break;
+			case '"':
+				switch (status)
+				{
+					case START_TO:
+						to_b->body.s = tmp;
+						to_b->display.s = tmp;
+						status = DISPLAY_QUOTED;
+						break;
+					case DISPLAY_QUOTED:
+						status = E_DISPLAY_QUOTED;
+						to_b->display.len = tmp-to_b->display.s+1;
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), buffer);
+						goto error;
+				}
+				break;
+			case ';' :
+				switch (status)
+				{
+					case DISPLAY_QUOTED:
+					case URI_ENCLOSED:
+						break;
+					case URI_OR_TOKEN:
+						foo = tmp;
+					case MAYBE_URI_END:
+						to_b->uri.len = foo - to_b->uri.s;
+					case END:
+						to_b->body.len = tmp-to_b->body.s;
+						tmp = parse_to_param(tmp,end,to_b,allow_comma_sep,&saved_status);
+						goto endofheader;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+							"in status %d: <<%.*s>> .\n",
+							*tmp,status, (int)(tmp-buffer), buffer);
+						goto error;
+				}
+				break;
+			case ',' :
+				if (allow_comma_sep)
+				{
+					switch (status)
+					{
+						case DISPLAY_QUOTED:
+						case URI_ENCLOSED:
+							break;
+						case URI_OR_TOKEN:
+							foo = tmp;
+						case MAYBE_URI_END:
+							to_b->uri.len = foo - to_b->uri.s;
+						case END:
+							to_b->body.len = tmp-to_b->body.s;
+							saved_status = END;
+							goto endofheader;
+						case F_CRLF:
+						case F_LF:
+						case F_CR:
+							/*previous=crlf and now !=' '*/
+							goto endofheader;
+						default:
+							LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
+								"in status %d: <<%.*s>> .\n",
+								*tmp,status, (int)(tmp-buffer), buffer);
+							goto error;
+					}
+					break;
+				}
+				/* If commas not allowed treat as a default character */
+			default:
+				switch (status)
+				{
+					case START_TO:
+						to_b->uri.s = to_b->body.s = tmp;
+						status = URI_OR_TOKEN;
+						to_b->display.s=tmp;
+						break;
+					case S_URI_ENCLOSED:
+						to_b->uri.s=tmp;
+						status=URI_ENCLOSED;
+						break;
+					case MAYBE_URI_END:
+					case DISPLAY_TOKEN_SP:
+						status = DISPLAY_TOKEN;
+					case DISPLAY_QUOTED:
+					case DISPLAY_TOKEN:
+					case URI_ENCLOSED:
+					case URI_OR_TOKEN:
+						break;
+					case F_CRLF:
+					case F_LF:
+					case F_CR:
+						/*previous=crlf and now !=' '*/
+						goto endofheader;
+					default:
+						DBG("DEBUG:parse_to: spitting out [%c] in status %d\n",
+						*tmp,status );
+						goto error;
+				}
+		}/*char switch*/
+	}/*for*/
+
+	/* Reached end of buffer */
+	switch (status)
+	{
+		case URI_OR_TOKEN:
+		case MAYBE_URI_END:
+		case END:
+			saved_status = status;
+			foo = tmp;
+	}
+
+endofheader:
+	if (to_b->display.len==0) to_b->display.s=0;
+	status=saved_status;
+	DBG("end of header reached, state=%d\n", status);
+	/* check if error*/
+	switch(status){
+		case URI_OR_TOKEN:
+		case MAYBE_URI_END:
+			to_b->uri.len = foo - to_b->uri.s;
+		case END:
+			to_b->body.len = tmp - to_b->body.s;
+		case E_PARA_VALUE:
+			break;
+		default:
+			LOG(L_ERR, "ERROR: parse_to: invalid To -  unexpected "
+					"end of header in state %d\n", status);
+			goto error;
+	}
+	return tmp;
+
+error:
+	to_b->error=PARSE_ERROR;
+	return tmp;
+
+}
+
+
+void free_to_params(struct to_body* const tb)
+{
+	struct to_param *tp=tb->param_lst;
+	struct to_param *foo;
+	while (tp){
+		foo = tp->next;
+		pkg_free(tp);
+		tp=foo;
+	}
+	tb->param_lst = NULL;
+}
+
+
+void free_to(struct to_body* const tb)
+{
+	free_to_params(tb);
+	pkg_free(tb);
+}
+
diff --git a/parser/parse_addr_spec.h b/parser/parse_addr_spec.h
new file mode 100644
index 0000000..f23fcb0
--- /dev/null
+++ b/parser/parse_addr_spec.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2001-2003 Fhg Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*! \file
+ * \brief Parser :: Parse addr-spec
+ *
+ * \ingroup parser
+ */
+
+#ifndef PARSE_ADDR_SPEC
+#define PARSE_ADDR_SPEC
+
+#include "../str.h"
+#include "msg_parser.h"
+
+enum {
+	TAG_PARAM = 400, GENERAL_PARAM
+};
+
+typedef struct to_param{
+	int type;              /*!< Type of parameter */
+	str name;              /*!< Name of parameter */
+	str value;             /*!< Parameter value */
+	struct to_param* next; /*!< Next parameter in the list */
+} to_param_t;
+
+
+typedef struct to_body{
+	int error;                    /*!< Error code */
+	str body;                     /*!< The whole header field body */
+	str uri;                      /*!< URI */
+	str display;				  /*!< Display Name */
+	str tag_value;                /*!< Value of tag */
+	struct sip_uri parsed_uri;
+	struct to_param *param_lst;   /*!< Linked list of parameters */
+	struct to_param *last_param;  /*!< Last parameter in the list */
+} to_body_t;
+
+
+/*! \brief
+ * To header field parser
+ */
+char* parse_addr_spec(char* const buffer, const char* const end, struct to_body* const to_b, int allow_comma_separated);
+
+void free_to_params(struct to_body* const tb);
+
+void free_to(struct to_body* const tb);
+
+int parse_to_header(struct sip_msg* const msg);
+
+sip_uri_t *parse_to_uri(struct sip_msg* const msg);
+
+#endif
diff --git a/parser/parse_body.h b/parser/parse_body.h
index a8c4f92..ff50d8b 100644
--- a/parser/parse_body.h
+++ b/parser/parse_body.h
@@ -42,7 +42,7 @@ char *get_body_part(	struct sip_msg *msg,
 			int *len);
 
 /*! \brief Returns the pointer within the msg body to the given part matching
- * type/subtype, content id or content lenght. It sets the length.
+ * type/subtype, content id or content length. It sets the length.
  * The result can be the whole msg body, or a part of a multipart body.
  */
 char *get_body_part_by_filter(struct sip_msg *msg,
diff --git a/parser/parse_content.c b/parser/parse_content.c
index 6c704a4..51347e8 100644
--- a/parser/parse_content.c
+++ b/parser/parse_content.c
@@ -204,11 +204,15 @@ static type_node_t subtype_tree[] = {
 											{'o',SUBTYPE_UNKNOWN,1,-1},
 												{'d',SUBTYPE_UNKNOWN,1,-1},
 													{'y',SUBTYPE_EXTERNAL_BODY,0,-1},
-	{'m',SUBTYPE_UNKNOWN,1,-1}, /* 107 */
+	{'m',SUBTYPE_UNKNOWN,1,112}, /* 107 */
 		{'i',SUBTYPE_UNKNOWN,1,-1},
 			{'x',SUBTYPE_UNKNOWN,1,-1},
 				{'e',SUBTYPE_UNKNOWN,1,-1},
 					{'d',SUBTYPE_MIXED,0,-1},
+	{'i',SUBTYPE_UNKNOWN,1,-1}, /* 112 */
+		{'s',SUBTYPE_UNKNOWN,1,-1},
+			{'u',SUBTYPE_UNKNOWN,1,-1},
+				{'p',SUBTYPE_ISUP,0,-1},
 };
 
 
diff --git a/parser/parse_content.h b/parser/parse_content.h
index 6b03ce5..eb67f60 100644
--- a/parser/parse_content.h
+++ b/parser/parse_content.h
@@ -64,6 +64,7 @@ struct mime_type {
 #define SUBTYPE_XML_MSRTC_PIDF     12
 #define SUBTYPE_CPIM_PIDFXML       13
 #define SUBTYPE_MIXED              14
+#define SUBTYPE_ISUP               15
 #define SUBTYPE_ALL          0xfe
 #define SUBTYPE_UNKNOWN      0xff
 
diff --git a/parser/parse_fline.c b/parser/parse_fline.c
index 25ab944..8dacfe5 100644
--- a/parser/parse_fline.c
+++ b/parser/parse_fline.c
@@ -45,7 +45,7 @@
 #include "../mem/mem.h"
 #include "../ut.h"
 
-int http_reply_hack = 0;
+int http_reply_parse = 0;
 
 /* grammar:
 	request  =  method SP uri SP version CRLF
@@ -98,7 +98,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
 			fl->type=SIP_REPLY;
 			fl->u.reply.version.len=SIP_VERSION_LEN;
 			tmp=buffer+SIP_VERSION_LEN;
-	} else if (http_reply_hack != 0 && 
+	} else if (http_reply_parse != 0 &&
 		 	(*tmp=='H' || *tmp=='h') &&
 			/* 'HTTP/1.' */
 			strncasecmp( tmp+1, HTTP_VERSION+1, HTTP_VERSION_LEN-1)==0 &&
@@ -225,21 +225,21 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
 	return nl;
 
 error:
-	LOG(L_INFO, "ERROR:parse_first_line: bad %s first line\n",
+	LOG(L_DBG, "parse_first_line: bad %s first line\n",
 		(fl->type==SIP_REPLY)?"reply(status)":"request");
 
-	LOG(L_INFO, "ERROR: at line 0 char %d: \n", offset );
+	LOG(L_DBG, "at line 0 char %d: \n", offset );
 	prn=pkg_malloc( offset );
 	if (prn) {
 		for (t=0; t<offset; t++)
 			if (*(buffer+t)) *(prn+t)=*(buffer+t);
 			else *(prn+t)='�';
-		LOG(L_INFO, "ERROR: parsed so far: %.*s\n", offset, ZSW(prn) );
+		LOG(L_DBG, "parsed so far: %.*s\n", offset, ZSW(prn) );
 		pkg_free( prn );
 	};
 error1:
 	fl->type=SIP_INVALID;
-	LOG(L_INFO, "ERROR:parse_first_line: bad message\n");
+	LOG(L_ERR, "parse_first_line: bad message\n");
 	/* skip  line */
 	nl=eat_line(buffer,len);
 	return nl;
diff --git a/parser/parse_option_tags.c b/parser/parse_option_tags.c
new file mode 100644
index 0000000..e28e1d0
--- /dev/null
+++ b/parser/parse_option_tags.c
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../mem/mem.h"
+#include "parse_option_tags.h"
+
+static inline void free_option_tag(struct option_tag_body **otb)
+{
+	if (otb && *otb) {
+		pkg_free(*otb);
+		*otb = 0;
+	}
+}
+
+void hf_free_option_tag(void *parsed)
+{
+	struct option_tag_body *otb;
+	otb = (struct option_tag_body *) parsed;
+	free_option_tag(&otb);
+}
diff --git a/parser/parse_option_tags.h b/parser/parse_option_tags.h
new file mode 100644
index 0000000..c41ce63
--- /dev/null
+++ b/parser/parse_option_tags.h
@@ -0,0 +1,166 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
+ * 
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef OPTION_TAGS_H
+#define OPTION_TAGS_H
+
+#include <strings.h>
+#include "hf.h"
+#include "keys.h"
+
+#define F_OPTION_TAG_PATH	(1 << 0)
+#define F_OPTION_TAG_100REL	(1 << 1)
+#define F_OPTION_TAG_TIMER	(1 << 2)
+#define F_OPTION_TAG_EVENTLIST	(1 << 3)
+#define F_OPTION_TAG_GRUU	(1 << 4)
+#define F_OPTION_TAG_OUTBOUND	(1 << 5)
+
+#define OPTION_TAG_PATH_STR		"path"
+#define OPTION_TAG_PATH_LEN		(sizeof(OPTION_TAG_PATH_STR)-1)
+
+/* RFC 3262 (PRACK) */
+#define OPTION_TAG_100REL_STR		"100rel"
+#define OPTION_TAG_100REL_LEN		(sizeof(OPTION_TAG_100REL_STR)-1)
+
+/* RFC 4028 */
+#define OPTION_TAG_TIMER_STR		"timer"
+#define OPTION_TAG_TIMER_LEN		(sizeof(OPTION_TAG_TIMER_STR)-1)
+
+/* RFC 4662 (RLS) */
+#define OPTION_TAG_EVENTLIST_STR	"eventlist"
+#define OPTION_TAG_EVENTLIST_LEN	(sizeof(OPTION_TAG_EVENTLIST_STR)-1)
+
+/* RFC 5627 */
+#define OPTION_TAG_GRUU_STR		"gruu"
+#define OPTION_TAG_GRUU_LEN		(sizeof(OPTION_TAG_GRUU_STR)-1)
+
+/* RFC 5626 */
+#define OPTION_TAG_OUTBOUND_STR		"outbound"
+#define OPTION_TAG_OUTBOUND_LEN		(sizeof(OPTION_TAG_OUTBOUND_STR)-1)
+
+
+struct option_tag_body {
+	hf_parsed_free_f hfree;        /* function to free the content */
+	unsigned int option_tags;      /* option-tag mask for the current hdr */
+	unsigned int option_tags_all;  /* option-tag mask for the all hdr
+	                                *  - it's set only for the first hdr in 
+	                                *  sibling list*/
+};
+
+
+#define IS_DELIM(c) (*(c) == ' ' || *(c) == '\t' || *(c) == '\r' || *(c) == '\n' || *(c) == ',')
+
+/* from parser/parse_hname2.c: */
+#define LOWER_BYTE(b) ((b) | 0x20)
+#define LOWER_DWORD(d) ((d) | 0x20202020)
+#define READ(val) \
+	(*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
+
+/*!
+ * Parse HF body containing option-tags.
+ */
+static inline int parse_option_tag_body(str *body, unsigned int *tags)
+{
+	register char* p;
+	register unsigned int val;
+	int len, pos = 0;
+
+	*tags = 0;
+
+	p = body->s;
+	len = body->len;
+
+	while (pos < len) {
+		/* skip spaces and commas */
+		for (; pos < len && IS_DELIM(p); ++pos, ++p);
+
+		val = LOWER_DWORD(READ(p));
+		switch (val) {
+
+			/* "path" */
+			case _path_:
+				if(pos + 4 <= len && IS_DELIM(p+4)) {
+					*tags |= F_OPTION_TAG_PATH;
+					pos += 5; p += 5;
+				}
+				break;
+
+			/* "100rel" */
+			case _100r_:
+				if ( pos+6 <= len
+					 && LOWER_BYTE(*(p+4))=='e' && LOWER_BYTE(*(p+5))=='l'
+					 && IS_DELIM(p+6)) {
+					*tags |= F_OPTION_TAG_100REL;
+					pos += OPTION_TAG_100REL_LEN + 1;
+					p   += OPTION_TAG_100REL_LEN + 1;
+				}
+				break;
+
+			/* "timer" */
+			case _time_:
+				if ( pos+5 <= len && LOWER_BYTE(*(p+4))=='r'
+					 && IS_DELIM(p+5) ) {
+					*tags |= F_OPTION_TAG_TIMER;
+					pos += OPTION_TAG_TIMER_LEN + 1;
+					p   += OPTION_TAG_TIMER_LEN + 1;
+				}
+				break;
+
+			/* extra require or unknown */
+			default:
+				if(pos+OPTION_TAG_EVENTLIST_LEN<=len
+						&& strncasecmp(p, OPTION_TAG_EVENTLIST_STR,
+							OPTION_TAG_EVENTLIST_LEN)==0
+						&& IS_DELIM(p+OPTION_TAG_EVENTLIST_LEN) ) {
+					*tags |= F_OPTION_TAG_EVENTLIST;
+					pos += OPTION_TAG_EVENTLIST_LEN + 1;
+					p   += OPTION_TAG_EVENTLIST_LEN + 1;
+				} else if(pos+OPTION_TAG_GRUU_LEN<=len
+						&& strncasecmp(p, OPTION_TAG_GRUU_STR,
+							OPTION_TAG_GRUU_LEN)==0
+						&& IS_DELIM(p+OPTION_TAG_GRUU_LEN)) {
+					*tags |= F_OPTION_TAG_GRUU;
+					pos += OPTION_TAG_GRUU_LEN + 1;
+					p   += OPTION_TAG_GRUU_LEN + 1;
+				} else if(pos+OPTION_TAG_OUTBOUND_LEN<=len
+						&& strncasecmp(p, OPTION_TAG_OUTBOUND_STR,
+							OPTION_TAG_OUTBOUND_LEN)==0
+						&& IS_DELIM(p+OPTION_TAG_OUTBOUND_LEN)) {
+					*tags |= F_OPTION_TAG_OUTBOUND;
+					pos += OPTION_TAG_OUTBOUND_LEN + 1;
+					p   += OPTION_TAG_OUTBOUND_LEN + 1;
+				} else {
+					/* skip element */
+					for (; pos < len && !IS_DELIM(p); ++pos, ++p);
+				}
+				break;
+		}
+	}
+	
+	return 0;
+}
+
+
+void hf_free_option_tag(void *parsed);
+
+#endif /* OPTION_TAGS_H */
diff --git a/parser/parse_param.c b/parser/parse_param.c
index ac22387..45ca4e8 100644
--- a/parser/parse_param.c
+++ b/parser/parse_param.c
@@ -331,7 +331,7 @@ static inline int parse_quoted_param(str* _s, str* _r)
  * let _r point to the token and update _s
  * to point right behind the token
  */
-static inline int parse_token_param(str* _s, str* _r)
+static inline int parse_token_param(str* _s, str* _r, char separator)
 {
 	int i;
 
@@ -361,12 +361,14 @@ static inline int parse_token_param(str* _s, str* _r)
 		case '\r':
 		case '\n':
 		case ',':
-		case ';':
 			     /* So if you find
 			      * any of them
 			      * stop iterating
 			      */
 			goto out;
+		default:
+			if(_s->s[i] == separator)
+				goto out;
 		}
 	}
  out:
@@ -391,7 +393,7 @@ static inline int parse_token_param(str* _s, str* _r)
 /*! \brief
  * Parse a parameter name
  */
-static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p)
+static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p, char separator)
 {
 
 	if (!_s->s) {
@@ -407,10 +409,12 @@ static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, par
 		case '\t':
 		case '\r':
 		case '\n':
-		case ';':
 		case ',':
 		case '=':
 			goto out;
+		default:
+			if (_s->s[0] == separator)
+				goto out;
 		}
 		_s->s++;
 		_s->len--;
@@ -435,7 +439,7 @@ static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, par
  * Parse body of a parameter. It can be quoted string or
  * a single token.
  */
-static inline int parse_param_body(str* _s, param_t* _c)
+static inline int parse_param_body(str* _s, param_t* _c, char separator)
 {
 	if (_s->s[0] == '\"' || _s->s[0] == '\'') {
 		if (parse_quoted_param(_s, &(_c->body)) < 0) {
@@ -443,7 +447,7 @@ static inline int parse_param_body(str* _s, param_t* _c)
 			return -2;
 		}
 	} else {
-		if (parse_token_param(_s, &(_c->body)) < 0) {
+		if (parse_token_param(_s, &(_c->body), separator) < 0) {
 			LOG(L_ERR, "parse_param_body(): Error while parsing token\n");
 			return -3;
 		}
@@ -453,6 +457,8 @@ static inline int parse_param_body(str* _s, param_t* _c)
 }
 
 
+
+
 /*!  \brief
  * Only parse one parameter
  * Returns:
@@ -461,11 +467,11 @@ static inline int parse_param_body(str* _s, param_t* _c)
  * 	0: success, but expect a next paramter
  * 	1: success and exepect no more parameters
  */
-inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
+static inline int parse_param2(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t, char separator)
 {
 	memset(t, 0, sizeof(param_t));
 
-	parse_param_name(_s, _c, _h, t);
+	parse_param_name(_s, _c, _h, t, separator);
 	trim_leading(_s);
 	
 	if (_s->len == 0) { /* The last parameter without body */
@@ -483,7 +489,7 @@ inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
 		     * we just set the length of parameter body to 0. */
 		    t->body.s = _s->s;
 		    t->body.len = 0;
-		} else if (parse_param_body(_s, t) < 0) {
+		} else if (parse_param_body(_s, t, separator) < 0) {
 			LOG(L_ERR, "parse_params(): Error while parsing param body\n");
 			goto error;
 		}
@@ -501,8 +507,9 @@ inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
 	if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */
 	if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */
 
-	if (_s->s[0] != ';') {
-		LOG(L_ERR, "parse_params(): Invalid character, ; expected\n");
+	if (_s->s[0] != separator) {
+		LOG(L_ERR, "parse_params(): Invalid character, %c expected\n",
+			separator);
 		goto error;
 	}
 
@@ -511,7 +518,8 @@ inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
 	trim_leading(_s);
 	
 	if (_s->len == 0) {
-		LOG(L_ERR, "parse_params(): Param name missing after ;\n");
+		LOG(L_ERR, "parse_params(): Param name missing after %c\n",
+				separator);
 		goto error;
 	}
 
@@ -523,7 +531,18 @@ error:
 	return -1;
 }
 
-
+/*!  \brief
+ * Only parse one parameter
+ * Returns:
+ * 	t: out parameter
+ * 	-1: on error
+ * 	0: success, but expect a next paramter
+ * 	1: success and exepect no more parameters
+ */
+inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
+{
+	return parse_param2(_s, _c, _h, t, ';');
+}
 
 /*! \brief
  * Parse parameters
@@ -535,6 +554,21 @@ error:
  */
 int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
 {
+	return parse_params2(_s, _c, _h, _p, ';');
+}
+
+/*! \brief
+ * Parse parameters with configurable separator
+ * \param _s is string containing parameters, it will be updated to point behind the parameters
+ * \param _c is class of parameters
+ * \param _h is pointer to structure that will be filled with pointer to well known parameters
+ * \param _p pointing to linked list where parsed parameters will be stored
+ * \param separator single character separator
+ * \return 0 on success and negative number on an error
+ */
+int parse_params2(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p,
+			char separator)
+{
 	param_t* t;
 
 	if (!_s || !_p) {
@@ -558,7 +592,7 @@ int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
 			goto error;
 		}
 
-		switch(parse_param(_s, _c, _h, t)) {
+		switch(parse_param2(_s, _c, _h, t, separator)) {
 		case 0: break;
 		case 1: goto ok;
 		default: goto error;
diff --git a/parser/parse_param.h b/parser/parse_param.h
index d544f62..f91a1a2 100644
--- a/parser/parse_param.h
+++ b/parser/parse_param.h
@@ -167,6 +167,19 @@ extern inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *
  */
 int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p);
 
+/*! \brief
+ * Parse parameters
+ *  \param _s is string containing parameters
+ *  \param _c is class of parameters
+ *  \param _h is pointer to structure that will be filled with pointer to well known parameters
+ * linked list of parsed parameters will be stored in the variable _p is pointing to
+ * \param separator single character separator
+ * \return The function returns 0 on success and negative number
+ * on an error
+ */
+int parse_params2(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p,
+			char separator);
+
 
 /*! \brief
  * Free linked list of parameters
diff --git a/parser/parse_ppi_pai.c b/parser/parse_ppi_pai.c
new file mode 100644
index 0000000..f1b8d91
--- /dev/null
+++ b/parser/parse_ppi_pai.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2013 Hugh Waite
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * ---------
+ * 2013-03-06 Created (hpw)
+ */
+
+/** Parser :: Parse P-Asserted-Identity: header.
+ * @file
+ * @ingroup parser
+ */
+
+#include "parse_ppi_pai.h"
+#include <stdlib.h>
+#include <string.h>
+#include "../dprint.h"
+#include "msg_parser.h"
+#include "parse_uri.h"
+#include "../ut.h"
+#include "../mem/mem.h"
+
+/* 
+ * A P-Asserted-Identity or P-Preferred-Identity header value is an addr-spec or name-addr
+ * There can be only one of any URI scheme (sip(s), tel etc), which may occur on separate
+ * headers or can be comma separated in a single header.
+ * RFC3325 only mentions sip(s) and tel schemes, but there is no reason why other schemes
+ * cannot be used in the future.
+ */
+
+/*!
+ *
+ */
+#define NUM_PAI_BODIES 10
+int parse_pai_ppi_body(char *buf, int len, p_id_body_t **body)
+{
+	static to_body_t uri_b[NUM_PAI_BODIES]; /* Temporary storage */
+	int num_uri = 0;
+	char *tmp;
+	int i;
+	memset(uri_b, 0, NUM_PAI_BODIES * sizeof(to_body_t));
+
+	tmp = parse_addr_spec(buf, buf+len, &uri_b[num_uri], 1);
+	if (uri_b[num_uri].error == PARSE_ERROR)
+	{
+		LM_ERR("Error parsing PAI/PPI body %u '%.*s'\n", num_uri, len, buf);
+		return -1;
+	}
+	num_uri++;
+	while ((*tmp == ',') && (num_uri < NUM_PAI_BODIES))
+	{
+		tmp++;
+		tmp = parse_addr_spec(tmp, buf+len, &uri_b[num_uri], 1);
+		if (uri_b[num_uri].error == PARSE_ERROR)
+		{
+			LM_ERR("Error parsing PAI/PPI body %u '%.*s'\n", num_uri, len, buf);
+			return -1;
+		}
+		num_uri++;
+	}
+	if (num_uri >= NUM_PAI_BODIES)
+	{
+		LM_WARN("Too many bodies in PAI/PPI header '%.*s'\n", len, buf);
+		LM_WARN("Ignoring bodies beyond %u\n", NUM_PAI_BODIES);
+	}
+	*body = pkg_malloc(sizeof(p_id_body_t) + num_uri * sizeof(to_body_t));
+	if (*body == NULL)
+	{
+		LM_ERR("No pkg memory for pai/ppi body\n");
+		return -1;
+	}
+	memset(*body, 0, sizeof(p_id_body_t));
+	(*body)->id = (to_body_t*)((char*)(*body) + sizeof(p_id_body_t));
+	(*body)->num_ids = num_uri;
+	for (i=0; i< num_uri; i++)
+	{
+		memcpy(&(*body)->id[i], &uri_b[i], sizeof(to_body_t));
+	}
+	return 0;
+}
+
+int free_pai_ppi_body(p_id_body_t *pid_b)
+{
+	if (pid_b != NULL)
+	{
+		pkg_free(pid_b);
+	}
+	return 0;
+}
+
+/*!
+ * \brief Parse all P-Asserted-Identity headers
+ * \param msg The SIP message structure
+ * \return 0 on success, -1 on failure
+ */
+int parse_pai_header(struct sip_msg* const msg)
+{
+	p_id_body_t *pai_b;
+	p_id_body_t **prev_pid_b;
+	hdr_field_t *hf;
+	void **vp;
+
+	if ( !msg->pai )
+	{
+		if (parse_headers(msg, HDR_PAI_F, 0) < 0)
+		{
+			LM_ERR("Error parsing PAI header\n");
+			return -1;
+		}
+		if ( !msg->pai )
+			/* No PAI headers */
+			return -1;
+	}
+
+	if ( msg->pai->parsed )
+		return 0;
+
+	vp = &msg->pai->parsed;
+	prev_pid_b = (p_id_body_t**)vp;
+
+	for (hf = msg->pai; hf != NULL; hf = next_sibling_hdr(hf))
+	{
+		if (parse_pai_ppi_body(hf->body.s, hf->body.len, &pai_b) < 0)
+		{
+			return -1;
+		}
+		hf->parsed = (void*)pai_b;
+		*prev_pid_b = pai_b;
+		prev_pid_b = &pai_b->next;
+
+		if (parse_headers(msg, HDR_PAI_F, 1) < 0)
+		{
+			LM_ERR("Error looking for subsequent PAI header");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*!
+ * \brief Parse all P-Preferred-Identity headers
+ * \param msg The SIP message structure
+ * \return 0 on success, -1 on failure
+ */
+int parse_ppi_header(struct sip_msg* const msg)
+{
+	p_id_body_t *ppi_b, *prev_pidb;
+	hdr_field_t *hf;
+
+	if ( !msg->ppi )
+	{
+		if (parse_headers(msg, HDR_PPI_F, 0) < 0)
+		{
+			LM_ERR("Error parsing PPI header\n");
+			return -1;
+		}
+		if ( !msg->ppi )
+			/* No PPI headers */
+			return -1;
+	}
+
+	if ( msg->ppi->parsed )
+		return 0;
+
+	if (parse_pai_ppi_body(msg->ppi->body.s, msg->ppi->body.len, &ppi_b) < 0)
+	{
+		return -1;
+	}
+	msg->ppi->parsed = (void*)ppi_b;
+
+	if (parse_headers(msg, HDR_PPI_F, 1) < 0)
+	{
+		LM_ERR("Error looking for subsequent PPI header");
+		return -1;
+	}
+	prev_pidb = ppi_b;
+	hf = msg->ppi;
+
+	if ((hf = next_sibling_hdr(hf)) != NULL)
+	{
+		if (parse_pai_ppi_body(hf->body.s, hf->body.len, &ppi_b) < 0)
+		{
+			return -1;
+		}
+		hf->parsed = (void*)ppi_b;
+
+		if (parse_headers(msg, HDR_PPI_F, 1) < 0)
+		{
+			LM_ERR("Error looking for subsequent PPI header");
+			return -1;
+		}
+		prev_pidb->next = ppi_b;
+		prev_pidb = ppi_b;
+	}
+	return 0;
+}
+
diff --git a/parser/parse_ppi_pai.h b/parser/parse_ppi_pai.h
new file mode 100644
index 0000000..28bec2f
--- /dev/null
+++ b/parser/parse_ppi_pai.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Hugh Waite
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*! \file
+ * \brief Parser :: Parse P-Asserted-Identity: header
+ *
+ * \ingroup parser
+ */
+
+#ifndef PARSE_PAI_PPI_H
+#define PARSE_PAI_PPI_H
+
+#include "../str.h"
+#include "msg_parser.h"
+#include "parse_to.h"
+
+typedef struct p_id_body {
+	to_body_t *id;
+	int num_ids;
+	struct p_id_body *next;
+} p_id_body_t;
+
+int parse_pai_header(struct sip_msg* const msg);
+int parse_ppi_header(struct sip_msg* const msg);
+
+/*! casting macro for accessing P-Asserted-Identity body */
+#define get_pai(p_msg)  ((p_id_body_t*)(p_msg)->pai->parsed)
+
+/*! casting macro for accessing P-Preferred-Identity body */
+#define get_ppi(p_msg)  ((p_id_body_t*)(p_msg)->ppi->parsed)
+
+int free_pai_ppi_body(p_id_body_t *pid_b);
+
+#endif
diff --git a/parser/parse_require.c b/parser/parse_require.c
new file mode 100644
index 0000000..6c24598
--- /dev/null
+++ b/parser/parse_require.c
@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
+ * 
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*!
+ * \file
+ * \brief Require parser
+ * \ingroup parser
+ */
+
+#include "../mem/mem.h"
+#include "parse_require.h"
+
+/*!
+ * Parse all Require headers
+ */
+int parse_require( struct sip_msg *msg)
+{
+	unsigned int require;
+	struct hdr_field  *hdr;
+	struct option_tag_body *rb;
+
+	/* maybe the header is already parsed! */
+	if (msg->require && msg->require->parsed)
+		return 0;
+
+	/* parse to the end in order to get all SUPPORTED headers */
+	if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->require)
+		return -1;
+
+	/* bad luck! :-( - we have to parse them */
+	require = 0;
+	for( hdr=msg->require ; hdr ; hdr=next_sibling_hdr(hdr)) {
+		if (hdr->parsed) {
+			require |= ((struct option_tag_body*)hdr->parsed)->option_tags;
+			continue;
+		}
+
+		rb = (struct option_tag_body*)pkg_malloc(sizeof(struct option_tag_body));
+		if (rb == 0) {
+			LM_ERR("out of pkg_memory\n");
+			return -1;
+		}
+
+		parse_option_tag_body(&(hdr->body), &(rb->option_tags));
+		rb->hfree = hf_free_option_tag;
+		rb->option_tags_all = 0;
+		hdr->parsed = (void*)rb;
+		require |= rb->option_tags;
+	}
+
+	((struct option_tag_body*)msg->require->parsed)->option_tags_all = 
+		require;
+	return 0;
+}
diff --git a/parser/parse_require.h b/parser/parse_require.h
new file mode 100644
index 0000000..3ffaf10
--- /dev/null
+++ b/parser/parse_require.h
@@ -0,0 +1,50 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Require parser
+ * \ingroup parser
+ */
+
+#ifndef PARSE_REQUIRE_H
+#define PARSE_REQUIRE_H
+
+#include "msg_parser.h"
+#include "hf.h"
+#include "../mem/mem.h"
+#include "parse_option_tags.h"
+
+#define get_require(p_msg) \
+	((p_msg)->require ? ((struct option_tag_body*)(p_msg)->require->parsed)->option_tags_all : 0)
+
+
+/*!
+ * Parse all Require headers.
+ */
+int parse_require( struct sip_msg *msg);
+
+
+void free_require(struct option_tag_body **rb);
+
+#endif /* PARSE_REQUIRE_H */
diff --git a/parser/parse_supported.c b/parser/parse_supported.c
new file mode 100644
index 0000000..a69bd1d
--- /dev/null
+++ b/parser/parse_supported.c
@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*!
+ * \file
+ * \brief Supported parser
+ * \ingroup parser
+ */
+
+#include "../mem/mem.h"
+#include "parse_supported.h"
+
+/*!
+ * Parse all Supported headers
+ */
+int parse_supported( struct sip_msg *msg)
+{
+	unsigned int supported;
+	struct hdr_field  *hdr;
+	struct option_tag_body *sb;
+
+	/* maybe the header is already parsed! */
+	if (msg->supported && msg->supported->parsed)
+		return 0;
+
+	/* parse to the end in order to get all SUPPORTED headers */
+	if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->supported)
+		return -1;
+
+	/* bad luck! :-( - we have to parse them */
+	supported = 0;
+	for( hdr=msg->supported ; hdr ; hdr=next_sibling_hdr(hdr)) {
+		if (hdr->parsed) {
+			supported |= ((struct option_tag_body*)hdr->parsed)->option_tags;
+			continue;
+		}
+
+		sb = (struct option_tag_body*)pkg_malloc(sizeof(struct option_tag_body));
+		if (sb == 0) {
+			LM_ERR("out of pkg_memory\n");
+			return -1;
+		}
+
+		parse_option_tag_body(&(hdr->body), &(sb->option_tags));
+		sb->hfree = hf_free_option_tag;
+		sb->option_tags_all = 0;
+		hdr->parsed = (void*)sb;
+		supported |= sb->option_tags;
+	}
+
+	((struct option_tag_body*)msg->supported->parsed)->option_tags_all = 
+		supported;
+	return 0;
+}
diff --git a/parser/parse_supported.h b/parser/parse_supported.h
new file mode 100644
index 0000000..fb664c3
--- /dev/null
+++ b/parser/parse_supported.h
@@ -0,0 +1,54 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 Andreas Granig <agranig at linguin.org>
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * History:
+ * -------
+ * 2006-03-02  parse_supported() parses and cumulates all SUPPORTED 
+ *             headers (bogdan)
+ */
+
+/*!
+ * \file
+ * \brief Supported parser
+ * \ingroup parser
+ */
+
+#ifndef PARSE_SUPPORTED_H
+#define PARSE_SUPPORTED_H
+
+#include "msg_parser.h"
+#include "../mem/mem.h"
+#include "parse_option_tags.h"
+
+#define get_supported(p_msg) \
+	((p_msg)->supported ? ((struct option_tag_body*)(p_msg)->supported->parsed)->option_tags_all : 0)
+
+
+/*!
+ * Parse all Supported headers.
+ */
+int parse_supported( struct sip_msg *msg);
+
+
+void free_supported(struct option_tag_body **sb);
+
+#endif /* PARSE_SUPPORTED_H */
diff --git a/parser/parse_to.c b/parser/parse_to.c
index b97f8b0..95e3f22 100644
--- a/parser/parse_to.c
+++ b/parser/parse_to.c
@@ -29,6 +29,7 @@
  */
 
 #include "parse_to.h"
+#include "parse_addr_spec.h"
 #include <stdlib.h>
 #include <string.h>
 #include "../dprint.h"
@@ -38,803 +39,9 @@
 #include "../mem/mem.h"
 
 
-enum {
-	START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN,
-	DISPLAY_TOKEN_SP, S_URI_ENCLOSED, URI_ENCLOSED, E_URI_ENCLOSED,
-	URI_OR_TOKEN, MAYBE_URI_END, END, F_CR, F_LF, F_CRLF
-};
-
-
-enum {
-	S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2,
-	TAG3, PARA_VALUE_TOKEN , PARA_VALUE_QUOTED, E_PARA_VALUE
-};
-
-
-
-#define add_param( _param , _body , _newparam ) \
-	do{\
-		DBG("DEBUG: add_param: %.*s=%.*s\n",param->name.len,ZSW(param->name.s),\
-			param->value.len,ZSW(param->value.s));\
-		if (!(_body)->param_lst)  (_body)->param_lst=(_param);\
-		else (_body)->last_param->next=(_param);\
-		(_body)->last_param =(_param);\
-		if ((_param)->type==TAG_PARAM)\
-			memcpy(&((_body)->tag_value),&((_param)->value),sizeof(str));\
-		_newparam = 0;\
-	}while(0);
-
-
-
-
-
-static char* parse_to_param(char* const buffer, const char* const end,
-					struct to_body* const to_b,
-					int* const returned_status)
-{
-	struct to_param *param;
-	struct to_param *newparam;
-	int status;
-	int saved_status;
-	char  *tmp;
-
-	param=0;
-	newparam=0;
-	status=E_PARA_VALUE;
-	saved_status=E_PARA_VALUE;
-	for( tmp=buffer; tmp<end; tmp++)
-	{
-		switch(*tmp)
-		{
-			case ' ':
-			case '\t':
-				switch (status)
-				{
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						status = S_EQUAL;
-						break;
-					case PARA_VALUE_TOKEN:
-						param->value.len = tmp-param->value.s;
-						status = E_PARA_VALUE;
-						add_param(param, to_b, newparam);
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now =' '*/
-						status=saved_status;
-						break;
-				}
-				break;
-			case '\n':
-				switch (status)
-				{
-					case S_PARA_NAME:
-					case S_EQUAL:
-					case S_PARA_VALUE:
-					case E_PARA_VALUE:
-						saved_status=status;
-						status=F_LF;
-						break;
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						saved_status = S_EQUAL;
-						status = F_LF;
-						break;
-					case PARA_VALUE_TOKEN:
-						param->value.len = tmp-param->value.s;
-						saved_status = E_PARA_VALUE;
-						status = F_LF;
-						add_param(param, to_b, newparam);
-						break;
-					case F_CR:
-						status=F_CRLF;
-						break;
-					case F_CRLF:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\r':
-				switch (status)
-				{
-					case S_PARA_NAME:
-					case S_EQUAL:
-					case S_PARA_VALUE:
-					case E_PARA_VALUE:
-						saved_status=status;
-						status=F_CR;
-						break;
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						saved_status = S_EQUAL;
-						status = F_CR;
-						break;
-					case PARA_VALUE_TOKEN:
-						param->value.len = tmp-param->value.s;
-						saved_status = E_PARA_VALUE;
-						status = F_CR;
-						add_param(param, to_b, newparam);
-						break;
-					case F_CRLF:
-					case F_CR:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 0:
-				switch (status)
-				{
-					case TAG3:
-						param->type = TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						status = S_EQUAL;
-					case S_EQUAL:
-					case S_PARA_VALUE:
-						saved_status=status;
-						goto endofheader;
-					case PARA_VALUE_TOKEN:
-						status = E_PARA_VALUE;
-						param->value.len = tmp-param->value.s;
-						add_param(param , to_b, newparam);
-					case E_PARA_VALUE:
-						saved_status = status;
-						goto endofheader;
-						break;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\\':
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-						switch (*(tmp+1))
-						{
-							case '\r':
-							case '\n':
-								break;
-							default:
-								tmp++;
-						}
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '"':
-				switch (status)
-				{
-					case S_PARA_VALUE:
-						param->value.s = tmp+1;
-						status = PARA_VALUE_QUOTED;
-						break;
-					case PARA_VALUE_QUOTED:
-						param->value.len=tmp-param->value.s;
-						add_param(param, to_b, newparam);
-						status = E_PARA_VALUE;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param :"
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status,(int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case ';' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-						break;
-					case TAG3:
-						param->type = TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-					case S_EQUAL:
-						param->value.s = 0;
-						param->value.len = 0;
-						goto semicolon_add_param;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-					case PARA_VALUE_TOKEN:
-						param->value.len=tmp-param->value.s;
-semicolon_add_param:
-						add_param(param, to_b, newparam);
-					case E_PARA_VALUE:
-						param = (struct to_param*)
-							pkg_malloc(sizeof(struct to_param));
-						if (!param){
-							LOG( L_ERR , "ERROR: parse_to_param"
-							" - out of memory\n" );
-							goto error;
-						}
-						memset(param,0,sizeof(struct to_param));
-						param->type=GENERAL_PARAM;
-						status = S_PARA_NAME;
-						/* link to free mem if not added in to_body list */
-						newparam = param;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param :"
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 'T':
-			case 't' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = TAG1;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case TAG1:
-					case TAG2:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param :"
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 'A':
-			case 'a' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = PARA_NAME;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case TAG1:
-						status = TAG2;
-						break;
-					case TAG2:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 'G':
-			case 'g' :
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = PARA_NAME;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case TAG1:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case TAG2:
-						status = TAG3;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '=':
-				switch (status)
-				{
-					case PARA_VALUE_QUOTED:
-						break;
-					case TAG3:
-						param->type=TAG_PARAM;
-					case PARA_NAME:
-					case TAG1:
-					case TAG2:
-						param->name.len = tmp-param->name.s;
-						status = S_PARA_VALUE;
-						break;
-					case S_EQUAL:
-						status = S_PARA_VALUE;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to_param : "
-							"unexpected char [%c] in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			default:
-				switch (status)
-				{
-					case TAG1:
-					case TAG2:
-					case TAG3:
-						status = PARA_NAME;
-						break;
-					case PARA_VALUE_TOKEN:
-					case PARA_NAME:
-					case PARA_VALUE_QUOTED:
-						break;
-					case S_PARA_NAME:
-						param->name.s = tmp;
-						status = PARA_NAME;
-						break;
-					case S_PARA_VALUE:
-						param->value.s = tmp;
-						status = PARA_VALUE_TOKEN;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG(L_ERR, "ERROR: parse_to_param: "
-							"spitting out [%c] in status %d\n",*tmp,status );
-						goto error;
-				}
-		}/*switch*/
-	}/*for*/
-	if (!(status==F_CR || status==F_LF || status==F_CRLF))
-		saved_status=status;
-
-
-endofheader:
-	switch(saved_status){
-		case TAG3:
-			param->type = TAG_PARAM; /* tag at the end */
-			/* no break */
-		case PARA_NAME:
-		case TAG1:
-		case TAG2:
-			param->name.len = tmp-param->name.s;
-			/* no break */
-		case S_EQUAL:
-			/* parameter without '=', e.g. foo */
-			param->value.s=0;
-			param->value.len=0;
-			add_param(param, to_b, newparam);
-			saved_status=E_PARA_VALUE;
-			break;
-		case S_PARA_VALUE:
-			/* parameter with null value, e.g. foo= */
-			param->value.s=tmp;
-			param->value.len=0;
-			add_param(param, to_b, newparam);
-			saved_status=E_PARA_VALUE;
-			break;
-		case PARA_VALUE_TOKEN:
-			param->value.len=tmp-param->value.s;
-			add_param(param, to_b, newparam);
-			saved_status=E_PARA_VALUE;
-			break;
-		case E_PARA_VALUE:
-			break;
-		default:
-			LOG( L_ERR , "ERROR: parse_to_param : unexpected end of header,"
-						" status %d: <<%.*s>> .\n",
-						saved_status, (int)(tmp-buffer), ZSW(buffer));
-			goto error;
-	}
-	*returned_status=saved_status;
-	return tmp;
-
-error:
-	if (newparam) pkg_free(newparam);
-	to_b->error=PARSE_ERROR;
-	*returned_status = status;
-	return tmp;
-}
-
-
-
 char* parse_to(char* const buffer, const char* const end, struct to_body* const to_b)
 {
-	int status;
-	int saved_status;
-	char  *tmp,*foo;
-	
-	saved_status=START_TO; /* fixes gcc 4.x warning */
-	status=START_TO;
-	memset(to_b, 0, sizeof(struct to_body));
-	to_b->error=PARSE_OK;
-	foo=0;
-
-	for( tmp=buffer; tmp<end; tmp++)
-	{
-		switch(*tmp)
-		{
-			case ' ':
-			case '\t':
-				switch (status)
-				{
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now =' '*/
-						status=saved_status;
-						break;
-					case URI_ENCLOSED:
-						to_b->uri.len = tmp - to_b->uri.s;
-						status = E_URI_ENCLOSED;
-						break;
-					case URI_OR_TOKEN:
-						foo = tmp;
-						status = MAYBE_URI_END;
-						break;
-					case DISPLAY_TOKEN:
-						foo = tmp;
-						status = DISPLAY_TOKEN_SP;
-						break;
-				}
-				break;
-			case '\n':
-				switch (status)
-				{
-					case URI_OR_TOKEN:
-						foo = tmp;
-						status = MAYBE_URI_END;
-					case MAYBE_URI_END:
-					case DISPLAY_TOKEN_SP:
-					case E_DISPLAY_QUOTED:
-					case END:
-						saved_status=status;
-						status=F_LF;
-						break;
-					case DISPLAY_TOKEN:
-						foo=tmp;
-						saved_status=DISPLAY_TOKEN_SP;
-						status=F_LF;
-						break;
-					case F_CR:
-						status=F_CRLF;
-						break;
-					case F_CRLF:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\r':
-				switch (status)
-				{
-					case URI_OR_TOKEN:
-						foo = tmp;
-						status = MAYBE_URI_END;
-					case MAYBE_URI_END:
-					case DISPLAY_TOKEN_SP:
-					case E_DISPLAY_QUOTED:
-					case END:
-						saved_status=status;
-						status=F_CR;
-						break;
-					case DISPLAY_TOKEN:
-						foo=tmp;
-						saved_status=DISPLAY_TOKEN_SP;
-						status=F_CR;
-						break;
-					case F_CRLF:
-					case F_CR:
-					case F_LF:
-						status=saved_status;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case 0:
-				switch (status)
-				{
-					case URI_OR_TOKEN:
-					case MAYBE_URI_END:
-						to_b->uri.len = tmp - to_b->uri.s;
-					case END:
-						saved_status = status = END;
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '\\':
-				switch (status)
-				{
-					case DISPLAY_QUOTED:
-						tmp++; /* jump over next char */
-						break;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '<':
-				switch (status)
-				{
-					case START_TO:
-						to_b->body.s=tmp;
-						status = S_URI_ENCLOSED;
-						break;
-					case DISPLAY_QUOTED:
-						break;
-					case E_DISPLAY_QUOTED:
-						status = S_URI_ENCLOSED;
-						break;
-					case URI_OR_TOKEN:
-					case DISPLAY_TOKEN:
-						to_b->display.len=tmp-to_b->display.s;
-						status = S_URI_ENCLOSED;
-						break;
-					case DISPLAY_TOKEN_SP:
-					case MAYBE_URI_END:
-						to_b->display.len=foo-to_b->display.s;
-						status = S_URI_ENCLOSED;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '>':
-				switch (status)
-				{
-					case DISPLAY_QUOTED:
-						break;
-					case URI_ENCLOSED:
-						to_b->uri.len = tmp - to_b->uri.s;
-					case E_URI_ENCLOSED:
-						status = END;
-						foo = 0;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), ZSW(buffer));
-						goto error;
-				}
-				break;
-			case '"':
-				switch (status)
-				{
-					case START_TO:
-						to_b->body.s = tmp;
-						to_b->display.s = tmp;
-						status = DISPLAY_QUOTED;
-						break;
-					case DISPLAY_QUOTED:
-						status = E_DISPLAY_QUOTED;
-						to_b->display.len = tmp-to_b->display.s+1;
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), buffer);
-						goto error;
-				}
-				break;
-			case ';' :
-				switch (status)
-				{
-					case DISPLAY_QUOTED:
-					case URI_ENCLOSED:
-						break;
-					case URI_OR_TOKEN:
-						foo = tmp;
-					case MAYBE_URI_END:
-						to_b->uri.len = foo - to_b->uri.s;
-					case END:
-						to_b->body.len = tmp-to_b->body.s;
-						tmp = parse_to_param(tmp,end,to_b,&saved_status);
-						goto endofheader;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						LOG( L_ERR , "ERROR: parse_to : unexpected char [%c] "
-							"in status %d: <<%.*s>> .\n",
-							*tmp,status, (int)(tmp-buffer), buffer);
-						goto error;
-				}
-				break;
-			default:
-				switch (status)
-				{
-					case START_TO:
-						to_b->uri.s = to_b->body.s = tmp;
-						status = URI_OR_TOKEN;
-						to_b->display.s=tmp;
-						break;
-					case S_URI_ENCLOSED:
-						to_b->uri.s=tmp;
-						status=URI_ENCLOSED;
-						break;
-					case MAYBE_URI_END:
-					case DISPLAY_TOKEN_SP:
-						status = DISPLAY_TOKEN;
-					case DISPLAY_QUOTED:
-					case DISPLAY_TOKEN:
-					case URI_ENCLOSED:
-					case URI_OR_TOKEN:
-						break;
-					case F_CRLF:
-					case F_LF:
-					case F_CR:
-						/*previous=crlf and now !=' '*/
-						goto endofheader;
-					default:
-						DBG("DEBUG:parse_to: spitting out [%c] in status %d\n",
-						*tmp,status );
-						goto error;
-				}
-		}/*char switch*/
-	}/*for*/
-
-endofheader:
-	if (to_b->display.len==0) to_b->display.s=0;
-	status=saved_status;
-	DBG("end of header reached, state=%d\n", status);
-	/* check if error*/
-	switch(status){
-		case MAYBE_URI_END:
-			to_b->uri.len = foo - to_b->uri.s;
-		case END:
-			to_b->body.len = tmp - to_b->body.s;
-		case E_PARA_VALUE:
-			break;
-		default:
-			LOG(L_ERR, "ERROR: parse_to: invalid To -  unexpected "
-					"end of header in state %d\n", status);
-			goto error;
-	}
-	return tmp;
-
-error:
-	to_b->error=PARSE_ERROR;
-	return tmp;
-
-}
-
-
-void free_to_params(struct to_body* const tb)
-{
-	struct to_param *tp=tb->param_lst;
-	struct to_param *foo;
-	while (tp){
-		foo = tp->next;
-		pkg_free(tp);
-		tp=foo;
-	}
-}
-
-
-void free_to(struct to_body* const tb)
-{
-	free_to_params(tb);
-	pkg_free(tb);
+	return parse_addr_spec(buffer, end, to_b, 0);
 }
 
 
diff --git a/parser/parse_to.h b/parser/parse_to.h
index aaed1be..2fd580a 100644
--- a/parser/parse_to.h
+++ b/parser/parse_to.h
@@ -29,30 +29,7 @@
 
 #include "../str.h"
 #include "msg_parser.h"
-
-enum {
-	TAG_PARAM = 400, GENERAL_PARAM
-};
-
-typedef struct to_param{
-	int type;              /*!< Type of parameter */
-	str name;              /*!< Name of parameter */
-	str value;             /*!< Parameter value */
-	struct to_param* next; /*!< Next parameter in the list */
-} to_param_t;
-
-
-typedef struct to_body{
-	int error;                    /*!< Error code */
-	str body;                     /*!< The whole header field body */
-	str uri;                      /*!< URI */
-	str display;				  /*!< Display Name */
-	str tag_value;                /*!< Value of tag */
-	struct sip_uri parsed_uri;
-	struct to_param *param_lst;   /*!< Linked list of parameters */
-	struct to_param *last_param;  /*!< Last parameter in the list */
-} to_body_t;
-
+#include "parse_addr_spec.h"
 
 /* casting macro for accessing To body */
 #define get_to(p_msg)      ((struct to_body*)(p_msg)->to->parsed)
@@ -65,10 +42,6 @@ typedef struct to_body{
  */
 char* parse_to(char* const buffer, const char* const end, struct to_body* const to_b);
 
-void free_to_params(struct to_body* const tb);
-
-void free_to(struct to_body* const tb);
-
 int parse_to_header(struct sip_msg* const msg);
 
 sip_uri_t *parse_to_uri(struct sip_msg* const msg);
diff --git a/pkg/kamailio/centos/6/README b/pkg/kamailio/centos/6/README
deleted file mode 120000
index 3c35ded..0000000
--- a/pkg/kamailio/centos/6/README
+++ /dev/null
@@ -1 +0,0 @@
-../../fedora/17/README
\ No newline at end of file
diff --git a/pkg/kamailio/centos/6/README b/pkg/kamailio/centos/6/README
new file mode 100644
index 0000000..8d61c17
--- /dev/null
+++ b/pkg/kamailio/centos/6/README
@@ -0,0 +1,27 @@
+The following modules are not included in CentOS 6 builds because they have
+dependencies that cannot be met by the base or EPEL CentOS YUM repos or are
+obsolete.
+
+Obsolete modules
+----------------
+* iptrtpproxy		use the rtpproxy-ng module with mediaproxy-ng instead
+* jabber		use the xmpp and pua_xmpp modules instead
+
+Modules with unmet dependencies
+-------------------------------
+Note: If you need any of these modules you will need to find (and possibly
+      build) and install the dependencies and then do a manual build of
+      Kamailio.
+
+Ordered by module name:
+* app_mono	requires mono-devel-??? or higher (EPEL contains
+		mono-devel 2.4.3.1)
+* db_cassandra	requires thrift 0.6.1 or 0.7.0
+* db_oracle	requires instantclient-sdk-10.2.0.3
+* osp		requires the OSP Toolkit
+
+Ordered by unmet dependency:
+* instantclient-sdk-10.2.0.3	db_oracle
+* mono-devel-??? or higher	app_mono
+* OSP Toolkit			osp
+* thrift 0.6.1 or 0.7.0		db_cassandra
diff --git a/pkg/kamailio/centos/6/kamailio-build.appl b/pkg/kamailio/centos/6/kamailio-build.appl
deleted file mode 100644
index b0de9e2..0000000
--- a/pkg/kamailio/centos/6/kamailio-build.appl
+++ /dev/null
@@ -1,41 +0,0 @@
-name: "kamailio-build-c6-#BASE_ARCH#"
-summary: "CentOS 6 image for building Kamailio #BASE_ARCH# RPMs"
-os:
-  name: centos
-  version: 6
-  password: kamailio
-hardware:
-  memory: 1024
-  partitions:
-    "/":
-      size: 6
-packages:
-  - @core
-  - bison			# kamailio
-  - db4-devel			# kamailio-bdb
-  - expat-devel			# kamailio-xmpp
-  - flex			# kamailio
-  - gcc
-  - git
-  - glib2-devel			# kamailio-purple
-  - libcurl-devel		# kamailio-utils, kamailio-presence
-  - libevent-devel		# kamailio-json
-  - libpurple-devel		# kamailio-purple
-  - libunistring-devel		# kamailio-websocket
-  - libxml2-devel		# kamailio-cdp, kamailio-cpl, kamailio-ims, kamailio-presence, kamailio-purple, kamailio-utils, kamailio-xhttp-pi, kamailio-xmlops, kamailio-xmlrpc
-  - lksctp-tools-devel		# kamailio
-  - lua-devel			# kamailio-lua
-  - make			# kamailio
-  - mod_perl-devel		# kamailio-perl
-  - mysql-devel			# kamailio-mysql
-  - net-snmp-devel		# kamailio-snmpstats
-  - openldap-devel		# kamailio-ldap
-  - openssl-devel		# kamailio
-  - pcre-devel			# kamailio-regex, kamailio-dialplan, kamailio-lcr
-  - postgresql-devel		# kamailio-postgresql
-  - python-devel		# kamailio-python
-  - redhat-rpm-config		# kamailio-debuginfo
-  - rpm-build
-  - sqlite-devel		# kamailio-sqlite
-  - unixODBC-devel		# kamailio-unixODBC
-  - zlib-devel			# kamailio-mysql
diff --git a/pkg/kamailio/centos/6/kamailio.appl b/pkg/kamailio/centos/6/kamailio.appl
deleted file mode 100644
index d640671..0000000
--- a/pkg/kamailio/centos/6/kamailio.appl
+++ /dev/null
@@ -1,35 +0,0 @@
-name: "kamailio-c6-#BASE_ARCH#"
-summary: "CentOS 6 image for installing Kamailio #BASE_ARCH# RPMs"
-os:
-  name: centos
-  version: 6
-  password: kamailio
-hardware:
-  memory: 1024
-  partitions:
-    "/":
-      size: 2
-packages:
-  - @core
-  - db4				# kamailio-bdb
-  - expat			# kamailio-xmpp
-  - glib2			# kamailio-purple
-  - libcurl			# kamailio-utils, kamailio-presence
-  - libevent			# kamailio-json
-  - libpurple			# kamailio-purple
-  - libunistring		# kamailio-websocket
-  - libxml2			# kamailio-cdp, kamailio-cpl, kamailio-ims, kamailio-presence, kamailio-purple, kamailio-utils, kamailio-xhttp-pi, kamailio-xmlops, kamailio-xmlrpc
-  - lksctp-tools		# kamailio
-  - mod_perl			# kamailio-perl
-  - mysql-libs			# kamailio-mysql
-  - net-snmp-libs		# kamailio-snmpstats
-  - openldap			# kamailio-ldap
-  - openssl			# kamailio
-  - pcre			# kamailio-regex, kamailio-dialplan, kamailio-lcr
-  - perl-Authen-SASL		# kamailio-perl
-  - perl-LDAP			# kamailio-perl
-  - postgresql-libs		# kamailio-postgresql
-  - python			# kamailio-python
-  - sqlite			# kamailio-sqlite
-  - unixODBC			# kamailio-unixODBC
-  - zlib			# kamailio-mysql
diff --git a/pkg/kamailio/centos/6/kamailio.init b/pkg/kamailio/centos/6/kamailio.init
index 9bbfa22..3ee9677 100644
--- a/pkg/kamailio/centos/6/kamailio.init
+++ b/pkg/kamailio/centos/6/kamailio.init
@@ -20,49 +20,100 @@
 # Source function library.
 . /etc/rc.d/init.d/functions
 
-kam=/usr/sbin/kamailio
-prog=kamailio
+KAM=/usr/sbin/kamailio
+KAMCFG=/etc/kamailio/kamailio.cfg
+PROG=kamailio
+PID_FILE=/var/run/kamailio.pid
+LOCK_FILE=/var/lock/subsys/kamailio
 RETVAL=0
+DEFAULTS=/etc/sysconfig/kamailio
+RUN_KAMAILIO=no
+
+
+# Do not start kamailio if fork=no is set in the config file
+# otherwise the boot process will just stop
+check_fork ()
+{
+    if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $KAMCFG; then
+        echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/kamailio debug instead"
+        exit 1
+    fi
+}
+
+check_kamailio_config ()
+{
+        # Check if kamailio configuration is valid before starting the server
+        out=$($KAM -c 2>&1 > /dev/null)
+        retcode=$?
+        if [ "$retcode" != '0' ]; then
+            echo "Not starting $DESC: invalid configuration file!"
+            echo -e "\n$out\n"
+            exit 1
+        fi
+}
 
-[ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
 
 start() {
-	echo -n $"Starting $prog: "
-	# there is something at end of this output which is needed to
-	# report proper [ OK ] status in CentOS scripts
-	daemon $kam $OPTIONS 2>/dev/null | tail -1
+	check_kamailio_config
+        if [ "$1" != "debug" ]; then
+            check_fork
+        fi
+	echo -n $"Starting $PROG: "
+	daemon $KAM $OPTIONS >/dev/null 2>/dev/null
 	RETVAL=$?
+	[ $RETVAL = 0 ] && touch $LOCK_FILE && success
 	echo
-	[ $RETVAL = 0 ] && touch /var/lock/subsys/$prog
+	return $RETVAL
 }
 
 stop() {
-	echo -n $"Stopping $prog: "
-	killproc $kam
+	echo -n $"Stopping $PROG: "
+	killproc $KAM
 	RETVAL=$?
 	echo
-	[ $RETVAL = 0 ] && rm -f /var/lock/subsys/$prog /var/run/$prog.pid
+	[ $RETVAL = 0 ] && rm -f $LOCK_FILE $PID_FILE
 }
 
-MEMORY=$((`echo $MEMORY | sed -e 's/[^0-9]//g'`))
+# Load startup options if available
+if [ -f $DEFAULTS ]; then
+   . $DEFAULTS || true
+fi
+
+if [ "$RUN_KAMAILIO" != "yes" ]; then
+    echo "Kamailio not yet configured. Edit /etc/default/kamailio first."
+    exit 0
+fi
+
+
+SHM_MEMORY=$((`echo $SHM_MEMORY | sed -e 's/[^0-9]//g'`))
 PKG_MEMORY=$((`echo $PKG_MEMORY | sed -e 's/[^0-9]//g'`))
 [ -z "$USER" ]  && USER=kamailio
 [ -z "$GROUP" ] && GROUP=kamailio
-[ $MEMORY -le 0 ] && MEMORY=32
+[ $SHM_MEMORY -le 0 ] && SHM_MEMORY=32
 [ $PKG_MEMORY -le 0 ] && PKG_MEMORY=4
 
-OPTIONS="-P /var/run/$prog.pid -m $MEMORY -M $PKG_MEMORY -u $USER -g $GROUP"
+if test "$DUMP_CORE" = "yes" ; then
+    # set proper ulimit
+    ulimit -c unlimited
+
+    # directory for the core dump files
+    COREDIR=/tmp
+    echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
+fi
+
+OPTIONS="-P $PID_FILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP $EXTRA_OPTIONS"
+
 
 # See how we were called.
 case "$1" in
-	start)
+	start|debug)
 		start
 		;;
 	stop)
 		stop
 		;;
 	status)
-		status $kam
+		status $KAM
 		RETVAL=$?
 		;;
 	restart)
@@ -70,13 +121,13 @@ case "$1" in
 		start
 		;;
 	condrestart)
-		if [ -f /var/run/$prog.pid ] ; then
+		if [ -f $PID_FILE ] ; then
 			stop
 			start
 		fi
 		;;
 	*)
-		echo $"Usage: $prog {start|stop|reload|restart|condrestart|status|help}"
+		echo $"Usage: $PROG {start|stop|restart|condrestart|status|debug|help}"
 		exit 1
 esac
 
diff --git a/pkg/kamailio/centos/6/kamailio.spec b/pkg/kamailio/centos/6/kamailio.spec
deleted file mode 120000
index 740ed1a..0000000
--- a/pkg/kamailio/centos/6/kamailio.spec
+++ /dev/null
@@ -1 +0,0 @@
-../../fedora/17/kamailio.spec
\ No newline at end of file
diff --git a/pkg/kamailio/centos/6/kamailio.spec b/pkg/kamailio/centos/6/kamailio.spec
new file mode 100644
index 0000000..9f0de02
--- /dev/null
+++ b/pkg/kamailio/centos/6/kamailio.spec
@@ -0,0 +1,1179 @@
+%define name	kamailio
+%define ver	4.1.0
+%define rel	0%{dist}
+
+
+
+Summary:	Kamailio (former OpenSER) - the Open Source SIP Server
+Name:		%name
+Version:	%ver
+Release:	%rel
+Packager:	Peter Dunkley <peter at dunkley.me.uk>
+License:	GPL
+Group:		System Environment/Daemons
+Source:		http://kamailio.org/pub/kamailio/%{ver}/src/%{name}-%{ver}_src.tar.gz
+URL:		http://kamailio.org/
+Vendor:		kamailio.org
+BuildRoot:	%{_tmppath}/%{name}-%{ver}-buildroot
+Conflicts:	kamailio-auth-ephemeral < %ver, kamailio-bdb < %ver
+Conflicts:	kamailio-carrierroute < %ver, kamailio-cpl < %ver
+Conflicts:	kamailio-dialplan < %ver, kamailio-dnssec < %ver
+Conflicts:	kamailio-geoip < %ver, kamailio-gzcompress < %ver
+Conflicts:	kamailio-ims < %ver, kamailio-java < %ver, kamailio-json < %ver
+Conflicts:	kamailio-lcr < %ver, kamailio-ldap < %ver, kamailio-lua < %ver
+Conflicts:	kamailio-memcached < %ver, kamailio-mysql < %ver
+Conflicts:	kamailio-outbound < %ver, kamailio-perl < %ver
+Conflicts:	kamailio-postgresql < %ver, kamailio-presence < %ver
+Conflicts:	kamailio-purple < %ver, kamailio-python < %ver
+Conflicts:	kamailio-radius < % ver, kamailio-redis < %ver
+Conflicts:	kamailio-regex < %ver, kamailio-sctp < %ver
+Conflicts:	kamailio-snmpstats < %ver, kamailio-sqlite < %ver
+Conflicts:	kamailio-tls < %ver, kamailio-unixodbc < %ver
+Conflicts:	kamailio-utils < %ver, kamailio-websocket < %ver
+Conflicts:	kamailio-xhttp-pi < %ver, kamailio-xmlops < %ver
+Conflicts:	kamailio-xmlrpc < %ver, kamailio-xmpp < %ver
+BuildRequires:	bison, flex, gcc, make, redhat-rpm-config
+
+%description
+Kamailio (former OpenSER) is an Open Source SIP Server released under GPL, able
+to handle thousands of call setups per second. Among features: asynchronous TCP,
+UDP and SCTP, secure communication via TLS for VoIP (voice, video); IPv4 and
+IPv6; SIMPLE instant messaging and presence with embedded XCAP server and MSRP
+relay; ENUM; DID and least cost routing; load balancing; routing fail-over;
+accounting, authentication and authorization; support for many backend systems
+such as MySQL, Postgres, Oracle, Radius, LDAP, Redis, Cassandra; XMLRPC control
+interface, SNMP monitoring. It can be used to build large VoIP servicing
+platforms or to scale up SIP-to-PSTN gateways, PBX systems or media servers
+like Asterisk™, FreeSWITCH™ or SEMS.
+
+
+%package	auth-ephemeral
+Summary:	Functions for authentication using ephemeral credentials.
+Group:		System Environment/Daemons
+Requires:	openssl, kamailio = %ver
+BuildRequires:	openssl-devel
+
+%description auth-ephemeral
+Functions for authentication using ephemeral credentials.
+
+
+%package	bdb
+Summary:	Berkeley database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	db4, kamailio = %ver
+BuildRequires:	db4-devel
+
+%description	bdb
+Berkeley database connectivity for Kamailio.
+
+
+%package	carrierroute
+Summary:	The carrierroute module for Kamailio.
+Group:		System Environment/Daemons
+Requires:	epel-release, libconfuse, kamailio = %ver
+BuildRequires:	epel-release, libconfuse-devel
+
+%description	carrierroute
+The carrierroute module for Kamailio.
+
+
+%package	cpl
+Summary:	CPL (Call Processing Language) interpreter for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
+
+%description	cpl
+CPL (Call Processing Language) interpreter for Kamailio.
+
+
+%package	dialplan
+Summary:	String translations based on rules for Kamailio.
+Group:		System Environment/Daemons
+Requires:	pcre, kamailio = %ver
+BuildRequires:	pcre-devel
+
+%description	dialplan
+String translations based on rules for Kamailio.
+
+
+%package	dnssec
+Summary:	DNSSEC support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	epel-release, dnssec-tools-libs, kamailio = %ver
+BuildRequires:	epel-release, dnssec-tools-libs-devel
+
+%description	dnssec
+DNSSEC support for Kamailio.
+
+
+%package	geoip
+Summary:	MaxMind GeoIP support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	epel-release, GeoIP, kamailio = %ver
+BuildRequires:	epel-release, GeoIP-devel
+
+%description	geoip
+MaxMind GeoIP support for Kamailio.
+
+
+%package	gzcompress
+Summary:	Compressed body (SIP and HTTP) handling for kamailio.
+Group:		System Environment/Daemons
+Requires:	zlib, kamailio = %ver
+BuildRequires:	zlib-devel
+
+%description	gzcompress
+Compressed body (SIP and HTTP) handling for kamailio.
+
+
+%package	ims
+Summary:	IMS modules and extensions module for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
+
+%description	ims
+IMS modules and extensions module for Kamailio.
+
+
+%package	java
+Summary:	Java extensions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libgcj, java-1.6.0-openjdk, kamailio = %ver
+BuildRequires:	libgcj-devel, java-1.6.0-openjdk-devel, ant
+
+%description	java
+Java extensions for Kamailio.
+
+
+%package	json
+Summary:	json string handling and RPC modules for Kamailio.
+Group:		System Environment/Daemons
+Requires:	epel-release, json-c, libevent, kamailio = %ver
+BuildRequires:	epel-release, json-c-devel, libevent-devel
+
+%description	json
+json string handling and RPC modules for Kamailio.
+
+
+%package	lcr
+Summary:	Least cost routing for Kamailio.
+Group:		System Environment/Daemons
+Requires:	pcre, kamailio = %ver
+BuildRequires:	pcre-devel
+
+%description	lcr
+Least cost routing for Kamailio.
+
+
+%package	ldap
+Summary:	LDAP search interface for Kamailio.
+Group:		System Environment/Daemons
+Requires:	openldap, kamailio = %ver
+BuildRequires:	openldap-devel
+
+%description	ldap
+LDAP search interface for Kamailio.
+
+
+%package	lua
+Summary:	Lua extensions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	kamailio = %ver
+BuildRequires:	lua-devel
+
+%description	lua
+Lua extensions for Kamailio.
+
+
+%package	memcached
+Summary:	memcached configuration file support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libmemcached, kamailio = %ver
+BuildRequires:	libmemcached-devel
+
+%description	memcached
+memcached configuration file support for Kamailio.
+
+
+%package	mysql
+Summary:	MySQL database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	mysql-libs, kamailio = %ver
+BuildRequires:	mysql-devel zlib-devel
+
+%description	mysql
+MySQL database connectivity for Kamailio.
+
+
+%package	outbound
+Summary:	Outbound (RFC 5626) support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	openssl, kamailio = %ver
+BuildRequires:	openssl-devel
+
+%description	outbound
+RFC 5626, "Managing Client-Initiated Connections in the Session Initiation
+Protocol (SIP)" support for Kamailio.
+
+
+%package	perl
+Summary:	Perl extensions and database driver for Kamailio.
+Group:		System Environment/Daemons 
+Requires:	mod_perl, kamailio = %ver
+BuildRequires:	mod_perl-devel
+
+%description	perl
+Perl extensions and database driver for Kamailio.
+
+
+%package	postgresql
+Summary:	PostgreSQL database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	postgresql-libs, kamailio = %ver
+BuildRequires:	postgresql-devel
+
+%description	postgresql
+PostgreSQL database connectivity for Kamailio.
+
+
+%package	presence
+Summary:	SIP Presence (and RLS, XCAP, etc) support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, libcurl, kamailio = %ver, kamailio-xmpp = %ver
+BuildRequires:	libxml2-devel, libcurl-devel
+
+%description	presence
+SIP Presence (and RLS, XCAP, etc) support for Kamailio.
+
+
+%package	purple
+Summary:	Multi-protocol IM and presence gateway module.
+Group:		System Environment/Daemons
+Requires:	glib2, libpurple, libxml2, kamailio = %ver
+Requires:	kamailio-presence = %ver
+BuildRequires:	glib2-devel, libpurple-devel, libxml2-devel
+
+%description	purple
+Multi-protocol IM and presence gateway module.
+
+
+%package	python
+Summary:	Python extensions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	python, kamailio = %ver
+BuildRequires:	python-devel
+
+%description	python
+Python extensions for Kamailio.
+
+
+%package	radius
+Summary:	RADIUS modules for Kamailio.
+Group:		System Environment/Daemons
+Requires:	epel-release, radiusclient-ng, kamailio = %ver
+BuildRequires:	epel-release, radiusclient-ng-devel
+
+%description	radius
+RADIUS modules for Kamailio.
+
+
+%package	redis
+Summary:	Redis configuration file support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	epel-release, hiredis, kamailio = %ver
+BuildRequires:	epel-release, hiredis-devel
+
+%description	redis
+Redis configuration file support for Kamailio.
+
+
+%package	regex
+Summary:	PCRE mtaching operations for Kamailio.
+Group:		System Environment/Daemons
+Requires:	pcre, kamailio = %ver
+BuildRequires:	pcre-devel
+
+%description	regex
+PCRE mtaching operations for Kamailio.
+
+
+%package	sctp
+Summary:	SCTP transport for Kamailio.
+Group:		System Environment/Daemons
+Requires:	lksctp-tools, kamailio = %ver
+BuildRequires:	lksctp-tools-devel
+
+%description	sctp
+SCTP transport for Kamailio.
+
+
+%package	snmpstats
+Summary:	SNMP management interface (scalar statistics) for Kamailio.
+Group:		System Environment/Daemons
+Requires:	net-snmp-libs, kamailio = %ver
+BuildRequires:	net-snmp-devel
+
+%description	snmpstats
+SNMP management interface (scalar statistics) for Kamailio.
+
+
+%package	sqlite
+Summary:	SQLite database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	sqlite, kamailio = %ver
+BuildRequires:	sqlite-devel
+
+%description	sqlite
+SQLite database connectivity for Kamailio.
+
+
+%package	tls
+Summary:	TLS transport for Kamailio.
+Group:		System Environment/Daemons
+Requires:	openssl, kamailio = %ver
+BuildRequires:	openssl-devel
+
+%description	tls
+TLS transport for Kamailio.
+
+
+%package	unixodbc
+Summary:	unixODBC database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	unixODBC, kamailio = %ver
+BuildRequires:	unixODBC-devel
+
+%description	unixodbc
+unixODBC database connectivity for Kamailio.
+
+
+%package	utils
+Summary:	Non-SIP utitility functions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libcurl, libxml2, kamailio = %ver
+BuildRequires:	libcurl-devel, libxml2-devel
+
+%description	utils
+Non-SIP utitility functions for Kamailio.
+
+
+%package	websocket
+Summary:	WebSocket transport for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libunistring, openssl, kamailio = %ver
+BuildRequires:	libunistring-devel, openssl-devel
+
+%description	websocket
+WebSocket transport for Kamailio.
+
+
+%package	xhttp-pi
+Summary:	Web-provisioning interface for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
+
+%description	xhttp-pi
+Web-provisioning interface for Kamailio.
+
+
+%package	xmlops
+Summary:	XML operation functions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
+
+%description	xmlops
+XML operation functions for Kamailio.
+
+
+%package	xmlrpc
+Summary:	XMLRPC transport and encoding for Kamailio RPCs and MI commands.
+Group:		System Environment/Daemons
+Requires:	libxml2, xmlrpc-c, kamailio = %ver
+BuildRequires:	libxml2-devel, xmlrpc-c-devel
+
+%description	xmlrpc
+XMLRPC transport and encoding for Kamailio RPCs and MI commands.
+
+
+%package	xmpp
+Summary:	SIP/XMPP IM gateway for Kamailio.
+Group:		System Environment/Daemons
+Requires:	expat, kamailio = %ver
+BuildRequires:	expat-devel
+
+%description	xmpp
+SIP/XMPP IM gateway for Kamailio.
+
+
+
+%prep
+%setup -n %{name}-%{ver}
+
+
+
+%build
+make cfg prefix=/usr cfg_prefix=$RPM_BUILD_ROOT basedir=$RPM_BUILD_ROOT \
+	cfg_target=/%{_sysconfdir}/kamailio/ modules_dirs="modules"
+make
+make every-module skip_modules="app_mono db_cassandra db_oracle iptrtpproxy \
+	jabber osp" \
+	group_include="kstandard kautheph kberkeley kcarrierroute kcpl \
+	kdnssec kgeoip kims kjava kjson kldap klua kmemcached kmi_xmlrpc \
+	kmysql koutbound kperl kpostgres kpresence kpurple kpython kradius \
+	kredis ksctp ksnmpstats ksqlite ktls kunixodbc kutils kwebsocket \
+	kxml kxmpp" 
+cd modules/app_java/kamailio_java_folder/java
+ant
+cd ../../../..
+make utils
+
+
+
+%install
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
+
+make install
+make install-modules-all skip_modules="app_mono db_cassandra db_oracle \
+	iptrtpproxy jabber osp" \
+	group_include="kstandard kautheph kberkeley kcarrierroute kcpl \
+	kdnssec kgeoip kims kjava kjson kldap klua kmemcached kmi_xmlrpc \
+	kmysql koutbound kperl kpostgres kpresence kpurple kpython kradius \
+	kredis ksctp ksnmpstats ksqlite ktls kunixodbc kutils kwebsocket \
+	kxml kxmpp" 
+
+mkdir -p $RPM_BUILD_ROOT/%{_libdir}/kamailio/java
+install -m644 modules/app_java/kamailio_java_folder/java/Kamailio.class \
+	$RPM_BUILD_ROOT/%{_libdir}/kamailio/java
+install -m644 modules/app_java/kamailio_java_folder/java/kamailio.jar \
+	$RPM_BUILD_ROOT/%{_libdir}/kamailio/java
+
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rc.d/init.d
+install -m755 pkg/kamailio/centos/%{?centos}/kamailio.init \
+		$RPM_BUILD_ROOT/%{_sysconfdir}/rc.d/init.d/kamailio
+
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig
+install -m644 pkg/kamailio/centos/%{?centos}/kamailio.sysconfig \
+		$RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/kamailio
+
+
+
+%pre
+/usr/sbin/groupadd -r kamailio 2> /dev/null || :
+/usr/sbin/useradd -r -g kamailio -s /bin/false -c "Kamailio daemon" -d \
+		%{_libdir}/kamailio kamailio 2> /dev/null || :
+
+
+
+%clean
+rm -rf "$RPM_BUILD_ROOT"
+
+
+
+%post
+/sbin/chkconfig --add kamailio
+
+
+
+%preun
+if [ $1 = 0 ]; then
+	/sbin/service kamailio stop > /dev/null 2>&1
+	/sbin/chkconfig --del kamailio
+fi
+
+
+
+%files
+%defattr(-,root,root)
+%dir %{_docdir}/kamailio
+%doc %{_docdir}/kamailio/AUTHORS
+%doc %{_docdir}/kamailio/NEWS
+%doc %{_docdir}/kamailio/INSTALL
+%doc %{_docdir}/kamailio/README
+%doc %{_docdir}/kamailio/README-MODULES
+
+%dir %{_docdir}/kamailio/modules
+%doc %{_docdir}/kamailio/modules/README.acc
+%doc %{_docdir}/kamailio/modules/README.alias_db
+%doc %{_docdir}/kamailio/modules/README.async
+%doc %{_docdir}/kamailio/modules/README.auth
+%doc %{_docdir}/kamailio/modules/README.auth_db
+%doc %{_docdir}/kamailio/modules/README.auth_diameter
+%doc %{_docdir}/kamailio/modules/README.avp
+%doc %{_docdir}/kamailio/modules/README.avpops
+%doc %{_docdir}/kamailio/modules/README.benchmark
+%doc %{_docdir}/kamailio/modules/README.blst
+%doc %{_docdir}/kamailio/modules/README.call_control
+%doc %{_docdir}/kamailio/modules/README.cfg_db
+%doc %{_docdir}/kamailio/modules/README.cfg_rpc
+%doc %{_docdir}/kamailio/modules/README.cfgutils
+%doc %{_docdir}/kamailio/modules/README.cnxcc
+%doc %{_docdir}/kamailio/modules/README.corex
+%doc %{_docdir}/kamailio/modules/README.counters
+%doc %{_docdir}/kamailio/modules/README.ctl
+%doc %{_docdir}/kamailio/modules/README.db_cluster
+%doc %{_docdir}/kamailio/modules/README.db_flatstore
+%doc %{_docdir}/kamailio/modules/README.db_text
+%doc %{_docdir}/kamailio/modules/README.db2_ops
+%doc %{_docdir}/kamailio/modules/README.debugger
+%doc %{_docdir}/kamailio/modules/README.dialog
+%doc %{_docdir}/kamailio/modules/README.dialog_ng
+%doc %{_docdir}/kamailio/modules/README.dispatcher
+%doc %{_docdir}/kamailio/modules/README.diversion
+%doc %{_docdir}/kamailio/modules/README.dmq
+%doc %{_docdir}/kamailio/modules/README.domain
+%doc %{_docdir}/kamailio/modules/README.domainpolicy
+%doc %{_docdir}/kamailio/modules/README.drouting
+%doc %{_docdir}/kamailio/modules/README.enum
+%doc %{_docdir}/kamailio/modules/README.exec
+%doc %{_docdir}/kamailio/modules/README.group
+%doc %{_docdir}/kamailio/modules/README.htable
+%doc %{_docdir}/kamailio/modules/README.imc
+%doc %{_docdir}/kamailio/modules/README.ipops
+%doc %{_docdir}/kamailio/modules/README.kex
+%doc %{_docdir}/kamailio/modules/README.malloc_test
+%doc %{_docdir}/kamailio/modules/README.mangler
+%doc %{_docdir}/kamailio/modules/README.matrix
+%doc %{_docdir}/kamailio/modules/README.maxfwd
+%doc %{_docdir}/kamailio/modules/README.mediaproxy
+%doc %{_docdir}/kamailio/modules/README.mi_datagram
+%doc %{_docdir}/kamailio/modules/README.mi_fifo
+%doc %{_docdir}/kamailio/modules/README.mi_rpc
+%doc %{_docdir}/kamailio/modules/README.mohqueue
+%doc %{_docdir}/kamailio/modules/README.mqueue
+%doc %{_docdir}/kamailio/modules/README.msilo
+%doc %{_docdir}/kamailio/modules/README.msrp
+%doc %{_docdir}/kamailio/modules/README.mtree
+%doc %{_docdir}/kamailio/modules/README.nat_traversal
+%doc %{_docdir}/kamailio/modules/README.nathelper
+%doc %{_docdir}/kamailio/modules/README.p_usrloc
+%doc %{_docdir}/kamailio/modules/README.path
+%doc %{_docdir}/kamailio/modules/README.pdb
+%doc %{_docdir}/kamailio/modules/README.pdt
+%doc %{_docdir}/kamailio/modules/README.permissions
+%doc %{_docdir}/kamailio/modules/README.pike
+%doc %{_docdir}/kamailio/modules/README.pipelimit
+%doc %{_docdir}/kamailio/modules/README.prefix_route
+%doc %{_docdir}/kamailio/modules/README.print
+%doc %{_docdir}/kamailio/modules/README.print_lib
+%doc %{_docdir}/kamailio/modules/README.pv
+%doc %{_docdir}/kamailio/modules/README.qos
+%doc %{_docdir}/kamailio/modules/README.ratelimit
+%doc %{_docdir}/kamailio/modules/README.registrar
+%doc %{_docdir}/kamailio/modules/README.rr
+%doc %{_docdir}/kamailio/modules/README.rtimer
+%doc %{_docdir}/kamailio/modules/README.rtpproxy
+%doc %{_docdir}/kamailio/modules/README.rtpproxy-ng
+%doc %{_docdir}/kamailio/modules/README.sanity
+%doc %{_docdir}/kamailio/modules/README.sca
+%doc %{_docdir}/kamailio/modules/README.sdpops
+%doc %{_docdir}/kamailio/modules/README.seas
+%doc %{_docdir}/kamailio/modules/README.sipcapture
+%doc %{_docdir}/kamailio/modules/README.sipt
+%doc %{_docdir}/kamailio/modules/README.siptrace
+%doc %{_docdir}/kamailio/modules/README.siputils
+%doc %{_docdir}/kamailio/modules/README.sl
+%doc %{_docdir}/kamailio/modules/README.sms
+%doc %{_docdir}/kamailio/modules/README.speeddial
+%doc %{_docdir}/kamailio/modules/README.sqlops
+%doc %{_docdir}/kamailio/modules/README.sst
+%doc %{_docdir}/kamailio/modules/README.statistics
+%doc %{_docdir}/kamailio/modules/README.stun
+%doc %{_docdir}/kamailio/modules/README.textops
+%doc %{_docdir}/kamailio/modules/README.textopsx
+%doc %{_docdir}/kamailio/modules/README.timer
+%doc %{_docdir}/kamailio/modules/README.tm
+%doc %{_docdir}/kamailio/modules/README.tmrec
+%doc %{_docdir}/kamailio/modules/README.tmx
+%doc %{_docdir}/kamailio/modules/README.topoh
+%doc %{_docdir}/kamailio/modules/README.uac
+%doc %{_docdir}/kamailio/modules/README.uac_redirect
+%doc %{_docdir}/kamailio/modules/README.uid_auth_db
+%doc %{_docdir}/kamailio/modules/README.uid_avp_db
+%doc %{_docdir}/kamailio/modules/README.uid_domain
+%doc %{_docdir}/kamailio/modules/README.uid_gflags
+%doc %{_docdir}/kamailio/modules/README.uid_uri_db
+%doc %{_docdir}/kamailio/modules/README.uri_db
+%doc %{_docdir}/kamailio/modules/README.userblacklist
+%doc %{_docdir}/kamailio/modules/README.usrloc
+%doc %{_docdir}/kamailio/modules/README.xhttp
+%doc %{_docdir}/kamailio/modules/README.xhttp_rpc
+%doc %{_docdir}/kamailio/modules/README.xlog
+%doc %{_docdir}/kamailio/modules/README.xprint
+
+%dir %attr(-,kamailio,kamailio) %{_sysconfdir}/kamailio
+%config(noreplace) %{_sysconfdir}/kamailio/*
+%config %{_sysconfdir}/rc.d/init.d/*
+%config %{_sysconfdir}/sysconfig/*
+
+%dir %{_libdir}/kamailio
+%{_libdir}/kamailio/libbinrpc.so
+%{_libdir}/kamailio/libbinrpc.so.0
+%{_libdir}/kamailio/libbinrpc.so.0.1
+%{_libdir}/kamailio/libkcore.so
+%{_libdir}/kamailio/libkcore.so.1
+%{_libdir}/kamailio/libkcore.so.1.0
+%{_libdir}/kamailio/libkmi.so
+%{_libdir}/kamailio/libkmi.so.1
+%{_libdir}/kamailio/libkmi.so.1.0
+%{_libdir}/kamailio/libprint.so
+%{_libdir}/kamailio/libprint.so.1
+%{_libdir}/kamailio/libprint.so.1.2
+%{_libdir}/kamailio/libsrdb1.so
+%{_libdir}/kamailio/libsrdb1.so.1
+%{_libdir}/kamailio/libsrdb1.so.1.0
+%{_libdir}/kamailio/libsrdb2.so
+%{_libdir}/kamailio/libsrdb2.so.1
+%{_libdir}/kamailio/libsrdb2.so.1.0
+%{_libdir}/kamailio/libsrutils.so
+%{_libdir}/kamailio/libsrutils.so.1
+%{_libdir}/kamailio/libsrutils.so.1.0
+%{_libdir}/kamailio/libtrie.so
+%{_libdir}/kamailio/libtrie.so.1
+%{_libdir}/kamailio/libtrie.so.1.0
+
+%dir %{_libdir}/kamailio/modules
+%{_libdir}/kamailio/modules/acc.so
+%{_libdir}/kamailio/modules/alias_db.so
+%{_libdir}/kamailio/modules/async.so
+%{_libdir}/kamailio/modules/auth.so
+%{_libdir}/kamailio/modules/auth_db.so
+%{_libdir}/kamailio/modules/auth_diameter.so
+%{_libdir}/kamailio/modules/avp.so
+%{_libdir}/kamailio/modules/avpops.so
+%{_libdir}/kamailio/modules/benchmark.so
+%{_libdir}/kamailio/modules/blst.so
+%{_libdir}/kamailio/modules/call_control.so
+%{_libdir}/kamailio/modules/cfg_db.so
+%{_libdir}/kamailio/modules/cfg_rpc.so
+%{_libdir}/kamailio/modules/cfgutils.so
+%{_libdir}/kamailio/modules/cnxcc.so
+%{_libdir}/kamailio/modules/corex.so
+%{_libdir}/kamailio/modules/counters.so
+%{_libdir}/kamailio/modules/ctl.so
+%{_libdir}/kamailio/modules/db_cluster.so
+%{_libdir}/kamailio/modules/db_flatstore.so
+%{_libdir}/kamailio/modules/db_text.so
+%{_libdir}/kamailio/modules/db2_ops.so
+%{_libdir}/kamailio/modules/debugger.so
+%{_libdir}/kamailio/modules/dialog.so
+%{_libdir}/kamailio/modules/dialog_ng.so
+%{_libdir}/kamailio/modules/dispatcher.so
+%{_libdir}/kamailio/modules/diversion.so
+%{_libdir}/kamailio/modules/dmq.so
+%{_libdir}/kamailio/modules/domain.so
+%{_libdir}/kamailio/modules/domainpolicy.so
+%{_libdir}/kamailio/modules/drouting.so
+%{_libdir}/kamailio/modules/enum.so
+%{_libdir}/kamailio/modules/exec.so
+%{_libdir}/kamailio/modules/group.so
+%{_libdir}/kamailio/modules/htable.so
+%{_libdir}/kamailio/modules/imc.so
+%{_libdir}/kamailio/modules/ipops.so
+%{_libdir}/kamailio/modules/kex.so
+%{_libdir}/kamailio/modules/malloc_test.so
+%{_libdir}/kamailio/modules/mangler.so
+%{_libdir}/kamailio/modules/matrix.so
+%{_libdir}/kamailio/modules/maxfwd.so
+%{_libdir}/kamailio/modules/mediaproxy.so
+%{_libdir}/kamailio/modules/mi_datagram.so
+%{_libdir}/kamailio/modules/mi_fifo.so
+%{_libdir}/kamailio/modules/mi_rpc.so
+%{_libdir}/kamailio/modules/mohqueue.so
+%{_libdir}/kamailio/modules/mqueue.so
+%{_libdir}/kamailio/modules/msilo.so
+%{_libdir}/kamailio/modules/msrp.so
+%{_libdir}/kamailio/modules/mtree.so
+%{_libdir}/kamailio/modules/nat_traversal.so
+%{_libdir}/kamailio/modules/nathelper.so
+%{_libdir}/kamailio/modules/p_usrloc.so
+%{_libdir}/kamailio/modules/path.so
+%{_libdir}/kamailio/modules/pdb.so
+%{_libdir}/kamailio/modules/pdt.so
+%{_libdir}/kamailio/modules/permissions.so
+%{_libdir}/kamailio/modules/pike.so
+%{_libdir}/kamailio/modules/pipelimit.so
+%{_libdir}/kamailio/modules/prefix_route.so
+%{_libdir}/kamailio/modules/print.so
+%{_libdir}/kamailio/modules/print_lib.so
+%{_libdir}/kamailio/modules/pv.so
+%{_libdir}/kamailio/modules/qos.so
+%{_libdir}/kamailio/modules/ratelimit.so
+%{_libdir}/kamailio/modules/registrar.so
+%{_libdir}/kamailio/modules/rr.so
+%{_libdir}/kamailio/modules/rtimer.so
+%{_libdir}/kamailio/modules/rtpproxy.so
+%{_libdir}/kamailio/modules/rtpproxy-ng.so
+%{_libdir}/kamailio/modules/sanity.so
+%{_libdir}/kamailio/modules/sca.so
+%{_libdir}/kamailio/modules/sdpops.so
+%{_libdir}/kamailio/modules/seas.so
+%{_libdir}/kamailio/modules/sipcapture.so
+%{_libdir}/kamailio/modules/sipt.so
+%{_libdir}/kamailio/modules/siptrace.so
+%{_libdir}/kamailio/modules/siputils.so
+%{_libdir}/kamailio/modules/sl.so
+%{_libdir}/kamailio/modules/sms.so
+%{_libdir}/kamailio/modules/speeddial.so
+%{_libdir}/kamailio/modules/sqlops.so
+%{_libdir}/kamailio/modules/sst.so
+%{_libdir}/kamailio/modules/statistics.so
+%{_libdir}/kamailio/modules/stun.so
+%{_libdir}/kamailio/modules/textops.so
+%{_libdir}/kamailio/modules/textopsx.so
+%{_libdir}/kamailio/modules/timer.so
+%{_libdir}/kamailio/modules/tm.so
+%{_libdir}/kamailio/modules/tmrec.so
+%{_libdir}/kamailio/modules/tmx.so
+%{_libdir}/kamailio/modules/topoh.so
+%{_libdir}/kamailio/modules/uac.so
+%{_libdir}/kamailio/modules/uac_redirect.so
+%{_libdir}/kamailio/modules/uid_auth_db.so
+%{_libdir}/kamailio/modules/uid_avp_db.so
+%{_libdir}/kamailio/modules/uid_domain.so
+%{_libdir}/kamailio/modules/uid_gflags.so
+%{_libdir}/kamailio/modules/uid_uri_db.so
+%{_libdir}/kamailio/modules/uri_db.so
+%{_libdir}/kamailio/modules/userblacklist.so
+%{_libdir}/kamailio/modules/usrloc.so
+%{_libdir}/kamailio/modules/xhttp.so
+%{_libdir}/kamailio/modules/xhttp_rpc.so
+%{_libdir}/kamailio/modules/xlog.so
+%{_libdir}/kamailio/modules/xprint.so
+
+%{_sbindir}/kamailio
+%{_sbindir}/kamctl
+%{_sbindir}/kamdbctl
+%{_sbindir}/kamcmd
+
+%dir %{_libdir}/kamailio/kamctl
+%{_libdir}/kamailio/kamctl/kamctl.base
+%{_libdir}/kamailio/kamctl/kamctl.ctlbase
+%{_libdir}/kamailio/kamctl/kamctl.dbtext
+%{_libdir}/kamailio/kamctl/kamctl.fifo
+%{_libdir}/kamailio/kamctl/kamctl.ser
+%{_libdir}/kamailio/kamctl/kamctl.ser_mi
+%{_libdir}/kamailio/kamctl/kamctl.sqlbase
+%{_libdir}/kamailio/kamctl/kamctl.unixsock
+%{_libdir}/kamailio/kamctl/kamdbctl.base
+%{_libdir}/kamailio/kamctl/kamdbctl.dbtext
+
+%dir %{_libdir}/kamailio/kamctl/dbtextdb
+%{_libdir}/kamailio/kamctl/dbtextdb/dbtextdb.py
+%{_libdir}/kamailio/kamctl/dbtextdb/dbtextdb.pyc
+%{_libdir}/kamailio/kamctl/dbtextdb/dbtextdb.pyo
+
+%{_mandir}/man5/*
+%{_mandir}/man8/*
+
+%dir %{_datadir}/kamailio
+%dir %{_datadir}/kamailio/dbtext
+%dir %{_datadir}/kamailio/dbtext/kamailio
+%{_datadir}/kamailio/dbtext/kamailio/*
+
+
+%files		auth-ephemeral
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.auth_ephemeral
+%{_libdir}/kamailio/modules/auth_ephemeral.so
+
+
+%files		bdb
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.db_berkeley
+%{_sbindir}/kambdb_recover
+%{_libdir}/kamailio/modules/db_berkeley.so
+%{_libdir}/kamailio/kamctl/kamctl.db_berkeley
+%{_libdir}/kamailio/kamctl/kamdbctl.db_berkeley
+%dir %{_datadir}/kamailio/db_berkeley
+%{_datadir}/kamailio/db_berkeley/*
+
+
+%files		carrierroute
+%defattr(-,root,root)
+%{_docdir}/kamailio/modules/README.carrierroute
+%{_libdir}/kamailio/modules/carrierroute.so
+
+
+%files		cpl
+%defattr(-,root,root)
+%{_docdir}/kamailio/modules/README.cpl-c
+%{_libdir}/kamailio/modules/cpl-c.so
+
+
+%files		dialplan
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.dialplan
+%{_libdir}/kamailio/modules/dialplan.so
+
+
+%files		dnssec
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.dnssec
+%{_libdir}/kamailio/modules/dnssec.so
+
+
+%files		geoip
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.geoip
+%{_libdir}/kamailio/modules/geoip.so
+
+
+%files		gzcompress
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.gzcompress
+%{_libdir}/kamailio/modules/gzcompress.so
+
+
+%files		ims
+%defattr(-,root,root)
+%{_libdir}/kamailio/libkamailio_ims.so
+%{_libdir}/kamailio/libkamailio_ims.so.0
+%{_libdir}/kamailio/libkamailio_ims.so.0.1
+
+%doc %{_docdir}/kamailio/modules/README.cdp
+%doc %{_docdir}/kamailio/modules/README.cdp_avp
+%doc %{_docdir}/kamailio/modules/README.ims_auth
+%doc %{_docdir}/kamailio/modules/README.ims_charging
+%doc %{_docdir}/kamailio/modules/README.ims_icscf
+%doc %{_docdir}/kamailio/modules/README.ims_isc
+%doc %{_docdir}/kamailio/modules/README.ims_qos
+#%doc %{_docdir}/kamailio/modules/README.ims_registrar_pcscf
+#%doc %{_docdir}/kamailio/modules/README.ims_registrar_scscf
+%doc %{_docdir}/kamailio/modules/README.ims_usrloc_pcscf
+#%doc %{_docdir}/kamailio/modules/README.ims_usrloc_scscf
+%{_libdir}/kamailio/modules/cdp.so
+%{_libdir}/kamailio/modules/cdp_avp.so
+%{_libdir}/kamailio/modules/ims_auth.so
+%{_libdir}/kamailio/modules/ims_charging.so
+%{_libdir}/kamailio/modules/ims_icscf.so
+%{_libdir}/kamailio/modules/ims_isc.so
+%{_libdir}/kamailio/modules/ims_qos.so
+%{_libdir}/kamailio/modules/ims_registrar_pcscf.so
+%{_libdir}/kamailio/modules/ims_registrar_scscf.so
+%{_libdir}/kamailio/modules/ims_usrloc_pcscf.so
+%{_libdir}/kamailio/modules/ims_usrloc_scscf.so
+
+
+%files		java
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.app_java
+%{_libdir}/kamailio/modules/app_java.so
+%dir %{_libdir}/kamailio/java
+%{_libdir}/kamailio/java/Kamailio.class
+%{_libdir}/kamailio/java/kamailio.jar
+
+
+%files		json
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.json
+%doc %{_docdir}/kamailio/modules/README.jsonrpc-c
+%{_libdir}/kamailio/modules/json.so
+%{_libdir}/kamailio/modules/jsonrpc-c.so
+
+
+%files		lcr
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.lcr
+%{_libdir}/kamailio/modules/lcr.so
+
+
+%files		ldap
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.db2_ldap
+%doc %{_docdir}/kamailio/modules/README.h350
+%doc %{_docdir}/kamailio/modules/README.ldap
+%{_libdir}/kamailio/modules/db2_ldap.so
+%{_libdir}/kamailio/modules/h350.so
+%{_libdir}/kamailio/modules/ldap.so
+
+
+%files		lua
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.app_lua
+%{_libdir}/kamailio/modules/app_lua.so
+
+
+%files		memcached
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.memcached
+%{_libdir}/kamailio/modules/memcached.so
+
+
+%files		mysql
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.db_mysql
+%{_libdir}/kamailio/modules/db_mysql.so
+%{_libdir}/kamailio/kamctl/kamctl.mysql
+%{_libdir}/kamailio/kamctl/kamdbctl.mysql
+%dir %{_datadir}/kamailio/mysql
+%{_datadir}/kamailio/mysql/*
+
+
+%files		outbound
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.outbound
+%{_libdir}/kamailio/modules/outbound.so
+
+
+%files		perl
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.app_perl
+%doc %{_docdir}/kamailio/modules/README.db_perlvdb
+%{_libdir}/kamailio/modules/app_perl.so
+%{_libdir}/kamailio/modules/db_perlvdb.so
+%dir %{_libdir}/kamailio/perl
+%{_libdir}/kamailio/perl/Kamailio.pm
+%dir %{_libdir}/kamailio/perl/Kamailio
+%{_libdir}/kamailio/perl/Kamailio/Constants.pm
+%{_libdir}/kamailio/perl/Kamailio/Message.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB.pm
+%dir %{_libdir}/kamailio/perl/Kamailio/LDAPUtils
+%{_libdir}/kamailio/perl/Kamailio/LDAPUtils/LDAPConf.pm
+%{_libdir}/kamailio/perl/Kamailio/LDAPUtils/LDAPConnection.pm
+%dir %{_libdir}/kamailio/perl/Kamailio/Utils
+%{_libdir}/kamailio/perl/Kamailio/Utils/Debug.pm
+%{_libdir}/kamailio/perl/Kamailio/Utils/PhoneNumbers.pm
+%dir %{_libdir}/kamailio/perl/Kamailio/VDB
+%{_libdir}/kamailio/perl/Kamailio/VDB/Column.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Pair.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/ReqCond.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Result.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/VTab.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Value.pm
+%dir %{_libdir}/kamailio/perl/Kamailio/VDB/Adapter
+%{_libdir}/kamailio/perl/Kamailio/VDB/Adapter/AccountingSIPtrace.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Adapter/Alias.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Adapter/Auth.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Adapter/Describe.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Adapter/Speeddial.pm
+%{_libdir}/kamailio/perl/Kamailio/VDB/Adapter/TableVersions.pm
+
+
+%files		postgresql
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.db_postgres
+%{_libdir}/kamailio/modules/db_postgres.so
+%{_libdir}/kamailio/kamctl/kamctl.pgsql
+%{_libdir}/kamailio/kamctl/kamdbctl.pgsql
+%dir %{_datadir}/kamailio/postgres
+%{_datadir}/kamailio/postgres/*
+
+
+%files		presence
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.presence
+%doc %{_docdir}/kamailio/modules/README.presence_conference
+%doc %{_docdir}/kamailio/modules/README.presence_dialoginfo
+%doc %{_docdir}/kamailio/modules/README.presence_mwi
+%doc %{_docdir}/kamailio/modules/README.presence_profile
+%doc %{_docdir}/kamailio/modules/README.presence_reginfo
+%doc %{_docdir}/kamailio/modules/README.presence_xml
+%doc %{_docdir}/kamailio/modules/README.pua
+%doc %{_docdir}/kamailio/modules/README.pua_bla
+%doc %{_docdir}/kamailio/modules/README.pua_dialoginfo
+%doc %{_docdir}/kamailio/modules/README.pua_mi
+%doc %{_docdir}/kamailio/modules/README.pua_reginfo
+%doc %{_docdir}/kamailio/modules/README.pua_usrloc
+%doc %{_docdir}/kamailio/modules/README.pua_xmpp
+%doc %{_docdir}/kamailio/modules/README.rls
+%doc %{_docdir}/kamailio/modules/README.xcap_client
+%doc %{_docdir}/kamailio/modules/README.xcap_server
+%{_libdir}/kamailio/modules/presence.so
+%{_libdir}/kamailio/modules/presence_conference.so
+%{_libdir}/kamailio/modules/presence_dialoginfo.so
+%{_libdir}/kamailio/modules/presence_mwi.so
+%{_libdir}/kamailio/modules/presence_profile.so
+%{_libdir}/kamailio/modules/presence_reginfo.so
+%{_libdir}/kamailio/modules/presence_xml.so
+%{_libdir}/kamailio/modules/pua.so
+%{_libdir}/kamailio/modules/pua_bla.so
+%{_libdir}/kamailio/modules/pua_dialoginfo.so
+%{_libdir}/kamailio/modules/pua_mi.so
+%{_libdir}/kamailio/modules/pua_reginfo.so
+%{_libdir}/kamailio/modules/pua_usrloc.so
+%{_libdir}/kamailio/modules/pua_xmpp.so
+%{_libdir}/kamailio/modules/rls.so
+%{_libdir}/kamailio/modules/xcap_client.so
+%{_libdir}/kamailio/modules/xcap_server.so
+
+
+%files		purple
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.purple
+%{_libdir}/kamailio/modules/purple.so
+
+
+%files		python
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.app_python
+%{_libdir}/kamailio/modules/app_python.so
+
+
+%files		radius
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.acc_radius
+%doc %{_docdir}/kamailio/modules/README.auth_radius
+%doc %{_docdir}/kamailio/modules/README.misc_radius
+%doc %{_docdir}/kamailio/modules/README.peering
+%{_libdir}/kamailio/modules/acc_radius.so
+%{_libdir}/kamailio/modules/auth_radius.so
+%{_libdir}/kamailio/modules/misc_radius.so
+%{_libdir}/kamailio/modules/peering.so
+
+
+%files		redis
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.ndb_redis
+%{_libdir}/kamailio/modules/ndb_redis.so
+
+
+%files		regex
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.regex
+%{_libdir}/kamailio/modules/regex.so
+
+
+%files		sctp
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.sctp
+%{_libdir}/kamailio/modules/sctp.so
+
+
+%files		snmpstats
+%defattr(-,root,root)
+%{_docdir}/kamailio/modules/README.snmpstats
+%{_libdir}/kamailio/modules/snmpstats.so
+
+
+%files		sqlite
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.db_sqlite
+%{_libdir}/kamailio/modules/db_sqlite.so
+%{_libdir}/kamailio/kamctl/kamctl.sqlite
+%{_libdir}/kamailio/kamctl/kamdbctl.sqlite
+%dir %{_datadir}/kamailio/db_sqlite
+%{_datadir}/kamailio/db_sqlite/*
+
+
+%files		tls
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.auth_identity
+%doc %{_docdir}/kamailio/modules/README.tls
+%{_libdir}/kamailio/modules/auth_identity.so
+%{_libdir}/kamailio/modules/tls.so
+
+
+%files		unixodbc
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.db_unixodbc
+%{_libdir}/kamailio/modules/db_unixodbc.so
+
+
+%files		utils
+%defattr(-,root,root)
+%{_docdir}/kamailio/modules/README.utils
+%{_libdir}/kamailio/modules/utils.so
+
+
+%files		websocket
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.websocket
+%{_libdir}/kamailio/modules/websocket.so
+
+
+%files		xhttp-pi
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.xhttp_pi
+%{_libdir}/kamailio/modules/xhttp_pi.so
+%dir %{_datadir}/kamailio/xhttp_pi
+%{_datadir}/kamailio/xhttp_pi/*
+
+
+%files		xmlops
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.xmlops
+%{_libdir}/kamailio/modules/xmlops.so
+
+
+%files		xmlrpc
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.xmlrpc
+%{_libdir}/kamailio/modules/xmlrpc.so
+%doc %{_docdir}/kamailio/modules/README.mi_xmlrpc
+%{_libdir}/kamailio/modules/mi_xmlrpc.so
+
+
+%files		xmpp
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.xmpp
+%{_libdir}/kamailio/modules/xmpp.so
+
+
+
+%changelog
+* Mon Oct 7 2013 Peter Dunkley <peter.dunkley at crocodilertc.net>
+  - Consolidating changelog for 4.1.0 into a single entry...
+  - Added new modules to main package:
+    - cnxcc
+    - gzcompress
+    - mohqueue
+    - rtpproxy-ng
+    - sipt
+    - stun (STUN functionality moved from compile time in core to own module)
+  - Added new modules to other packages:
+    - ims_charging module to ims package
+  - Added new packages for new modules:
+    - app_java
+    - auth_ephemeral
+    - sctp (SCTP functionality moved from compile time in core to own module)
+  - Moved existing modules to different packages:
+    - auth_identity to tls package (previously not built for CentOS)
+    - cdp and cdp_avp to ims package
+    - dialog_ng to main package
+    - memcached to own package (previously not built for CentOS)
+    - mi_xmlrpc to own package (previously not built for CentOS)
+    - tls to own package
+  - Added packages for (new and existing) modules that require EPEL:
+    - carrierroute in own package
+    - dnssec in own package
+    - geoip in own package
+    - json and jsonrpc-c in new json package
+    - redis in own package
+    - acc_radius, auth_radius, misc_radius, and peering in new radius package
+  - Removed Fedora stuff as I am only maintaining this for CentOS now
+  - Refactored .spec
+  - Updated make commands to match updated module groups
+  - Updated version to 4.1.0
+* Mon Mar 11 2013 Peter Dunkley <peter.dunkley at crocodilertc.net>
+  - Consolidating changelog for 4.0.0 into a single entry...
+  - Added new modules to main package:
+    - corex
+    - sca
+  - Added new packages for new modules:
+    - cdp (cdp, cdp_avp)
+    - ims (dialog_ng, ims_auth, ims_icscf, ims_isc, ims_qos,
+      ims_registrar_pcscf, ims_registrar_scscf, ims_usrloc_pcscf,
+      ims_usrloc_scscf)
+    - outbound
+    - websocket
+    - xhttp_pi
+  - Moved existing modules to different packages:
+    - Various SER modules added to main package (avp, db2_ops, mangler, timer,
+      uid_auth_db, uid_avp_db, uid_domain, uid_gflags, uid_uri_db, print,
+      print_lib, xprint)
+    - db2_ldap SER module added to ldap package
+    - tls to main package (as OpenSSL was needed in core for STUN)
+  - Moved modules from modules_k/ to modules/
+  - Renamed perl modules
+  - Added installation of auth.7.gz for Fedora now that manpages are built for
+    Fedora
+  - SCTP and STUN now included in this build
+  - Refactored .spec
+  - Updated ver to 4.0.0
+* Mon Jun 18 2012 Peter Dunkley <peter.dunkley at crocodilertc.net>
+  - Consolidating changelog for 3.3.0 into a single entry...
+  - See revision control for details this far back
diff --git a/pkg/kamailio/centos/6/kamailio.sysconfig b/pkg/kamailio/centos/6/kamailio.sysconfig
index d932d63..1a7316f 100644
--- a/pkg/kamailio/centos/6/kamailio.sysconfig
+++ b/pkg/kamailio/centos/6/kamailio.sysconfig
@@ -2,14 +2,29 @@
 # Kamailio startup options
 #
 
+# Set to yes to enable kamailio, once configured properly.
+RUN_KAMAILIO=yes
+
 # User to run as
 USER=kamailio
 
 # Group to run as
 GROUP=kamailio
 
-# Amount of shared memory to allocate for Kamailio (in Mb)
-MEMORY=32
+# Amount of shared memory to allocate for the running Kamailio server (in Mb)
+SHM_MEMORY=64
 
 # Amount of per-process (package) memory to allocate for Kamailio (in Mb)
 PKG_MEMORY=4
+
+# Enable the server to leave a core file when it crashes.
+# Set this to 'yes' to enable kamailio to leave a core file when it crashes
+# or 'no' to disable this feature. This option is case sensitive and only
+# accepts 'yes' and 'no' and only in lowercase letters.
+# On some systems (e.g. Ubuntu 6.10, Debian 4.0) it is necessary to specify
+# a directory for the core files to get a dump. Look into the kamailio
+# init file for an example configuration.
+DUMP_CORE=no
+
+# Add extra command line parameters in the EXTRA_OPTIONS variable
+# EXTRA_OPTIONS="-a no"
diff --git a/pkg/kamailio/deb/debian/changelog b/pkg/kamailio/deb/debian/changelog
index 7e8459b..f5d3633 100644
--- a/pkg/kamailio/deb/debian/changelog
+++ b/pkg/kamailio/deb/debian/changelog
@@ -1,26 +1,8 @@
-kamailio (4.0.4) unstable; urgency=low
+kamailio (4.1.0) unstable; urgency=low
 
-  * update to 4.0.4 from upstream
+  * update to 4.1.0
 
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 02 Oct 2013 16:05:20 +0100
-
-kamailio (4.0.3) unstable; urgency=low
-
-  * update to 4.0.3 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 15 Aug 2013 10:35:20 +0100
-
-kamailio (4.0.2) unstable; urgency=low
-
-  * update to 4.0.2 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 12 Jun 2013 10:55:50 +0100
-
-kamailio (4.0.1) unstable; urgency=low
-
-  * update to 4.0.1 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 25 Apr 2013 11:50:20 +0100
+ -- Victor Seva <linuxmaniac at torreviejawireless.org>  Wed, 04 Dec 2013 11:42:27 +0100
 
 kamailio (4.0.0) unstable; urgency=low
 
diff --git a/pkg/kamailio/deb/debian/control b/pkg/kamailio/deb/debian/control
index f614f42..8271807 100644
--- a/pkg/kamailio/deb/debian/control
+++ b/pkg/kamailio/deb/debian/control
@@ -4,6 +4,7 @@ Priority: optional
 Maintainer: Jon Bonilla <manwe at aholab.ehu.es>
 Build-Depends: bison,
                debhelper (>= 5),
+               default-jdk,
                docbook-xml,
                dpatch,
                dpkg-dev (>= 1.13.19),
@@ -18,8 +19,8 @@ Build-Depends: bison,
                libjson0-dev,
                libldap2-dev,
                liblua5.1-0-dev,
-               libmemcache-dev,
-               libmono-dev,
+               libmemcached-dev,
+               libmono-2.0-dev,
                libmysqlclient-dev,
                libncurses5-dev,
                libpcre3-dev,
@@ -29,12 +30,14 @@ Build-Depends: bison,
                libradiusclient-ng-dev,
                libreadline-dev,
                libsasl2-dev,
+               libsctp-dev,
                libsnmp-dev,
                libsqlite3-dev,
                libssl-dev,
                libxml2-dev,
                libxmlrpc-c3-dev,
                libunistring-dev,
+               libval-dev,
                python,
                python-dev,
                unixodbc-dev,
@@ -49,10 +52,13 @@ Depends: adduser,
          ${misc:Depends},
          ${shlibs:Depends}
 Conflicts: kamailio-regex-modules
-Suggests: kamailio-berkeley-modules,
+Suggests: kamailio-autheph-modules,
+          kamailio-berkeley-modules,
           kamailio-carrierroute-modules,
           kamailio-cpl-modules,
           kamailio-dbg,
+          kamailio-dnssec-modules,
+          kamailio-java-modules,
           kamailio-ldap-modules,
           kamailio-lua-modules,
           kamailio-mono-modules,
@@ -62,6 +68,7 @@ Suggests: kamailio-berkeley-modules,
           kamailio-presence-modules,
           kamailio-python-modules,
           kamailio-radius-modules,
+          kamailio-sctp-modules,
           kamailio-snmpstats-modules,
           kamailio-tls-modules,
           kamailio-unixodbc-modules,
@@ -462,3 +469,48 @@ Description: Kamailio - Websocket Module
  .
  This package contains the module implementing WebSocket transport layer.
 
+Package: kamailio-autheph-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the ephemeral module for Kamailio.
+
+Package: kamailio-sctp-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the sctp module for Kamailio.
+
+Package: kamailio-java-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         default-jre,
+         ${shlibs:Depends}
+Description: contains the app_java module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the app_java module, an extension allowing to
+ execute embedded Java applications within configuration file.
+
+Package: kamailio-dnssec-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         ${shlibs:Depends}
+Description: contains the dnssec module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the dnssec module for Kamailio.
diff --git a/pkg/kamailio/deb/debian/rules b/pkg/kamailio/deb/debian/rules
index 2223f12..25b9656 100755
--- a/pkg/kamailio/deb/debian/rules
+++ b/pkg/kamailio/deb/debian/rules
@@ -42,7 +42,8 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils purple memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python geoip \
-			   redis sqlite json mono ims outbound websocket
+			   redis sqlite json mono ims outbound websocket \
+			   autheph sctp java dnssec
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
diff --git a/pkg/kamailio/deb/jessie/changelog b/pkg/kamailio/deb/jessie/changelog
new file mode 100644
index 0000000..f5d3633
--- /dev/null
+++ b/pkg/kamailio/deb/jessie/changelog
@@ -0,0 +1,88 @@
+kamailio (4.1.0) unstable; urgency=low
+
+  * update to 4.1.0
+
+ -- Victor Seva <linuxmaniac at torreviejawireless.org>  Wed, 04 Dec 2013 11:42:27 +0100
+
+kamailio (4.0.0) unstable; urgency=low
+
+  * update to 4.0.0 from upstream
+
+ -- Daniel-Constantin Mierla <miconda at gmail.com>  Mon, 11 Mar 2013 10:40:30 +0100
+
+kamailio (3.4.0~dev0) unstable; urgency=low
+
+  * update version to 3.4.0~dev0
+
+ -- Jon Bonilla <manwe at aholab.ehu.es>  Wed, 15 Jun 2012 03:15:00 +0100
+
+kamailio (3.2.0) unstable; urgency=low
+
+  * update to 3.2.0 from upstream
+
+ -- Daniel-Constantin Mierla <miconda at gmail.com>  Fri, 29 Apr 2011 12:25:30 +0100
+
+kamailio (3.1.1) unstable; urgency=low
+
+  * update to 3.1.1 from upstream
+
+ -- Jon Bonilla <manwe at aholab.ehu.es>  Fri, 3 Dec 2010 16:30:00 +0100
+
+kamailio (3.1.0) unstable; urgency=low
+
+  * update to 3.1.0 from upstream
+
+ -- Jon Bonilla <manwe at aholab.ehu.es>  Wed, 6 Oct 2010 17:24:00 +0100
+
+kamailio (3.0.2.99) unstable; urgency=low
+
+  * update to 3.0.2.99 for development version builds
+
+ -- Jon Bonilla <manwe at aholab.ehu.es>  Fri, 28 May 2010 22:26:00 +0100
+
+kamailio (3.0.2) unstable; urgency=low
+
+  * update to 3.0.2 from upstream
+
+ -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 27 May 2010 10:27:36 +0100
+
+kamailio (3.0.1) unstable; urgency=low
+
+  * update to 3.0.1 from upstream
+
+ -- Daniel-Constantin Mierla <miconda at gmail.com>  Mon, 08 Mar 2010 20:30:48 +0100
+
+kamailio (3.0.0) unstable; urgency=low
+
+  * update to 3.0.0 from upstream
+
+ -- Daniel-Constantin Mierla <miconda at gmail.com>  Mon, 11 Jan 2010 18:30:42 +0100
+
+kamailio (3.0.0-rc3) unstable; urgency=low
+
+  * update to 3.0.0-rc3 from upstream
+  * updated debian/rules to work with the SIP Router style module packaging
+
+ -- Daniel-Constantin Mierla <miconda at gmail.com>  Fri, 10 Dec 2009 12:10:02 +0100
+
+kamailio (3.0.0-rc2) unstable; urgency=low
+
+  * update to 3.0.0-rc2 from upstream
+  * updated debian/rules to work with the new style module packaging
+
+ -- Jonas Bergler <jonas.bergler at staff.snap.net.nz>  Wed, 18 Nov 2009 12:30:02 +1300
+
+kamailio (1.5.0-svn1) unstable; urgency=low
+
+  * increment debian packaging for trunk
+
+ -- Henning Westerholt <henning.westerholt at 1und1.de>  Mon, 02 Mar 2009 17:40:02 +0100
+
+kamailio (1.4.0-svn1) unstable; urgency=low
+
+  [ Klaus Darilion ]
+  * first release of Kamailio (after renaming from Openser)
+
+ -- Julien BLACHE <jblache at debian.org>  Wed, 12 Dec 2007 17:25:31 +0100
+
+
diff --git a/pkg/kamailio/deb/lenny/compat b/pkg/kamailio/deb/jessie/compat
similarity index 100%
rename from pkg/kamailio/deb/lenny/compat
rename to pkg/kamailio/deb/jessie/compat
diff --git a/pkg/kamailio/deb/jessie/control b/pkg/kamailio/deb/jessie/control
new file mode 100644
index 0000000..8271807
--- /dev/null
+++ b/pkg/kamailio/deb/jessie/control
@@ -0,0 +1,516 @@
+Source: kamailio
+Section: net
+Priority: optional
+Maintainer: Jon Bonilla <manwe at aholab.ehu.es>
+Build-Depends: bison,
+               debhelper (>= 5),
+               default-jdk,
+               docbook-xml,
+               dpatch,
+               dpkg-dev (>= 1.13.19),
+               flex,
+               libconfuse-dev,
+               libcurl3-openssl-dev,
+               libdb-dev (>= 4.6.19),
+               libevent-dev,
+               libexpat1-dev,
+               libgeoip-dev (>= 1.4.5),
+               libhiredis-dev (>= 0.10.0),
+               libjson0-dev,
+               libldap2-dev,
+               liblua5.1-0-dev,
+               libmemcached-dev,
+               libmono-2.0-dev,
+               libmysqlclient-dev,
+               libncurses5-dev,
+               libpcre3-dev,
+               libperl-dev,
+               libpq-dev,
+               libpurple-dev,
+               libradiusclient-ng-dev,
+               libreadline-dev,
+               libsasl2-dev,
+               libsctp-dev,
+               libsnmp-dev,
+               libsqlite3-dev,
+               libssl-dev,
+               libxml2-dev,
+               libxmlrpc-c3-dev,
+               libunistring-dev,
+               libval-dev,
+               python,
+               python-dev,
+               unixodbc-dev,
+               xsltproc,
+               zlib1g-dev
+Standards-Version: 3.9.3
+Homepage: http://www.kamailio.org/
+
+Package: kamailio
+Architecture: any
+Depends: adduser,
+         ${misc:Depends},
+         ${shlibs:Depends}
+Conflicts: kamailio-regex-modules
+Suggests: kamailio-autheph-modules,
+          kamailio-berkeley-modules,
+          kamailio-carrierroute-modules,
+          kamailio-cpl-modules,
+          kamailio-dbg,
+          kamailio-dnssec-modules,
+          kamailio-java-modules,
+          kamailio-ldap-modules,
+          kamailio-lua-modules,
+          kamailio-mono-modules,
+          kamailio-mysql-modules,
+          kamailio-perl-modules,
+          kamailio-postgres-modules,
+          kamailio-presence-modules,
+          kamailio-python-modules,
+          kamailio-radius-modules,
+          kamailio-sctp-modules,
+          kamailio-snmpstats-modules,
+          kamailio-tls-modules,
+          kamailio-unixodbc-modules,
+          kamailio-xml-modules,
+          kamailio-xmpp-modules
+Description: very fast and configurable SIP proxy
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ C Shell-like scripting language provides full control over the server's
+ behaviour. Its modular architecture allows only required functionality to be
+ loaded.
+ .
+ Among others, the following modules are available: Digest Authentication, CPL
+ scripts, Instant Messaging, MySQL support, Presence Agent, Radius
+ Authentication, Record Routing, SMS Gateway, Jabber/XMPP Gateway, Transaction
+ Module, Registrar and User Location, XMLRPC Interface.
+ .
+ This package contains the main Kamailio binary along with the principal modules
+ and support binaries.
+
+Package: kamailio-dbg
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: Debugging symbols for Kamailio SIP proxy
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides gdb debugging symbols  for Kamailio
+
+Package: kamailio-mysql-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         mysql-client,
+         ${shlibs:Depends}
+Replaces: kamailio-mysql-module
+Description: MySQL database connectivity module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the MySQL database driver for Kamailio.
+
+Package: kamailio-postgres-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         postgresql-client,
+         ${shlibs:Depends}
+Replaces: kamailio-postgres-module
+Description: PostgreSQL database connectivity module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the PostgreSQL database driver for Kamailio.
+
+Package: kamailio-cpl-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-cpl-module
+Description: CPL module (CPL interpreter engine) for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides a CPL (Call Processing Language) interpreter for
+ Kamailio, turning Kamailio into a CPL server (storage and interpreter).
+
+Package: kamailio-radius-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: radius modules for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides a set of Radius modules for Kamailio, for
+ authentication, peering, group membership and messages URIs checking
+ against a Radius Server.
+
+Package: kamailio-unixodbc-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-unixodbc-module
+Description: unixODBC database connectivity module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the unixODBC database driver for Kamailio.
+
+Package: kamailio-presence-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: SIMPLE presence modules for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides several Kamailio modules for implementing presence
+ server and presence user agent for RICH presence, registrar-based presence,
+ external triggered presence and XCAP support.
+
+Package: kamailio-xml-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-xml-module,
+          kamailio-xmlrpc-module
+Provides: kamailio-xmlrpc-modules
+Description: XML based extensions for Kamailio's Management Interface
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides:
+ - the XMLRPC transport implementations for Kamailio's
+ Management and Control Interface.
+ - xmlops module for XPath operations in configuration file
+
+Package: kamailio-xmlrpc-modules
+Architecture: any
+Depends: kamailio-xml-modules (= ${binary:Version})
+Description: Transitional package for kamailio-xml-modules
+ Dummy package for transition handling
+
+Package: kamailio-perl-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-perl-module
+Conflicts: kamailio-perl-module
+Description: Perl extensions and database driver for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides an interface for Kamailio to write Perl extensions and
+ the perlvdb database driver for Kamailio.
+
+Package: kamailio-snmpstats-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         snmpd,
+         ${shlibs:Depends}
+Replaces: kamailio-snmpstats-module
+Description: SNMP AgentX subagent module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the snmpstats module for Kamailio. This module acts
+ as an AgentX subagent which connects to a master agent.
+
+Package: kamailio-xmpp-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-xmpp-module
+Description: XMPP gateway module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the SIP to XMPP IM translator module for Kamailio.
+
+Package: kamailio-carrierroute-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-carrierroute-module
+Description: Carrierroute module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the carrierroute module for Kamailio, an integrated
+ solution for routing, balancing and blacklisting.
+
+Package: kamailio-berkeley-modules
+Architecture: any
+Depends: db4.6-util,
+         kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-berkeley-module
+Description: Berkeley Database module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the berkeley database module for Kamailio, a
+ high-performance embedded DB kernel. All database tables are stored
+ in files, no additional server is necessary.
+
+Package: kamailio-ldap-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: LDAP modules for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the ldap and h350 modules for Kamailio, enabling LDAP
+ queries from the Kamailio config and storage of SIP account data in an LDAP
+ directory.
+
+Package: kamailio-utils-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-utils-module
+Description: Provides a set utility functions for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ Provides a set of utility functions for Kamailio, which are not related
+ to the server configuration.
+
+Package: kamailio-purple-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-purple-module
+Description: Provides the purple module, a multi-protocol IM gateway
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the purple module, a multi-protocol instant
+ messaging gateway module.
+
+Package: kamailio-memcached-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Replaces: kamailio-memcached-module
+Description: Provides the memcached module, an interface to the memcached server
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the memcached module, an interface to the memcached
+ server, a high-performance, distributed memory object caching system.
+
+Package: kamailio-tls-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         ${shlibs:Depends}
+Description: contains the TLS kamailio transport module
+ This has been split out of the main kamailio package, so that kamailio will not
+ depend on openssl. This module will enable you to use the TLS transport.
+
+Package: kamailio-lua-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         ${shlibs:Depends}
+Description: contains the app_lua module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the app_lua module, an extension allowing to
+ execute embedded Lua applications within configuration file.
+
+Package: kamailio-mono-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         ${shlibs:Depends}
+Description: contains the app_mono module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the app_mono module, an extension allowing to
+ execute embedded Mono applications within configuration file.
+
+Package: kamailio-python-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         ${shlibs:Depends}
+Description: contains the app_python module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the app_python module, an extension allowing to
+ execute embedded Python applications within configuration file.
+
+Package: kamailio-geoip-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         ${shlibs:Depends}
+Description: contains the geoip module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the geoip module, an extension allowing to
+ use GeoIP API within configuration file.
+
+Package: kamailio-redis-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         libhiredis0.10,
+         ${shlibs:Depends}
+Description: Redis database connectivity module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the Redis NOSQL database driver for Kamailio.
+
+Package: kamailio-sqlite-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         libsqlite3-0,
+         ${shlibs:Depends}
+Description: SQLite database connectivity module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the SQLite database driver for Kamailio.
+
+Package: kamailio-json-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         libevent-1.4-2,
+         libjson0,
+         ${shlibs:Depends}
+Description: Json parser and jsonrpc modules for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides json parser for Kamailio's configuration file
+ and the JSON-RPC client over netstrings.
+
+Package: kamailio-nth
+Architecture: any
+Depends: binutils,
+         bison,
+         bvi,
+         flex,
+         gcc,
+         gdb,
+         iftop,
+         lsof,
+         mc,
+         most,
+         ngrep,
+         psmisc,
+         screen,
+         sipsak,
+         tcpdump,
+         vim
+Description: Kamailio - package for "nice to have" installation
+ This is a meta-package for easy installation various useful tools that may be
+ handy on server with Kamailio installed.
+
+Package: kamailio-ims-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - IMS Modules
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains various Diameter interfaces and modules for Kamailio
+ to run as an IMS core.
+
+Package: kamailio-outbound-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - Outbound Module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains the module implementing SIP outbound extension.
+
+Package: kamailio-websocket-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - Websocket Module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains the module implementing WebSocket transport layer.
+
+Package: kamailio-autheph-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the ephemeral module for Kamailio.
+
+Package: kamailio-sctp-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the sctp module for Kamailio.
+
+Package: kamailio-java-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         default-jre,
+         ${shlibs:Depends}
+Description: contains the app_java module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the app_java module, an extension allowing to
+ execute embedded Java applications within configuration file.
+
+Package: kamailio-dnssec-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         ${shlibs:Depends}
+Description: contains the dnssec module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the dnssec module for Kamailio.
diff --git a/pkg/kamailio/deb/lenny/copyright b/pkg/kamailio/deb/jessie/copyright
similarity index 100%
rename from pkg/kamailio/deb/lenny/copyright
rename to pkg/kamailio/deb/jessie/copyright
diff --git a/pkg/kamailio/deb/lenny/kamailio.README.Debian b/pkg/kamailio/deb/jessie/kamailio.README.Debian
similarity index 100%
rename from pkg/kamailio/deb/lenny/kamailio.README.Debian
rename to pkg/kamailio/deb/jessie/kamailio.README.Debian
diff --git a/pkg/kamailio/deb/lenny/kamailio.default b/pkg/kamailio/deb/jessie/kamailio.default
similarity index 100%
rename from pkg/kamailio/deb/lenny/kamailio.default
rename to pkg/kamailio/deb/jessie/kamailio.default
diff --git a/pkg/kamailio/deb/lenny/kamailio.dirs b/pkg/kamailio/deb/jessie/kamailio.dirs
similarity index 100%
rename from pkg/kamailio/deb/lenny/kamailio.dirs
rename to pkg/kamailio/deb/jessie/kamailio.dirs
diff --git a/pkg/kamailio/deb/lenny/kamailio.examples b/pkg/kamailio/deb/jessie/kamailio.examples
similarity index 100%
rename from pkg/kamailio/deb/lenny/kamailio.examples
rename to pkg/kamailio/deb/jessie/kamailio.examples
diff --git a/pkg/kamailio/deb/jessie/kamailio.init b/pkg/kamailio/deb/jessie/kamailio.init
new file mode 100644
index 0000000..6b0a1ee
--- /dev/null
+++ b/pkg/kamailio/deb/jessie/kamailio.init
@@ -0,0 +1,240 @@
+#! /bin/sh
+#
+### BEGIN INIT INFO
+# Provides:          kamailio
+# Required-Start:    $syslog $network $local_fs $remote_fs $time
+# Required-Stop:     $syslog $network $local_fs $remote_fs
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Should-Start:      postgresql mysql radius
+# Should-Stop:       postgresql mysql radius
+# Short-Description: Start the Kamailio SIP proxy server
+# Description:       Start the Kamailio SIP proxy server
+### END INIT INFO
+
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/kamailio
+NAME=kamailio
+DESC=Kamailio
+HOMEDIR=/var/run/kamailio
+PIDFILE=$HOMEDIR/$NAME.pid
+DEFAULTS=/etc/default/kamailio
+CFGFILE=/etc/kamailio/kamailio.cfg
+RUN_KAMAILIO=no
+
+
+# Do not start kamailio if fork=no is set in the config file
+# otherwise the boot process will just stop.
+check_fork ()
+{
+  if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then
+    echo "Not starting $DESC: fork=no specified in config file. Run /etc/init.d/kamailio debug instead."
+    exit 1
+  fi
+}
+
+
+check_kamailio_config ()
+{
+  # Check if kamailio configuration is valid before starting the server.
+  set +e
+  out=$($DAEMON -f $CFGFILE -M $PKG_MEMORY -c 2>&1 > /dev/null)
+  retcode=$?
+  set -e
+  if [ "$retcode" != '0' ]; then
+    echo "Not starting $DESC: invalid configuration file!"
+    echo -e "\n$out\n"
+    exit 1
+  fi
+}
+
+
+check_homedir ()
+{
+  # Create HOMEDIR directory in case it doesn't exist.
+  # Useful in Ubuntu as /var/run/ content is deleted in shutdown.
+  if [ ! -d $HOMEDIR ]; then
+    mkdir $HOMEDIR
+  fi
+
+  # Set the appropiate owner and group
+  chown ${USER}:${GROUP} $HOMEDIR
+}
+
+
+create_radius_seqfile ()
+{
+  # Create a radius sequence file to be used by the radius client if
+  # radius accounting is enabled. This is needed to avoid any issue
+  # with the file not being writable if kamailio first starts as user
+  # root because DUMP_CORE is enabled and creates this file as user
+  # root and then later it switches back to user kamailio and cannot
+  # write to the file. If the file exists before kamailio starts, it
+  # won't change it's ownership and will be writable for both root
+  # and kamailio, no matter what options are chosen at install time
+  RADIUS_SEQ_FILE=$HOMEDIR/kamailio_radius.seq
+
+  if [ ! -f $RADIUS_SEQ_FILE ]; then
+      touch $RADIUS_SEQ_FILE
+  fi
+
+  chown ${USER}:${GROUP} $RADIUS_SEQ_FILE
+  chmod 660 $RADIUS_SEQ_FILE
+}
+
+
+if [ ! -f $DAEMON ]; then
+  echo "No $DESC daemon at $DAEMON."
+  case "$1" in
+  status)
+    # LSB - 4: program or service status is unknown.
+    exit 4
+    ;;
+  *)
+    # LSB - 5: program is not installed.
+    exit 5
+    ;;
+  esac
+fi
+
+
+# Load startup options if available.
+if [ -f $DEFAULTS ]; then
+  . $DEFAULTS || true
+fi
+
+
+if [ "$RUN_KAMAILIO" != "yes" ]; then
+  echo "$DESC not yet configured. Edit $DEFAULTS first."
+  exit 0
+fi
+
+
+set -e
+
+
+SHM_MEMORY=$((`echo $SHM_MEMORY | sed -e 's/[^0-9]//g'`))
+PKG_MEMORY=$((`echo $PKG_MEMORY | sed -e 's/[^0-9]//g'`))
+[ $SHM_MEMORY -le 0 ] && SHM_MEMORY=64
+[ $PKG_MEMORY -le 0 ] && PKG_MEMORY=4
+[ -z "$USER" ]  && USER=kamailio
+[ -z "$GROUP" ] && GROUP=kamailio
+
+
+if test "$DUMP_CORE" = "yes" ; then
+  # set proper ulimit.
+  ulimit -c unlimited
+
+  # directory for the core dump files.
+  # COREDIR=/tmp/corefiles
+  # [ -d $COREDIR ] || mkdir $COREDIR
+  # chmod 777 $COREDIR
+  # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
+fi
+
+
+if [ "$SSD_SUID" != "yes" ]; then
+  OPTIONS="-f $CFGFILE -P $PIDFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP"
+  SSDOPTS=""
+else
+  OPTIONS="-f $CFGFILE -P $PIDFILE -m $SHM_MEMORY -M $PKG_MEMORY"
+  SSDOPTS="--chuid $USER:$GROUP"
+fi
+
+
+start_kamailio_daemon ()
+{
+  start-stop-daemon --start --quiet --pidfile $PIDFILE $SSDOPTS \
+    --exec $DAEMON -- $OPTIONS
+  res=$?
+
+  echo -n "$NAME "
+  if [ $res -eq 0 ] ; then
+    echo "started."
+    exit 0
+  else
+    if [ ! -r "$PIDFILE" ]; then
+      echo "error, failed to start."
+      exit 1
+    elif read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then
+      echo "already running."
+      exit 0
+    else
+      echo "error, failed to start ($PIDFILE exists)."
+      exit 1
+    fi
+  fi
+}
+
+
+case "$1" in
+  start|debug)
+    check_kamailio_config
+    check_homedir
+    create_radius_seqfile
+
+    if [ "$1" != "debug" ]; then
+      check_fork
+    fi
+
+    echo "Starting $DESC:"
+    set +e
+    start_kamailio_daemon
+    ;;
+
+  stop)
+    echo -n "Stopping $DESC: $NAME "
+    set +e
+    start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
+      --exec $DAEMON
+
+    if [ $? -eq 0 ] ; then
+      echo "stopped."
+      exit 0
+    else
+      echo "failed to stop."
+      exit 1
+    fi
+    ;;
+    
+  restart|force-reload)
+    check_kamailio_config
+    check_homedir
+    create_radius_seqfile
+
+    echo "Restarting $DESC:"
+    set +e
+    start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE --retry=5 \
+      --exec $DAEMON
+    if [ $? -ne 0 ] ; then
+      echo "$NAME failed to stop."
+      exit 1
+    fi
+    start_kamailio_daemon
+    ;;
+
+  status)
+    echo -n "Status of $DESC: $NAME "
+    if [ ! -r "$PIDFILE" ]; then
+      echo "is not running."
+      exit 3
+    fi
+    if read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then
+      echo "is running."
+      exit 0
+    else
+      echo "is not running but $PIDFILE exists."
+      exit 1
+    fi
+    ;;
+
+  *)
+    N=/etc/init.d/$NAME
+    echo "Usage: $N {start|stop|restart|force-reload|debug|status}" >&2
+    exit 1
+    ;;
+esac
+
+
+exit 0
diff --git a/pkg/kamailio/deb/lenny/kamailio.postinst b/pkg/kamailio/deb/jessie/kamailio.postinst
similarity index 100%
rename from pkg/kamailio/deb/lenny/kamailio.postinst
rename to pkg/kamailio/deb/jessie/kamailio.postinst
diff --git a/pkg/kamailio/deb/jessie/rules b/pkg/kamailio/deb/jessie/rules
new file mode 100755
index 0000000..25b9656
--- /dev/null
+++ b/pkg/kamailio/deb/jessie/rules
@@ -0,0 +1,228 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+#
+# $Id$
+#
+# History:
+# --------
+#  2009-07-08  updated for sip-router (andrei)
+#  2009-12-10  updated for kamailio 3.0 (daniel)
+
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatibility version to use.
+# export DH_COMPAT=4
+#  -- already set in compat
+export DEB_BUILD_OPTIONS:="$(DEB_BUILD_OPTIONS) debug"
+
+# modules not in the "main" kamailio package
+EXCLUDED_MODULES= 
+
+# extra modules to skip, because they are not compilable now
+# - regardless if they go to the main kamailio package or to some module package,
+# they will be excluded from compile and install of all
+EXTRA_EXCLUDED_MODULES=bdb dbtext oracle pa iptrtpproxy
+#EXTRA_EXCLUDED_MODULES=
+
+# possible module directories that can appear in MODULES_SP
+# (only used for deducing a module name)
+MDIRS=modules
+
+# modules packaged in separate packages (complete with full modules_* path)
+# with the package name: kamailio-$(module_name)-module
+MODULES_SP=
+
+# module groups that are packaged in seperate packages
+# (with the name kamailio-$(group_name)-modules)
+# Note: the order is important (should be in dependency order, the one
+# on which other depend first)
+PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
+			   ldap xml perl utils purple memcached tls \
+			   snmpstats carrierroute xmpp cpl lua python geoip \
+			   redis sqlite json mono ims outbound websocket \
+			   autheph sctp java dnssec
+
+# name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
+LIBDIR ?= lib
+
+# directories with possible duplicate libraries (that should be deleted
+# from current module* packages)
+DUP_LIBS_DIRS=$(CURDIR)/debian/kamailio/usr/$(LIBDIR)/kamailio \
+			$(CURDIR)/debian/kamailio-db-modules/usr/$(LIBDIR)/kamailio
+
+# modules names out of modules sp
+MODULES_SP_NAMES=$(filter-out $(MDIRS),$(subst /, ,$(MODULES_SP)))
+
+# "function" to get package short name out of a dir/module_name
+# it also transforms db_foo into foo
+mod_name=$(subst db_,,$(lastword $(subst /, ,$(1))))
+
+define PACKAGE_GRP_BUILD_template
+	# package all the modules in PACKAGE_GROUPS in separate packages
+	$(foreach grp,$(PACKAGE_GROUPS),\
+		$(MAKE) every-module group_include="k$(grp)"
+	)
+endef
+
+
+define PACKAGE_MODULE_BUILD_template
+	# package all the modules MODULES_SP in separate packages
+	$(foreach mod,$(MODULES_SP),\
+		$(MAKE) modules modules="$(mod)"
+	)
+endef
+
+
+define PACKAGE_GRP_INSTALL_template
+	$(foreach grp,$(PACKAGE_GROUPS),\
+		$(MAKE) install-modules-all group_include="k$(grp)" \
+		basedir=$(CURDIR)/debian/kamailio-$(grp)-modules \
+		cfg_prefix=$(CURDIR)/debian/kamailio-$(grp)-modules \
+		doc-dir=share/doc/kamailio-$(grp)-modules
+		# eliminate duplicate libs
+		-for d in $(DUP_LIBS_DIRS); do \
+			test "$$d" != "$(CURDIR)/debian/kamailio-$(grp)-modules/usr/$(LIBDIR)/kamailio" &&\
+			for r in $$d/lib*; do \
+				if [ "$$r" != "$$d/lib*" ]; then \
+					echo "removing $(grp) lib `basename $$r` present also in $$d";\
+					rm -f $(CURDIR)/debian/kamailio-$(grp)-modules/usr/$(LIBDIR)/kamailio/`basename "$$r"` ; \
+				fi \
+			done ; \
+		done
+	)
+endef
+
+
+define PACKAGE_MODULE_INSTALL_template
+	$(foreach mod,$(MODULES_SP),
+		$(MAKE) install-modules-all modules="$(mod)" \
+				modules_s="" modules_k="" \
+				basedir=$(CURDIR)/debian/kamailio-$(call mod_name,$(mod))-module \
+				doc-dir=share/doc/kamailio-$(call mod_name,$(mod))-module
+		# eliminate duplicate libs
+		-for d in $(DUP_LIBS_DIRS); do \
+			test "$$d" != "$(CURDIR)/debian/kamailio-$(call mod_name,$(mod))-module/usr/$(LIBDIR)/kamailio" &&\
+			for r in $$d/lib*; do \
+				if [ "$$r" != "$$d/lib*" ]; then \
+					echo "removing $(call mod_name, $(mod)) lib `basename $$r` present also in $$d";\
+					rm -f $(CURDIR)/debian/kamailio-$(call mod_name,$(mod))-module/usr/$(LIBDIR)/kamailio/`basename "$$r"` ; \
+				fi \
+			done ; \
+		done
+	)
+endef
+
+ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -g
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+	INSTALL_PROGRAM += -s
+endif
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	# Add here commands to configure the package.
+	$(MAKE) FLAVOUR=kamailio cfg prefix=/usr cfg_prefix=$(CURDIR)/debian/kamailio \
+			cfg_target=/etc/kamailio/ \
+			basedir=$(CURDIR)/debian/kamailio \
+			skip_modules="$(EXCLUDED_MODULES) $(EXTRA_EXCLUDED_MODULES)" \
+			group_include="kstandard"
+
+	touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp 
+	dh_testdir
+	# Add here commands to compile the package.
+	$(MAKE) all
+	# make groups
+	$(call PACKAGE_GRP_BUILD_template)
+	# make single-module packages
+	$(call PACKAGE_MODULE_BUILD_template)
+	touch build-stamp
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+	# Add here commands to clean up after the build process.
+	-$(MAKE) maintainer-clean
+	dh_clean
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k
+	dh_installdirs
+	# Add here commands to install the package into debian/kamailio
+	$(MAKE) install group_include="kstandard"
+	# fix etc/kamailio dir location -- not needed -- andrei
+	# mv -f $(CURDIR)/debian/kamailio/usr/etc $(CURDIR)/debian/kamailio
+	# make group packages
+	$(call PACKAGE_GRP_INSTALL_template)
+	# make single module packages
+	$(call PACKAGE_MODULE_INSTALL_template)
+	# install /etc/default/kamailio file
+	mkdir -p $(CURDIR)/debian/kamailio/etc/default
+	cp -f debian/kamailio.default $(CURDIR)/debian/kamailio/etc/default/kamailio
+	#dh_movefiles
+
+
+
+# This single target is used to build all the packages, all at once, or
+# one at a time. So keep in mind: any options passed to commands here will
+# affect _all_ packages. Anything you want to only affect one package
+# should be put in another target, such as the install target.
+binary-common: 
+	dh_testdir
+	dh_testroot
+	dh_installdebconf	
+	dh_installdocs
+	dh_installexamples
+	dh_installmenu
+#	dh_installlogrotate
+#	dh_installemacsen
+#	dh_installpam
+#	dh_installmime
+	dh_installinit  -- defaults 23
+	dh_installcron
+	dh_installman
+	dh_installinfo
+#	dh_undocumented
+	dh_installchangelogs ChangeLog 
+	dh_link
+	dh_strip --dbg-package=kamailio-dbg
+	dh_compress 
+	dh_fixperms
+	dh_makeshlibs
+	dh_installdeb
+#	dh_perl
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+# Build architecture-independent packages using the common target
+binary-indep: build install
+# (Uncomment this next line if you have such packages.)
+#        $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
+# We have nothing to do by default.
+
+
+# Build architecture-dependent packages using the common target
+binary-arch: build install
+	$(MAKE) -f debian/rules DH_OPTIONS=-a binary-common
+
+# Any other binary targets build just one binary package at a time.
+binary-%: build install
+	$(MAKE) -f debian/rules binary-common DH_OPTIONS=-p$*
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+
diff --git a/pkg/kamailio/deb/lenny/changelog b/pkg/kamailio/deb/lenny/changelog
deleted file mode 100644
index 7e8459b..0000000
--- a/pkg/kamailio/deb/lenny/changelog
+++ /dev/null
@@ -1,106 +0,0 @@
-kamailio (4.0.4) unstable; urgency=low
-
-  * update to 4.0.4 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 02 Oct 2013 16:05:20 +0100
-
-kamailio (4.0.3) unstable; urgency=low
-
-  * update to 4.0.3 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 15 Aug 2013 10:35:20 +0100
-
-kamailio (4.0.2) unstable; urgency=low
-
-  * update to 4.0.2 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 12 Jun 2013 10:55:50 +0100
-
-kamailio (4.0.1) unstable; urgency=low
-
-  * update to 4.0.1 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 25 Apr 2013 11:50:20 +0100
-
-kamailio (4.0.0) unstable; urgency=low
-
-  * update to 4.0.0 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Mon, 11 Mar 2013 10:40:30 +0100
-
-kamailio (3.4.0~dev0) unstable; urgency=low
-
-  * update version to 3.4.0~dev0
-
- -- Jon Bonilla <manwe at aholab.ehu.es>  Wed, 15 Jun 2012 03:15:00 +0100
-
-kamailio (3.2.0) unstable; urgency=low
-
-  * update to 3.2.0 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Fri, 29 Apr 2011 12:25:30 +0100
-
-kamailio (3.1.1) unstable; urgency=low
-
-  * update to 3.1.1 from upstream
-
- -- Jon Bonilla <manwe at aholab.ehu.es>  Fri, 3 Dec 2010 16:30:00 +0100
-
-kamailio (3.1.0) unstable; urgency=low
-
-  * update to 3.1.0 from upstream
-
- -- Jon Bonilla <manwe at aholab.ehu.es>  Wed, 6 Oct 2010 17:24:00 +0100
-
-kamailio (3.0.2.99) unstable; urgency=low
-
-  * update to 3.0.2.99 for development version builds
-
- -- Jon Bonilla <manwe at aholab.ehu.es>  Fri, 28 May 2010 22:26:00 +0100
-
-kamailio (3.0.2) unstable; urgency=low
-
-  * update to 3.0.2 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 27 May 2010 10:27:36 +0100
-
-kamailio (3.0.1) unstable; urgency=low
-
-  * update to 3.0.1 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Mon, 08 Mar 2010 20:30:48 +0100
-
-kamailio (3.0.0) unstable; urgency=low
-
-  * update to 3.0.0 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Mon, 11 Jan 2010 18:30:42 +0100
-
-kamailio (3.0.0-rc3) unstable; urgency=low
-
-  * update to 3.0.0-rc3 from upstream
-  * updated debian/rules to work with the SIP Router style module packaging
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Fri, 10 Dec 2009 12:10:02 +0100
-
-kamailio (3.0.0-rc2) unstable; urgency=low
-
-  * update to 3.0.0-rc2 from upstream
-  * updated debian/rules to work with the new style module packaging
-
- -- Jonas Bergler <jonas.bergler at staff.snap.net.nz>  Wed, 18 Nov 2009 12:30:02 +1300
-
-kamailio (1.5.0-svn1) unstable; urgency=low
-
-  * increment debian packaging for trunk
-
- -- Henning Westerholt <henning.westerholt at 1und1.de>  Mon, 02 Mar 2009 17:40:02 +0100
-
-kamailio (1.4.0-svn1) unstable; urgency=low
-
-  [ Klaus Darilion ]
-  * first release of Kamailio (after renaming from Openser)
-
- -- Julien BLACHE <jblache at debian.org>  Wed, 12 Dec 2007 17:25:31 +0100
-
-
diff --git a/pkg/kamailio/deb/lenny/control b/pkg/kamailio/deb/lenny/control
deleted file mode 100644
index 4f5ea76..0000000
--- a/pkg/kamailio/deb/lenny/control
+++ /dev/null
@@ -1,387 +0,0 @@
-Source: kamailio
-Section: net
-Priority: optional
-Maintainer: Jon Bonilla <manwe at aholab.ehu.es>
-Build-Depends: bison,
-               debhelper (>= 5),
-               docbook-xml,
-               dpatch,
-               dpkg-dev (>= 1.13.19),
-               flex,
-               libconfuse-dev,
-               libcurl3-openssl-dev,
-               libdb-dev (>= 4.6.19),
-               libexpat1-dev,
-               libldap2-dev,
-               liblua5.1-0-dev,
-               libmemcache-dev,
-               libmysqlclient-dev,
-               libncurses5-dev,
-               libpcre3-dev,
-               libperl-dev,
-               libpq-dev,
-               libpurple-dev,
-               libradiusclient-ng-dev,
-               libreadline-dev,
-               libsasl2-dev,
-               libsnmp-dev,
-               libsqlite3-dev,
-               libssl-dev,
-               libxml2-dev,
-               libxmlrpc-c3-dev,
-               python,
-               python-dev,
-               unixodbc-dev,
-               xsltproc,
-               zlib1g-dev
-Standards-Version: 3.9.3
-Homepage: http://www.kamailio.org/
-
-Package: kamailio
-Architecture: any
-Depends: adduser,
-         ${misc:Depends},
-         ${shlibs:Depends}
-Conflicts: kamailio-regex-modules
-Suggests: kamailio-berkeley-modules,
-          kamailio-carrierroute-modules,
-          kamailio-cpl-modules,
-          kamailio-dbg,
-          kamailio-ldap-modules,
-          kamailio-lua-modules,
-          kamailio-mysql-modules,
-          kamailio-perl-modules,
-          kamailio-postgres-modules,
-          kamailio-presence-modules,
-          kamailio-python-modules,
-          kamailio-radius-modules,
-          kamailio-snmpstats-modules,
-          kamailio-tls-modules,
-          kamailio-unixodbc-modules,
-          kamailio-xml-modules,
-          kamailio-xmpp-modules
-Description: very fast and configurable SIP proxy
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- C Shell-like scripting language provides full control over the server's
- behaviour. Its modular architecture allows only required functionality to be
- loaded.
- .
- Among others, the following modules are available: Digest Authentication, CPL
- scripts, Instant Messaging, MySQL support, Presence Agent, Radius
- Authentication, Record Routing, SMS Gateway, Jabber/XMPP Gateway, Transaction
- Module, Registrar and User Location, XMLRPC Interface.
- .
- This package contains the main Kamailio binary along with the principal modules
- and support binaries.
-
-Package: kamailio-dbg
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Description: Debugging symbols for Kamailio SIP proxy
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides gdb debugging symbols  for Kamailio
-
-Package: kamailio-mysql-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         mysql-client,
-         ${shlibs:Depends}
-Replaces: kamailio-mysql-module
-Description: MySQL database connectivity module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the MySQL database driver for Kamailio.
-
-Package: kamailio-postgres-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         postgresql-client,
-         ${shlibs:Depends}
-Replaces: kamailio-postgres-module
-Description: PostgreSQL database connectivity module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the PostgreSQL database driver for Kamailio.
-
-Package: kamailio-cpl-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-cpl-module
-Description: CPL module (CPL interpreter engine) for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides a CPL (Call Processing Language) interpreter for
- Kamailio, turning Kamailio into a CPL server (storage and interpreter).
-
-Package: kamailio-radius-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Description: radius modules for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides a set of Radius modules for Kamailio, for
- authentication, peering, group membership and messages URIs checking
- against a Radius Server.
-
-Package: kamailio-unixodbc-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-unixodbc-module
-Description: unixODBC database connectivity module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the unixODBC database driver for Kamailio.
-
-Package: kamailio-presence-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Description: SIMPLE presence modules for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides several Kamailio modules for implementing presence
- server and presence user agent for RICH presence, registrar-based presence,
- external triggered presence and XCAP support.
-
-Package: kamailio-xml-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-xml-module,
-          kamailio-xmlrpc-module
-Provides: kamailio-xmlrpc-modules
-Description: XML based extensions for Kamailio's Management Interface
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides:
- - the XMLRPC transport implementations for Kamailio's
- Management and Control Interface.
- - xmlops module for XPath operations in configuration file
-
-Package: kamailio-xmlrpc-modules
-Architecture: any
-Depends: kamailio-xml-modules (= ${binary:Version})
-Description: Transitional package for kamailio-xml-modules
- Dummy package for transition handling
-
-Package: kamailio-perl-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-perl-module
-Conflicts: kamailio-perl-module
-Description: Perl extensions and database driver for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides an interface for Kamailio to write Perl extensions and
- the perlvdb database driver for Kamailio.
-
-Package: kamailio-snmpstats-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         snmpd,
-         ${shlibs:Depends}
-Replaces: kamailio-snmpstats-module
-Description: SNMP AgentX subagent module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the snmpstats module for Kamailio. This module acts
- as an AgentX subagent which connects to a master agent.
-
-Package: kamailio-xmpp-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-xmpp-module
-Description: XMPP gateway module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the SIP to XMPP IM translator module for Kamailio.
-
-Package: kamailio-carrierroute-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-carrierroute-module
-Description: Carrierroute module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the carrierroute module for Kamailio, an integrated
- solution for routing, balancing and blacklisting.
-
-Package: kamailio-berkeley-modules
-Architecture: any
-Depends: db4.6-util,
-         kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-berkeley-module
-Description: Berkeley Database module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the berkeley database module for Kamailio, a
- high-performance embedded DB kernel. All database tables are stored
- in files, no additional server is necessary.
-
-Package: kamailio-ldap-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Description: LDAP modules for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the ldap and h350 modules for Kamailio, enabling LDAP
- queries from the Kamailio config and storage of SIP account data in an LDAP
- directory.
-
-Package: kamailio-utils-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-utils-module
-Description: Provides a set utility functions for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- Provides a set of utility functions for Kamailio, which are not related
- to the server configuration.
-
-Package: kamailio-purple-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-purple-module
-Description: Provides the purple module, a multi-protocol IM gateway
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the purple module, a multi-protocol instant
- messaging gateway module.
-
-Package: kamailio-memcached-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         ${shlibs:Depends}
-Replaces: kamailio-memcached-module
-Description: Provides the memcached module, an interface to the memcached server
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the memcached module, an interface to the memcached
- server, a high-performance, distributed memory object caching system.
-
-Package: kamailio-tls-modules
-Architecture: any
-Depends: kamailio (= ${Source-Version}),
-         ${shlibs:Depends}
-Description: contains the TLS kamailio transport module
- This has been split out of the main kamailio package, so that kamailio will not
- depend on openssl. This module will enable you to use the TLS transport.
-
-Package: kamailio-lua-modules
-Architecture: any
-Depends: kamailio (= ${Source-Version}),
-         ${shlibs:Depends}
-Description: contains the app_lua module
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the app_lua module, an extension allowing to
- execute embedded Lua applications within configuration file.
-
-Package: kamailio-python-modules
-Architecture: any
-Depends: kamailio (= ${Source-Version}),
-         ${shlibs:Depends}
-Description: contains the app_python module
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the app_python module, an extension allowing to
- execute embedded Python applications within configuration file.
-
-Package: kamailio-sqlite-modules
-Architecture: any
-Depends: kamailio (= ${binary:Version}),
-         libsqlite3-0,
-         ${shlibs:Depends}
-Description: SQLite database connectivity module for Kamailio
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package provides the SQLite database driver for Kamailio.
-
-Package: kamailio-nth
-Architecture: any
-Depends: binutils,
-         bison,
-         bvi,
-         flex,
-         gcc,
-         gdb,
-         iftop,
-         lsof,
-         mc,
-         most,
-         ngrep,
-         psmisc,
-         screen,
-         sipsak,
-         tcpdump,
-         vim
-Description: Kamailio - package for "nice to have" installation
- This is a meta-package for easy installation various useful tools that may be
- handy on server with Kamailio installed.
-
-Package: kamailio-ims-modules
-Architecture: any
-Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
-Description: Kamailio - IMS Modules
- Kamailio is a very fast and flexible SIP (RFC3261)
- proxy server. Written entirely in C, Kamailio can handle thousands calls
- per second even on low-budget hardware.
- .
- This package contains various Diameter interfaces and modules for Kamailio
- to run as an IMS core.
-
diff --git a/pkg/kamailio/deb/lenny/kamailio.init b/pkg/kamailio/deb/lenny/kamailio.init
deleted file mode 100644
index 03b7888..0000000
--- a/pkg/kamailio/deb/lenny/kamailio.init
+++ /dev/null
@@ -1,240 +0,0 @@
-#! /bin/sh
-#
-### BEGIN INIT INFO
-# Provides:          kamailio
-# Required-Start:    $syslog $network $local_fs $remote_fs $time
-# Required-Stop:     $syslog $network $local_fs $remote_fs
-# Default-Start:     2 3 4 5
-# Default-Stop:      0 1 6
-# Should-Start:      postgresql mysql radius
-# Should-Stop:       postgresql mysql radius
-# Short-Description: Start the Kamailio SIP proxy server
-# Description:       Start the Kamailio SIP proxy server
-### END INIT INFO
-
-
-PATH=/sbin:/bin:/usr/sbin:/usr/bin
-DAEMON=/usr/sbin/kamailio
-NAME=kamailio
-DESC=Kamailio
-HOMEDIR=/var/run/kamailio
-PIDFILE=$HOMEDIR/$NAME.pid
-DEFAULTS=/etc/default/kamailio
-CFGFILE=/etc/kamailio/kamailio.cfg
-RUN_KAMAILIO=no
-
-
-# Do not start kamailio if fork=no is set in the config file
-# otherwise the boot process will just stop.
-check_fork ()
-{
-  if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then
-    echo "Not starting $DESC: fork=no specified in config file. Run /etc/init.d/kamailio debug instead."
-    exit 1
-  fi
-}
-
-
-check_kamailio_config ()
-{
-  # Check if kamailio configuration is valid before starting the server.
-  set +e
-  out=$($DAEMON -M $PKG_MEMORY -c 2>&1 > /dev/null)
-  retcode=$?
-  set -e
-  if [ "$retcode" != '0' ]; then
-    echo "Not starting $DESC: invalid configuration file!"
-    echo -e "\n$out\n"
-    exit 1
-  fi
-}
-
-
-check_homedir ()
-{
-  # Create HOMEDIR directory in case it doesn't exist.
-  # Useful in Ubuntu as /var/run/ content is deleted in shutdown.
-  if [ ! -d $HOMEDIR ]; then
-    mkdir $HOMEDIR
-  fi
-
-  # Set the appropiate owner and group
-  chown ${USER}:${GROUP} $HOMEDIR
-}
-
-
-create_radius_seqfile ()
-{
-  # Create a radius sequence file to be used by the radius client if
-  # radius accounting is enabled. This is needed to avoid any issue
-  # with the file not being writable if kamailio first starts as user
-  # root because DUMP_CORE is enabled and creates this file as user
-  # root and then later it switches back to user kamailio and cannot
-  # write to the file. If the file exists before kamailio starts, it
-  # won't change it's ownership and will be writable for both root
-  # and kamailio, no matter what options are chosen at install time
-  RADIUS_SEQ_FILE=$HOMEDIR/kamailio_radius.seq
-
-  if [ ! -f $RADIUS_SEQ_FILE ]; then
-      touch $RADIUS_SEQ_FILE
-  fi
-
-  chown ${USER}:${GROUP} $RADIUS_SEQ_FILE
-  chmod 660 $RADIUS_SEQ_FILE
-}
-
-
-if [ ! -f $DAEMON ]; then
-  echo "No $DESC daemon at $DAEMON."
-  case "$1" in
-  status)
-    # LSB - 4: program or service status is unknown.
-    exit 4
-    ;;
-  *)
-    # LSB - 5: program is not installed.
-    exit 5
-    ;;
-  esac
-fi
-
-
-# Load startup options if available.
-if [ -f $DEFAULTS ]; then
-  . $DEFAULTS || true
-fi
-
-
-if [ "$RUN_KAMAILIO" != "yes" ]; then
-  echo "$DESC not yet configured. Edit $DEFAULTS first."
-  exit 0
-fi
-
-
-set -e
-
-
-SHM_MEMORY=$((`echo $SHM_MEMORY | sed -e 's/[^0-9]//g'`))
-PKG_MEMORY=$((`echo $PKG_MEMORY | sed -e 's/[^0-9]//g'`))
-[ $SHM_MEMORY -le 0 ] && SHM_MEMORY=64
-[ $PKG_MEMORY -le 0 ] && PKG_MEMORY=4
-[ -z "$USER" ]  && USER=kamailio
-[ -z "$GROUP" ] && GROUP=kamailio
-
-
-if test "$DUMP_CORE" = "yes" ; then
-  # set proper ulimit.
-  ulimit -c unlimited
-
-  # directory for the core dump files.
-  # COREDIR=/tmp/corefiles
-  # [ -d $COREDIR ] || mkdir $COREDIR
-  # chmod 777 $COREDIR
-  # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
-fi
-
-
-if [ "$SSD_SUID" != "yes" ]; then
-  OPTIONS="-f $CFGFILE -P $PIDFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP"
-  SSDOPTS=""
-else
-  OPTIONS="-f $CFGFILE -P $PIDFILE -m $SHM_MEMORY -M $PKG_MEMORY"
-  SSDOPTS="--chuid $USER:$GROUP"
-fi
-
-
-start_kamailio_daemon ()
-{
-  start-stop-daemon --start --quiet --pidfile $PIDFILE $SSDOPTS \
-    --exec $DAEMON -- $OPTIONS
-  res=$?
-
-  echo -n "$NAME "
-  if [ $res -eq 0 ] ; then
-    echo "started."
-    exit 0
-  else
-    if [ ! -r "$PIDFILE" ]; then
-      echo "error, failed to start."
-      exit 1
-    elif read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then
-      echo "already running."
-      exit 0
-    else
-      echo "error, failed to start ($PIDFILE exists)."
-      exit 1
-    fi
-  fi
-}
-
-
-case "$1" in
-  start|debug)
-    check_kamailio_config
-    check_homedir
-    create_radius_seqfile
-
-    if [ "$1" != "debug" ]; then
-      check_fork
-    fi
-
-    echo "Starting $DESC:"
-    set +e
-    start_kamailio_daemon
-    ;;
-
-  stop)
-    echo -n "Stopping $DESC: $NAME "
-    set +e
-    start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
-      --exec $DAEMON
-
-    if [ $? -eq 0 ] ; then
-      echo "stopped."
-      exit 0
-    else
-      echo "failed to stop."
-      exit 1
-    fi
-    ;;
-    
-  restart|force-reload)
-    check_kamailio_config
-    check_homedir
-    create_radius_seqfile
-
-    echo "Restarting $DESC:"
-    set +e
-    start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE --retry=5 \
-      --exec $DAEMON
-    if [ $? -ne 0 ] ; then
-      echo "$NAME failed to stop."
-      exit 1
-    fi
-    start_kamailio_daemon
-    ;;
-
-  status)
-    echo -n "Status of $DESC: $NAME "
-    if [ ! -r "$PIDFILE" ]; then
-      echo "is not running."
-      exit 3
-    fi
-    if read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then
-      echo "is running."
-      exit 0
-    else
-      echo "is not running but $PIDFILE exists."
-      exit 1
-    fi
-    ;;
-
-  *)
-    N=/etc/init.d/$NAME
-    echo "Usage: $N {start|stop|restart|force-reload|debug|status}" >&2
-    exit 1
-    ;;
-esac
-
-
-exit 0
diff --git a/pkg/kamailio/deb/lenny/rules b/pkg/kamailio/deb/lenny/rules
deleted file mode 100755
index eb76052..0000000
--- a/pkg/kamailio/deb/lenny/rules
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/make -f
-# Sample debian/rules that uses debhelper.
-# GNU copyright 1997 to 1999 by Joey Hess.
-#
-# $Id$
-#
-# History:
-# --------
-#  2009-07-08  updated for sip-router (andrei)
-#  2009-12-10  updated for kamailio 3.0 (daniel)
-
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-# This is the debhelper compatibility version to use.
-# export DH_COMPAT=4
-#  -- already set in compat
-export DEB_BUILD_OPTIONS:="$(DEB_BUILD_OPTIONS) debug"
-
-# modules not in the "main" kamailio package
-EXCLUDED_MODULES= geoip
-
-# extra modules to skip, because they are not compilable now
-# - regardless if they go to the main kamailio package or to some module package,
-# they will be excluded from compile and install of all
-EXTRA_EXCLUDED_MODULES=bdb dbtext oracle pa iptrtpproxy
-#EXTRA_EXCLUDED_MODULES=
-
-# possible module directories that can appear in MODULES_SP
-# (only used for deducing a module name)
-MDIRS=modules
-
-# modules packaged in separate packages (complete with full modules_* path)
-# with the package name: kamailio-$(module_name)-module
-MODULES_SP=
-
-# module groups that are packaged in seperate packages
-# (with the name kamailio-$(group_name)-modules)
-# Note: the order is important (should be in dependency order, the one
-# on which other depend first)
-PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
-			   ldap xml perl utils purple memcached tls \
-			   snmpstats carrierroute xmpp cpl lua python \
-			   sqlite ims
-
-# name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
-LIBDIR ?= lib
-
-# directories with possible duplicate libraries (that should be deleted
-# from current module* packages)
-DUP_LIBS_DIRS=$(CURDIR)/debian/kamailio/usr/$(LIBDIR)/kamailio \
-			$(CURDIR)/debian/kamailio-db-modules/usr/$(LIBDIR)/kamailio
-
-# modules names out of modules sp
-MODULES_SP_NAMES=$(filter-out $(MDIRS),$(subst /, ,$(MODULES_SP)))
-
-# "function" to get package short name out of a dir/module_name
-# it also transforms db_foo into foo
-mod_name=$(subst db_,,$(lastword $(subst /, ,$(1))))
-
-define PACKAGE_GRP_BUILD_template
-	# package all the modules in PACKAGE_GROUPS in separate packages
-	$(foreach grp,$(PACKAGE_GROUPS),\
-		$(MAKE) every-module group_include="k$(grp)"
-	)
-endef
-
-
-define PACKAGE_MODULE_BUILD_template
-	# package all the modules MODULES_SP in separate packages
-	$(foreach mod,$(MODULES_SP),\
-		$(MAKE) modules modules="$(mod)"
-	)
-endef
-
-
-define PACKAGE_GRP_INSTALL_template
-	$(foreach grp,$(PACKAGE_GROUPS),\
-		$(MAKE) install-modules-all group_include="k$(grp)" \
-		basedir=$(CURDIR)/debian/kamailio-$(grp)-modules \
-		cfg_prefix=$(CURDIR)/debian/kamailio-$(grp)-modules \
-		doc-dir=share/doc/kamailio-$(grp)-modules
-		# eliminate duplicate libs
-		-for d in $(DUP_LIBS_DIRS); do \
-			test "$$d" != "$(CURDIR)/debian/kamailio-$(grp)-modules/usr/$(LIBDIR)/kamailio" &&\
-			for r in $$d/lib*; do \
-				if [ "$$r" != "$$d/lib*" ]; then \
-					echo "removing $(grp) lib `basename $$r` present also in $$d";\
-					rm -f $(CURDIR)/debian/kamailio-$(grp)-modules/usr/$(LIBDIR)/kamailio/`basename "$$r"` ; \
-				fi \
-			done ; \
-		done
-	)
-endef
-
-
-define PACKAGE_MODULE_INSTALL_template
-	$(foreach mod,$(MODULES_SP),
-		$(MAKE) install-modules-all modules="$(mod)" \
-				modules_s="" modules_k="" \
-				basedir=$(CURDIR)/debian/kamailio-$(call mod_name,$(mod))-module \
-				doc-dir=share/doc/kamailio-$(call mod_name,$(mod))-module
-		# eliminate duplicate libs
-		-for d in $(DUP_LIBS_DIRS); do \
-			test "$$d" != "$(CURDIR)/debian/kamailio-$(call mod_name,$(mod))-module/usr/$(LIBDIR)/kamailio" &&\
-			for r in $$d/lib*; do \
-				if [ "$$r" != "$$d/lib*" ]; then \
-					echo "removing $(call mod_name, $(mod)) lib `basename $$r` present also in $$d";\
-					rm -f $(CURDIR)/debian/kamailio-$(call mod_name,$(mod))-module/usr/$(LIBDIR)/kamailio/`basename "$$r"` ; \
-				fi \
-			done ; \
-		done
-	)
-endef
-
-ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
-	CFLAGS += -g
-endif
-ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
-	INSTALL_PROGRAM += -s
-endif
-
-configure: configure-stamp
-configure-stamp:
-	dh_testdir
-	# Add here commands to configure the package.
-	$(MAKE) FLAVOUR=kamailio cfg prefix=/usr cfg_prefix=$(CURDIR)/debian/kamailio \
-			cfg_target=/etc/kamailio/ \
-			basedir=$(CURDIR)/debian/kamailio \
-			skip_modules="$(EXCLUDED_MODULES) $(EXTRA_EXCLUDED_MODULES)" \
-			group_include="kstandard"
-
-	touch configure-stamp
-
-
-build: build-stamp
-
-build-stamp: configure-stamp 
-	dh_testdir
-	# Add here commands to compile the package.
-	$(MAKE) all
-	# make groups
-	$(call PACKAGE_GRP_BUILD_template)
-	# make single-module packages
-	$(call PACKAGE_MODULE_BUILD_template)
-	touch build-stamp
-
-clean:
-	dh_testdir
-	dh_testroot
-	rm -f build-stamp configure-stamp
-	# Add here commands to clean up after the build process.
-	-$(MAKE) maintainer-clean
-	dh_clean
-
-install: build
-	dh_testdir
-	dh_testroot
-	dh_clean -k
-	dh_installdirs
-	# Add here commands to install the package into debian/kamailio
-	$(MAKE) install group_include="kstandard"
-	# fix etc/kamailio dir location -- not needed -- andrei
-	# mv -f $(CURDIR)/debian/kamailio/usr/etc $(CURDIR)/debian/kamailio
-	# make group packages
-	$(call PACKAGE_GRP_INSTALL_template)
-	# make single module packages
-	$(call PACKAGE_MODULE_INSTALL_template)
-	# install /etc/default/kamailio file
-	mkdir -p $(CURDIR)/debian/kamailio/etc/default
-	cp -f debian/kamailio.default $(CURDIR)/debian/kamailio/etc/default/kamailio
-	#dh_movefiles
-
-
-
-# This single target is used to build all the packages, all at once, or
-# one at a time. So keep in mind: any options passed to commands here will
-# affect _all_ packages. Anything you want to only affect one package
-# should be put in another target, such as the install target.
-binary-common: 
-	dh_testdir
-	dh_testroot
-	dh_installdebconf	
-	dh_installdocs
-	dh_installexamples
-	dh_installmenu
-#	dh_installlogrotate
-#	dh_installemacsen
-#	dh_installpam
-#	dh_installmime
-	dh_installinit  -- defaults 23
-	dh_installcron
-	dh_installman
-	dh_installinfo
-#	dh_undocumented
-	dh_installchangelogs ChangeLog 
-	dh_link
-	dh_strip --dbg-package=kamailio-dbg
-	dh_compress 
-	dh_fixperms
-	dh_makeshlibs
-	dh_installdeb
-#	dh_perl
-	dh_shlibdeps
-	dh_gencontrol
-	dh_md5sums
-	dh_builddeb
-
-# Build architecture-independent packages using the common target
-binary-indep: build install
-# (Uncomment this next line if you have such packages.)
-#        $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
-# We have nothing to do by default.
-
-
-# Build architecture-dependent packages using the common target
-binary-arch: build install
-	$(MAKE) -f debian/rules DH_OPTIONS=-a binary-common
-
-# Any other binary targets build just one binary package at a time.
-binary-%: build install
-	$(MAKE) -f debian/rules binary-common DH_OPTIONS=-p$*
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install configure
-
diff --git a/pkg/kamailio/deb/lucid/changelog b/pkg/kamailio/deb/lucid/changelog
index 7e8459b..f5d3633 100644
--- a/pkg/kamailio/deb/lucid/changelog
+++ b/pkg/kamailio/deb/lucid/changelog
@@ -1,26 +1,8 @@
-kamailio (4.0.4) unstable; urgency=low
+kamailio (4.1.0) unstable; urgency=low
 
-  * update to 4.0.4 from upstream
+  * update to 4.1.0
 
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 02 Oct 2013 16:05:20 +0100
-
-kamailio (4.0.3) unstable; urgency=low
-
-  * update to 4.0.3 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 15 Aug 2013 10:35:20 +0100
-
-kamailio (4.0.2) unstable; urgency=low
-
-  * update to 4.0.2 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 12 Jun 2013 10:55:50 +0100
-
-kamailio (4.0.1) unstable; urgency=low
-
-  * update to 4.0.1 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 25 Apr 2013 11:50:20 +0100
+ -- Victor Seva <linuxmaniac at torreviejawireless.org>  Wed, 04 Dec 2013 11:42:27 +0100
 
 kamailio (4.0.0) unstable; urgency=low
 
diff --git a/pkg/kamailio/deb/lucid/control b/pkg/kamailio/deb/lucid/control
index af9f473..3084c47 100644
--- a/pkg/kamailio/deb/lucid/control
+++ b/pkg/kamailio/deb/lucid/control
@@ -11,11 +11,13 @@ Build-Depends: bison,
                libconfuse-dev,
                libcurl3-openssl-dev,
                libdb-dev (>= 4.6.19),
+               libevent-dev,
                libexpat1-dev,
                libgeoip-dev (>= 1.4.5),
+               libjson0-dev,
                libldap2-dev,
                liblua5.1-0-dev,
-               libmemcache-dev,
+               libmemcached-dev,
                libmysqlclient-dev,
                libncurses5-dev,
                libpcre3-dev,
@@ -25,11 +27,13 @@ Build-Depends: bison,
                libradiusclient-ng-dev,
                libreadline-dev,
                libsasl2-dev,
+               libsctp-dev,
                libsnmp-dev,
                libsqlite3-dev,
                libssl-dev,
                libxml2-dev,
                libxmlrpc-c3-dev,
+               libunistring-dev,
                python,
                python-dev,
                unixodbc-dev,
@@ -365,6 +369,20 @@ Description: SQLite database connectivity module for Kamailio
  .
  This package provides the SQLite database driver for Kamailio.
 
+Package: kamailio-json-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         libevent-1.4-2,
+         libjson0,
+         ${shlibs:Depends}
+Description: Json parser and jsonrpc modules for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides json parser for Kamailio's configuration file
+ and the JSON-RPC client over netstrings.
+
 Package: kamailio-nth
 Architecture: any
 Depends: binutils,
@@ -398,3 +416,44 @@ Description: Kamailio - IMS Modules
  This package contains various Diameter interfaces and modules for Kamailio
  to run as an IMS core.
 
+Package: kamailio-outbound-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - Outbound Module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains the module implementing SIP outbound extension.
+
+Package: kamailio-websocket-modules
+Architecture: any
+Depends: ${shlibs:Depends}, kamailio (= ${binary:Version})
+Description: Kamailio - Websocket Module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package contains the module implementing WebSocket transport layer.
+
+Package: kamailio-autheph-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the ephemeral module for Kamailio.
+
+Package: kamailio-sctp-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the sctp module for Kamailio.
diff --git a/pkg/kamailio/deb/lucid/rules b/pkg/kamailio/deb/lucid/rules
index d042a5c..612a713 100755
--- a/pkg/kamailio/deb/lucid/rules
+++ b/pkg/kamailio/deb/lucid/rules
@@ -29,7 +29,7 @@ EXTRA_EXCLUDED_MODULES=bdb dbtext oracle pa iptrtpproxy
 
 # possible module directories that can appear in MODULES_SP
 # (only used for deducing a module name)
-MDIRS=modules modules_s modules_k
+MDIRS=modules
 
 # modules packaged in separate packages (complete with full modules_* path)
 # with the package name: kamailio-$(module_name)-module
@@ -42,7 +42,8 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils purple memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python geoip \
-			   sqlite ims
+			   sqlite json ims outbound websocket \
+			   autheph sctp
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
diff --git a/pkg/kamailio/deb/precise/changelog b/pkg/kamailio/deb/precise/changelog
index 8867e3c..74a19e1 100644
--- a/pkg/kamailio/deb/precise/changelog
+++ b/pkg/kamailio/deb/precise/changelog
@@ -1,26 +1,8 @@
-kamailio (4.0.4) unstable; urgency=low
+kamailio (4.1.0) unstable; urgency=low
 
-  * update to 4.0.4 from upstream
+  * update to 4.1.0
 
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 02 Oct 2013 16:05:20 +0100
-
-kamailio (4.0.3) unstable; urgency=low
-
-  * update to 4.0.3 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 15 Aug 2013 10:35:20 +0100
-
-kamailio (4.0.2) unstable; urgency=low
-
-  * update to 4.0.2 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 12 Jun 2013 10:55:50 +0100
-
-kamailio (4.0.1) unstable; urgency=low
-
-  * update to 4.0.1 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 25 Apr 2013 11:50:20 +0100
+ -- Victor Seva <linuxmaniac at torreviejawireless.org>  Wed, 04 Dec 2013 11:42:27 +0100
 
 kamailio (4.0.0) unstable; urgency=low
 
diff --git a/pkg/kamailio/deb/precise/control b/pkg/kamailio/deb/precise/control
index 6b4dd51..03ec249 100644
--- a/pkg/kamailio/deb/precise/control
+++ b/pkg/kamailio/deb/precise/control
@@ -18,7 +18,7 @@ Build-Depends: bison,
                libjson0-dev,
                libldap2-dev,
                liblua5.1-0-dev,
-               libmemcache-dev,
+               libmemcached-dev,
                libmono-2.0-dev,
                libmysqlclient-dev,
                libncurses5-dev,
@@ -29,6 +29,7 @@ Build-Depends: bison,
                libradiusclient-ng-dev,
                libreadline-dev,
                libsasl2-dev,
+               libsctp-dev,
                libsnmp-dev,
                libsqlite3-dev,
                libssl-dev,
@@ -456,3 +457,24 @@ Description: Kamailio - Websocket Module
  .
  This package contains the module implementing WebSocket transport layer.
 
+Package: kamailio-autheph-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the ephemeral module for Kamailio.
+
+Package: kamailio-sctp-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the sctp module for Kamailio.
diff --git a/pkg/kamailio/deb/precise/rules b/pkg/kamailio/deb/precise/rules
index b36d840..914da59 100755
--- a/pkg/kamailio/deb/precise/rules
+++ b/pkg/kamailio/deb/precise/rules
@@ -42,7 +42,8 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils purple memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python geoip \
-			   redis sqlite json mono ims outbound websocket
+			   redis sqlite json mono ims outbound websocket \
+			   autheph sctp
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
diff --git a/pkg/kamailio/deb/squeeze/changelog b/pkg/kamailio/deb/squeeze/changelog
index 7e8459b..f5d3633 100644
--- a/pkg/kamailio/deb/squeeze/changelog
+++ b/pkg/kamailio/deb/squeeze/changelog
@@ -1,26 +1,8 @@
-kamailio (4.0.4) unstable; urgency=low
+kamailio (4.1.0) unstable; urgency=low
 
-  * update to 4.0.4 from upstream
+  * update to 4.1.0
 
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 02 Oct 2013 16:05:20 +0100
-
-kamailio (4.0.3) unstable; urgency=low
-
-  * update to 4.0.3 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 15 Aug 2013 10:35:20 +0100
-
-kamailio (4.0.2) unstable; urgency=low
-
-  * update to 4.0.2 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 12 Jun 2013 10:55:50 +0100
-
-kamailio (4.0.1) unstable; urgency=low
-
-  * update to 4.0.1 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 25 Apr 2013 11:50:20 +0100
+ -- Victor Seva <linuxmaniac at torreviejawireless.org>  Wed, 04 Dec 2013 11:42:27 +0100
 
 kamailio (4.0.0) unstable; urgency=low
 
diff --git a/pkg/kamailio/deb/squeeze/control b/pkg/kamailio/deb/squeeze/control
index 0abff2b..6f49d63 100644
--- a/pkg/kamailio/deb/squeeze/control
+++ b/pkg/kamailio/deb/squeeze/control
@@ -17,7 +17,7 @@ Build-Depends: bison,
                libjson0-dev,
                libldap2-dev,
                liblua5.1-0-dev,
-               libmemcache-dev,
+               libmemcached-dev,
                libmysqlclient-dev,
                libncurses5-dev,
                libpcre3-dev,
@@ -26,6 +26,7 @@ Build-Depends: bison,
                libradiusclient-ng-dev,
                libreadline-dev,
                libsasl2-dev,
+               libsctp-dev,
                libsnmp-dev,
                libsqlite3-dev,
                libssl-dev,
@@ -421,3 +422,24 @@ Description: Kamailio - Websocket Module
  .
  This package contains the module implementing WebSocket transport layer.
 
+Package: kamailio-autheph-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the ephemeral module for Kamailio.
+
+Package: kamailio-sctp-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the sctp module for Kamailio.
diff --git a/pkg/kamailio/deb/squeeze/rules b/pkg/kamailio/deb/squeeze/rules
index 074c8d1..7f02341 100755
--- a/pkg/kamailio/deb/squeeze/rules
+++ b/pkg/kamailio/deb/squeeze/rules
@@ -42,7 +42,8 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils geoip memcached tls \
 			   snmpstats carrierroute xmpp cpl lua python \
-			   sqlite json ims outbound websocket
+			   sqlite json ims outbound websocket \
+			   autheph sctp
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
diff --git a/pkg/kamailio/deb/wheezy/changelog b/pkg/kamailio/deb/wheezy/changelog
index 7e8459b..f5d3633 100644
--- a/pkg/kamailio/deb/wheezy/changelog
+++ b/pkg/kamailio/deb/wheezy/changelog
@@ -1,26 +1,8 @@
-kamailio (4.0.4) unstable; urgency=low
+kamailio (4.1.0) unstable; urgency=low
 
-  * update to 4.0.4 from upstream
+  * update to 4.1.0
 
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 02 Oct 2013 16:05:20 +0100
-
-kamailio (4.0.3) unstable; urgency=low
-
-  * update to 4.0.3 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 15 Aug 2013 10:35:20 +0100
-
-kamailio (4.0.2) unstable; urgency=low
-
-  * update to 4.0.2 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Wed, 12 Jun 2013 10:55:50 +0100
-
-kamailio (4.0.1) unstable; urgency=low
-
-  * update to 4.0.1 from upstream
-
- -- Daniel-Constantin Mierla <miconda at gmail.com>  Thu, 25 Apr 2013 11:50:20 +0100
+ -- Victor Seva <linuxmaniac at torreviejawireless.org>  Wed, 04 Dec 2013 11:42:27 +0100
 
 kamailio (4.0.0) unstable; urgency=low
 
diff --git a/pkg/kamailio/deb/wheezy/control b/pkg/kamailio/deb/wheezy/control
index e5323db..319dcb3 100644
--- a/pkg/kamailio/deb/wheezy/control
+++ b/pkg/kamailio/deb/wheezy/control
@@ -4,6 +4,7 @@ Priority: optional
 Maintainer: Jon Bonilla <manwe at aholab.ehu.es>
 Build-Depends: bison,
                debhelper (>= 5),
+               default-jdk,
                docbook-xml,
                dpatch,
                dpkg-dev (>= 1.13.19),
@@ -18,7 +19,7 @@ Build-Depends: bison,
                libjson0-dev,
                libldap2-dev,
                liblua5.1-0-dev,
-               libmemcache-dev,
+               libmemcached-dev,
                libmono-2.0-dev,
                libmysqlclient-dev,
                libncurses5-dev,
@@ -28,6 +29,7 @@ Build-Depends: bison,
                libradiusclient-ng-dev,
                libreadline-dev,
                libsasl2-dev,
+               libsctp-dev,
                libsnmp-dev,
                libsqlite3-dev,
                libssl-dev,
@@ -48,10 +50,12 @@ Depends: adduser,
          ${misc:Depends},
          ${shlibs:Depends}
 Conflicts: kamailio-regex-modules
-Suggests: kamailio-berkeley-modules,
+Suggests: kamailio-autheph-modules,
+          kamailio-berkeley-modules,
           kamailio-carrierroute-modules,
           kamailio-cpl-modules,
           kamailio-dbg,
+          kamailio-java-modules,
           kamailio-ldap-modules,
           kamailio-lua-modules,
           kamailio-mono-modules,
@@ -61,6 +65,7 @@ Suggests: kamailio-berkeley-modules,
           kamailio-presence-modules,
           kamailio-python-modules,
           kamailio-radius-modules,
+          kamailio-sctp-modules,
           kamailio-snmpstats-modules,
           kamailio-tls-modules,
           kamailio-unixodbc-modules,
@@ -448,3 +453,37 @@ Description: Kamailio - Websocket Module
  .
  This package contains the module implementing WebSocket transport layer.
 
+Package: kamailio-autheph-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the ephemeral module for Kamailio.
+
+Package: kamailio-sctp-modules
+Architecture: any
+Depends: kamailio (= ${binary:Version}),
+         ${shlibs:Depends}
+Description: authentication using ephemeral credentials module for Kamailio
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the sctp module for Kamailio.
+
+Package: kamailio-java-modules
+Architecture: any
+Depends: kamailio (= ${Source-Version}),
+         default-jre,
+         ${shlibs:Depends}
+Description: contains the app_java module
+ Kamailio is a very fast and flexible SIP (RFC3261)
+ proxy server. Written entirely in C, Kamailio can handle thousands calls
+ per second even on low-budget hardware.
+ .
+ This package provides the app_java module, an extension allowing to
+ execute embedded Java applications within configuration file.
diff --git a/pkg/kamailio/deb/wheezy/rules b/pkg/kamailio/deb/wheezy/rules
index 1c3587d..6709a72 100755
--- a/pkg/kamailio/deb/wheezy/rules
+++ b/pkg/kamailio/deb/wheezy/rules
@@ -42,7 +42,8 @@ MODULES_SP=
 PACKAGE_GROUPS=mysql postgres berkeley unixodbc radius presence \
 			   ldap xml perl utils lua memcached tls \
 			   snmpstats carrierroute xmpp cpl redis python geoip \
-			   sqlite json mono ims outbound websocket
+			   sqlite json mono ims outbound websocket \
+			   autheph sctp java
 
 # name of libdir in the path for libraries (e.g., lib for 32b, lib64 for 64b)
 LIBDIR ?= lib
diff --git a/pkg/kamailio/fedora/17/kamailio.spec b/pkg/kamailio/fedora/17/kamailio.spec
index c1b6e9a..2ceb8ea 100644
--- a/pkg/kamailio/fedora/17/kamailio.spec
+++ b/pkg/kamailio/fedora/17/kamailio.spec
@@ -1,43 +1,42 @@
-%define name    kamailio
-%define ver     4.0.0
-%define rel     0%{dist}
-
-
-
-Summary:       Kamailio (former OpenSER) - the Open Source SIP Server
-Name:          %name
-Version:       %ver
-Release:       %rel
-Packager:      Peter Dunkley <peter at dunkley.me.uk>
-License:       GPL
-Group:         System Environment/Daemons
-Source:        http://kamailio.org/pub/kamailio/%{ver}/src/%{name}-%{ver}_src.tar.gz
-URL:           http://kamailio.org/
-Vendor:        kamailio.org
-BuildRoot:     %{_tmppath}/%{name}-%{ver}-buildroot
-Conflicts:     kamailio-mysql < %ver, kamailio-postgresql < %ver
-Conflicts:     kamailio-unixODBC < %ver, kamailio-bdb < %ver
-Conflicts:     kamailio-sqlite < %ver, kamailio-utils < %ver
-Conflicts:     kamailio-cpl < %ver, kamailio-snmpstats < %ver
-Conflicts:     kamailio-presence < %ver, kamailio-xmpp < %ver
-Conflicts:     kamailio-purple < %ver, kamailio-ldap < %ver
-Conflicts:     kamailio-xmlrpc < %ver, kamailio-perl < %ver, kamailio-lua < %ver
-Conflicts:     kamailio-python < %ver, kamailio-regex < %ver
-Conflicts:     kamailio-dialplan < %ver, kamailio-lcr < %ver
-Conflicts:     kamailio-xmlops < %ver, kamailio-cdp < %ver
-Conflicts:     kamailio-websocket < %ver, kamailio-xhttp-pi < %ver
-Conflicts:     kamailio-outbound < %ver, kamailio-ims < %ver
-Conflicts:     kamailio-auth-identity < %ver
+%define name	kamailio
+%define ver	4.1.0
+%define rel	dev7.2%{dist}
+
+
+
+Summary:	Kamailio (former OpenSER) - the Open Source SIP Server
+Name:		%name
+Version:	%ver
+Release:	%rel
+Packager:	Peter Dunkley <peter at dunkley.me.uk>
+License:	GPL
+Group:		System Environment/Daemons
+Source:		http://kamailio.org/pub/kamailio/%{ver}/src/%{name}-%{ver}_src.tar.gz
+URL:		http://kamailio.org/
+Vendor:		kamailio.org
+BuildRoot:	%{_tmppath}/%{name}-%{ver}-buildroot
+Conflicts:	kamailio-auth-ephemeral < %ver, kamailio-auth-identity < %ver
+Conflicts:	kamailio-bdb < %ver, kamailio-cdp < %ver, kamailio-cdp < %ver
+Conflicts:	kamailio-dialplan < %ver, kamailio-ims < %ver
+Conflicts:	kamailio-lcr < %ver, kamailio-ldap < %ver, kamailio-lua < %ver
+Conflicts:	kamailio-mysql < %ver, kamailio-outbound < %ver
+Conflicts:	kamailio-perl < %ver, kamailio-postgresql < %ver
+Conflicts:	kamailio-presence < %ver, kamailio-purple < %ver
+Conflicts:	kamailio-python < %ver, kamailio-regex < %ver
+Conflicts:	kamailio-sctp < %ver, kamailio-snmpstats < %ver
+Conflicts:	kamailio-sqlite < %ver, kamailio-stun < %ver
+Conflicts:	kamailio-tls < %ver, kamailio-unixODBC < %ver
+Conflicts:	kamailio-utils < %ver, kamailio-websocket < %ver
+Conflicts:	kamailio-xhttp-pi < %ver, kamailio-xmlops < %ver
+Conflicts:	kamailio-xmlrpc < %ver, kamailio-xmpp < %ver
 %if 0%{?fedora}
-Conflicts:     kamailio-radius < %ver, kamailio-carrierroute < %ver
-Conflicts:     kamailio-redis < %ver, kamailio-json < %ver 
-Conflicts:     kamailio-mono < %ver, kamailio-GeoIP < %ver
+Conflicts:	kamailio-carrierroute < %ver, kamailio-GeoIP < %ver
+Conflicts:	kamailio-json < %ver, kamailio-mono < %ver
+Conflicts: 	kamailio-radius < %ver, kamailio-redis < %ver
 %endif
-Requires:      openssl lksctp-tools
-BuildRequires: bison flex gcc make redhat-rpm-config openssl-devel
-BuildRequires: lksctp-tools-devel
+BuildRequires:	bison, flex, gcc, make, redhat-rpm-config
 %if 0%{?fedora}
-BuildRequires: docbook2X
+BuildRequires:	docbook2X
 %endif
 
 %description
@@ -53,335 +52,378 @@ platforms or to scale up SIP-to-PSTN gateways, PBX systems or media servers
 like Asterisk™, FreeSWITCH™ or SEMS.
 
 
-%package mysql
-Summary:       MySQL database connectivity for Kamailio.
-Group:         System Environment/Daemons
-Requires:      mysql-libs, kamailio = %ver
-BuildRequires: mysql-devel zlib-devel
+%package	auth-ephemeral
+Summary:	Functions for authentication using ephemeral credentials.
+Group:		System Environment/Daemons
+Requires:	openssl, kamailio = %ver
+BuildRequires:	openssl-devel
 
-%description mysql
-MySQL database connectivity for Kamailio.
+%description auth-ephemeral
+Functions for authentication using ephemeral credentials.
 
 
-%package postgresql
-Summary:       PostgreSQL database connectivity for Kamailio.
-Group:         System Environment/Daemons
-Requires:      postgresql-libs, kamailio = %ver
-BuildRequires: postgresql-devel
+%package	auth-identity
+Summary:	Functions for secure identification of originators of SIP messages for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libcurl, openssl, kamailio = %ver
+BuildRequires:	libcurl-devel, openssl-devel
 
-%description postgresql
-PostgreSQL database connectivity for Kamailio.
+%description auth-identity
+Functions for secure identification of originators of SIP messages for Kamailio.
 
 
-%package unixODBC
-Summary:       unixODBC database connectivity for Kamailio.
-Group:         System Environment/Daemons
-Requires:      unixODBC, kamailio = %ver
-BuildRequires: unixODBC-devel
+%package	bdb
+Summary:	Berkeley database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	db4, kamailio = %ver
+BuildRequires:	db4-devel
 
-%description unixODBC
-unixODBC database connectivity for Kamailio.
+%description	bdb
+Berkeley database connectivity for Kamailio.
 
 
-%package bdb
-Summary:       Berkeley database connectivity for Kamailio.
-Group:         System Environment/Daemons
-Requires:      db4, kamailio = %ver
-BuildRequires: db4-devel
+%package	cdp
+Summary:	C Diameter Peer module and extensions module for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
 
-%description bdb
-Berkeley database connectivity for Kamailio.
+%description	cdp
+C Diameter Peer module and extensions module for Kamailio.
 
 
-%package sqlite
-Summary:       SQLite database connectivity for Kamailio.
-Group:         System Environment/Daemons
-Requires:      sqlite, kamailio = %ver
-BuildRequires: sqlite-devel
+%package	cpl
+Summary:	CPL (Call Processing Language) interpreter for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
 
-%description sqlite
-SQLite database connectivity for Kamailio.
+%description	cpl
+CPL (Call Processing Language) interpreter for Kamailio.
 
 
-%package utils
-Summary:       Non-SIP utitility functions for Kamailio.
-Group:         System Environment/Daemons
-Requires:      libcurl, libxml2, kamailio = %ver
-BuildRequires: libcurl-devel, libxml2-devel
+%package	dialplan
+Summary:	String translations based on rules for Kamailio.
+Group:		System Environment/Daemons
+Requires:	pcre, kamailio = %ver
+BuildRequires:	pcre-devel
 
-%description utils
-Non-SIP utitility functions for Kamailio.
+%description	dialplan
+String translations based on rules for Kamailio.
 
 
-%package cpl
-Summary:       CPL (Call Processing Language) interpreter for Kamailio.
-Group:         System Environment/Daemons
-Requires:      libxml2, kamailio = %ver
-BuildRequires: libxml2-devel
+%package	ims
+Summary:	IMS modules and extensions module for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver, kamailio-cdp = %ver
+BuildRequires:	libxml2-devel
 
-%description cpl
-CPL (Call Processing Language) interpreter for Kamailio.
+%description	ims
+IMS modules and extensions module for Kamailio.
 
 
-%package snmpstats
-Summary:       SNMP management interface (scalar statistics) for Kamailio.
-Group:         System Environment/Daemons
-%if 0%{?fedora}
-Requires:      net-snmp-agent-libs, kamailio = %ver
-%else
-Requires:      net-snmp-libs, kamailio = %ver
-%endif
-BuildRequires: net-snmp-devel
+%package	lcr
+Summary:	Least cost routing for Kamailio.
+Group:		System Environment/Daemons
+Requires:	pcre, kamailio = %ver
+BuildRequires:	pcre-devel
 
-%description snmpstats
-SNMP management interface (scalar statistics) for Kamailio.
+%description	lcr
+Least cost routing for Kamailio.
 
 
-%package presence
-Summary:       SIP Presence (and RLS, XCAP, etc) support for Kamailio.
-Group:         System Environment/Daemons
-Requires:      libxml2, libcurl, kamailio = %ver, kamailio-xmpp = %ver
-BuildRequires: libxml2-devel, libcurl-devel
+%package	ldap
+Summary:	LDAP search interface for Kamailio.
+Group:		System Environment/Daemons
+Requires:	openldap, kamailio = %ver
+BuildRequires:	openldap-devel
 
-%description presence
-SIP Presence (and RLS, XCAP, etc) support for Kamailio.
+%description	ldap
+LDAP search interface for Kamailio.
 
 
-%package xmpp
-Summary:       SIP/XMPP IM gateway for Kamailio.
-Group:         System Environment/Daemons
-Requires:      expat, kamailio = %ver
-BuildRequires: expat-devel
+%package	lua
+Summary:	Lua extensions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	kamailio = %ver
+BuildRequires:	lua-devel
 
-%description xmpp
-SIP/XMPP IM gateway for Kamailio.
+%description	lua
+Lua extensions for Kamailio.
 
 
-%package  purple
-Summary:  Multi-protocol IM and presence gateway module.
-Group:    System Environment/Daemons
-%if 0%{?fedora}
-Requires: glib, libpurple, libxml2, kamailio = %ver, kamailio-presence = %ver
-BuildRequires: glib-devel, libpurple-devel, libxml2-devel
-%else
-Requires: glib2, libpurple, libxml2, kamailio = %ver, kamailio-presence = %ver
-BuildRequires: glib2-devel, libpurple-devel, libxml2-devel
-%endif
+%package	mysql
+Summary:	MySQL database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	mysql-libs, kamailio = %ver
+BuildRequires:	mysql-devel zlib-devel
 
-%description purple
-Multi-protocol IM and presence gateway module.
+%description	mysql
+MySQL database connectivity for Kamailio.
 
 
-%package ldap
-Summary:       LDAP search interface for Kamailio.
-Group:         System Environment/Daemons
-Requires:      openldap, kamailio = %ver
-BuildRequires: openldap-devel
+%package	outbound
+Summary:	Outbound (RFC 5626) support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	openssl, kamailio = %ver
+BuildRequires:	openssl-devel
 
-%description ldap
-LDAP search interface for Kamailio.
+%description	outbound
+RFC 5626, "Managing Client-Initiated Connections in the Session Initiation
+Protocol (SIP)" support for Kamailio.
 
 
-%package xmlrpc
-Summary:       XMLRPC trasnport and encoding for Kamailio RPCs.
-Group:         System Environment/Daemons
-Requires:      libxml2, kamailio = %ver
-BuildRequires: libxml2-devel
+%package	perl
+Summary:	Perl extensions and database driver for Kamailio.
+Group:		System Environment/Daemons 
+Requires:	mod_perl, kamailio = %ver
+BuildRequires:	mod_perl-devel
 
-%description xmlrpc
-XMLRPC trasnport and encoding for Kamailio RPCs.
+%description	perl
+Perl extensions and database driver for Kamailio.
 
 
-%package perl
-Summary:       Perl extensions and database driver for Kamailio.
-Group:         System Environment/Daemons 
-Requires:      mod_perl, kamailio = %ver
-BuildRequires: mod_perl-devel
+%package	postgresql
+Summary:	PostgreSQL database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	postgresql-libs, kamailio = %ver
+BuildRequires:	postgresql-devel
 
-%description perl
-Perl extensions and database driver for Kamailio.
+%description	postgresql
+PostgreSQL database connectivity for Kamailio.
 
 
-%package lua
-Summary:       Lua extensions for Kamailio.
-Group:         System Environment/Daemons
-Requires:      kamailio = %ver
-BuildRequires: lua-devel
+%package	presence
+Summary:	SIP Presence (and RLS, XCAP, etc) support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, libcurl, kamailio = %ver, kamailio-xmpp = %ver
+BuildRequires:	libxml2-devel, libcurl-devel
 
-%description lua
-Lua extensions for Kamailio.
+%description	presence
+SIP Presence (and RLS, XCAP, etc) support for Kamailio.
+
+
+%package	purple
+Summary:	Multi-protocol IM and presence gateway module.
+Group:		System Environment/Daemons
+%if 0%{?fedora}
+Requires:	glib, libpurple, libxml2, kamailio = %ver
+Requires:	kamailio-presence = %ver
+BuildRequires:	glib-devel, libpurple-devel, libxml2-devel
+%else
+Requires:	glib2, libpurple, libxml2, kamailio = %ver
+Requires:	kamailio-presence = %ver
+BuildRequires:	glib2-devel, libpurple-devel, libxml2-devel
+%endif
+
+%description	purple
+Multi-protocol IM and presence gateway module.
 
 
-%package python
-Summary:       Python extensions for Kamailio.
-Group:         System Environment/Daemons
-Requires:      python, kamailio = %ver
-BuildRequires: python-devel
+%package	python
+Summary:	Python extensions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	python, kamailio = %ver
+BuildRequires:	python-devel
 
-%description python
+%description	python
 Python extensions for Kamailio.
 
 
-%package regex
-Summary:       PCRE mtaching operations for Kamailio.
-Group:         System Environment/Daemons
-Requires:      pcre, kamailio = %ver
-BuildRequires: pcre-devel
+%package	regex
+Summary:	PCRE mtaching operations for Kamailio.
+Group:		System Environment/Daemons
+Requires:	pcre, kamailio = %ver
+BuildRequires:	pcre-devel
 
-%description regex
+%description	regex
 PCRE mtaching operations for Kamailio.
 
 
-%package dialplan
-Summary:       String translations based on rules for Kamailio.
-Group:         System Environment/Daemons
-Requires:      pcre, kamailio = %ver
-BuildRequires: pcre-devel
+%package	sctp
+Summary:	SCTP transport for Kamailio.
+Group:		System Environment/Daemons
+Requires:	lksctp-tools, kamailio = %ver
+BuildRequires:	lksctp-tools-devel
 
-%description dialplan
-String translations based on rules for Kamailio.
+%description	sctp
+SCTP transport for Kamailio.
 
 
-%package lcr
-Summary:       Least cost routing for Kamailio.
-Group:         System Environment/Daemons
-Requires:      pcre, kamailio = %ver
-BuildRequires: pcre-devel
+%package	snmpstats
+Summary:	SNMP management interface (scalar statistics) for Kamailio.
+Group:		System Environment/Daemons
+%if 0%{?fedora}
+Requires:	net-snmp-agent-libs, kamailio = %ver
+%else
+Requires:	net-snmp-libs, kamailio = %ver
+%endif
+BuildRequires:	net-snmp-devel
 
-%description lcr
-Least cost routing for Kamailio.
+%description	snmpstats
+SNMP management interface (scalar statistics) for Kamailio.
 
 
-%package xmlops
-Summary:       XML operation functions for Kamailio.
-Group:         System Environment/Daemons
-Requires:      libxml2, kamailio = %ver
-BuildRequires: libxml2-devel
+%package	sqlite
+Summary:	SQLite database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	sqlite, kamailio = %ver
+BuildRequires:	sqlite-devel
 
-%description xmlops
-XML operation functions for Kamailio.
+%description	sqlite
+SQLite database connectivity for Kamailio.
 
 
-%package  cdp
-Summary:  C Diameter Peer module and extensions module for Kamailio.
-Group:    System Environment/Daemons
-Requires: libxml2, kamailio = %ver
-BuildRequires: libxml2-devel
+%package	stun
+Summary:	Limited STUN (RFC 5389) support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	openssl, kamailio = %ver
+BuildRequires:	openssl-devel
 
-%description cdp
-C Diameter Peer module and extensions module for Kamailio.
+%description	stun
+Limited RFC 5389, "Session Traversal Utilities for NAT (STUN)" support for
+Kamailio.
 
 
-%package  ims
-Summary:  IMS modules and extensions module for Kamailio.
-Group:    System Environment/Daemons
-Requires: libxml2, kamailio = %ver, kamailio-cdp = %ver
-BuildRequires: libxml2-devel
+%package	tls
+Summary:	TLS transport for Kamailio.
+Group:		System Environment/Daemons
+Requires:	openssl, kamailio = %ver
+BuildRequires:	openssl-devel
 
-%description ims
-IMS modules and extensions module for Kamailio.
+%description	tls
+TLS transport for Kamailio.
 
 
-%package  auth-identity
-Summary:  Functions for secure identification of originators of SIP messages for Kamailio.
-Group:    System Environment/Daemons
-Requires: libcurl, kamailio = %ver
-BuildRequires: libcurl-devel
+%package	unixODBC
+Summary:	unixODBC database connectivity for Kamailio.
+Group:		System Environment/Daemons
+Requires:	unixODBC, kamailio = %ver
+BuildRequires:	unixODBC-devel
 
-%description auth-identity
-Functions for secure identification of originators of SIP messages for Kamailio.
+%description	unixODBC
+unixODBC database connectivity for Kamailio.
+
+
+%package	utils
+Summary:	Non-SIP utitility functions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libcurl, libxml2, kamailio = %ver
+BuildRequires:	libcurl-devel, libxml2-devel
+
+%description	utils
+Non-SIP utitility functions for Kamailio.
 
 
-%package websocket
-Summary:       WebSocket transport for Kamailio.
-Group:         System Environment/Daemons
-Requires:      libunistring, kamailio = %ver
-BuildRequires: libunistring-devel
+%package	websocket
+Summary:	WebSocket transport for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libunistring, openssl, kamailio = %ver
+BuildRequires:	libunistring-devel, openssl-devel
 
-%description websocket
+%description	websocket
 WebSocket transport for Kamailio.
 
 
-%package xhttp-pi
-Summary:       Web-provisioning interface for Kamailio.
-Group:         System Environment/Daemons
-Requires:      libxml2, kamailio = %ver
-BuildRequires: libxml2-devel
+%package	xhttp-pi
+Summary:	Web-provisioning interface for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
 
-%description xhttp-pi
+%description	xhttp-pi
 Web-provisioning interface for Kamailio.
 
 
-%package outbound
-Summary:       Outbound (RFC 5626) support for Kamailio.
-Group:         System Environment/Daemons
-Requires:      openssl, kamailio = %ver
-BuildRequires: openssl-devel
+%package	xmlops
+Summary:	XML operation functions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
 
-%description outbound
-RFC 5626, "Managing Client-Initiated Connections in the Session Initiation
-Protocol (SIP)" support for Kamailio.
+%description	xmlops
+XML operation functions for Kamailio.
 
 
-%if 0%{?fedora}
-%package radius
-Summary:       Radius AAA API for Kamailio.
-Group:         System Environment/Daemons
-Requires:      radiusclient-ng, kamailio = %ver
-BuildRequires: radiusclient-ng-devel
+%package	xmlrpc
+Summary:	XMLRPC trasnport and encoding for Kamailio RPCs.
+Group:		System Environment/Daemons
+Requires:	libxml2, kamailio = %ver
+BuildRequires:	libxml2-devel
 
-%description radius
-Radius AAA API for Kamailio.
+%description	xmlrpc
+XMLRPC trasnport and encoding for Kamailio RPCs.
+
+
+%package	xmpp
+Summary:	SIP/XMPP IM gateway for Kamailio.
+Group:		System Environment/Daemons
+Requires:	expat, kamailio = %ver
+BuildRequires:	expat-devel
+
+%description	xmpp
+SIP/XMPP IM gateway for Kamailio.
 
 
-%package carrierroute
-Summary:       Routing, balancing, and blacklisting for Kamailio.
-Group:         System Environment/Daemons
-Requires:      libconfuse, kamailio = %ver
-BuildRequires: libconfuse-devel
+%if 0%{?fedora}
+%package	carrierroute
+Summary:	Routing, balancing, and blacklisting for Kamailio.
+Group:		System Environment/Daemons
+Requires:	libconfuse, kamailio = %ver
+BuildRequires:	libconfuse-devel
 
-%description carrierroute
+%description	carrierroute
 Routing, balancing, and blacklisting for Kamailio.
 
 
-%package redis
-Summary:       REDIS NoSQL database connector for Kamailio.
-Group:         System Environment/Daemons
-Requires:      hiredis, kamailio = %ver
-BuildRequires: hiredis-devel
+%package	GeoIP
+Summary:	Max Mind GeoIP real-time query support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	GeoIP, kamailio = %ver
+BuildRequires:	GeoIP-devel
 
-%description redis
-REDIS NoSQL database connector for Kamailio.
+%description	GeoIP
+Max Mind GeoIP real-time query support for Kamailio.
 
 
-%package json
-Summary:       json string operation and rpc support for Kamailio.
-Group:         System Environment/Daemons
-Requires:      json-c, libevent, kamailio = %ver
-BuildRequires: json-c-devel, libevent-devel
+%package	json
+Summary:	json string operation and rpc support for Kamailio.
+Group:		System Environment/Daemons
+Requires:	json-c, libevent, kamailio = %ver
+BuildRequires:	json-c-devel, libevent-devel
 
-%description json
+%description	json
 json string operation and rpc support for Kamailio.
 
 
-%package mono
-Summary:       Mono extensions for Kamailio.
-Group:         System Environment/Daemons
-Requires:      mono-core, kamailio = %ver
-BuildRequires: mono-devel
+%package	mono
+Summary:	Mono extensions for Kamailio.
+Group:		System Environment/Daemons
+Requires:	mono-core, kamailio = %ver
+BuildRequires:	mono-devel
 
-%description mono
+%description	mono
 Mono extensions for Kamailio.
 
 
-%package GeoIP
-Summary:       Max Mind GeoIP real-time query support for Kamailio.
-Group:         System Environment/Daemons
-Requires:      GeoIP, kamailio = %ver
-BuildRequires: GeoIP-devel
+%package	radius
+Summary:	Radius AAA API for Kamailio.
+Group:		System Environment/Daemons
+Requires:	radiusclient-ng, kamailio = %ver
+BuildRequires:	radiusclient-ng-devel
 
-%description GeoIP
-Max Mind GeoIP real-time query support for Kamailio.
+%description	radius
+Radius AAA API for Kamailio.
+
+
+%package	redis
+Summary:	REDIS NoSQL database connector for Kamailio.
+Group:		System Environment/Daemons
+Requires:	hiredis, kamailio = %ver
+BuildRequires:	hiredis-devel
+
+%description	redis
+REDIS NoSQL database connector for Kamailio.
 %endif
 
 
@@ -392,24 +434,23 @@ Max Mind GeoIP real-time query support for Kamailio.
 
 
 %build
-make FLAVOUR=kamailio cfg prefix=/usr cfg_prefix=$RPM_BUILD_ROOT\
-	basedir=$RPM_BUILD_ROOT cfg_target=/%{_sysconfdir}/kamailio/\
-	modules_dirs="modules" SCTP=1 STUN=1
+make cfg prefix=/usr cfg_prefix=$RPM_BUILD_ROOT basedir=$RPM_BUILD_ROOT \
+	cfg_target=/%{_sysconfdir}/kamailio/ modules_dirs="modules"
 make
 %if 0%{?fedora}
-make every-module skip_modules="db_cassandra iptrtpproxy db_oracle memcached \
-	mi_xmlrpc osp" \
+make every-module skip_modules="app_java db_cassandra db_oracle dnssec \
+	iptrtpproxy memcached mi_xmlrpc osp" \
 	group_include="kstandard kmysql kpostgres kcpl kxml kradius kunixodbc \
 	kperl ksnmpstats kxmpp kcarrierroute kberkeley kldap kutils kpurple \
 	ktls kwebsocket kpresence klua kpython kgeoip ksqlite kjson kredis \
-	kmono kims koutbound"
+	kmono kims koutbound ksctp kstun kautheph"
 %else
-make every-module skip_modules="db_cassandra iptrtpproxy db_oracle memcached \
-	mi_xmlrpc osp" \
+make every-module skip_modules="app_java db_cassandra db_oracle dnssec \
+	iptrtpproxy memcached mi_xmlrpc osp" \
 	group_include="kstandard kmysql kpostgres kcpl kxml kunixodbc \
 	kperl ksnmpstats kxmpp kberkeley kldap kutils kpurple \
 	ktls kwebsocket kpresence klua kpython ksqlite \
-	kims koutbound"
+	kims koutbound ksctp kstun kautheph"
 %endif
 make utils
 
@@ -425,7 +466,7 @@ make install-modules-all skip_modules="db_cassandra iptrtpproxy db_oracle \
 	group_include="kstandard kmysql kpostgres kcpl kxml kradius kunixodbc \
 	kperl ksnmpstats kxmpp kcarrierroute kberkeley kldap kutils kpurple \
 	ktls kwebsocket kpresence klua kpython kgeoip ksqlite kjson kredis \
-	kmono kims koutbound"
+	kmono kims koutbound ksctp kstun kautheph"
 
 mkdir -p $RPM_BUILD_ROOT/%{_unitdir}
 install -m644 pkg/kamailio/fedora/%{?fedora}/kamailio.service \
@@ -440,7 +481,7 @@ make install-modules-all skip_modules="db_cassandra iptrtpproxy db_oracle \
 	group_include="kstandard kmysql kpostgres kcpl kxml kunixodbc \
 	kperl ksnmpstats kxmpp kberkeley kldap kutils kpurple \
 	ktls kwebsocket kpresence klua kpython ksqlite \
-	kims koutbound"
+	kims koutbound ksctp kstun kautheph"
 
 mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rc.d/init.d
 install -m755 pkg/kamailio/centos/%{?centos}/kamailio.init \
@@ -518,6 +559,7 @@ fi
 %doc %{_docdir}/kamailio/modules/README.cfg_db
 %doc %{_docdir}/kamailio/modules/README.cfg_rpc
 %doc %{_docdir}/kamailio/modules/README.cfgutils
+%doc %{_docdir}/kamailio/modules/README.cnxcc
 %doc %{_docdir}/kamailio/modules/README.corex
 %doc %{_docdir}/kamailio/modules/README.counters
 %doc %{_docdir}/kamailio/modules/README.ctl
@@ -571,11 +613,13 @@ fi
 %doc %{_docdir}/kamailio/modules/README.rr
 %doc %{_docdir}/kamailio/modules/README.rtimer
 %doc %{_docdir}/kamailio/modules/README.rtpproxy
+%doc %{_docdir}/kamailio/modules/README.rtpproxy-ng
 %doc %{_docdir}/kamailio/modules/README.sanity
 %doc %{_docdir}/kamailio/modules/README.sca
 %doc %{_docdir}/kamailio/modules/README.sdpops
 %doc %{_docdir}/kamailio/modules/README.seas
 %doc %{_docdir}/kamailio/modules/README.sipcapture
+%doc %{_docdir}/kamailio/modules/README.sipt
 %doc %{_docdir}/kamailio/modules/README.siptrace
 %doc %{_docdir}/kamailio/modules/README.siputils
 %doc %{_docdir}/kamailio/modules/README.sl
@@ -587,7 +631,6 @@ fi
 %doc %{_docdir}/kamailio/modules/README.textops
 %doc %{_docdir}/kamailio/modules/README.textopsx
 %doc %{_docdir}/kamailio/modules/README.timer
-%doc %{_docdir}/kamailio/modules/README.tls
 %doc %{_docdir}/kamailio/modules/README.tm
 %doc %{_docdir}/kamailio/modules/README.tmrec
 %doc %{_docdir}/kamailio/modules/README.tmx
@@ -657,6 +700,7 @@ fi
 %{_libdir}/kamailio/modules/cfg_db.so
 %{_libdir}/kamailio/modules/cfg_rpc.so
 %{_libdir}/kamailio/modules/cfgutils.so
+%{_libdir}/kamailio/modules/cnxcc.so
 %{_libdir}/kamailio/modules/corex.so
 %{_libdir}/kamailio/modules/counters.so
 %{_libdir}/kamailio/modules/ctl.so
@@ -710,10 +754,12 @@ fi
 %{_libdir}/kamailio/modules/rr.so
 %{_libdir}/kamailio/modules/rtimer.so
 %{_libdir}/kamailio/modules/rtpproxy.so
+%{_libdir}/kamailio/modules/rtpproxy-ng.so
 %{_libdir}/kamailio/modules/sanity.so
 %{_libdir}/kamailio/modules/sca.so
 %{_libdir}/kamailio/modules/seas.so
 %{_libdir}/kamailio/modules/sipcapture.so
+%{_libdir}/kamailio/modules/sipt.so
 %{_libdir}/kamailio/modules/siptrace.so
 %{_libdir}/kamailio/modules/siputils.so
 %{_libdir}/kamailio/modules/sl.so
@@ -726,7 +772,6 @@ fi
 %{_libdir}/kamailio/modules/textops.so
 %{_libdir}/kamailio/modules/textopsx.so
 %{_libdir}/kamailio/modules/timer.so
-%{_libdir}/kamailio/modules/tls.so
 %{_libdir}/kamailio/modules/tm.so
 %{_libdir}/kamailio/modules/tmrec.so
 %{_libdir}/kamailio/modules/tmx.so
@@ -780,33 +825,19 @@ fi
 %{_datadir}/kamailio/dbtext/kamailio/*
 
 
-%files mysql
+%files		auth-ephemeral
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.db_mysql
-%{_libdir}/kamailio/modules/db_mysql.so
-%{_libdir}/kamailio/kamctl/kamctl.mysql
-%{_libdir}/kamailio/kamctl/kamdbctl.mysql
-%dir %{_datadir}/kamailio/mysql
-%{_datadir}/kamailio/mysql/*
+%doc %{_docdir}/kamailio/modules/README.auth_ephemeral
+%{_libdir}/kamailio/modules/auth_ephemeral.so
 
 
-%files postgresql
+%files		auth-identity
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.db_postgres
-%{_libdir}/kamailio/modules/db_postgres.so
-%{_libdir}/kamailio/kamctl/kamctl.pgsql
-%{_libdir}/kamailio/kamctl/kamdbctl.pgsql
-%dir %{_datadir}/kamailio/postgres
-%{_datadir}/kamailio/postgres/*
-
-
-%files unixODBC
-%defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.db_unixodbc
-%{_libdir}/kamailio/modules/db_unixodbc.so
+%doc %{_docdir}/kamailio/modules/README.auth_identity
+%{_libdir}/kamailio/modules/auth_identity.so
 
 
-%files bdb
+%files		bdb
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.db_berkeley
 %{_sbindir}/kambdb_recover
@@ -817,85 +848,58 @@ fi
 %{_datadir}/kamailio/db_berkeley/*
 
 
-%files sqlite
+%files		cdp
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.db_sqlite
-%{_libdir}/kamailio/modules/db_sqlite.so
-%{_libdir}/kamailio/kamctl/kamctl.sqlite
-%{_libdir}/kamailio/kamctl/kamdbctl.sqlite
-%dir %{_datadir}/kamailio/db_sqlite
-%{_datadir}/kamailio/db_sqlite/*
-
-
-%files utils
-%defattr(-,root,root)
-%{_docdir}/kamailio/modules/README.utils
-%{_libdir}/kamailio/modules/utils.so
+%doc %{_docdir}/kamailio/modules/README.cdp
+%{_libdir}/kamailio/modules/cdp.so
+%doc %{_docdir}/kamailio/modules/README.cdp_avp
+%{_libdir}/kamailio/modules/cdp_avp.so
 
 
-%files cpl
+%files		cpl
 %defattr(-,root,root)
 %{_docdir}/kamailio/modules/README.cpl-c
 %{_libdir}/kamailio/modules/cpl-c.so
 
 
-%files snmpstats
+%files		dialplan
 %defattr(-,root,root)
-%{_docdir}/kamailio/modules/README.snmpstats
-%{_libdir}/kamailio/modules/snmpstats.so
-
-
-%files presence
-%defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.presence
-%doc %{_docdir}/kamailio/modules/README.presence_conference
-%doc %{_docdir}/kamailio/modules/README.presence_dialoginfo
-%doc %{_docdir}/kamailio/modules/README.presence_mwi
-%doc %{_docdir}/kamailio/modules/README.presence_profile
-%doc %{_docdir}/kamailio/modules/README.presence_reginfo
-%doc %{_docdir}/kamailio/modules/README.presence_xml
-%doc %{_docdir}/kamailio/modules/README.pua
-%doc %{_docdir}/kamailio/modules/README.pua_bla
-%doc %{_docdir}/kamailio/modules/README.pua_dialoginfo
-%doc %{_docdir}/kamailio/modules/README.pua_mi
-%doc %{_docdir}/kamailio/modules/README.pua_reginfo
-%doc %{_docdir}/kamailio/modules/README.pua_usrloc
-%doc %{_docdir}/kamailio/modules/README.pua_xmpp
-%doc %{_docdir}/kamailio/modules/README.rls
-%doc %{_docdir}/kamailio/modules/README.xcap_client
-%doc %{_docdir}/kamailio/modules/README.xcap_server
-%{_libdir}/kamailio/modules/presence.so
-%{_libdir}/kamailio/modules/presence_conference.so
-%{_libdir}/kamailio/modules/presence_dialoginfo.so
-%{_libdir}/kamailio/modules/presence_mwi.so
-%{_libdir}/kamailio/modules/presence_profile.so
-%{_libdir}/kamailio/modules/presence_reginfo.so
-%{_libdir}/kamailio/modules/presence_xml.so
-%{_libdir}/kamailio/modules/pua.so
-%{_libdir}/kamailio/modules/pua_bla.so
-%{_libdir}/kamailio/modules/pua_dialoginfo.so
-%{_libdir}/kamailio/modules/pua_mi.so
-%{_libdir}/kamailio/modules/pua_reginfo.so
-%{_libdir}/kamailio/modules/pua_usrloc.so
-%{_libdir}/kamailio/modules/pua_xmpp.so
-%{_libdir}/kamailio/modules/rls.so
-%{_libdir}/kamailio/modules/xcap_client.so
-%{_libdir}/kamailio/modules/xcap_server.so
+%doc %{_docdir}/kamailio/modules/README.dialplan
+%{_libdir}/kamailio/modules/dialplan.so
 
 
-%files xmpp
+%files		ims
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.xmpp
-%{_libdir}/kamailio/modules/xmpp.so
+%{_libdir}/kamailio/libkamailio_ims.so
+%{_libdir}/kamailio/libkamailio_ims.so.0
+%{_libdir}/kamailio/libkamailio_ims.so.0.1
+%doc %{_docdir}/kamailio/modules/README.dialog_ng
+%{_libdir}/kamailio/modules/dialog_ng.so
+%doc %{_docdir}/kamailio/modules/README.ims_auth
+%{_libdir}/kamailio/modules/ims_auth.so
+%doc %{_docdir}/kamailio/modules/README.ims_icscf
+%{_libdir}/kamailio/modules/ims_icscf.so
+%doc %{_docdir}/kamailio/modules/README.ims_isc
+%{_libdir}/kamailio/modules/ims_isc.so
+%doc %{_docdir}/kamailio/modules/README.ims_qos
+%{_libdir}/kamailio/modules/ims_qos.so
+#%doc %{_docdir}/kamailio/modules/README.ims_registrar_pcscf
+%{_libdir}/kamailio/modules/ims_registrar_pcscf.so
+#%doc %{_docdir}/kamailio/modules/README.ims_registrar_scscf
+%{_libdir}/kamailio/modules/ims_registrar_scscf.so
+%doc %{_docdir}/kamailio/modules/README.ims_usrloc_pcscf
+%{_libdir}/kamailio/modules/ims_usrloc_pcscf.so
+#%doc %{_docdir}/kamailio/modules/README.ims_usrloc_scscf
+%{_libdir}/kamailio/modules/ims_usrloc_scscf.so
 
 
-%files purple
+%files		lcr
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.purple
-%{_libdir}/kamailio/modules/purple.so
+%doc %{_docdir}/kamailio/modules/README.lcr
+%{_libdir}/kamailio/modules/lcr.so
 
 
-%files ldap
+%files		ldap
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.db2_ldap
 %doc %{_docdir}/kamailio/modules/README.h350
@@ -905,13 +909,29 @@ fi
 %{_libdir}/kamailio/modules/ldap.so
 
 
-%files xmlrpc
+%files		lua
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.xmlrpc
-%{_libdir}/kamailio/modules/xmlrpc.so
+%doc %{_docdir}/kamailio/modules/README.app_lua
+%{_libdir}/kamailio/modules/app_lua.so
 
 
-%files perl
+%files		mysql
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.db_mysql
+%{_libdir}/kamailio/modules/db_mysql.so
+%{_libdir}/kamailio/kamctl/kamctl.mysql
+%{_libdir}/kamailio/kamctl/kamdbctl.mysql
+%dir %{_datadir}/kamailio/mysql
+%{_datadir}/kamailio/mysql/*
+
+
+%files		outbound
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.outbound
+%{_libdir}/kamailio/modules/outbound.so
+
+
+%files		perl
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.app_perl
 %doc %{_docdir}/kamailio/modules/README.db_perlvdb
@@ -945,88 +965,125 @@ fi
 %{_libdir}/kamailio/perl/Kamailio/VDB/Adapter/TableVersions.pm
 
 
-%files lua
+%files		postgresql
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.app_lua
-%{_libdir}/kamailio/modules/app_lua.so
+%doc %{_docdir}/kamailio/modules/README.db_postgres
+%{_libdir}/kamailio/modules/db_postgres.so
+%{_libdir}/kamailio/kamctl/kamctl.pgsql
+%{_libdir}/kamailio/kamctl/kamdbctl.pgsql
+%dir %{_datadir}/kamailio/postgres
+%{_datadir}/kamailio/postgres/*
+
+
+%files		presence
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.presence
+%doc %{_docdir}/kamailio/modules/README.presence_conference
+%doc %{_docdir}/kamailio/modules/README.presence_dialoginfo
+%doc %{_docdir}/kamailio/modules/README.presence_mwi
+%doc %{_docdir}/kamailio/modules/README.presence_profile
+%doc %{_docdir}/kamailio/modules/README.presence_reginfo
+%doc %{_docdir}/kamailio/modules/README.presence_xml
+%doc %{_docdir}/kamailio/modules/README.pua
+%doc %{_docdir}/kamailio/modules/README.pua_bla
+%doc %{_docdir}/kamailio/modules/README.pua_dialoginfo
+%doc %{_docdir}/kamailio/modules/README.pua_mi
+%doc %{_docdir}/kamailio/modules/README.pua_reginfo
+%doc %{_docdir}/kamailio/modules/README.pua_usrloc
+%doc %{_docdir}/kamailio/modules/README.pua_xmpp
+%doc %{_docdir}/kamailio/modules/README.rls
+%doc %{_docdir}/kamailio/modules/README.xcap_client
+%doc %{_docdir}/kamailio/modules/README.xcap_server
+%{_libdir}/kamailio/modules/presence.so
+%{_libdir}/kamailio/modules/presence_conference.so
+%{_libdir}/kamailio/modules/presence_dialoginfo.so
+%{_libdir}/kamailio/modules/presence_mwi.so
+%{_libdir}/kamailio/modules/presence_profile.so
+%{_libdir}/kamailio/modules/presence_reginfo.so
+%{_libdir}/kamailio/modules/presence_xml.so
+%{_libdir}/kamailio/modules/pua.so
+%{_libdir}/kamailio/modules/pua_bla.so
+%{_libdir}/kamailio/modules/pua_dialoginfo.so
+%{_libdir}/kamailio/modules/pua_mi.so
+%{_libdir}/kamailio/modules/pua_reginfo.so
+%{_libdir}/kamailio/modules/pua_usrloc.so
+%{_libdir}/kamailio/modules/pua_xmpp.so
+%{_libdir}/kamailio/modules/rls.so
+%{_libdir}/kamailio/modules/xcap_client.so
+%{_libdir}/kamailio/modules/xcap_server.so
 
 
-%files python
+%files		purple
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.purple
+%{_libdir}/kamailio/modules/purple.so
+
+
+%files		python
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.app_python
 %{_libdir}/kamailio/modules/app_python.so
 
 
-%files regex
+%files		regex
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.regex
 %{_libdir}/kamailio/modules/regex.so
 
 
-%files dialplan
+%files		sctp
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.dialplan
-%{_libdir}/kamailio/modules/dialplan.so
+%doc %{_docdir}/kamailio/modules/README.sctp
+%{_libdir}/kamailio/modules/sctp.so
 
 
-%files lcr
+%files		snmpstats
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.lcr
-%{_libdir}/kamailio/modules/lcr.so
+%{_docdir}/kamailio/modules/README.snmpstats
+%{_libdir}/kamailio/modules/snmpstats.so
 
 
-%files xmlops
+%files		sqlite
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.xmlops
-%{_libdir}/kamailio/modules/xmlops.so
+%doc %{_docdir}/kamailio/modules/README.db_sqlite
+%{_libdir}/kamailio/modules/db_sqlite.so
+%{_libdir}/kamailio/kamctl/kamctl.sqlite
+%{_libdir}/kamailio/kamctl/kamdbctl.sqlite
+%dir %{_datadir}/kamailio/db_sqlite
+%{_datadir}/kamailio/db_sqlite/*
 
 
-%files cdp
+%files		stun
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.cdp
-%{_libdir}/kamailio/modules/cdp.so
-%doc %{_docdir}/kamailio/modules/README.cdp_avp
-%{_libdir}/kamailio/modules/cdp_avp.so
+%doc %{_docdir}/kamailio/modules/README.stun
+%{_libdir}/kamailio/modules/stun.so
 
 
-%files ims
+%files		tls
 %defattr(-,root,root)
-%{_libdir}/kamailio/libkamailio_ims.so
-%{_libdir}/kamailio/libkamailio_ims.so.0
-%{_libdir}/kamailio/libkamailio_ims.so.0.1
-%doc %{_docdir}/kamailio/modules/README.dialog_ng
-%{_libdir}/kamailio/modules/dialog_ng.so
-%doc %{_docdir}/kamailio/modules/README.ims_auth
-%{_libdir}/kamailio/modules/ims_auth.so
-%doc %{_docdir}/kamailio/modules/README.ims_icscf
-%{_libdir}/kamailio/modules/ims_icscf.so
-%doc %{_docdir}/kamailio/modules/README.ims_isc
-%{_libdir}/kamailio/modules/ims_isc.so
-%doc %{_docdir}/kamailio/modules/README.ims_qos
-%{_libdir}/kamailio/modules/ims_qos.so
-#%doc %{_docdir}/kamailio/modules/README.ims_registrar_pcscf
-%{_libdir}/kamailio/modules/ims_registrar_pcscf.so
-#%doc %{_docdir}/kamailio/modules/README.ims_registrar_scscf
-%{_libdir}/kamailio/modules/ims_registrar_scscf.so
-%doc %{_docdir}/kamailio/modules/README.ims_usrloc_pcscf
-%{_libdir}/kamailio/modules/ims_usrloc_pcscf.so
-#%doc %{_docdir}/kamailio/modules/README.ims_usrloc_scscf
-%{_libdir}/kamailio/modules/ims_usrloc_scscf.so
+%doc %{_docdir}/kamailio/modules/README.tls
+%{_libdir}/kamailio/modules/tls.so
 
 
-%files auth-identity
+%files		unixODBC
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.auth_identity
-%{_libdir}/kamailio/modules/auth_identity.so
+%doc %{_docdir}/kamailio/modules/README.db_unixodbc
+%{_libdir}/kamailio/modules/db_unixodbc.so
+
+
+%files		utils
+%defattr(-,root,root)
+%{_docdir}/kamailio/modules/README.utils
+%{_libdir}/kamailio/modules/utils.so
 
 
-%files websocket
+%files		websocket
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.websocket
 %{_libdir}/kamailio/modules/websocket.so
 
 
-%files xhttp-pi
+%files		xhttp-pi
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.xhttp_pi
 %{_libdir}/kamailio/modules/xhttp_pi.so
@@ -1034,14 +1091,32 @@ fi
 %{_datadir}/kamailio/xhttp_pi/*
 
 
-%files outbound
+%files		xmlops
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.outbound
-%{_libdir}/kamailio/modules/outbound.so
+%doc %{_docdir}/kamailio/modules/README.xmlops
+%{_libdir}/kamailio/modules/xmlops.so
+
+
+%files		xmlrpc
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.xmlrpc
+%{_libdir}/kamailio/modules/xmlrpc.so
+
+
+%files		xmpp
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.xmpp
+%{_libdir}/kamailio/modules/xmpp.so
 
 
 %if 0%{?fedora}
-%files radius
+%files		carrierroute
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.carrierroute
+%{_libdir}/kamailio/modules/carrierroute.so
+
+
+%files		radius
 %defattr(-,root,root)
 %{_docdir}/kamailio/modules/README.acc_radius
 %{_docdir}/kamailio/modules/README.auth_radius
@@ -1053,19 +1128,7 @@ fi
 %{_libdir}/kamailio/modules/peering.so
 
 
-%files carrierroute
-%defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.carrierroute
-%{_libdir}/kamailio/modules/carrierroute.so
-
-
-%files redis
-%defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.ndb_redis
-%{_libdir}/kamailio/modules/ndb_redis.so
-
-
-%files json
+%files		json
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.json
 %doc %{_docdir}/kamailio/modules/README.jsonrpc-c
@@ -1073,28 +1136,57 @@ fi
 %{_libdir}/kamailio/modules/jsonrpc-c.so
 
 
-%files mono
+%files		GeoIP
+%defattr(-,root,root)
+%doc %{_docdir}/kamailio/modules/README.geoip
+%{_libdir}/kamailio/modules/geoip.so
+
+
+%files		mono
 %defattr(-,root,root)
 %doc %{_docdir}/kamailio/modules/README.app_mono
 %{_libdir}/kamailio/modules/app_mono.so
 
 
-%files GeoIP
+%files		redis
 %defattr(-,root,root)
-%doc %{_docdir}/kamailio/modules/README.geoip
-%{_libdir}/kamailio/modules/geoip.so
+%doc %{_docdir}/kamailio/modules/README.ndb_redis
+%{_libdir}/kamailio/modules/ndb_redis.so
 %endif
 
 
 
 %changelog
+* Thu Aug 22 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Added rtpproxy-ng module to build
+* Wed Aug 14 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Updated rel to dev7
+* Mon May 27 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Created package for auth_ephemeral module
+* Sun May 26 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Created package for sctp module
+  - Updated rel to dev6
+* Sat May 18 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Refactored .spec
+  - Put tls module back in its own .spec (OpenSSL no longer needed by core as
+    stun is in its own module)
+  - Updated rel to dev5
+* Wed Apr 24 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Updated rel to dev3
+* Wed Apr 10 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Added sipt module to .spec
+  - Updated rel to dev2
+* Fri Mar 29 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Added stun module to .spec
+  - Updated rel to dev1
+* Wed Mar 27 2013 Peter Dunkley <peter at dunkley.me.uk>
+  - Added cnxcc module to .spec
 * Thu Mar 7 2013 Peter Dunkley <peter at dunkley.me.uk>
-  - Changed rel from rc1 to 0 in preparation for 4.0.0 release
   - Added build requirement for docbook2X for Fedora builds
 * Wed Mar 6 2013 Peter Dunkley <peter at dunkley.me.uk>
   - Restored perl related files
 * Tue Mar 5 2013 Peter Dunkley <peter at dunkley.me.uk>
-  - Updated pre1 to rc1
+  - Updated rel to dev0 and ver to 4.1.0
   - Re-ordered file to make it internally consistent
   - Updated make commands to match updated module groups
   - Added auth_identity back in
diff --git a/pkg/kamailio/rpm/kamailio.spec-4.1 b/pkg/kamailio/rpm/kamailio.spec-4.1
index b13679d..12b02f0 100644
--- a/pkg/kamailio/rpm/kamailio.spec-4.1
+++ b/pkg/kamailio/rpm/kamailio.spec-4.1
@@ -1,5 +1,5 @@
 %define name    kamailio
-%define ver     4.0.4
+%define ver     1.2.0
 %define rel     0
 
 %define EXCLUDED_MODULES	mysql jabber cpl-c avp_radius auth_radius group_radius uri_radius pa postgres osp tlsops unixodbc
diff --git a/pkg/kamailio/rpm/kamailio.spec.CenOS b/pkg/kamailio/rpm/kamailio.spec.CenOS
index 66a8d28..6b396c7 100644
--- a/pkg/kamailio/rpm/kamailio.spec.CenOS
+++ b/pkg/kamailio/rpm/kamailio.spec.CenOS
@@ -1,5 +1,5 @@
 %define name    kamailio
-%define ver     4.0.4
+%define ver     3.2.0
 %define rel     0
 %define _sharedir %{_prefix}/share
 
diff --git a/pkg/kamailio/rpm/kamailio.spec.SuSE b/pkg/kamailio/rpm/kamailio.spec.SuSE
index 024b981..77af948 100644
--- a/pkg/kamailio/rpm/kamailio.spec.SuSE
+++ b/pkg/kamailio/rpm/kamailio.spec.SuSE
@@ -1,5 +1,5 @@
 %define name    kamailio
-%define ver     4.0.4
+%define ver     1.2.0
 %define rel     0
 
 %define EXCLUDED_MODULES	mysql jabber cpl-c auth_radius misc_radius peering postgress pa unixodbc osp tlsops
diff --git a/pt.c b/pt.c
index 46fc30c..9721869 100644
--- a/pt.c
+++ b/pt.c
@@ -95,11 +95,7 @@ static int calc_common_open_fds_no(void)
 									  tmp. tcp send +
 									  tmp dns.*/
 				-1 /* timer (no udp)*/ + 3 /* stdin/out/err */ +
-#ifdef USE_IPV6
 				2*mhomed
-#else
-				mhomed
-#endif /* USE_IPV6*/
 				;
 	return max_fds_no;
 }
diff --git a/pvapi.c b/pvapi.c
index 6245ee9..7f5fcc2 100644
--- a/pvapi.c
+++ b/pvapi.c
@@ -41,7 +41,6 @@
 #include "pvar.h"
 
 #define PV_TABLE_SIZE	32  /*!< pseudo-variables table size */
-#define PV_CACHE_SIZE	32  /*!< pseudo-variables table size */
 #define TR_TABLE_SIZE	16  /*!< transformations table size */
 
 
@@ -58,14 +57,6 @@ typedef struct _pv_item
 static pv_item_t* _pv_table[PV_TABLE_SIZE];
 static int _pv_table_set = 0;
 
-typedef struct _pv_cache
-{
-	str pvname;
-	unsigned int pvid;
-	pv_spec_t spec;
-	struct _pv_cache *next;
-} pv_cache_t;
-
 static pv_cache_t* _pv_cache[PV_CACHE_SIZE];
 static int _pv_cache_set = 0;
 
@@ -87,6 +78,14 @@ void pv_init_cache(void)
 	_pv_cache_set = 1;
 }
 
+/**
+ *
+ */
+pv_cache_t **pv_cache_get_table(void)
+{
+	if(_pv_cache_set==1) return _pv_cache;
+	return NULL;
+}
 
 /**
  * @brief Check if a char is valid according to the PV syntax
@@ -357,6 +356,36 @@ pv_spec_t* pv_cache_get(str *name)
 	return pv_cache_add(&tname);
 }
 
+str* pv_cache_get_name(pv_spec_t *spec)
+{
+	int i;
+	pv_cache_t *pvi;
+	if(spec==NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return NULL;
+	}
+
+	if(_pv_cache_set==0)
+		return NULL;
+
+	for(i=0;i<PV_CACHE_SIZE;i++)
+	{
+		pvi = _pv_cache[i];
+		while(pvi)
+		{
+			if(&pvi->spec == spec)
+			{
+				LM_DBG("pvar[%p]->name[%.*s] found in cache\n", spec,
+					pvi->pvname.len, pvi->pvname.s);
+				return &pvi->pvname;
+			}
+			pvi = pvi->next;
+		}
+	}
+	return NULL;
+}
+
 /**
  *
  */
diff --git a/pvar.h b/pvar.h
index f6d6318..4d69a43 100644
--- a/pvar.h
+++ b/pvar.h
@@ -78,7 +78,7 @@ enum _pv_type {
 	PVT_DSTURI,           PVT_COLOR,             PVT_BRANCH,
 	PVT_FROM,             PVT_TO,                PVT_OURI,
 	PVT_SCRIPTVAR,        PVT_MSG_BODY,          PVT_CONTEXT,
-	PVT_OTHER,            PVT_EXTRA /* keep it last */
+	PVT_XAVP,             PVT_OTHER,             PVT_EXTRA /* keep it last */
 };
 
 typedef enum _pv_type pv_type_t;
@@ -207,6 +207,7 @@ int pv_free_extra_list(void);
 
 int pv_locate_name(str *in);
 pv_spec_t* pv_cache_get(str *name);
+str* pv_cache_get_name(pv_spec_t *spec);
 
 /*! \brief PV helper functions */
 int pv_get_null(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
@@ -225,6 +226,22 @@ int pv_get_intstrval(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res, int ival, str *sval);
 
 /**
+ * Core PV Cache
+ */
+typedef struct _pv_cache
+{
+	str pvname;
+	unsigned int pvid;
+	pv_spec_t spec;
+	struct _pv_cache *next;
+} pv_cache_t;
+
+#define PV_CACHE_SIZE	32  /*!< pseudo-variables cache table size */
+
+pv_cache_t **pv_cache_get_table(void);
+
+
+/**
  * Transformations
  */
 #define TR_LBRACKET_STR		"{"
@@ -271,5 +288,15 @@ void tr_param_free(tr_param_t *tp);
 
 int register_trans_mod(char *mod_name, tr_export_t *items);
 
+
+/**
+ * XAVP
+ */
+typedef struct _pv_xavp_name {
+	str name;
+	pv_spec_t index;
+	struct _pv_xavp_name *next;
+} pv_xavp_name_t;
+
 #endif
 
diff --git a/receive.c b/receive.c
index 6b5740f..7dcc26f 100644
--- a/receive.c
+++ b/receive.c
@@ -146,6 +146,7 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
 				"core parsing of SIP message failed (%s:%d/%d)\n",
 				ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port,
 				(int)msg->rcv.proto);
+		sr_core_ert_run(msg, SR_CORE_ERT_RECEIVE_PARSE_ERROR);
 		goto error02;
 	}
 	DBG("After parse_msg...\n");
diff --git a/resolve.c b/resolve.c
index e29e189..d0ef16c 100644
--- a/resolve.c
+++ b/resolve.c
@@ -92,23 +92,58 @@ counter_def_t dns_cnt_defs[] =  {
 #ifdef USE_NAPTR
 static int naptr_proto_pref[PROTO_LAST+1];
 #endif
+static int srv_proto_pref[PROTO_LAST+1];
 
 #ifdef USE_NAPTR
-void init_naptr_proto_prefs()
+static void init_naptr_proto_prefs()
 {
+	int ignore_rfc, udp, tcp, tls, sctp;
+
 	if ((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) ||
 		(PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)){
 		BUG("init_naptr_proto_prefs: array too small \n");
 		return;
 	}
-	naptr_proto_pref[PROTO_UDP]=cfg_get(core, core_cfg, dns_udp_pref);
-	naptr_proto_pref[PROTO_TCP]=cfg_get(core, core_cfg, dns_tcp_pref);
-	naptr_proto_pref[PROTO_TLS]=cfg_get(core, core_cfg, dns_tls_pref);
-	naptr_proto_pref[PROTO_SCTP]=cfg_get(core, core_cfg, dns_sctp_pref);
+
+	ignore_rfc = cfg_get(core, core_cfg, dns_naptr_ignore_rfc);
+	udp = cfg_get(core, core_cfg, dns_udp_pref);
+	tcp = cfg_get(core, core_cfg, dns_tcp_pref);
+	tls = cfg_get(core, core_cfg, dns_tls_pref);
+	sctp = cfg_get(core, core_cfg, dns_sctp_pref);
+
+	/* Old implementation ignored the Order field in the NAPTR RR and
+	 * thus violated a MUST in RFC 2915. Currently still the default. */
+	if (ignore_rfc) {
+		naptr_proto_pref[PROTO_UDP] = udp;
+		naptr_proto_pref[PROTO_TCP] = tcp;
+		naptr_proto_pref[PROTO_TLS] = tls;
+		naptr_proto_pref[PROTO_SCTP] = sctp;
+	} else {
+		/* If value is less than 0, proto is disabled, otherwise
+		 * ignored. */
+		naptr_proto_pref[PROTO_UDP] = udp < 0 ? udp : 1;
+		naptr_proto_pref[PROTO_TCP] = tcp < 0 ? tcp : 1;
+		naptr_proto_pref[PROTO_TLS] = tls < 0 ? tls : 1;
+		naptr_proto_pref[PROTO_SCTP] = sctp < 0 ? sctp : 1;
+	}
 }
 
 #endif /* USE_NAPTR */
 
+static void init_srv_proto_prefs()
+{
+	if ((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) ||
+		(PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)){
+		BUG("init_srv_proto_prefs: array too small \n");
+		return;
+	}
+
+	srv_proto_pref[PROTO_UDP] = cfg_get(core, core_cfg, dns_udp_pref);
+	srv_proto_pref[PROTO_TCP] = cfg_get(core, core_cfg, dns_tcp_pref);
+	srv_proto_pref[PROTO_TLS] = cfg_get(core, core_cfg, dns_tls_pref);
+	srv_proto_pref[PROTO_SCTP] = cfg_get(core, core_cfg, dns_sctp_pref);
+}
+
 #ifdef DNS_WATCHDOG_SUPPORT
 static on_resolv_reinit	on_resolv_reinit_cb = NULL;
 
@@ -153,7 +188,7 @@ error:
  */
 static int _resolv_init(void)
 {
-	res_init();
+	dns_func.sr_res_init();
 #ifdef HAVE_RESOLV_RES
 	if (cfg_get(core, core_cfg, dns_retr_time)>0)
 		_res.retrans=cfg_get(core, core_cfg, dns_retr_time);
@@ -178,9 +213,7 @@ int resolv_init(void)
 	int res = -1;
 	_resolv_init();
 
-#ifdef USE_NAPTR
-	init_naptr_proto_prefs();
-#endif
+	reinit_proto_prefs(NULL,NULL);
 	/* init counter API only at startup
 	 * This function must be called before DNS cache init method (if available)
 	 */
@@ -212,12 +245,13 @@ int dns_reinit_fixup(void *handle, str *gname, str *name, void **val)
 	return 0;
 }
 
-/* wrapper function to recalculate the naptr protocol preferences */
-void reinit_naptr_proto_prefs(str *gname, str *name)
+/* wrapper function to recalculate the naptr and srv protocol preferences */
+void reinit_proto_prefs(str *gname, str *name)
 {
 #ifdef USE_NAPTR
 	init_naptr_proto_prefs();
 #endif
+	init_srv_proto_prefs();
 }
 
 /* fixup function for dns_try_ipv6
@@ -714,10 +748,6 @@ struct rdata* get_record(char* name, int type, int flags)
 	struct rdata* fullname_rd;
 	char c;
 	
-#ifdef USE_DNSSEC
-	val_status_t val_status;
-#endif
-
 	name_len=strlen(name);
 
 	for (i = 0; i < name_len; i++) {
@@ -738,20 +768,7 @@ struct rdata* get_record(char* name, int type, int flags)
 	}
 	fullname_rd=0;
 
-#ifndef USE_DNSSEC
-	size=res_search(name, C_IN, type, buff.buff, sizeof(buff));
-#else
-	size=val_res_query((val_context_t *) NULL,
-                      (char *) name, 
-                      (int) C_IN,
-		      (int) type, 
-                      (unsigned char *) buff.buff, 
-		      (int) sizeof(buff),
-                      &val_status);	
-	if(!val_istrusted(val_status)){
-		LOG(L_INFO, "INFO: got not trusted record when resolving %s\n",name);
-	}
-#endif
+	size=dns_func.sr_res_search(name, C_IN, type, buff.buff, sizeof(buff));
 
 	if (unlikely(size<0)) {
 		DBG("get_record: lookup(%s, %d) failed\n", name, type);
@@ -1097,19 +1114,26 @@ char naptr_get_sip_proto(struct naptr_rdata* n)
 
 
 
-inline static int proto_pref_score(char proto)
+inline static int naptr_proto_pref_score(char proto)
 {
 	if ((proto>=PROTO_UDP) && (proto<= PROTO_LAST))
 		return naptr_proto_pref[(int)proto];
 	return 0;
 }
 
+inline static int srv_proto_pref_score(char proto)
+{
+	if ((proto>=PROTO_UDP) && (proto<= PROTO_LAST))
+		return srv_proto_pref[(int)proto];
+	return 0;
+}
+
 
 
 /* returns true if we support the protocol */
 int naptr_proto_supported(char proto)
 {
-	if (proto_pref_score(proto)<0)
+	if (naptr_proto_pref_score(proto)<0)
 		return 0;
 	switch(proto){
 		case PROTO_UDP:
@@ -1136,7 +1160,7 @@ int naptr_proto_supported(char proto)
 /* returns true if new_proto is preferred over old_proto */
 int naptr_proto_preferred(char new_proto, char old_proto)
 {
-	return proto_pref_score(new_proto)>proto_pref_score(old_proto);
+	return naptr_proto_pref_score(new_proto)>naptr_proto_pref_score(old_proto);
 }
 
 
@@ -1210,7 +1234,7 @@ struct hostent* srv_sip_resolvehost(str* name, int zt, unsigned short* port,
 	srv_head=0;
 	srv_target=0;
 	if (name->len >= MAX_DNS_NAME) {
-		LOG(L_ERR, "sip_resolvehost: domain name too long\n");
+		LOG(L_ERR, "srv_sip_resolvehost: domain name too long\n");
 		he=0;
 		goto end;
 	}
@@ -1246,46 +1270,26 @@ struct hostent* srv_sip_resolvehost(str* name, int zt, unsigned short* port,
 														  don't find another */
 		/* check if it's an ip address */
 		if (((ip=str2ip(name))!=0)
-#ifdef	USE_IPV6
 			  || ((ip=str2ip6(name))!=0) 
-#endif
 			 ){
 			/* we are lucky, this is an ip address */
 			he=ip_addr2he(name, ip);
 			goto end;
 		}
 		if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){
-			LOG(L_WARN, "WARNING: sip_resolvehost: domain name too long (%d),"
+			LOG(L_WARN, "WARNING: srv_sip_resolvehost: domain name too long (%d),"
 						" unable to perform SRV lookup\n", name->len);
 		}else{
 			
 			switch(srv_proto){
-				case PROTO_NONE: /* no proto specified, use udp */
-					if (proto)
-						*proto=PROTO_UDP;
-					/* no break */
 				case PROTO_UDP:
-					memcpy(tmp, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
-					memcpy(tmp+SRV_UDP_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_UDP_PREFIX_LEN + name->len] = '\0';
-					break;
 				case PROTO_TCP:
-					memcpy(tmp, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
-					memcpy(tmp+SRV_TCP_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_TCP_PREFIX_LEN + name->len] = '\0';
-					break;
 				case PROTO_TLS:
-					memcpy(tmp, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
-					memcpy(tmp+SRV_TLS_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_TLS_PREFIX_LEN + name->len] = '\0';
-					break;
 				case PROTO_SCTP:
-					memcpy(tmp, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN);
-					memcpy(tmp+SRV_SCTP_PREFIX_LEN, name->s, name->len);
-					tmp[SRV_SCTP_PREFIX_LEN + name->len] = '\0';
+					create_srv_name(srv_proto, name, tmp);
 					break;
 				default:
-					LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n",
+					LOG(L_CRIT, "BUG: srv_sip_resolvehost: unknown proto %d\n",
 							srv_proto);
 					he=0;
 					goto end;
@@ -1297,7 +1301,7 @@ do_srv:
 				if (l->type!=T_SRV) continue; 
 				srv=(struct srv_rdata*) l->rdata;
 				if (srv==0){
-					LOG(L_CRIT, "sip_resolvehost: BUG: null rdata\n");
+					LOG(L_CRIT, "srv_sip_resolvehost: BUG: null rdata\n");
 					/* cleanup on exit only */
 					break;
 				}
@@ -1305,7 +1309,7 @@ do_srv:
 				if (he!=0){
 					/* we found it*/
 #ifdef RESOLVE_DBG
-					DBG("sip_resolvehost: found SRV(%s) = %s:%d in AR\n",
+					DBG("srv_sip_resolvehost: found SRV(%s) = %s:%d in AR\n",
 							srv_target, srv->name, srv->port);
 #endif
 					*port=srv->port;
@@ -1318,7 +1322,7 @@ do_srv:
 				if (l->type!=T_SRV) continue; /*should never happen*/
 				srv=(struct srv_rdata*) l->rdata;
 				if (srv==0){
-					LOG(L_CRIT, "sip_resolvehost: BUG: null rdata\n");
+					LOG(L_CRIT, "srv_sip_resolvehost: BUG: null rdata\n");
 					/* cleanup on exit only */
 					break;
 				}
@@ -1326,7 +1330,7 @@ do_srv:
 				if (he!=0){
 					/* we found it*/
 #ifdef RESOLVE_DBG
-					DBG("sip_resolvehost: SRV(%s) = %s:%d\n",
+					DBG("srv_sip_resolvehost: SRV(%s) = %s:%d\n",
 							srv_target, srv->name, srv->port);
 #endif
 					*port=srv->port;
@@ -1342,12 +1346,11 @@ do_srv:
 			}
 			/* cleanup on exit */
 #ifdef RESOLVE_DBG
-			DBG("sip_resolvehost: no SRV record found for %.*s," 
+			DBG("srv_sip_resolvehost: no SRV record found for %.*s," 
 					" trying 'normal' lookup...\n", name->len, name->s);
 #endif
 		}
 	}
-/*skip_srv:*/
 	if (likely(!zt)){
 		memcpy(tmp, name->s, name->len);
 		tmp[name->len] = '\0';
@@ -1448,6 +1451,89 @@ end:
 	return 0;
 }
 
+/* Prepend srv prefix according to the proto. */
+void create_srv_name(char proto, str *name, char *srv) {
+	switch (proto) {
+		case PROTO_UDP:
+			memcpy(srv, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
+			memcpy(srv+SRV_UDP_PREFIX_LEN, name->s, name->len);
+			srv[SRV_UDP_PREFIX_LEN + name->len] = '\0';
+			break;
+		case PROTO_TCP:
+			memcpy(srv, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
+			memcpy(srv+SRV_TCP_PREFIX_LEN, name->s, name->len);
+			srv[SRV_TCP_PREFIX_LEN + name->len] = '\0';
+			break;
+		case PROTO_TLS:
+			memcpy(srv, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
+			memcpy(srv+SRV_TLS_PREFIX_LEN, name->s, name->len);
+			srv[SRV_TLS_PREFIX_LEN + name->len] = '\0';
+			break;
+		case PROTO_SCTP:
+			memcpy(srv, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN);
+			memcpy(srv+SRV_SCTP_PREFIX_LEN, name->s, name->len);
+			srv[SRV_SCTP_PREFIX_LEN + name->len] = '\0';
+			break;
+		default:
+			LOG(L_CRIT, "BUG: %s: unknown proto %d\n", __func__, proto);
+	}
+}
+
+size_t create_srv_pref_list(char *proto, struct dns_srv_proto *list) {
+	struct dns_srv_proto tmp;
+	size_t i,j,list_len;
+	int default_order,max;
+
+	/* if proto available, then add only the forced protocol to the list */
+	if (proto && *proto!=PROTO_NONE){
+		list[0].proto=*proto;
+		list_len=1;
+	} else {
+		list_len = 0;
+		/*get protocols and preference scores, and add availble protocol(s) and score(s) to the list*/
+		for (i=PROTO_UDP; i<PROTO_LAST;i++) {
+			tmp.proto_pref = srv_proto_pref_score(i);
+			/* if -1 so disabled continue with next protocol*/
+			if (naptr_proto_supported(i) == 0) {
+				continue;
+			} else {
+				list[i-1].proto_pref=tmp.proto_pref;
+				list[i-1].proto=i;
+				list_len++;
+			}
+		};
+
+		/* if all protocol prefence scores equal, then set the perference to default values: udp,tcp,tls,sctp */
+		for (i=1; i<list_len;i++) {
+			if(list[0].proto_pref!=list[i].proto_pref){
+				default_order=0;
+			}
+		}
+		if (default_order){
+			for (i=0; i<list_len;i++) {
+				list[i].proto_pref=srv_proto_pref_score(i);
+			}
+		}
+
+		/* sorting the list */
+		for (i=0;i<list_len-1;i++) {
+			max=i;
+			for (j=i+1;j<list_len;j++) {
+				if (list[j].proto_pref>list[max].proto_pref) { 
+					max=j; 
+				}
+			}
+			if (i!=max) {
+				tmp=list[i];
+				list[i]=list[max];
+				list[max]=tmp;
+			}
+		}
+
+	}
+	return list_len;
+}
+
 /* Resolves SRV if no naptr found. 
  * It reuse dns_pref values and according that resolves supported protocols. 
  * If dns_pref are equal then it use udp,tcp,tls,sctp order.
@@ -1457,25 +1543,18 @@ end:
 
 struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port, char* proto)
 {
-	struct dns_srv_proto_t {
-		char proto;
-		int proto_pref;
-	} srv_proto_list[PROTO_LAST], tmp_srv_element;
+	struct dns_srv_proto srv_proto_list[PROTO_LAST];
 	struct hostent* he;
 	struct ip_addr* ip;
 	str srv_name;
 	static char tmp_srv[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */
-	int len;
-	unsigned char i,j,max,default_order=0,list_len=0;
+	size_t i,list_len;
 	/* init variables */
 	he=0;
-	len=0;
 
 	/* check if it's an ip address */
 	if (((ip=str2ip(name))!=0)
-#ifdef	USE_IPV6
 			  || ((ip=str2ip6(name))!=0)
-#endif
 			 ){
 		/* we are lucky, this is an ip address */
 		/* set proto if needed - default udp */
@@ -1492,86 +1571,18 @@ struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port, ch
 		LOG(L_WARN, "WARNING: no_naptr_srv_sip_resolvehost: domain name too long"
 						" (%d), unable to perform SRV lookup\n", name->len);
 	} else {
-		/* if proto available, then add only the forced protocol to the list */
-		if (proto && *proto!=PROTO_NONE){
-			srv_proto_list[0].proto=*proto;
-			list_len=1;
-		} else {
-	
-			/*get protocols and preference scores, and add availble protocol(s) and score(s) to the list*/
-			for (i=PROTO_UDP; i<PROTO_LAST;i++) {
-				tmp_srv_element.proto_pref = proto_pref_score(i);
-				/* if -1 so disabled continue with next protocol*/
-				if (naptr_proto_supported(i) == 0 ) {
-					continue;
-				} else {
-					srv_proto_list[i-1].proto_pref=tmp_srv_element.proto_pref;
-					srv_proto_list[i-1].proto=i;
-					list_len++;
-				}
-			};
-
-			/* if all protocol prefence scores equal, then set the perference to default values: udp,tcp,tls,sctp */
-			for (i=1; i<list_len;i++) {
-				if(srv_proto_list[0].proto_pref!=srv_proto_list[i].proto_pref){
-					default_order=0;
-				}
-			}
-			if (default_order){
-				for (i=0; i<list_len;i++) {
-					srv_proto_list[i].proto_pref=proto_pref_score(i);;
-				}
-			}
-
-			/* sorting the list */
-			for (i=0;i<list_len-1;i++) {
-				max=i;
-				for (j=i+1;j<list_len;j++) {
-					if (srv_proto_list[j].proto_pref>srv_proto_list[max].proto_pref) { 
-						max=j; 
-					}
-				}
-				if (i!=max) {
-					tmp_srv_element=srv_proto_list[i];
-					srv_proto_list[i]=srv_proto_list[max];
-					srv_proto_list[max]=tmp_srv_element;
-				}
-			}
-
-		}
 		/* looping on the ordered list until we found a protocol what has srv record */
+		list_len = create_srv_pref_list(proto, srv_proto_list);
 		for (i=0; i<list_len;i++) {	
 			switch (srv_proto_list[i].proto) {
-				case PROTO_NONE: /* no proto specified, use udp */
-					if (proto)
-						*proto=PROTO_UDP;
-					/* no break */
 				case PROTO_UDP:
-					memcpy(tmp_srv, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
-					memcpy(tmp_srv+SRV_UDP_PREFIX_LEN, name->s, name->len);
-					tmp_srv[SRV_UDP_PREFIX_LEN + name->len] = '\0';
-					len=SRV_UDP_PREFIX_LEN + name->len;
-					break;
 				case PROTO_TCP:
-					memcpy(tmp_srv, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
-					memcpy(tmp_srv+SRV_TCP_PREFIX_LEN, name->s, name->len);
-					tmp_srv[SRV_TCP_PREFIX_LEN + name->len] = '\0';
-					len=SRV_TCP_PREFIX_LEN + name->len;
-					break;
 				case PROTO_TLS:
-					memcpy(tmp_srv, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
-					memcpy(tmp_srv+SRV_TLS_PREFIX_LEN, name->s, name->len);
-					tmp_srv[SRV_TLS_PREFIX_LEN + name->len] = '\0';
-					len=SRV_TLS_PREFIX_LEN + name->len;
-					break;
 				case PROTO_SCTP:
-					memcpy(tmp_srv, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN);
-					memcpy(tmp_srv+SRV_SCTP_PREFIX_LEN, name->s, name->len);
-					tmp_srv[SRV_SCTP_PREFIX_LEN + name->len] = '\0';
-					len=SRV_SCTP_PREFIX_LEN + name->len;
+					create_srv_name(srv_proto_list[i].proto, name, tmp_srv);
 					break;
 				default:
-					LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n",
+					LOG(L_CRIT, "BUG: no_naptr_srv_sip_resolvehost: unknown proto %d\n",
 							(int)srv_proto_list[i].proto);
 					return 0;
 			}
@@ -1583,13 +1594,14 @@ struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port, ch
 				*proto = PROTO_UDP;
 			}
 			srv_name.s=tmp_srv;
-			srv_name.len=len;
+			srv_name.len=strlen(tmp_srv);
 			#ifdef USE_DNS_CACHE
 			he=dns_srv_get_he(&srv_name, port, dns_flags);
 			#else
 			he=srv_sip_resolvehost(&srv_name, 0, port, proto, 1, 0);
 			#endif
 			if (he!=0) {
+				*proto = srv_proto_list[i].proto;
 				return he;
 			}
 		}
@@ -1636,9 +1648,7 @@ struct hostent* naptr_sip_resolvehost(str* name,  unsigned short* port,
 	if (port && proto && (*proto==0) && (*port==0)){
 		*proto=PROTO_UDP; /* just in case we don't find another */
 		if ( ((ip=str2ip(name))!=0)
-#ifdef	USE_IPV6
 			  || ((ip=str2ip6(name))!=0)
-#endif
 		){
 			/* we are lucky, this is an ip address */
 			he=ip_addr2he(name,ip);
diff --git a/resolve.h b/resolve.h
index 3ff5e23..2d67da7 100644
--- a/resolve.h
+++ b/resolve.h
@@ -48,6 +48,7 @@
 #include <arpa/nameser.h>
 #include <resolv.h>
 #include "counters.h"
+#include "dns_func.h"
 
 #ifdef __OS_darwin
 #include <arpa/nameser_compat.h>
@@ -58,9 +59,6 @@
 #include "dns_wrappers.h"
 #endif
 
-#ifdef USE_DNSSEC
-#include <validator/validator.h>
-#endif
 
 /* define RESOLVE_DBG for debugging info (very noisy) */
 #define RESOLVE_DBG
@@ -90,6 +88,7 @@ struct dns_counters_h {
 };
 
 extern struct dns_counters_h dns_cnts_h;
+extern struct dns_func_t dns_func;
 
 /* query union*/
 union dns_query{
@@ -277,7 +276,6 @@ error_dots:
 }
 
 
-#ifdef USE_IPV6
 /* returns an ip_addr struct.; on error returns 0
  * the ip_addr struct is static, so subsequent calls will destroy its content*/
 static inline struct ip_addr* str2ip6(str* st)
@@ -380,7 +378,6 @@ error_char:
 			st->s);*/
 	return 0;
 }
-#endif /* USE_IPV6 */
 
 
 
@@ -393,20 +390,13 @@ static inline struct hostent* _resolvehost(char* name)
 {
 	static struct hostent* he=0;
 #ifdef HAVE_GETIPNODEBYNAME 
-#ifdef USE_IPV6
 	int err;
 	static struct hostent* he2=0;
 #endif
-#endif
 #ifndef DNS_IP_HACK
-#ifdef USE_IPV6
 	int len;
 #endif
-#endif
 #ifdef DNS_IP_HACK
-#ifdef USE_DNSSEC
-	val_status_t val_status;
-#endif
 	struct ip_addr* ip;
 	str s;
 
@@ -415,16 +405,13 @@ static inline struct hostent* _resolvehost(char* name)
 
 	/* check if it's an ip address */
 	if ( ((ip=str2ip(&s))!=0)
-#ifdef	USE_IPV6
 		  || ((ip=str2ip6(&s))!=0)
-#endif
 		){
 		/* we are lucky, this is an ip address */
 		return ip_addr2he(&s, ip);
 	}
 	
 #else /* DNS_IP_HACK */
-#ifdef USE_IPV6
 	len=0;
 	if (*name=='['){
 		len=strlen(name);
@@ -435,32 +422,16 @@ static inline struct hostent* _resolvehost(char* name)
 		}
 	}
 #endif
-#endif
 	/* ipv4 */
-#ifndef USE_DNSSEC
-	he=gethostbyname(name);
-#else
-	he=val_gethostbyname( (val_context_t *) 0, name, &val_status);
-	if(!val_istrusted(val_status)){
-		LOG(L_INFO, "INFO: got not trusted record when resolving %s\n",name);
-	}
-#endif
+	he=dns_func.sr_gethostbyname(name);
 
-#ifdef USE_IPV6
 	if(he==0 && cfg_get(core, core_cfg, dns_try_ipv6)){
 #ifndef DNS_IP_HACK
 skip_ipv4:
 #endif
 		/*try ipv6*/
 	#ifdef HAVE_GETHOSTBYNAME2
-		#ifndef USE_DNSSEC
-		he=gethostbyname2(name, AF_INET6);
-		#else
-		he=val_gethostbyname2((val_context_t*)0, name, AF_INET6, &val_status);
-		if(!val_istrusted(val_status)){
-			LOG(L_INFO, "INFO: got not trusted record when resolving %s\n",name);
-		}
-		#endif //!USE_DNSSEC
+		he=dns_func.sr_gethostbyname2(name, AF_INET6);
 	#elif defined HAVE_GETIPNODEBYNAME
 		/* on solaris 8 getipnodebyname has a memory leak,
 		 * after some time calls to it will fail with err=3
@@ -474,7 +445,6 @@ skip_ipv4:
 		if (len) name[len-2]=']'; /* restore */
 #endif
 	}
-#endif
 	return he;
 }
 
@@ -485,7 +455,14 @@ int resolv_init(void);
 void resolv_reinit(str *gname, str *name);
 int dns_reinit_fixup(void *handle, str *gname, str *name, void **val);
 int dns_try_ipv6_fixup(void *handle, str *gname, str *name, void **val);
-void reinit_naptr_proto_prefs(str *gname, str *name);
+void reinit_proto_prefs(str *gname, str *name);
+
+struct dns_srv_proto {
+	char proto;
+	int proto_pref;
+};
+void create_srv_name(char proto, str *name, char *srv);
+size_t create_srv_pref_list(char *proto, struct dns_srv_proto *list);
 
 #ifdef DNS_WATCHDOG_SUPPORT
 /* callback function that is called by the child processes
diff --git a/route.h b/route.h
index 8f25fe3..8cdcd2a 100644
--- a/route.h
+++ b/route.h
@@ -53,6 +53,7 @@
 #define ERROR_ROUTE   (1 << 5)
 #define LOCAL_ROUTE   (1 << 6)
 #define CORE_ONREPLY_ROUTE (1 << 7)
+#define BRANCH_FAILURE_ROUTE (1 << 8)
 #define ONREPLY_ROUTE (TM_ONREPLY_ROUTE|CORE_ONREPLY_ROUTE)
 #define EVENT_ROUTE   REQUEST_ROUTE
 #define ANY_ROUTE     (0xFFFFFFFF)
diff --git a/rvalue.c b/rvalue.c
index cb0db9c..ddc97c2 100644
--- a/rvalue.c
+++ b/rvalue.c
@@ -527,6 +527,7 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 			return RV_INT;
 		case RVE_PLUS_OP:
@@ -572,6 +573,7 @@ int rve_is_constant(struct rval_expr* rve)
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 		case RVE_STR_OP:
 			return rve_is_constant(rve->left.rve);
@@ -636,6 +638,7 @@ static int rve_op_unary(enum rval_expr_op op)
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 		case RVE_STR_OP:
 			return 1;
@@ -839,6 +842,7 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 			*type=RV_INT;
 			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
 				if (type1==RV_INT){
@@ -2112,6 +2116,10 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 		case RVE_DEFINED_OP:
 			ret=int_rve_defined(h, msg, res, rve->left.rve);
 			break;
+		case RVE_NOTDEFINED_OP:
+			ret=int_rve_defined(h, msg, res, rve->left.rve);
+			*res = !(*res);
+			break;
 		case RVE_STREQ_OP:
 		case RVE_STRDIFF_OP:
 		case RVE_MATCH_OP:
@@ -2233,6 +2241,7 @@ int rval_expr_eval_rvint(			   struct run_act_ctx* h,
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 			/* operator forces integer type */
 			ret=rval_expr_eval_int(h, msg, res_i, rve);
@@ -2360,6 +2369,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 			/* operator forces integer type */
 			r=rval_expr_eval_int(h, msg, &i, rve);
@@ -2601,6 +2611,7 @@ struct rval_expr* mk_rval_expr1(enum rval_expr_op op, struct rval_expr* rve1,
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 		case RVE_STR_OP:
 			break;
@@ -2692,6 +2703,7 @@ static int rve_op_is_assoc(enum rval_expr_op op)
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 		case RVE_STR_OP:
 			/* one operand expression => cannot be assoc. */
@@ -2747,6 +2759,7 @@ static int rve_op_is_commutative(enum rval_expr_op op)
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 		case RVE_STR_OP:
 			/* one operand expression => cannot be commut. */
@@ -3796,6 +3809,7 @@ int fix_rval_expr(void* p)
 		case RVE_STRLEN_OP:
 		case RVE_STREMPTY_OP:
 		case RVE_DEFINED_OP:
+		case RVE_NOTDEFINED_OP:
 		case RVE_INT_OP:
 		case RVE_STR_OP:
 			ret=fix_rval_expr((void*)rve->left.rve);
diff --git a/rvalue.h b/rvalue.h
index 14675af..c0c2e0e 100644
--- a/rvalue.h
+++ b/rvalue.h
@@ -87,6 +87,7 @@ enum rval_expr_op{
 	RVE_MATCH_OP,  /**< 2 members, string ~),  returns left matches re(right) */
 	/* avp, pvars a.s.o */
 	RVE_DEFINED_OP, /**< one member, returns is_defined(val) (bool) */
+	RVE_NOTDEFINED_OP, /**< one member, returns is_not_defined(val) (bool) */
 	RVE_INT_OP,   /**< one member, returns (int)val  (int) */
 	RVE_STR_OP    /**< one member, returns (str)val  (str) */
 };
diff --git a/script_cb.c b/script_cb.c
index a10df7d..fe17819 100644
--- a/script_cb.c
+++ b/script_cb.c
@@ -53,7 +53,7 @@
 #include "mem/mem.h"
 
 /* Number of cb types = last cb type */
-#define SCRIPT_CB_NUM	EVENT_CB_TYPE
+#define SCRIPT_CB_NUM	(MAX_CB_TYPE-1)
 
 static struct script_cb *pre_script_cb[SCRIPT_CB_NUM];
 static struct script_cb *post_script_cb[SCRIPT_CB_NUM];
diff --git a/script_cb.h b/script_cb.h
index af557c7..fbfbbfc 100644
--- a/script_cb.h
+++ b/script_cb.h
@@ -49,14 +49,14 @@ typedef int (cb_function)(struct sip_msg *msg, unsigned int flags, void *param);
  */
 enum script_cb_flag { REQUEST_CB=1, FAILURE_CB=2, ONREPLY_CB=4,
 			BRANCH_CB=8, ONSEND_CB=16, ERROR_CB=32,
-			LOCAL_CB=64, EVENT_CB=128 };
+			LOCAL_CB=64, EVENT_CB=128, BRANCH_FAILURE_CB=256 };
 
 /* Callback types used for executing the callbacks.
  * Keep in sync with script_cb_flag!!!
  */
 enum script_cb_type { REQUEST_CB_TYPE=1, FAILURE_CB_TYPE, ONREPLY_CB_TYPE,
 			BRANCH_CB_TYPE, ONSEND_CB_TYPE, ERROR_CB_TYPE,
-			LOCAL_CB_TYPE, EVENT_CB_TYPE };
+			LOCAL_CB_TYPE, EVENT_CB_TYPE, BRANCH_FAILURE_CB_TYPE, MAX_CB_TYPE };
 
 struct script_cb{
 	cb_function *cbf;
diff --git a/sctp_core.c b/sctp_core.c
new file mode 100644
index 0000000..a27f603
--- /dev/null
+++ b/sctp_core.c
@@ -0,0 +1,109 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "sctp_core.h"
+
+/**
+ *
+ */
+static sctp_srapi_t _sctp_srapi = { 0 };
+static int _sctp_srapi_set = 0;
+
+/**
+ *
+ */
+int sctp_core_init(void)
+{
+	if(_sctp_srapi_set==0) {
+		LM_ERR("SCTP API not initialized\n");
+		return -1;
+	}
+
+	return _sctp_srapi.init();
+}
+
+/**
+ *
+ */
+void sctp_core_destroy(void)
+{
+	if(_sctp_srapi_set==0) {
+		LM_INFO("SCTP API not initialized\n");
+		return;
+	}
+
+	_sctp_srapi.destroy();
+}
+
+/**
+ *
+ */
+int sctp_core_init_sock(struct socket_info* sock_info)
+{
+	return _sctp_srapi.init_sock(sock_info);
+}
+
+/**
+ *
+ */
+int sctp_core_check_support(void)
+{
+	if(_sctp_srapi_set==0) {
+		LM_INFO("SCTP API not enabled"
+				" - if you want to use it, load sctp module\n");
+		return -1;
+	}
+
+	return _sctp_srapi.check_support();
+}
+
+/**
+ *
+ */
+int sctp_core_rcv_loop(void)
+{
+	return _sctp_srapi.rcv_loop();
+}
+
+/**
+ *
+ */
+int sctp_core_msg_send(struct dest_info* dst, char* buf, unsigned len)
+{
+	return _sctp_srapi.msg_send(dst, buf, len);
+}
+
+/**
+ *
+ */
+int sctp_core_register_api(sctp_srapi_t *api)
+{
+	if(api==NULL || api->init==NULL) {
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+	if(_sctp_srapi_set==1) {
+		LM_ERR("SCTP API already initialized\n");
+		return -1;
+	}
+	_sctp_srapi_set = 1;
+	memcpy(&_sctp_srapi, api, sizeof(sctp_srapi_t));
+	return 0;
+}
diff --git a/sctp_core.h b/sctp_core.h
new file mode 100644
index 0000000..88e0470
--- /dev/null
+++ b/sctp_core.h
@@ -0,0 +1,62 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __sctp_core_h__
+#define __sctp_core_h__
+
+#include "ip_addr.h"
+
+int sctp_core_init(void);
+typedef int (*sctp_srapi_init_f)(void);
+
+void sctp_core_destroy(void);
+typedef void (*sctp_srapi_destroy_f)(void);
+
+int sctp_core_init_sock(struct socket_info* sock_info);
+typedef int (*sctp_srapi_init_sock_f)(struct socket_info* sock_info);
+
+void sctp_core_init_options(void);
+typedef void (*sctp_srapi_init_options_f)(void);
+
+int sctp_core_check_compiled_sockopts(char* buf, int size);
+typedef int (*sctp_srapi_check_compiled_sockopts_f)(char* buf, int size);
+
+int sctp_core_check_support(void);
+typedef int (*sctp_srapi_check_support_f)(void);
+
+int sctp_core_rcv_loop(void);
+typedef int (*sctp_srapi_rcv_loop_f)(void);
+
+int sctp_core_msg_send(struct dest_info* dst, char* buf, unsigned len);
+typedef int (*sctp_srapi_msg_send_f)(struct dest_info* dst, char* buf,
+		unsigned len);
+
+typedef struct sctp_srapi {
+	sctp_srapi_init_f init;
+	sctp_srapi_destroy_f destroy;
+	sctp_srapi_init_sock_f init_sock;
+	sctp_srapi_check_support_f check_support;
+	sctp_srapi_rcv_loop_f rcv_loop;
+	sctp_srapi_msg_send_f msg_send;
+} sctp_srapi_t;
+
+int sctp_core_register_api(sctp_srapi_t *api);
+
+#endif
diff --git a/sctp_ev.h b/sctp_ev.h
deleted file mode 100644
index f801023..0000000
--- a/sctp_ev.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* 
- * $Id$
- * 
- * Copyright (C) 2009 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * sctp_ev.h - sctp events
- */
-/*
- * History:
- * --------
- *  2009-04-28  initial version (andrei)
-*/
-
-#ifndef __sctp_ev_h
-#define __sctp_ev_h
-
-#include <errno.h>
-#include <string.h>
-
-#ifndef USE_SCTP_EV
-
-#define SCTP_EV_ASSOC_CHANGE(lip, lport, src, reason, state)
-#define SCTP_EV_PEER_ADDR_CHANGE(lip, lport, src, reason, state, addr_su)
-#define SCTP_EV_REMOTE_ERROR(lip, lport, src, err)
-#define SCTP_EV_SEND_FAILED(lip, lport, src, err)
-#define SCTP_EV_SHUTDOWN_EVENT(lip, lport, src)
-#define SCTP_EV_SENDER_DRY_EVENT(lip, lport, src)
-
-#else /* USE_SCTP_EV */
-
-#include "ip_addr.h"
-
-
-/** an association has either been opened or closed.
- * called for each SCTP_ASSOC_CHANGE event.
- *
- * @param err - if 0 it should be ignored (no corresp. libc error), if non-0
- *                it will contain the errno.
- * @param lip   - pointer to an ip_addr containing the local ip
- *                   or 0 if dynamic (WARNING can be 0).
- * @param lport - pointer to an ip_addr containing the local port or 0
- *                   if unknown/dynamic.
- * @param src   - pointer to a sockaddr_union containing the src.
- * @param proto - protocol used
- */
-#define SCTP_EV_ASSOC_CHANGE(lip, lport, src, reason, state) \
-	DBG("SCTP_ASSOC_CHANGE from %s on %s:%d: %s\n", \
-			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, reason)
-
-/** an address part of an assoc. changed state.
- * called for the SCTP_PEER_ADDR_CHANGE event.*/
-#define SCTP_EV_PEER_ADDR_CHANGE(lip, lport, src, reason, state, addr_su) \
-	DBG("SCTP_PEER_ADDR_CHANGE from %s on %s:%d: %s\n", \
-			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, reason)
-
-/** remote operation error from the peer.
- * called for the SCTP_REMOTE_ERROR event.*/
-#define SCTP_EV_REMOTE_ERROR(lip, lport, src, err) \
-	DBG("SCTP_REMOTE_ERROR from %s on %s:%d: %d\n", \
-			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, err)
-
-/** send failed.
- * called for the SCTP_SEND_FAILED event.*/
-#define SCTP_EV_SEND_FAILED(lip, lport, src, err) \
-	DBG("SCTP_SEND_FAILED from %s on %s:%d: %d\n", \
-			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport, err)
-
-/** the peer has sent a shutdown.
- * called for the SCTP_SHUTDOWN_EVENT event.*/
-#define SCTP_EV_SHUTDOWN_EVENT(lip, lport, src) \
-	DBG("SCTP_SHUTDOWN_EVENT from %s on %s:%d\n", \
-			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport)
-
-/** kernel has finished sending all the queued data.
- * called for the SCTP_SENDER_DRY_EVENT event.*/
-#define SCTP_EV_SENDER_DRY_EVENT(lip, lport, src) \
-	DBG("SCTP_SENDER_DRY_EVENT from %s on %s:%d\n", \
-			su2a(src, sizeof(*(src))), ip_addr2a(lip), lport)
-
-#endif /* USE_SCTP_EV */
-
-#endif /*__sctp_ev_h*/
-
-/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/sctp_options.c b/sctp_options.c
deleted file mode 100644
index c027ff6..0000000
--- a/sctp_options.c
+++ /dev/null
@@ -1,746 +0,0 @@
-/* 
- * $Id$
- * 
- * Copyright (C) 2008 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/* 
- * sctp options
- */
-/*
- * History:
- * --------
- *  2008-08-07  initial version (andrei)
- *  2009-05-26  runtime cfg support (andrei)
- */
-
-/*!
- * \file
- * \brief SIP-router core :: 
- * \ingroup core
- * Module: \ref core
- */
-
-#include <string.h>
-#include <sys/types.h>
-#ifdef USE_SCTP
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/sctp.h>
-#endif /* USE_SCTP */
-#include <errno.h>
-
-#include "sctp_options.h"
-#include "dprint.h"
-#include "cfg/cfg.h"
-#include "socket_info.h"
-#include "sctp_server.h"
-
-struct cfg_group_sctp sctp_default_cfg;
-
-
-
-#ifdef USE_SCTP
-
-#include "sctp_sockopts.h"
-
-static int fix_autoclose(void* cfg_h, str* gname, str* name, void** val);
-static void set_autoclose(str* gname, str* name);
-static int fix_assoc_tracking(void* cfg_h, str* gname, str* name, void** val);
-static int fix_assoc_reuse(void* cfg_h, str* gname, str* name, void** val);
-static int fix_srto_initial(void* cfg_h, str* gname, str* name, void** val);
-static void set_srto_initial(str* gname, str* name);
-static int fix_srto_max(void* cfg_h, str* gname, str* name, void** val);
-static void set_srto_max(str* gname, str* name);
-static int fix_srto_min(void* cfg_h, str* gname, str* name, void** val);
-static void set_srto_min(str* gname, str* name);
-static int fix_asocmaxrxt(void* cfg_h, str* gname, str* name, void** val);
-static void set_asocmaxrxt(str* gname, str* name);
-static int fix_sinit_max_init_timeo(void* cfg_h, str* gname, str* name,
-										void** val);
-static void set_sinit_max_init_timeo(str* gname, str* name);
-static int fix_sinit_max_attempts(void* cfg_h, str* gname, str* name,
-										void** val);
-static void set_sinit_max_attempts(str* gname, str* name);
-static int fix_hbinterval(void* cfg_h, str* gname, str* name, void** val);
-static void set_hbinterval(str* gname, str* name);
-static int fix_pathmaxrxt(void* cfg_h, str* gname, str* name, void** val);
-static void set_pathmaxrxt(str* gname, str* name);
-static int fix_sack_delay(void* cfg_h, str* gname, str* name, void** val);
-static void set_sack_delay(str* gname, str* name);
-static int fix_sack_freq(void* cfg_h, str* gname, str* name, void** val);
-static void set_sack_freq(str* gname, str* name);
-static int fix_max_burst(void* cfg_h, str* gname, str* name, void** val);
-static void set_max_burst(str* gname, str* name);
-
-/** cfg_group_sctp description (for the config framework). */
-static cfg_def_t sctp_cfg_def[] = {
-	/*   name        , type |input type| chg type, min, max, fixup, proc. cbk.
-	      description */
-	{ "socket_rcvbuf", CFG_VAR_INT| CFG_READONLY, 512, 102400, 0, 0,
-		"socket receive buffer size (read-only)" },
-	{ "socket_sndbuf", CFG_VAR_INT| CFG_READONLY, 512, 102400, 0, 0,
-		"socket send buffer size (read-only)" },
-	{ "autoclose", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 1, 1<<30,
-		fix_autoclose, set_autoclose,
-		"seconds before closing and idle connection (must be non-zero)" },
-	{ "send_ttl", CFG_VAR_INT| CFG_ATOMIC, 0, 1<<30, 0, 0,
-		"milliseconds before aborting a send" },
-	{ "send_retries", CFG_VAR_INT| CFG_ATOMIC, 0, MAX_SCTP_SEND_RETRIES, 0, 0,
-		"re-send attempts on failure" },
-	{ "assoc_tracking", CFG_VAR_INT| CFG_ATOMIC, 0, 1, fix_assoc_tracking, 0,
-		"connection/association tracking (see also assoc_reuse)" },
-	{ "assoc_reuse", CFG_VAR_INT| CFG_ATOMIC, 0, 1, fix_assoc_reuse, 0,
-		"connection/association reuse (for now used only for replies)"
-		", depends on assoc_tracking being set"},
-	{ "max_assocs", CFG_VAR_INT| CFG_ATOMIC, 0, 0, 0, 0,
-		"maximum allowed open associations (-1 = disable, "
-			"as many as allowed by the OS)"},
-	{ "srto_initial", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
-		fix_srto_initial, set_srto_initial,
-		"initial value of the retr. timeout, used in RTO calculations,"
-			" in msecs" },
-	{ "srto_max", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
-		fix_srto_max, set_srto_max,
-		"maximum value of the retransmission timeout (RTO), in msecs" },
-	{ "srto_min", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
-		fix_srto_min, set_srto_min,
-		"minimum value of the retransmission timeout (RTO), in msecs" },
-	{ "asocmaxrxt", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
-		fix_asocmaxrxt, set_asocmaxrxt,
-		"maximum retransmission attempts per association" },
-	{ "init_max_attempts", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
-		fix_sinit_max_attempts, set_sinit_max_attempts,
-		"max INIT retransmission attempts" },
-	{ "init_max_timeo", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
-		fix_sinit_max_init_timeo, set_sinit_max_init_timeo,
-		"max INIT retransmission timeout (RTO max for INIT), in msecs" },
-	{ "hbinterval", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
-		fix_hbinterval, set_hbinterval, "heartbeat interval in msecs" },
-	{ "pathmaxrxt", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
-		fix_pathmaxrxt, set_pathmaxrxt,
-		"maximum retransmission attempts per path" },
-	{ "sack_delay", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<30,
-		fix_sack_delay, set_sack_delay,
-		"time since the last received packet before sending a SACK, in msecs"},
-	{ "sack_freq", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
-		fix_sack_freq, set_sack_freq,
-		"number of received packets that trigger the sending of a SACK"},
-	{ "max_burst", CFG_VAR_INT| CFG_CB_ONLY_ONCE, 0, 1<<10,
-		fix_max_burst, set_max_burst,
-		"maximum burst of packets that can be emitted by an association"},
-	{0, 0, 0, 0, 0, 0, 0}
-};
-
-
-
-void* sctp_cfg; /* sctp config handle */
-
-#endif /* USE_SCTP */
-
-void init_sctp_options()
-{
-#ifdef USE_SCTP
-	sctp_get_os_defaults(&sctp_default_cfg);
-#if 0
-	sctp_default_cfg.so_rcvbuf=0; /* do nothing, use the kernel default */
-	sctp_default_cfg.so_sndbuf=0; /* do nothing, use the kernel default */
-#endif
-	sctp_default_cfg.autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
-	sctp_default_cfg.send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
-	sctp_default_cfg.send_retries=DEFAULT_SCTP_SEND_RETRIES;
-	sctp_default_cfg.max_assocs=-1; /* as much as possible by default */
-#ifdef SCTP_CONN_REUSE
-	sctp_default_cfg.assoc_tracking=1; /* on by default */
-	sctp_default_cfg.assoc_reuse=1; /* on by default */
-#else
-	sctp_default_cfg.assoc_tracking=0;
-	sctp_default_cfg.assoc_reuse=0;
-#endif /* SCTP_CONN_REUSE */
-#endif
-}
-
-
-
-#define W_OPT_NSCTP(option) \
-	if (sctp_default_cfg.option){\
-		WARN("sctp_options: " #option \
-			" cannot be enabled (sctp support not compiled-in)\n"); \
-			sctp_default_cfg.option=0; \
-	}
-
-
-
-void sctp_options_check()
-{
-#ifndef USE_SCTP
-	W_OPT_NSCTP(autoclose);
-	W_OPT_NSCTP(send_ttl);
-	W_OPT_NSCTP(send_retries);
-	W_OPT_NSCTP(assoc_tracking);
-	W_OPT_NSCTP(assoc_reuse);
-	W_OPT_NSCTP(max_assocs);
-#else /* USE_SCTP */
-	if (sctp_default_cfg.send_retries>MAX_SCTP_SEND_RETRIES) {
-		WARN("sctp: sctp_send_retries too high (%d), setting it to %d\n",
-				sctp_default_cfg.send_retries, MAX_SCTP_SEND_RETRIES);
-		sctp_default_cfg.send_retries=MAX_SCTP_SEND_RETRIES;
-	}
-#ifndef CONN_REUSE
-	if (sctp_default_cfg.assoc_tracking || sctp_default_cfg.assoc_reuse){
-		WARN("sctp_options: assoc_tracking and assoc_reuse support cannnot"
-				" be enabled (CONN_REUSE support not compiled-in)\n");
-		sctp_default_cfg.assoc_tracking=0;
-		sctp_default_cfg.assoc_reuse=0;
-	}
-#else /* CONN_REUSE */
-	if (sctp_default_cfg.assoc_reuse && sctp_default_cfg.assoc_tracking==0){
-		sctp_default_cfg.assoc_tracking=1;
-	}
-#endif /* CONN_REUSE */
-#endif /* USE_SCTP */
-}
-
-
-
-void sctp_options_get(struct cfg_group_sctp *s)
-{
-#ifdef USE_SCTP
-	*s=*(struct cfg_group_sctp*)sctp_cfg;
-#else
-	memset(s, 0, sizeof(*s));
-#endif /* USE_SCTP */
-}
-
-
-
-#ifdef USE_SCTP
-/** register sctp config into the configuration framework.
- * @return 0 on success, -1 on error */
-int sctp_register_cfg()
-{
-	if (cfg_declare("sctp", sctp_cfg_def, &sctp_default_cfg, cfg_sizeof(sctp),
-				&sctp_cfg))
-		return -1;
-	if (sctp_cfg==0){
-		BUG("null sctp cfg");
-		return -1;
-	}
-	return 0;
-}
-
-
-
-#define SCTP_SET_SOCKOPT_DECLS \
-	int err; \
-	struct socket_info* si
-
-
-#define SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) \
-	err=0; \
-	for (si=sctp_listen; si; si=si->next){ \
-		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
-							sizeof((val)), (err_prefix))<0); \
-	}
-
-#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
-	SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) ; \
-	return -(err!=0)
-
-
-static int fix_autoclose(void*cfg_h, str* gname, str* name, void** val)
-{
-#ifdef SCTP_AUTOCLOSE
-	return 0;
-#else
-	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_AUTOCLOSE */
-}
-
-
-static void set_autoclose(str* gname, str* name)
-{
-#ifdef SCTP_AUTOCLOSE
-	int optval;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	optval=cfg_get(sctp, sctp_cfg, autoclose);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_AUTOCLOSE, optval,
-								"cfg: setting SCTP_AUTOCLOSE");
-#else
-	ERR("no SCTP_AUTOCLOSE support, please upgrade your sctp library\n");
-#endif /* SCTP_AUTOCLOSE */
-}
-
-
-
-static int fix_assoc_tracking(void* cfg_h, str* gname, str* name, void** val)
-{
-	int optval;
-	
-	optval=(int)(long)(*val);
-#ifndef SCTP_CONN_REUSE
-	if (optval!=0){
-		ERR("no SCTP_CONN_REUSE support, please recompile with it enabled\n");
-		return -1;
-	}
-#else /* SCTP_CONN_REUSE */
-	if (optval==0){
-		/* turn tracking off */
-		/* check if assoc_reuse is off */
-		if (cfg_get(sctp, cfg_h, assoc_reuse)!=0){
-			ERR("cannot turn sctp assoc_tracking off while assoc_reuse is"
-					" still on, please turn assoc_reuse off first\n");
-			return -1;
-		}
-		sctp_con_tracking_flush();
-	}else if (optval==1 && cfg_get(sctp, cfg_h, assoc_reuse)==0){
-		/* turning from off to on, make sure we flush the tracked list
-		   again, just incase the off flush was racing with a new connection*/
-		sctp_con_tracking_flush();
-	}
-#endif /* SCTP_CONN_REUSE */
-	return 0;
-}
-
-
-
-static int fix_assoc_reuse(void* cfg_h, str* gname, str* name, void** val)
-{
-	int optval;
-	
-	optval=(int)(long)(*val);
-#ifndef SCTP_CONN_REUSE
-	if (optval!=0){
-		ERR("no SCTP_CONN_REUSE support, please recompile with it enabled\n");
-		return -1;
-	}
-#else /* SCTP_CONN_REUSE */
-	if (optval==1 && cfg_get(sctp, cfg_h, assoc_tracking)==0){
-		/* conn reuse on, but assoc_tracking off => not possible */
-		ERR("cannot turn sctp assoc_reuse on while assoc_tracking is"
-					" off, please turn assoc_tracking on first\n");
-		return -1;
-	}
-#endif /* SCTP_CONN_REUSE */
-	return 0;
-}
-
-
-
-static int fix_srto_initial(void* cfg_h, str* gname, str* name, void** val)
-{
-#ifdef SCTP_RTOINFO
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_initial);
-	}
-	return 0;
-#else
-	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_RTOINFO */
-}
-
-
-static void set_srto_initial(str* gname, str* name)
-{
-#ifdef SCTP_RTOINFO
-	struct sctp_rtoinfo rto;
-	int optval;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	optval=cfg_get(sctp, sctp_cfg, srto_initial);
-	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
-	rto.srto_assoc_id=0; /* all */
-	rto.srto_initial=optval;
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_RTOINFO, rto,
-								"cfg: setting SCTP_RTOINFO");
-#else
-	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
-#endif /* SCTP_RTOINFO */
-}
-
-
-
-static int fix_srto_max(void* cfg_h, str* gname, str* name, void** val)
-{
-#ifdef SCTP_RTOINFO
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_max);
-	}
-	return 0;
-#else
-	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_RTOINFO */
-}
-
-
-static void set_srto_max(str* gname, str* name)
-{
-#ifdef SCTP_RTOINFO
-	struct sctp_rtoinfo rto;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
-	rto.srto_assoc_id=0; /* all */
-	rto.srto_max=cfg_get(sctp, sctp_cfg, srto_max);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_RTOINFO, rto,
-								"cfg: setting SCTP_RTOINFO");
-#else
-	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
-#endif /* SCTP_RTOINFO */
-}
-
-
-
-static int fix_srto_min(void* cfg_h, str* gname, str* name, void** val)
-{
-#ifdef SCTP_RTOINFO
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, srto_min);
-	}
-	return 0;
-#else
-	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_RTOINFO */
-}
-
-
-static void set_srto_min(str* gname, str* name)
-{
-#ifdef SCTP_RTOINFO
-	struct sctp_rtoinfo rto;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&rto, 0, sizeof(rto)); /* zero everything we don't care about */
-	rto.srto_assoc_id=0; /* all */
-	rto.srto_min=cfg_get(sctp, sctp_cfg, srto_min);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_RTOINFO, rto,
-								"cfg: setting SCTP_RTOINFO");
-#else
-	ERR("no SCTP_RTOINFO support, please upgrade your sctp library\n");
-#endif /* SCTP_RTOINFO */
-}
-
-
-
-static int fix_asocmaxrxt(void* cfg_h, str* gname, str* name, void** val)
-{
-#ifdef SCTP_ASSOCINFO
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, asocmaxrxt);
-	}
-	return 0;
-#else
-	ERR("no SCTP_ASSOCINFO support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_ASSOCINFO */
-}
-
-
-static void set_asocmaxrxt(str* gname, str* name)
-{
-#ifdef SCTP_ASSOCINFO
-	struct sctp_assocparams ap;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&ap, 0, sizeof(ap)); /* zero everything we don't care about */
-	ap.sasoc_assoc_id=0; /* all */
-	ap.sasoc_asocmaxrxt= cfg_get(sctp, sctp_cfg, asocmaxrxt);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_ASSOCINFO, ap,
-								"cfg: setting SCTP_ASSOCINFO");
-#else
-	ERR("no SCTP_ASSOCINFO support, please upgrade your sctp library\n");
-#endif /* SCTP_ASSOCINFO */
-}
-
-
-
-static int fix_sinit_max_init_timeo(void* cfg_h, str* gname, str* name,
-									void** val)
-{
-#ifdef SCTP_INITMSG
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, init_max_timeo);
-	}
-	return 0;
-#else
-	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_INITMSG */
-}
-
-
-static void set_sinit_max_init_timeo(str* gname, str* name)
-{
-#ifdef SCTP_INITMSG
-	struct sctp_initmsg im;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&im, 0, sizeof(im)); /* zero everything we don't care about */
-	im.sinit_max_init_timeo=cfg_get(sctp, sctp_cfg, init_max_timeo);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_INITMSG, im,
-								"cfg: setting SCTP_INITMSG");
-#else
-	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
-#endif /* SCTP_INITMSG */
-}
-
-
-
-static int fix_sinit_max_attempts(void* cfg_h, str* gname, str* name,
-									void** val)
-{
-#ifdef SCTP_INITMSG
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, init_max_attempts);
-	}
-	return 0;
-#else
-	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_INITMSG */
-}
-
-
-static void set_sinit_max_attempts(str* gname, str* name)
-{
-#ifdef SCTP_INITMSG
-	struct sctp_initmsg im;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&im, 0, sizeof(im)); /* zero everything we don't care about */
-	im.sinit_max_attempts=cfg_get(sctp, sctp_cfg, init_max_attempts);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_INITMSG, im,
-								"cfg: setting SCTP_INITMSG");
-#else
-	ERR("no SCTP_INITMSG support, please upgrade your sctp library\n");
-#endif /* SCTP_INITMSG */
-}
-
-
-
-static int fix_hbinterval(void* cfg_h, str* gname, str* name,
-									void** val)
-{
-#ifdef SCTP_PEER_ADDR_PARAMS
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, hbinterval);
-	}
-	return 0;
-#else
-	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
-			" sctp library\n");
-	return -1;
-#endif /* SCTP_PEER_ADDR_PARAMS */
-}
-
-
-static void set_hbinterval(str* gname, str* name)
-{
-#ifdef SCTP_PEER_ADDR_PARAMS
-	struct sctp_paddrparams pp;
-	int optval;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	optval=cfg_get(sctp, sctp_cfg, hbinterval);
-	memset(&pp, 0, sizeof(pp)); /* zero everything we don't care about */
-	if (optval!=-1){
-		pp.spp_hbinterval=optval;
-		pp.spp_flags=SPP_HB_ENABLE;
-	}else{
-		pp.spp_flags=SPP_HB_DISABLE;
-	}
-	err=0;
-	for (si=sctp_listen; si; si=si->next){
-		/* set the AF, needed on older linux kernels even for INADDR_ANY */
-		pp.spp_address.ss_family=si->address.af;
-		err+=(sctp_setsockopt(si->socket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS,
-								(void*)(&pp), sizeof(pp),
-								"cfg: setting SCTP_PEER_ADDR_PARAMS")<0);
-	}
-#else
-	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
-			" sctp library\n");
-#endif /* SCTP_PEER_ADDR_PARAMS */
-}
-
-
-
-static int fix_pathmaxrxt(void* cfg_h, str* gname, str* name,
-									void** val)
-{
-#ifdef SCTP_PEER_ADDR_PARAMS
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, pathmaxrxt);
-	}
-	return 0;
-#else
-	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
-			" sctp library\n");
-	return -1;
-#endif /* SCTP_PEER_ADDR_PARAMS */
-}
-
-
-static void set_pathmaxrxt(str* gname, str* name)
-{
-#ifdef SCTP_PEER_ADDR_PARAMS
-	struct sctp_paddrparams pp;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&pp, 0, sizeof(pp)); /* zero everything we don't care about */
-	pp.spp_pathmaxrxt=cfg_get(sctp, sctp_cfg, pathmaxrxt);
-	err=0;
-	for (si=sctp_listen; si; si=si->next){
-		/* set the AF, needed on older linux kernels even for INADDR_ANY */
-		pp.spp_address.ss_family=si->address.af;
-		err+=(sctp_setsockopt(si->socket, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS,
-								(void*)(&pp), sizeof(pp),
-								"cfg: setting SCTP_PEER_ADDR_PARAMS")<0);
-	}
-#else
-	ERR("no SCTP_PEER_ADDR_PARAMS support, please upgrade your"
-			" sctp library\n");
-#endif /* SCTP_PEER_ADDR_PARAMS */
-}
-
-
-
-static int fix_sack_delay(void* cfg_h, str* gname, str* name, void** val)
-{
-#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
-	}
-	return 0;
-#else
-	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_DELAYED_SACK | SCTP_DELAYED_ACK_TIME */
-}
-
-
-static void set_sack_delay(str* gname, str* name)
-{
-#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-#ifdef SCTP_DELAYED_SACK
-	struct sctp_sack_info sack_info;
-#endif /* SCTP_DELAYED_SACK */
-#ifdef	SCTP_DELAYED_ACK_TIME
-	struct sctp_assoc_value sack_val; /* old version, sack delay only */
-#endif /* SCTP_DELAYED_ACK_TIME */
-	SCTP_SET_SOCKOPT_DECLS;
-	
-#ifdef SCTP_DELAYED_SACK
-	memset(&sack_info, 0, sizeof(sack_info)); /* zero everything we don't
-												 care about */
-	sack_info.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_SACK, sack_info, 0);
-	if (err==0){
-		return;
-	}else
-#endif /* SCTP_DELAYED_SACK */
-	{
-		/* setting SCTP_DELAYED_SACK failed or no lib support for 
-		   SCTP_DELAYED_SACK => try the old obsolete SCTP_DELAYED_ACK_TIME */
-#ifdef	SCTP_DELAYED_ACK_TIME
-		memset(&sack_val, 0, sizeof(sack_val)); /* zero everything we don't
-												   care about */
-		sack_val.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
-		SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
-									sack_val,
-									"cfg: setting SCTP_DELAYED_ACK_TIME");
-		if (err==0)
-			return;
-#else	/* SCTP_DELAYED_ACK_TIME */
-		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
-		   => error */
-		ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
-					strerror(errno), errno);
-#endif /* SCTP_DELAYED_ACK_TIME */
-	}
-#else
-	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
-#endif /* SCTP_DELAYED_SACK | SCTP_DELAYED_ACK_TIME */
-}
-
-
-
-static int fix_sack_freq(void* cfg_h, str* gname, str* name, void** val)
-{
-#ifdef SCTP_DELAYED_SACK
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_freq);
-	}
-	return 0;
-#else
-	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_DELAYED_SACK */
-}
-
-
-static void set_sack_freq(str* gname, str* name)
-{
-#ifdef SCTP_DELAYED_SACK
-	struct sctp_sack_info sa;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
-	sa.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_SACK, sa,
-								"cfg: setting SCTP_DELAYED_SACK");
-#else
-	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
-#endif /* SCTP_DELAYED_SACK */
-}
-
-
-
-static int fix_max_burst(void* cfg_h, str* gname, str* name, void** val)
-{
-#ifdef SCTP_MAX_BURST
-	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
-		*val=(void*)(long)cfg_get(sctp, cfg_h, max_burst);
-	}
-	return 0;
-#else
-	ERR("no SCTP_MAX_BURST support, please upgrade your sctp library\n");
-	return -1;
-#endif /* SCTP_MAX_BURST */
-}
-
-
-static void set_max_burst(str* gname, str* name)
-{
-#ifdef SCTP_MAX_BURST
-	struct sctp_assoc_value av;
-	SCTP_SET_SOCKOPT_DECLS;
-	
-	memset(&av, 0, sizeof(av)); /* zero everything we don't care about */
-	av.assoc_value=cfg_get(sctp, sctp_cfg, max_burst);
-	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_MAX_BURST, av,
-								"cfg: setting SCTP_MAX_BURST");
-#else
-	ERR("no SCTP_MAX_BURST support, please upgrade your sctp library\n");
-#endif /* SCTP_MAX_BURST */
-}
-
-#endif /* USE_SCTP */
diff --git a/sctp_server.c b/sctp_server.c
deleted file mode 100644
index 511842e..0000000
--- a/sctp_server.c
+++ /dev/null
@@ -1,2926 +0,0 @@
-/* 
- * $Id$
- * 
- * Copyright (C) 2008 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/* 
- * sctp one to many 
- */
-/*
- * History:
- * --------
- *  2008-08-07  initial version (andrei)
- *  2009-02-27  blacklist support (andrei)
- *  2009-04-28  sctp stats & events macros (andrei)
- */
-
-/*!
- * \file
- * \brief SIP-router core :: 
- * \ingroup core
- * Module: \ref core
- */
-
-#ifdef USE_SCTP
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/sctp.h>
-#include <errno.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-
-#include "sctp_sockopts.h"
-#include "sctp_server.h"
-#include "sctp_options.h"
-#include "globals.h"
-#include "config.h"
-#include "dprint.h"
-#include "receive.h"
-#include "mem/mem.h"
-#include "ip_addr.h"
-#include "cfg/cfg_struct.h"
-#ifdef USE_DST_BLACKLIST
-#include "dst_blacklist.h"
-#endif /* USE_DST_BLACKLIST */
-#include "timer_ticks.h"
-#include "clist.h"
-#include "error.h"
-#include "timer.h"
-#include "sctp_stats.h"
-#include "sctp_ev.h"
-
-
-
-static atomic_t* sctp_conn_no;
-
-
-#define ABORT_REASON_MAX_ASSOCS \
-	"Maximum configured number of open associations exceeded"
-
-/* check if the underlying OS supports sctp
-   returns 0 if yes, -1 on error */
-int sctp_check_support()
-{
-	int s;
-	char buf[256];
-	
-	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
-	if (s!=-1){
-		close(s);
-		if (sctp_check_compiled_sockopts(buf, sizeof(buf))!=0){
-			LOG(L_WARN, "WARNING: sctp: your ser version was compiled"
-						" without support for the following sctp options: %s"
-						", which might cause unforseen problems \n", buf);
-			LOG(L_WARN, "WARNING: sctp: please consider recompiling ser with"
-						" an upgraded sctp library version\n");
-		}
-		return 0;
-	}
-	return -1;
-}
-
-
-
-/* append a token to a buffer (uses space between tokens) */
-inline static void append_tok2buf(char* buf, int blen, char* tok)
-{
-	char* p;
-	char* end;
-	int len;
-	
-	if (buf && blen){
-		end=buf+blen;
-		p=memchr(buf, 0, blen);
-		if (p==0) goto error;
-		if (p!=buf && p<(end-1)){
-			*p=' ';
-			p++;
-		}
-		len=MIN_int(strlen(tok), end-1-p);
-		memcpy(p, tok, len);
-		p[len]=0;
-	}
-error:
-	return;
-}
-
-
-
-/* check if support fot all the needed sockopts  was compiled;
-   an ascii list of the unsuported options is returned in buf
-   returns 0 on success and  -number of unsuported options on failure
-   (<0 on failure)
-*/
-int sctp_check_compiled_sockopts(char* buf, int size)
-{
-	int err;
-
-	err=0;
-	if (buf && (size>0)) *buf=0; /* "" */
-#ifndef SCTP_FRAGMENT_INTERLEAVE
-	err++;
-	append_tok2buf(buf, size, "SCTP_FRAGMENT_INTERLEAVE");
-#endif
-#ifndef SCTP_PARTIAL_DELIVERY_POINT
-	err++;
-	append_tok2buf(buf, size, "SCTP_PARTIAL_DELIVERY_POINT");
-#endif
-#ifndef SCTP_NODELAY
-	err++;
-	append_tok2buf(buf, size, "SCTP_NODELAY");
-#endif
-#ifndef SCTP_DISABLE_FRAGMENTS
-	err++;
-	append_tok2buf(buf, size, "SCTP_DISABLE_FRAGMENTS");
-#endif
-#ifndef SCTP_AUTOCLOSE
-	err++;
-	append_tok2buf(buf, size, "SCTP_AUTOCLOSE");
-#endif
-#ifndef SCTP_EVENTS
-	err++;
-	append_tok2buf(buf, size, "SCTP_EVENTS");
-#endif
-	
-	return -err;
-}
-
-
-
-/* init all the sockaddr_union members of the socket_info struct
-   returns 0 on success and -1 on error */
-inline static int sctp_init_su(struct socket_info* sock_info)
-{
-	union sockaddr_union* addr;
-	struct addr_info* ai;
-	
-	addr=&sock_info->su;
-	if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
-		LOG(L_ERR, "ERROR: sctp_init_su: could not init sockaddr_union for"
-					"primary sctp address %.*s:%d\n",
-					sock_info->address_str.len, sock_info->address_str.s,
-					sock_info->port_no );
-		goto error;
-	}
-	for (ai=sock_info->addr_info_lst; ai; ai=ai->next)
-		if (init_su(&ai->su, &ai->address, sock_info->port_no)<0){
-			LOG(L_ERR, "ERROR: sctp_init_su: could not init"
-					"backup sctp sockaddr_union for %.*s:%d\n",
-					ai->address_str.len, ai->address_str.s,
-					sock_info->port_no );
-			goto error;
-		}
-	return 0;
-error:
-	return -1;
-}
-
-
-
-/** set a socket option (wrapper over setsockopt).
-  * @param err_prefix - if 0 no error message is printed on failure, if !=0
-  *                     it will be prepended to the error message.
-  * @return 0 on success, -1 on error */
-int sctp_setsockopt(int s, int level, int optname, 
-					void* optval, socklen_t optlen, char* err_prefix)
-{
-	if (setsockopt(s, level, optname, optval, optlen) ==-1){
-		if (err_prefix)
-			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
-		return -1;
-	}
-	return 0;
-}
-
-
-
-/** get a socket option (wrapper over getsockopt).
-  * @param err_prefix - if 0 no error message is printed on failure, if !=0
-  *                     it will be prepended to the error message.
-  * @return 0 on success, -1 on error */
-int sctp_getsockopt(int s, int level, int optname, 
-					void* optval, socklen_t* optlen, char* err_prefix)
-{
-	if (getsockopt(s, level, optname, optval, optlen) ==-1){
-		if (err_prefix)
-			ERR("%s: %s [%d]\n", err_prefix, strerror(errno), errno);
-		return -1;
-	}
-	return 0;
-}
-
-
-
-/** get the os defaults for cfg options with os correspondents.
- *  @param cfg - filled with the os defaults
- *  @return -1 on error, 0 on success
- */
-int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
-{
-	int s;
-	int ret;
-	
-	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
-	if (s==-1)
-		return -1;
-	ret=sctp_get_cfg_from_sock(s, cfg);
-	close(s);
-	return ret;
-}
-
-
-
-/** get the os cfg options from a specific socket.
- *  @param s - intialized sctp socket
- *  @param cfg - filled with the os defaults
- *  @return -1 on error, 0 on success
- */
-int sctp_get_cfg_from_sock(int s, struct cfg_group_sctp* cfg)
-{
-	int optval;
-	socklen_t optlen;
-#ifdef SCTP_RTOINFO
-	struct sctp_rtoinfo rto;
-#endif /* SCTP_RTOINFO */
-#ifdef SCTP_ASSOCINFO
-	struct sctp_assocparams ap;
-#endif /* SCTP_ASSOCINFO */
-#ifdef SCTP_INITMSG
-	struct sctp_initmsg im;
-#endif /* SCTP_INITMSG */
-#ifdef SCTP_PEER_ADDR_PARAMS
-	struct sctp_paddrparams pp;
-#endif /* SCTP_PEER_ADDR_PARAMS */
-#ifdef	SCTP_DELAYED_SACK
-	struct sctp_sack_info sack_info;
-#endif	/* SCTP_DELAYED_SACK */
-#ifdef	SCTP_DELAYED_ACK_TIME
-	struct sctp_assoc_value sack_val; /* old version */
-#endif /* SCTP_DELAYED_ACK_TIME */
-#ifdef SCTP_MAX_BURST
-	struct sctp_assoc_value av;
-#endif /* SCTP_MAX_BURST */
-	
-	/* SO_RCVBUF */
-	optlen=sizeof(int);
-	if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
-							&optlen, "SO_RCVBUF")==0){
-		/* success => hack to set the "default" values*/
-		#ifdef __OS_linux
-			optval/=2; /* in linux getsockopt() returns 2*set_value */
-		#endif
-		cfg->so_rcvbuf=optval;
-	}
-	/* SO_SNDBUF */
-	optlen=sizeof(int);
-	if (sctp_getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&optval,
-							&optlen, "SO_SNDBUF")==0){
-		/* success => hack to set the "default" values*/
-		#ifdef __OS_linux
-			optval/=2; /* in linux getsockopt() returns 2*set_value */
-		#endif
-		cfg->so_sndbuf=optval;
-	}
-	/* SCTP_AUTOCLOSE */
-#ifdef SCTP_AUTOCLOSE
-	optlen=sizeof(int);
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE, (void*)&optval,
-							&optlen, "SCTP_AUTOCLOSE")==0){
-		cfg->autoclose=optval;
-	}
-#endif /* SCTP_AUTOCLOSE */
-	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
-#ifdef SCTP_RTOINFO
-	optlen=sizeof(rto);
-	rto.srto_assoc_id=0;
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
-							&optlen, "SCTP_RTOINFO")==0){
-		/* success => hack to set the "default" values*/
-		cfg->srto_initial=rto.srto_initial;
-		cfg->srto_min=rto.srto_min;
-		cfg->srto_max=rto.srto_max;
-	}
-#endif /* SCTP_RTOINFO */
-#ifdef SCTP_ASSOCINFO
-	optlen=sizeof(ap);
-	ap.sasoc_assoc_id=0;
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_ASSOCINFO, (void*)&ap,
-							&optlen, "SCTP_ASSOCINFO")==0){
-		/* success => hack to set the "default" values*/
-		cfg->asocmaxrxt=ap.sasoc_asocmaxrxt;
-	}
-#endif /* SCTP_ASSOCINFO */
-#ifdef SCTP_INITMSG
-	optlen=sizeof(im);
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, (void*)&im,
-							&optlen, "SCTP_INITMSG")==0){
-		/* success => hack to set the "default" values*/
-		cfg->init_max_attempts=im.sinit_max_attempts;
-		cfg->init_max_timeo=im.sinit_max_init_timeo;
-	}
-#endif /* SCTP_INITMSG */
-#ifdef SCTP_PEER_ADDR_PARAMS
-	optlen=sizeof(pp);
-	memset(&pp, 0, sizeof(pp)); /* get defaults */
-	/* set the AF, needed on older linux kernels even for INADDR_ANY */
-	pp.spp_address.ss_family=AF_INET;
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, (void*)&pp,
-							&optlen, "SCTP_PEER_ADDR_PARAMS")==0){
-		/* success => hack to set the "default" values*/
-		cfg->hbinterval=pp.spp_hbinterval;
-		cfg->pathmaxrxt=pp.spp_pathmaxrxt;
-	}
-#endif /* SCTP_PEER_ADDR_PARAMS */
-#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-#ifdef SCTP_DELAYED_SACK
-	optlen=sizeof(sack_info);
-	memset(&sack_info, 0, sizeof(sack_info));
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sack_info,
-							&optlen, 0)==0){
-		/* success => hack to set the "default" values*/
-		cfg->sack_delay=sack_info.sack_delay;
-		cfg->sack_freq=sack_info.sack_freq;
-	}else
-#endif /* SCTP_DELAYED_SACK */
-	{
-#ifdef	SCTP_DELAYED_ACK_TIME
-		optlen=sizeof(sack_val);
-		memset(&sack_val, 0, sizeof(sack_val));
-		/* if no SCTP_DELAYED_SACK supported by the sctp lib, or setting it
-		   failed (not supported by the kernel) try using the obsolete
-		   SCTP_DELAYED_ACK_TIME method */
-		if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
-								(void*)&sack_val, &optlen, 
-								"SCTP_DELAYED_ACK_TIME")==0){
-			/* success => hack to set the "default" values*/
-			cfg->sack_delay=sack_val.assoc_value;
-			cfg->sack_freq=0; /* unknown */
-		}
-#else	/* SCTP_DELAYED_ACK_TIME */
-		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
-		   => error */
-		ERR("cfg: SCTP_DELAYED_SACK: %s [%d]\n", strerror(errno), errno);
-#endif /* SCTP_DELAYED_ACK_TIME */
-	}
-#endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
-#ifdef SCTP_MAX_BURST
-	optlen=sizeof(av);
-	av.assoc_id=0;
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_MAX_BURST, (void*)&av,
-							&optlen, "SCTP_MAX_BURST")==0){
-		/* success => hack to set the "default" values*/
-		cfg->max_burst=av.assoc_value;
-	}
-#endif /* SCTP_MAX_BURST */
-	
-	return 0;
-}
-
-
-
-/* set common (for one to many and one to one) sctp socket options
-   tries to ignore non-critical errors (it will only log them), for
-   improved portability (for example older linux kernel version support
-   only a limited number of sctp socket options)
-   returns 0 on success, -1 on error
-   WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */
-static int sctp_init_sock_opt_common(int s, int af)
-{
-	int optval;
-	int pd_point;
-	int saved_errno;
-	socklen_t optlen;
-	int sctp_err;
-#ifdef SCTP_RTOINFO
-	struct sctp_rtoinfo rto;
-#endif /* SCTP_RTOINFO */
-#ifdef SCTP_ASSOCINFO
-	struct sctp_assocparams ap;
-#endif /* SCTP_ASSOCINFO */
-#ifdef SCTP_INITMSG
-	struct sctp_initmsg im;
-#endif /* SCTP_INITMSG */
-#ifdef SCTP_PEER_ADDR_PARAMS
-	struct sctp_paddrparams pp;
-#endif /* SCTP_PEER_ADDR_PARAMS */
-#ifdef SCTP_DELAYED_SACK
-	struct sctp_sack_info sack_info;
-#endif	/* SCTP_DELAYED_SACK */
-#ifdef	SCTP_DELAYED_ACK_TIME
-	struct sctp_assoc_value sack_val;
-#endif /* defined SCTP_DELAYED_ACK_TIME */
-#ifdef SCTP_MAX_BURST
-	struct sctp_assoc_value av;
-#endif /* SCTP_MAX_BURST */
-	
-#ifdef __OS_linux
-	union {
-		struct sctp_event_subscribe s;
-		char padding[sizeof(struct sctp_event_subscribe)+sizeof(__u8)];
-	} es;
-#else
-	struct sctp_event_subscribe es;
-#endif
-	struct sctp_event_subscribe* ev_s;
-	
-	sctp_err=0;
-#ifdef __OS_linux
-	ev_s=&es.s;
-#else
-	ev_s=&es;
-#endif
-	/* set tos */
-	optval = tos;
-	if(af==AF_INET){
-		if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,
-					sizeof(optval)) ==-1){
-			LM_WARN("sctp_init_sock_opt_common: setsockopt tos: %s\n",
-					strerror(errno));
-			/* continue since this is not critical */
-		}
-#ifdef USE_IPV6
-	} else if(af==AF_INET6){
-		if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS,
-					(void*)&optval, sizeof(optval)) ==-1) {
-			LM_WARN("sctp_init_sock_opt_common: setsockopt v6 tos: %s\n",
-					strerror(errno));
-			/* continue since this is not critical */
-		}
-#endif
-	}
-	
-	/* set receive buffer: SO_RCVBUF*/
-	if (cfg_get(sctp, sctp_cfg, so_rcvbuf)){
-		optval=cfg_get(sctp, sctp_cfg, so_rcvbuf);
-		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
-					(void*)&optval, sizeof(optval)) ==-1){
-			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt:"
-						" SO_RCVBUF (%d): %s\n", optval, strerror(errno));
-			/* continue, non-critical */
-		}
-	}
-	
-	/* set send buffer: SO_SNDBUF */
-	if (cfg_get(sctp, sctp_cfg, so_sndbuf)){
-		optval=cfg_get(sctp, sctp_cfg, so_sndbuf);
-		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
-					(void*)&optval, sizeof(optval)) ==-1){
-			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt:"
-						" SO_SNDBUF (%d): %s\n", optval, strerror(errno));
-			/* continue, non-critical */
-		}
-	}
-	
-	/* set reuseaddr */
-	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-						(void*)&optval, sizeof(optval))==-1){
-			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt:"
-						" SO_REUSEADDR (%d): %s\n", optval, strerror(errno));
-			/* continue, non-critical */
-	}
-
-	
-	/* disable fragments interleave (SCTP_FRAGMENT_INTERLEAVE) --
-	 * we don't want partial delivery, so fragment interleave must be off too
-	 */
-#ifdef SCTP_FRAGMENT_INTERLEAVE
-	optval=0;
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE ,
-					(void*)&optval, sizeof(optval)) ==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
-					"SCTP_FRAGMENT_INTERLEAVE: %s\n", strerror(errno));
-		sctp_err++;
-		/* try to continue */
-	}
-#else
-#warning no sctp lib support for SCTP_FRAGMENT_INTERLEAVE, consider upgrading
-#endif /* SCTP_FRAGMENT_INTERLEAVE */
-	
-	/* turn off partial delivery: on linux setting SCTP_PARTIAL_DELIVERY_POINT
-	 * to 0 or a very large number seems to be enough, however the portable
-	 * way to do it is to set it to the socket receive buffer size
-	 * (this is the maximum value allowed in the sctp api draft) */
-#ifdef SCTP_PARTIAL_DELIVERY_POINT
-	optlen=sizeof(optval);
-	if (getsockopt(s, SOL_SOCKET, SO_RCVBUF,
-					(void*)&optval, &optlen) ==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: getsockopt: "
-						"SO_RCVBUF: %s\n", strerror(errno));
-		/* try to continue */
-		optval=0;
-	}
-#ifdef __OS_linux
-	optval/=2; /* in linux getsockopt() returns twice the set value */
-#endif
-	pd_point=optval;
-	saved_errno=0;
-	while(pd_point &&
-			setsockopt(s, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
-					(void*)&pd_point, sizeof(pd_point)) ==-1){
-		if (!saved_errno)
-			saved_errno=errno;
-		pd_point--;
-	}
-	
-	if (pd_point!=optval){
-		if (pd_point==0){
-			/* all attempts failed */
-			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
-						"SCTP_PARTIAL_DELIVERY_POINT (%d): %s\n",
-						optval, strerror(errno));
-			sctp_err++;
-			/* try to continue */
-		}else{
-			/* success but to a lower value (might not be disabled) */
-			LOG(L_WARN, "setsockopt SCTP_PARTIAL_DELIVERY_POINT set to %d, but"
-				" the socket rcvbuf is %d (higher values fail with"
-				" \"%s\" [%d])\n",
-				pd_point, optval, strerror(saved_errno), saved_errno);
-		}
-	}
-#else
-#warning no sctp lib support for SCTP_PARTIAL_DELIVERY_POINT, consider upgrading
-#endif /* SCTP_PARTIAL_DELIVERY_POINT */
-	
-	/* nagle / no delay */
-#ifdef SCTP_NODELAY
-	optval=1;
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY,
-					(void*)&optval, sizeof(optval)) ==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
-						"SCTP_NODELAY: %s\n", strerror(errno));
-		sctp_err++;
-		/* non critical, try to continue */
-	}
-#else
-#warning no sctp lib support for SCTP_NODELAY, consider upgrading
-#endif /* SCTP_NODELAY */
-	
-	/* enable message fragmentation (SCTP_DISABLE_FRAGMENTS)  (on send) */
-#ifdef SCTP_DISABLE_FRAGMENTS
-	optval=0;
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
-					(void*)&optval, sizeof(optval)) ==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
-						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
-		sctp_err++;
-		/* non critical, try to continue */
-	}
-#else
-#warning no sctp lib support for SCTP_DISABLE_FRAGMENTS, consider upgrading
-#endif /* SCTP_DISABLE_FRAGMENTS */
-	
-	/* set autoclose */
-#ifdef SCTP_AUTOCLOSE
-	optval=cfg_get(sctp, sctp_cfg, autoclose);
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE,
-					(void*)&optval, sizeof(optval)) ==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
-						"SCTP_AUTOCLOSE: %s (critical)\n", strerror(errno));
-		/* critical: w/o autoclose we could have sctp connection living
-		   forever (if the remote side doesn't close them) */
-		sctp_err++;
-		goto error;
-	}
-#else
-#error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
-#endif /* SCTP_AUTOCLOSE */
-	/* set rtoinfo options: srto_initial, srto_min, srto_max */
-#ifdef SCTP_RTOINFO
-	memset(&rto, 0, sizeof(rto));
-	rto.srto_initial=cfg_get(sctp, sctp_cfg, srto_initial);
-	rto.srto_min=cfg_get(sctp, sctp_cfg, srto_min);
-	rto.srto_max=cfg_get(sctp, sctp_cfg, srto_max);
-	if (rto.srto_initial || rto.srto_min || rto.srto_max){
-		/* if at least one is non-null => we have to set it */
-		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_RTOINFO, (void*)&rto,
-							sizeof(rto), "setsockopt: SCTP_RTOINFO")!=0){
-			sctp_err++;
-			/* non critical, try to continue */
-		}
-	}
-#else
-#warning no sctp lib support for SCTP_RTOINFO, consider upgrading
-#endif /* SCTP_RTOINFO */
-	/* set associnfo options: assocmaxrxt */
-#ifdef SCTP_ASSOCINFO
-	memset(&ap, 0, sizeof(ap));
-	ap.sasoc_asocmaxrxt=cfg_get(sctp, sctp_cfg, asocmaxrxt);
-	if (ap.sasoc_asocmaxrxt){
-		/* if at least one is non-null => we have to set it */
-		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_ASSOCINFO, (void*)&ap,
-							sizeof(ap), "setsockopt: SCTP_ASSOCINFO")!=0){
-			sctp_err++;
-			/* non critical, try to continue */
-		}
-	}
-#else
-#warning no sctp lib support for SCTP_ASSOCINFO, consider upgrading
-#endif /* SCTP_ASOCINFO */
-	/* set initmsg options: init_max_attempts & init_max_init_timeo */
-#ifdef SCTP_INITMSG
-	memset(&im, 0, sizeof(im));
-	im.sinit_max_attempts=cfg_get(sctp, sctp_cfg, init_max_attempts);
-	im.sinit_max_init_timeo=cfg_get(sctp, sctp_cfg, init_max_timeo);
-	if (im.sinit_max_attempts || im.sinit_max_init_timeo){
-		/* if at least one is non-null => we have to set it */
-		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_INITMSG, (void*)&im,
-							sizeof(im), "setsockopt: SCTP_INITMSG")!=0){
-			sctp_err++;
-			/* non critical, try to continue */
-		}
-	}
-#else
-#warning no sctp lib support for SCTP_INITMSG, consider upgrading
-#endif /* SCTP_INITMSG */
-	/* set sctp peer addr options: hbinterval & pathmaxrxt */
-#ifdef SCTP_PEER_ADDR_PARAMS
-	memset(&pp, 0, sizeof(pp));
-	pp.spp_address.ss_family=af;
-	pp.spp_hbinterval=cfg_get(sctp, sctp_cfg, hbinterval);
-	pp.spp_pathmaxrxt=cfg_get(sctp, sctp_cfg, pathmaxrxt);
-	if (pp.spp_hbinterval || pp.spp_pathmaxrxt){
-		if (pp.spp_hbinterval > 0)
-			pp.spp_flags=SPP_HB_ENABLE;
-		else if (pp.spp_hbinterval==-1){
-			pp.spp_flags=SPP_HB_DISABLE;
-			pp.spp_hbinterval=0;
-		}
-#ifdef __OS_linux
-		if (pp.spp_pathmaxrxt){
-			/* hack to work on linux, pathmaxrxt is set only if
-			   SPP_PMTUD_ENABLE */
-			pp.spp_flags|=SPP_PMTUD_ENABLE;
-		}
-#endif /*__OS_linux */
-		/* if at least one is non-null => we have to set it */
-		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, (void*)&pp,
-						sizeof(pp), "setsockopt: SCTP_PEER_ADDR_PARAMS")!=0){
-			sctp_err++;
-			/* non critical, try to continue */
-		}
-	}
-#else
-#warning no sctp lib support for SCTP_PEER_ADDR_PARAMS, consider upgrading
-#endif /* SCTP_PEER_ADDR_PARAMS */
-	/* set delayed ack options: sack_delay & sack_freq */
-#if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-#ifdef SCTP_DELAYED_SACK
-	memset(&sack_info, 0, sizeof(sack_info));
-	sack_info.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
-	sack_info.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
-	if ((sack_info.sack_delay || sack_info.sack_freq) &&
-		(sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK,
-							(void*)&sack_info, sizeof(sack_info), 0)!=0)) {
-		/* if setting SCTP_DELAYED_SACK failed, try the old obsolete
-		   SCTP_DELAYED_ACK_TIME */
-#endif /* SCTP_DELAYED_SACK */
-#ifdef SCTP_DELAYED_ACK_TIME
-		memset(&sack_val, 0, sizeof(sack_val));
-		sack_val.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
-		if (sack_val.assoc_value){
-			if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
-									(void*)&sack_val, sizeof(sack_val),
-									"setsockopt: SCTP_DELAYED_ACK_TIME")!=0){
-				sctp_err++;
-				/* non critical, try to continue */
-			}
-		}
-#else /* SCTP_DELAYED_ACK_TIME */
-		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
-		   => error */
-		if (sack_info.sack_delay){
-			sctp_err++;
-			ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
-						strerror(errno), errno);
-		}
-#endif /* SCTP_DELAYED_ACK_TIME */
-		if (cfg_get(sctp, sctp_cfg, sack_freq)){
-#ifdef SCTP_DELAYED_SACK
-			sctp_err++;
-			WARN("could not set sctp sack_freq, please upgrade your kernel\n");
-#else /* SCTP_DELAYED_SACK */
-			WARN("could not set sctp sack_freq, please upgrade your sctp"
-					" library\n");
-#endif /* SCTP_DELAYED_SACK */
-			((struct cfg_group_sctp*)sctp_cfg)->sack_freq=0;
-		}
-#ifdef SCTP_DELAYED_SACK
-	}
-#endif /* SCTP_DELAYED_SACK */
-	
-#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
-#warning no sctp lib support for SCTP_DELAYED_SACK, consider upgrading
-#endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
-	/* set max burst option */
-#ifdef SCTP_MAX_BURST
-	memset(&av, 0, sizeof(av));
-	av.assoc_value=cfg_get(sctp, sctp_cfg, max_burst);
-	if (av.assoc_value){
-		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_MAX_BURST, (void*)&av,
-							sizeof(av), "setsockopt: SCTP_MAX_BURST")!=0){
-			sctp_err++;
-			/* non critical, try to continue */
-		}
-	}
-#else
-#warning no sctp lib support for SCTP_MAX_BURST, consider upgrading
-#endif /* SCTP_MAX_BURST */
-	
-	memset(&es, 0, sizeof(es));
-	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
-	 *  information in sctp_sndrcvinfo */
-	ev_s->sctp_data_io_event=1;
-	/* enable association event notifications */
-	ev_s->sctp_association_event=1; /* SCTP_ASSOC_CHANGE */
-	ev_s->sctp_address_event=1;  /* enable address events notifications */
-	ev_s->sctp_send_failure_event=1; /* SCTP_SEND_FAILED */
-	ev_s->sctp_peer_error_event=1;   /* SCTP_REMOTE_ERROR */
-	ev_s->sctp_shutdown_event=1;     /* SCTP_SHUTDOWN_EVENT */
-	ev_s->sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */
-	/* ev_s->sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/
-	/* ev_s->sctp_authentication_event=1; -- not supported on linux 2.6.25 */
-	
-	/* enable the SCTP_EVENTS */
-#ifdef SCTP_EVENTS
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s))==-1){
-		/* on linux the checks for the struct sctp_event_subscribe size
-		   are too strict, making certain lksctp/kernel combination
-		   unworkable => since we don't use the extra information
-		   (sctp_authentication_event) added in newer version, we can
-		   try with different sizes) */
-#ifdef __OS_linux
-		/* 1. lksctp 1.0.9 with kernel < 2.6.26 -> kernel expects 
-		      the structure without the authentication event member */
-		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s)-1)==0)
-			goto ev_success;
-		/* 2. lksctp < 1.0.9? with kernel >= 2.6.26: the sctp.h structure
-		   does not have the authentication member, but the newer kernels 
-		   check only for optlen > sizeof(...) => we should never reach
-		   this point. */
-		/* 3. just to be foolproof if we reached this point, try
-		    with a bigger size before giving up  (out of desperation) */
-		if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(es))==0)
-			goto ev_success;
-
-#endif
-		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
-				"SCTP_EVENTS: %s\n", strerror(errno));
-		sctp_err++;
-		goto error; /* critical */
-	}
-#ifdef __OS_linux
-ev_success:
-#endif
-#else
-#error no sctp lib support for SCTP_EVENTS, consider upgrading
-#endif /* SCTP_EVENTS */
-	
-	if (sctp_err){
-		LOG(L_ERR, "ERROR: sctp: setting some sctp sockopts failed, "
-					"consider upgrading your kernel\n");
-	}
-	return 0;
-error:
-	return -1;
-}
-
-
-
-/* bind all addresses from sock (sockaddr_unions)
-   returns 0 on success, .1 on error */
-static int sctp_bind_sock(struct socket_info* sock_info)
-{
-	struct addr_info* ai;
-	union sockaddr_union* addr;
-	
-	addr=&sock_info->su;
-	/* bind the addresses*/
-	if (bind(sock_info->socket,  &addr->s, sockaddru_len(*addr))==-1){
-		LOG(L_ERR, "ERROR: sctp_bind_sock: bind(%x, %p, %d) on %s: %s\n",
-				sock_info->socket, &addr->s, 
-				(unsigned)sockaddru_len(*addr),
-				sock_info->address_str.s,
-				strerror(errno));
-	#ifdef USE_IPV6
-		if (addr->s.sa_family==AF_INET6)
-			LOG(L_ERR, "ERROR: sctp_bind_sock: might be caused by using a "
-							"link local address, try site local or global\n");
-	#endif
-		goto error;
-	}
-	for (ai=sock_info->addr_info_lst; ai; ai=ai->next)
-		if (sctp_bindx(sock_info->socket, &ai->su.s, 1, SCTP_BINDX_ADD_ADDR)
-					==-1){
-			LOG(L_ERR, "ERROR: sctp_bind_sock: sctp_bindx(%x, %.*s:%d, 1, ...)"
-						" on %s:%d : [%d] %s (trying to continue)\n",
-						sock_info->socket,
-						ai->address_str.len, ai->address_str.s, 
-						sock_info->port_no,
-						sock_info->address_str.s, sock_info->port_no,
-						errno, strerror(errno));
-		#ifdef USE_IPV6
-			if (ai->su.s.sa_family==AF_INET6)
-				LOG(L_ERR, "ERROR: sctp_bind_sock: might be caused by using a "
-							"link local address, try site local or global\n");
-		#endif
-			/* try to continue, a secondary address bind failure is not 
-			 * critical */
-		}
-	return 0;
-error:
-	return -1;
-}
-
-
-
-/* init, bind & start listening on the corresp. sctp socket
-   returns 0 on success, -1 on error */
-int sctp_init_sock(struct socket_info* sock_info)
-{
-	union sockaddr_union* addr;
-	
-	sock_info->proto=PROTO_SCTP;
-	addr=&sock_info->su;
-	if (sctp_init_su(sock_info)!=0)
-		goto error;
-	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET, 
-								IPPROTO_SCTP);
-	if (sock_info->socket==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock: socket: %s\n", strerror(errno));
-		goto error;
-	}
-	INFO("sctp: socket %d initialized (%p)\n", sock_info->socket, sock_info);
-	/* make socket non-blocking */
-#if 0
-	/* recvmsg must block so use blocking sockets
-	 * and send with MSG_DONTWAIT */
-	optval=fcntl(sock_info->socket, F_GETFL);
-	if (optval==-1){
-		LOG(L_ERR, "ERROR: init_sctp: fnctl failed: (%d) %s\n",
-				errno, strerror(errno));
-		goto error;
-	}
-	if (fcntl(sock_info->socket, F_SETFL, optval|O_NONBLOCK)==-1){
-		LOG(L_ERR, "ERROR: init_sctp: fcntl: set non-blocking failed:"
-				" (%d) %s\n", errno, strerror(errno));
-		goto error;
-	}
-#endif
-
-	/* set sock opts */
-	if (sctp_init_sock_opt_common(sock_info->socket, sock_info->address.af)!=0)
-		goto error;
-	/* SCTP_EVENTS for send dried out -> present in the draft not yet
-	 * present in linux (might help to detect when we could send again to
-	 * some peer, kind of poor's man poll on write, based on received
-	 * SCTP_SENDER_DRY_EVENTs */
-	
-	if (sctp_bind_sock(sock_info)<0)
-		goto error;
-	if (listen(sock_info->socket, 1)<0){
-		LOG(L_ERR, "ERROR: sctp_init_sock: listen(%x, 1) on %s: %s\n",
-					sock_info->socket, sock_info->address_str.s,
-					strerror(errno));
-		goto error;
-	}
-	return 0;
-error:
-	return -1;
-}
-
-
-#define USE_SCTP_OO
-
-#ifdef USE_SCTP_OO
-
-/* init, bind & start listening on the corresp. sctp socket, using
-   sctp one-to-one mode
-   returns 0 on success, -1 on error */
-int sctp_init_sock_oo(struct socket_info* sock_info)
-{
-	union sockaddr_union* addr;
-	int optval;
-	
-	sock_info->proto=PROTO_SCTP;
-	addr=&sock_info->su;
-	if (sctp_init_su(sock_info)!=0)
-		goto error;
-	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_STREAM, 
-								IPPROTO_SCTP);
-	if (sock_info->socket==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_oo: socket: %s\n", strerror(errno));
-		goto error;
-	}
-	INFO("sctp:oo socket %d initialized (%p)\n", sock_info->socket, sock_info);
-	/* make socket non-blocking */
-	optval=fcntl(sock_info->socket, F_GETFL);
-	if (optval==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_oo: fnctl failed: (%d) %s\n",
-				errno, strerror(errno));
-		goto error;
-	}
-	if (fcntl(sock_info->socket, F_SETFL, optval|O_NONBLOCK)==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_oo: fcntl: set non-blocking failed:"
-				" (%d) %s\n", errno, strerror(errno));
-		goto error;
-	}
-	
-	/* set sock opts */
-	if (sctp_init_sock_opt_common(sock_info->socket, sock_info->address.af)!=0)
-		goto error;
-	
-#ifdef SCTP_REUSE_PORT
-	/* set reuse port */
-	optval=1;
-	if (setsockopt(sock_info->socket, IPPROTO_SCTP, SCTP_REUSE_PORT ,
-					(void*)&optval, sizeof(optval)) ==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_oo: setsockopt: "
-					"SCTP_REUSE_PORT: %s\n", strerror(errno));
-		goto error;
-	}
-#endif /* SCTP_REUSE_PORT */
-	
-	if (sctp_bind_sock(sock_info)<0)
-		goto error;
-	if (listen(sock_info->socket, 1)<0){
-		LOG(L_ERR, "ERROR: sctp_init_sock_oo: listen(%x, 1) on %s: %s\n",
-					sock_info->socket, sock_info->address_str.s,
-					strerror(errno));
-		goto error;
-	}
-	return 0;
-error:
-	return -1;
-}
-
-#endif /* USE_SCTP_OO */
-
-
-#ifdef SCTP_CONN_REUSE
-
-/* we  need SCTP_ADDR_HASH for being able to make inquires related to existing
-   sctp association to a particular address  (optional) */
-/*#define SCTP_ADDR_HASH*/
-
-#define SCTP_ID_HASH_SIZE 1024 /* must be 2^k */
-#define SCTP_ASSOC_HASH_SIZE 1024 /* must be 2^k */
-#define SCTP_ADDR_HASH_SIZE 1024 /* must be 2^k */
-
-/* lock method */
-#ifdef GEN_LOCK_T_UNLIMITED
-#define SCTP_HASH_LOCK_PER_BUCKET
-#elif defined GEN_LOCK_SET_T_UNLIMITED
-#define SCTP_HASH_LOCK_SET
-#else
-#define SCTP_HASH_ONE_LOCK
-#endif
-
-
-#ifdef SCTP_HASH_LOCK_PER_BUCKET
-/* lock included in the hash bucket */
-#define LOCK_SCTP_ID_H(h)		lock_get(&sctp_con_id_hash[(h)].lock)
-#define UNLOCK_SCTP_ID_H(h)		lock_release(&sctp_con_id_hash[(h)].lock)
-#define LOCK_SCTP_ASSOC_H(h)	lock_get(&sctp_con_assoc_hash[(h)].lock)
-#define UNLOCK_SCTP_ASSOC_H(h)	lock_release(&sctp_con_assoc_hash[(h)].lock)
-#define LOCK_SCTP_ADDR_H(h)		lock_get(&sctp_con_addr_hash[(h)].lock)
-#define UNLOCK_SCTP_ADDR_H(h)	lock_release(&sctp_con_addr_hash[(h)].lock)
-#elif defined SCTP_HASH_LOCK_SET
-static gen_lock_set_t* sctp_con_id_h_lock_set=0;
-static gen_lock_set_t* sctp_con_assoc_h_lock_set=0;
-static gen_lock_set_t* sctp_con_addr_h_lock_set=0;
-#define LOCK_SCTP_ID_H(h)		lock_set_get(sctp_con_id_h_lock_set, (h))
-#define UNLOCK_SCTP_ID_H(h)		lock_set_release(sctp_con_id_h_lock_set, (h))
-#define LOCK_SCTP_ASSOC_H(h)	lock_set_get(sctp_con_assoc_h_lock_set, (h))
-#define UNLOCK_SCTP_ASSOC_H(h)	\
-	lock_set_release(sctp_con_assoc_h_lock_set, (h))
-#define LOCK_SCTP_ADDR_H(h)	lock_set_get(sctp_con_addr_h_lock_set, (h))
-#define UNLOCK_SCTP_ADDR_H(h)	lock_set_release(sctp_con_addr_h_lock_set, (h))
-#else /* use only one lock */
-static gen_lock_t* sctp_con_id_h_lock=0;
-static gen_lock_t* sctp_con_assoc_h_lock=0;
-static gen_lock_t* sctp_con_addr_h_lock=0;
-#define LOCK_SCTP_ID_H(h)		lock_get(sctp_con_id_h_lock)
-#define UNLOCK_SCTP_ID_H(h)		lock_release(sctp_con_id_hlock)
-#define LOCK_SCTP_ASSOC_H(h)	lock_get(sctp_con_assoc_h_lock)
-#define UNLOCK_SCTP_ASSOC_H(h)	lock_release(sctp_con_assoc_h_lock)
-#define LOCK_SCTP_ADDR_H(h)	lock_get(sctp_con_addr_h_lock)
-#define UNLOCK_SCTP_ADDR_H(h)	lock_release(sctp_con_addr_h_lock)
-#endif /* SCTP_HASH_LOCK_PER_BUCKET */
-
-
-/* sctp connection flags */
-#define SCTP_CON_UP_SEEN   1
-#define SCTP_CON_RCV_SEEN  2
-#define SCTP_CON_DOWN_SEEN 4
-
-struct sctp_connection{
-	unsigned int id;       /**< ser unique global id */
-	unsigned int assoc_id; /**< sctp assoc id (can be reused for new assocs)*/
-	struct socket_info* si; /**< local socket used */
-	unsigned flags; /**< internal flags UP_SEEN, RCV_SEEN, DOWN_SEEN */
-	ticks_t start;
-	ticks_t expire; 
-	union sockaddr_union remote; /**< remote ip & port */
-};
-
-struct sctp_lst_connector{
-	/* id hash */
-	struct sctp_con_elem* next_id;
-	struct sctp_con_elem* prev_id;
-	/* assoc hash */
-	struct sctp_con_elem* next_assoc;
-	struct sctp_con_elem* prev_assoc;
-#ifdef SCTP_ADDR_HASH
-	/* addr hash */
-	struct sctp_con_elem* next_addr;
-	struct sctp_con_elem* prev_addr;
-#endif /* SCTP_ADDR_HASH */
-};
-
-struct sctp_con_elem{
-	struct sctp_lst_connector l; /* must be first */
-	atomic_t refcnt;
-	/* data */
-	struct sctp_connection con;
-};
-
-struct sctp_con_id_hash_head{
-	struct sctp_lst_connector l; /* must be first */
-#ifdef SCTP_HASH_LOCK_PER_BUCKET
-	gen_lock_t lock;
-#endif /* SCTP_HASH_LOCK_PER_BUCKET */
-};
-
-struct sctp_con_assoc_hash_head{
-	struct sctp_lst_connector l; /* must be first */
-#ifdef SCTP_HASH_LOCK_PER_BUCKET
-	gen_lock_t lock;
-#endif /* SCTP_HASH_LOCK_PER_BUCKET */
-};
-
-#ifdef SCTP_ADDR_HASH
-struct sctp_con_addr_hash_head{
-	struct sctp_lst_connector l; /* must be first */
-#ifdef SCTP_HASH_LOCK_PER_BUCKET
-	gen_lock_t lock;
-#endif /* SCTP_HASH_LOCK_PER_BUCKET */
-};
-#endif /* SCTP_ADDR_HASH */
-
-static struct sctp_con_id_hash_head*     sctp_con_id_hash;
-static struct sctp_con_assoc_hash_head*  sctp_con_assoc_hash;
-#ifdef SCTP_ADDR_HASH
-static struct sctp_con_addr_hash_head*  sctp_con_addr_hash;
-#endif /* SCTP_ADDR_HASH */
-
-static atomic_t* sctp_id;
-static atomic_t* sctp_conn_tracked;
-
-
-#define get_sctp_con_id_hash(id) ((id) % SCTP_ID_HASH_SIZE)
-#define get_sctp_con_assoc_hash(assoc_id)  ((assoc_id) % SCTP_ASSOC_HASH_SIZE)
-#ifdef SCTP_ADDR_HASH
-static inline unsigned get_sctp_con_addr_hash(union sockaddr_union* remote,
-											struct socket_info* si)
-{
-	struct ip_addr ip;
-	unsigned short port;
-	unsigned h;
-	
-	su2ip_addr(&ip, remote);
-	port=su_getport(remote);
-	if (likely(ip.len==4))
-		h=ip.u.addr32[0]^port;
-	else if (ip.len==16)
-		h=ip.u.addr32[0]^ip.u.addr32[1]^ip.u.addr32[2]^ ip.u.addr32[3]^port;
-	else
-		h=0; /* error */
-	/* make sure the first bits are influenced by all 32
-	 * (the first log2(SCTP_ADDR_HASH_SIZE) bits should be a mix of all
-	 *  32)*/
-	h ^= h>>17;
-	h ^= h>>7;
-	return h & (SCTP_ADDR_HASH_SIZE-1);
-}
-#endif /* SCTP_ADDR_HASH */
-
-
-
-/** destroy sctp conn hashes. */
-void destroy_sctp_con_tracking()
-{
-	int r;
-	
-#ifdef SCTP_HASH_LOCK_PER_BUCKET
-	if (sctp_con_id_hash)
-		for(r=0; r<SCTP_ID_HASH_SIZE; r++)
-			lock_destroy(&sctp_con_id_hash[r].lock);
-	if (sctp_con_assoc_hash)
-		for(r=0; r<SCTP_ASSOC_HASH_SIZE; r++)
-			lock_destroy(&sctp_con_assoc_hash[r].lock);
-#	ifdef SCTP_ADDR_HASH
-	if (sctp_con_addr_hash)
-		for(r=0; r<SCTP_ADDR_HASH_SIZE; r++)
-			lock_destroy(&sctp_con_addr_hash[r].lock);
-#	endif /* SCTP_ADDR_HASH */
-#elif defined SCTP_HASH_LOCK_SET
-	if (sctp_con_id_h_lock_set){
-		lock_set_destroy(sctp_con_id_h_lock_set);
-		lock_set_dealloc(sctp_con_id_h_lock_set);
-		sctp_con_id_h_lock_set=0;
-	}
-	if (sctp_con_assoc_h_lock_set){
-		lock_set_destroy(sctp_con_assoc_h_lock_set);
-		lock_set_dealloc(sctp_con_assoc_h_lock_set);
-		sctp_con_assoc_h_lock_set=0;
-	}
-#	ifdef SCTP_ADDR_HASH
-	if (sctp_con_addr_h_lock_set){
-		lock_set_destroy(sctp_con_addr_h_lock_set);
-		lock_set_dealloc(sctp_con_addr_h_lock_set);
-		sctp_con_addr_h_lock_set=0;
-	}
-#	endif /* SCTP_ADDR_HASH */
-#else /* SCTP_HASH_ONE_LOCK */
-	if (sctp_con_id_h_lock){
-		lock_destroy(sctp_con_id_h_lock);
-		lock_dealloc(sctp_con_id_h_lock);
-		sctp_con_id_h_lock=0;
-	}
-	if (sctp_con_assoc_h_lock){
-		lock_destroy(sctp_con_assoc_h_lock);
-		lock_dealloc(sctp_con_assoc_h_lock);
-		sctp_con_assoc_h_lock=0;
-	}
-#	ifdef SCTP_ADDR_HASH
-	if (sctp_con_addr_h_lock){
-		lock_destroy(sctp_con_addr_h_lock);
-		lock_dealloc(sctp_con_addr_h_lock);
-		sctp_con_addr_h_lock=0;
-	}
-#	endif /* SCTP_ADDR_HASH */
-#endif /* SCTP_HASH_LOCK_PER_BUCKET/SCTP_HASH_LOCK_SET/one lock */
-	if (sctp_con_id_hash){
-		shm_free(sctp_con_id_hash);
-		sctp_con_id_hash=0;
-	}
-	if (sctp_con_assoc_hash){
-		shm_free(sctp_con_assoc_hash);
-		sctp_con_assoc_hash=0;
-	}
-#ifdef SCTP_ADDR_HASH
-	if (sctp_con_addr_hash){
-		shm_free(sctp_con_addr_hash);
-		sctp_con_addr_hash=0;
-	}
-#endif /* SCTP_ADDR_HASH */
-	if (sctp_id){
-		shm_free(sctp_id);
-		sctp_id=0;
-	}
-	if (sctp_conn_tracked){
-		shm_free(sctp_conn_tracked);
-		sctp_conn_tracked=0;
-	}
-}
-
-
-
-/** intializaze sctp_conn hashes.
-  * @return 0 on success, <0 on error
-  */
-int init_sctp_con_tracking()
-{
-	int r, ret;
-	
-	sctp_con_id_hash=shm_malloc(SCTP_ID_HASH_SIZE*sizeof(*sctp_con_id_hash));
-	sctp_con_assoc_hash=shm_malloc(SCTP_ASSOC_HASH_SIZE*
-									sizeof(*sctp_con_assoc_hash));
-#ifdef SCTP_ADDR_HASH
-	sctp_con_addr_hash=shm_malloc(SCTP_ADDR_HASH_SIZE*
-									sizeof(*sctp_con_addr_hash));
-#endif /* SCTP_ADDR_HASH */
-	sctp_id=shm_malloc(sizeof(*sctp_id));
-	sctp_conn_tracked=shm_malloc(sizeof(*sctp_conn_tracked));
-	if (sctp_con_id_hash==0 || sctp_con_assoc_hash==0 ||
-#ifdef SCTP_ADDR_HASH
-			sctp_con_addr_hash==0 ||
-#endif /* SCTP_ADDR_HASH */
-			sctp_id==0 || sctp_conn_tracked==0){
-		ERR("sctp init: memory allocation error\n");
-		ret=E_OUT_OF_MEM;
-		goto error;
-	}
-	atomic_set(sctp_id, 0);
-	atomic_set(sctp_conn_tracked, 0);
-	for (r=0; r<SCTP_ID_HASH_SIZE; r++)
-		clist_init(&sctp_con_id_hash[r], l.next_id, l.prev_id);
-	for (r=0; r<SCTP_ASSOC_HASH_SIZE; r++)
-		clist_init(&sctp_con_assoc_hash[r], l.next_assoc, l.prev_assoc);
-#ifdef SCTP_ADDR_HASH
-	for (r=0; r<SCTP_ADDR_HASH_SIZE; r++)
-		clist_init(&sctp_con_addr_hash[r], l.next_addr, l.prev_addr);
-#endif /* SCTP_ADDR_HASH */
-#ifdef SCTP_HASH_LOCK_PER_BUCKET
-	for (r=0; r<SCTP_ID_HASH_SIZE; r++){
-		if (lock_init(&sctp_con_id_hash[r].lock)==0){
-			ret=-1;
-			ERR("sctp init: failed to initialize locks\n");
-			goto error;
-		}
-	}
-	for (r=0; r<SCTP_ASSOC_HASH_SIZE; r++){
-		if (lock_init(&sctp_con_assoc_hash[r].lock)==0){
-			ret=-1;
-			ERR("sctp init: failed to initialize locks\n");
-			goto error;
-		}
-	}
-#	ifdef SCTP_ADDR_HASH
-	for (r=0; r<SCTP_ADDR_HASH_SIZE; r++){
-		if (lock_init(&sctp_con_addr_hash[r].lock)==0){
-			ret=-1;
-			ERR("sctp init: failed to initialize locks\n");
-			goto error;
-		}
-	}
-#	endif /* SCTP_ADDR_HASH */
-#elif defined SCTP_HASH_LOCK_SET
-	sctp_con_id_h_lock_set=lock_set_alloc(SCTP_ID_HASH_SIZE);
-	sctp_con_assoc_h_lock_set=lock_set_alloc(SCTP_ASSOC_HASH_SIZE);
-#	ifdef SCTP_ADDR_HASH
-	sctp_con_addr_h_lock_set=lock_set_alloc(SCTP_ADDR_HASH_SIZE);
-#	endif /* SCTP_ADDR_HASH */
-	if (sctp_con_id_h_lock_set==0 || sctp_con_assoc_h_lock_set==0
-#	ifdef SCTP_ADDR_HASH
-			|| sctp_con_addr_h_lock_set==0
-#	endif /* SCTP_ADDR_HASH */
-			){
-		ret=E_OUT_OF_MEM;
-		ERR("sctp_init: failed to alloc lock sets\n");
-		goto error;
-	}
-	if (lock_set_init(sctp_con_id_h_lock_set)==0){
-		lock_set_dealloc(sctp_con_id_h_lock_set);
-		sctp_con_id_h_lock_set=0;
-		ret=-1;
-		ERR("sctp init: failed to initialize lock set\n");
-		goto error;
-	}
-	if (lock_set_init(sctp_con_assoc_h_lock_set)==0){
-		lock_set_dealloc(sctp_con_assoc_h_lock_set);
-		sctp_con_assoc_h_lock_set=0;
-		ret=-1;
-		ERR("sctp init: failed to initialize lock set\n");
-		goto error;
-	}
-#	ifdef SCTP_ADDR_HASH
-	if (lock_set_init(sctp_con_addr_h_lock_set)==0){
-		lock_set_dealloc(sctp_con_addr_h_lock_set);
-		sctp_con_addr_h_lock_set=0;
-		ret=-1;
-		ERR("sctp init: failed to initialize lock set\n");
-		goto error;
-	}
-#	endif /* SCTP_ADDR_HASH */
-#else /* SCTP_HASH_ONE_LOCK */
-	sctp_con_id_h_lock=lock_alloc();
-	sctp_con_assoc_h_lock=lock_alloc();
-#	ifdef SCTP_ADDR_HASH
-	sctp_con_addr_h_lock=lock_alloc();
-#	endif /* SCTP_ADDR_HASH */
-	if (sctp_con_id_h_lock==0 || sctp_con_assoc_h_lock==0
-#	ifdef SCTP_ADDR_HASH
-			|| sctp_con_addr_h_lock==0
-#	endif /* SCTP_ADDR_HASH */
-			){
-		ret=E_OUT_OF_MEM;
-		ERR("sctp init: failed to alloc locks\n");
-		goto error;
-	}
-	if (lock_init(sctp_con_id_h_lock)==0){
-		lock_dealloc(sctp_con_id_h_lock);
-		sctp_con_id_h_lock=0;
-		ret=-1;
-		ERR("sctp init: failed to initialize lock\n");
-		goto error;
-	}
-	if (lock_init(sctp_con_assoc_h_lock)==0){
-		lock_dealloc(sctp_con_assoc_h_lock);
-		sctp_con_assoc_h_lock=0;
-		ret=-1;
-		ERR("sctp init: failed to initialize lock\n");
-		goto error;
-	}
-#	ifdef SCTP_ADDR_HASH
-	if (lock_init(sctp_con_addr_h_lock)==0){
-		lock_dealloc(sctp_con_addr_h_lock);
-		sctp_con_addr_h_lock=0;
-		ret=-1;
-		ERR("sctp init: failed to initialize lock\n");
-		goto error;
-	}
-#	endif /* SCTP_ADDR_HASH */
-#endif /* SCTP_HASH_LOCK_PER_BUCKET/SCTP_HASH_LOCK_SET/one lock */
-	return 0;
-error:
-	destroy_sctp_con_tracking();
-	return ret;
-}
-
-
-
-#if 0
-/** adds "e" to the hashes, safe locking version.*/
-static void sctp_con_add(struct sctp_con_elem* e)
-{
-	unsigned hash;
-	DBG("sctp_con_add(%p) ( ser id %d, assoc_id %d)\n",
-			e, e->con.id, e->con.assoc_id);
-	
-	e->l.next_id=e->l.prev_id=0;
-	e->l.next_assoc=e->l.prev_assoc=0;
-#ifdef SCTP_ADDR_HASH
-	e->l.next_addr=e->l.prev_addr=0;
-	e->refcnt.val+=3; /* account for the 3 lists */
-#else /* SCTP_ADDR_HASH */
-	e->refcnt.val+=2; /* account for the 2 lists */
-#endif /* SCTP_ADDR_HASH */
-	hash=get_sctp_con_id_hash(e->con.id);
-	DBG("adding to con id hash %d\n", hash);
-	LOCK_SCTP_ID_H(hash);
-		clist_insert(&sctp_con_id_hash[hash], e, l.next_id, l.prev_id);
-	UNLOCK_SCTP_ID_H(hash);
-	hash=get_sctp_con_assoc_hash(e->con.assoc_id);
-	DBG("adding to assoc_id hash %d\n", hash);
-	LOCK_SCTP_ASSOC_H(hash);
-		clist_insert(&sctp_con_assoc_hash[hash], e,
-						l.next_assoc, l.prev_assoc);
-	UNLOCK_SCTP_ASSOC_H(hash);
-#ifdef SCTP_ADDR_HASH
-	hash=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
-	DBG("adding to addr hash %d\n", hash);
-	LOCK_SCTP_ADDR_H(hash);
-		clist_insert(&sctp_con_addr_hash[hash], e,
-						l.next_addr, l.prev_addr);
-	UNLOCK_SCTP_ADDR_H(hash);
-#endif /* SCTP_ADDR_HASH */
-	atomic_inc(sctp_conn_tracked);
-}
-#endif
-
-
-
-/** helper internal del elem function, the id hash must be locked.
-  * WARNING: the id hash(h) _must_ be locked (LOCK_SCTP_ID_H(h)).
-  * @param h - id hash
-  * @param e - sctp_con_elem to delete (from all the hashes)
-  * @return 0 if the id hash was unlocked, 1 if it's still locked */
-inline static int _sctp_con_del_id_locked(unsigned h, struct sctp_con_elem* e)
-{
-	unsigned assoc_id_h;
-	int deref; /* delayed de-reference counter */
-	int locked;
-#ifdef SCTP_ADDR_HASH
-	unsigned addr_h;
-#endif /* SCTP_ADDR_HASH */
-	
-	locked=1;
-	clist_rm(e, l.next_id, l.prev_id);
-	e->l.next_id=e->l.prev_id=0; /* mark it as id unhashed */
-	/* delay atomic dereference, so that we'll perform only one
-	   atomic op. even for multiple derefs. It also has the
-	   nice side-effect that the entry will be guaranteed to be
-	   referenced until we perform the delayed deref. at the end,
-	   so we don't need to keep some lock to prevent somebody from
-	   deleting the entry from under us */
-	deref=1; /* removed from one list =>  deref once */
-	/* remove it from the assoc hash if needed */
-	if (likely(e->l.next_assoc)){
-		UNLOCK_SCTP_ID_H(h);
-		locked=0; /* no longer id-locked */
-		/* we haven't dec. refcnt, so it's still safe to use e */
-		assoc_id_h=get_sctp_con_assoc_hash(e->con.assoc_id);
-		LOCK_SCTP_ASSOC_H(assoc_id_h);
-			/* make sure nobody removed it in the meantime */
-			if (likely(e->l.next_assoc)){
-				clist_rm(e, l.next_assoc, l.prev_assoc);
-				e->l.next_assoc=e->l.prev_assoc=0; /* mark it as removed */
-				deref++; /* rm'ed from the assoc list => inc. delayed deref. */
-			}
-		UNLOCK_SCTP_ASSOC_H(assoc_id_h);
-	}
-#ifdef SCTP_ADDR_HASH
-	/* remove it from the addr. hash if needed */
-	if (likely(e->l.next_addr)){
-		if (unlikely(locked)){
-			UNLOCK_SCTP_ID_H(h);
-			locked=0; /* no longer id-locked */
-		}
-		addr_h=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
-		LOCK_SCTP_ADDR_H(addr_h);
-			/* make sure nobody removed it in the meantime */
-			if (likely(e->l.next_addr)){
-				clist_rm(e, l.next_addr, l.prev_addr);
-				e->l.next_addr=e->l.prev_addr=0; /* mark it as removed */
-				deref++; /* rm'ed from the addr list => inc. delayed deref. */
-			}
-		UNLOCK_SCTP_ADDR_H(addr_h);
-	}
-#endif /* SCTP_ADDR_HASH */
-	
-	/* performed delayed de-reference */
-	if (atomic_add(&e->refcnt, -deref)==0){
-		atomic_dec(sctp_conn_tracked);
-		shm_free(e);
-	}
-	else
-		DBG("del assoc post-deref (kept): ser id %d, assoc_id %d,"
-			" post-refcnt %d, deref %d, post-tracked %d\n",
-			e->con.id, e->con.assoc_id, atomic_get(&e->refcnt), deref,
-			atomic_get(sctp_conn_tracked));
-	return locked;
-}
-
-
-
-/** helper internal del elem function, the assoc hash must be locked.
-  * WARNING: the assoc hash(h) _must_ be locked (LOCK_SCTP_ASSOC_H(h)).
-  * @param h - assoc hash
-  * @param e - sctp_con_elem to delete (from all the hashes)
-  * @return 0 if the assoc hash was unlocked, 1 if it's still locked */
-inline static int _sctp_con_del_assoc_locked(unsigned h,
-												struct sctp_con_elem* e)
-{
-	unsigned id_hash;
-	int deref; /* delayed de-reference counter */
-	int locked;
-#ifdef SCTP_ADDR_HASH
-	unsigned addr_h;
-#endif /* SCTP_ADDR_HASH */
-	
-	locked=1;
-	clist_rm(e, l.next_assoc, l.prev_assoc);
-	e->l.next_assoc=e->l.prev_assoc=0; /* mark it as assoc unhashed */
-	/* delay atomic dereference, so that we'll perform only one
-	   atomic op. even for multiple derefs. It also has the
-	   nice side-effect that the entry will be guaranteed to be
-	   referenced until we perform the delayed deref. at the end,
-	   so we don't need to keep some lock to prevent somebody from
-	   deleting the entry from under us */
-	deref=1; /* removed from one list =>  deref once */
-	/* remove it from the id hash if needed */
-	if (likely(e->l.next_id)){
-		UNLOCK_SCTP_ASSOC_H(h);
-		locked=0; /* no longer assoc-hash-locked */
-		/* we have a ref. to it so it's still safe to use e */
-		id_hash=get_sctp_con_id_hash(e->con.id);
-		LOCK_SCTP_ID_H(id_hash);
-			/* make sure nobody removed it in the meantime */
-			if (likely(e->l.next_id)){
-				clist_rm(e, l.next_id, l.prev_id);
-				e->l.next_id=e->l.prev_id=0; /* mark it as removed */
-				deref++; /* rm'ed from the id list => inc. delayed deref. */
-			}
-		UNLOCK_SCTP_ID_H(id_hash);
-	}
-#ifdef SCTP_ADDR_HASH
-	/* remove it from the addr. hash if needed */
-	if (likely(e->l.next_addr)){
-		if (unlikely(locked)){
-			UNLOCK_SCTP_ASSOC_H(h);
-			locked=0; /* no longer id-locked */
-		}
-		addr_h=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
-		LOCK_SCTP_ADDR_H(addr_h);
-			/* make sure nobody removed it in the meantime */
-			if (likely(e->l.next_addr)){
-				clist_rm(e, l.next_addr, l.prev_addr);
-				e->l.next_addr=e->l.prev_addr=0; /* mark it as removed */
-				deref++; /* rm'ed from the addr list => inc. delayed deref. */
-			}
-		UNLOCK_SCTP_ADDR_H(addr_h);
-	}
-#endif /* SCTP_ADDR_HASH */
-	if (atomic_add(&e->refcnt, -deref)==0){
-		atomic_dec(sctp_conn_tracked);
-		shm_free(e);
-	}
-	else
-		DBG("del assoc post-deref (kept): ser id %d, assoc_id %d,"
-				" post-refcnt %d, deref %d, post-tracked %d\n",
-				e->con.id, e->con.assoc_id, atomic_get(&e->refcnt), deref,
-				atomic_get(sctp_conn_tracked));
-	return locked;
-}
-
-
-
-#ifdef SCTP_ADDR_HASH
-/** helper internal del elem function, the addr hash must be locked.
-  * WARNING: the addr hash(h) _must_ be locked (LOCK_SCTP_ADDR_H(h)).
-  * @param h - addr hash
-  * @param e - sctp_con_elem to delete (from all the hashes)
-  * @return 0 if the addr hash was unlocked, 1 if it's still locked */
-inline static int _sctp_con_del_addr_locked(unsigned h,
-												struct sctp_con_elem* e)
-{
-	unsigned id_hash;
-	unsigned assoc_id_h;
-	int deref; /* delayed de-reference counter */
-	int locked;
-	
-	locked=1;
-	clist_rm(e, l.next_addr, l.prev_addr);
-	e->l.next_addr=e->l.prev_addr=0; /* mark it as addr unhashed */
-	/* delay atomic dereference, so that we'll perform only one
-	   atomic op. even for multiple derefs. It also has the
-	   nice side-effect that the entry will be guaranteed to be
-	   referenced until we perform the delayed deref. at the end,
-	   so we don't need to keep some lock to prevent somebody from
-	   deleting the entry from under us */
-	deref=1; /* removed from one list =>  deref once */
-	/* remove it from the id hash if needed */
-	if (likely(e->l.next_id)){
-		UNLOCK_SCTP_ADDR_H(h);
-		locked=0; /* no longer addr-hash-locked */
-		/* we have a ref. to it so it's still safe to use e */
-		id_hash=get_sctp_con_id_hash(e->con.id);
-		LOCK_SCTP_ID_H(id_hash);
-			/* make sure nobody removed it in the meantime */
-			if (likely(e->l.next_id)){
-				clist_rm(e, l.next_id, l.prev_id);
-				e->l.next_id=e->l.prev_id=0; /* mark it as removed */
-				deref++; /* rm'ed from the id list => inc. delayed deref. */
-			}
-		UNLOCK_SCTP_ID_H(id_hash);
-	}
-	/* remove it from the assoc hash if needed */
-	if (likely(e->l.next_assoc)){
-		if (locked){
-			UNLOCK_SCTP_ADDR_H(h);
-			locked=0; /* no longer addr-hash-locked */
-		}
-		/* we haven't dec. refcnt, so it's still safe to use e */
-		assoc_id_h=get_sctp_con_assoc_hash(e->con.assoc_id);
-		LOCK_SCTP_ASSOC_H(assoc_id_h);
-			/* make sure nobody removed it in the meantime */
-			if (likely(e->l.next_assoc)){
-				clist_rm(e, l.next_assoc, l.prev_assoc);
-				e->l.next_assoc=e->l.prev_assoc=0; /* mark it as removed */
-				deref++; /* rm'ed from the assoc list => inc. delayed deref. */
-			}
-		UNLOCK_SCTP_ASSOC_H(assoc_id_h);
-	}
-	if (atomic_add(&e->refcnt, -deref)==0){
-		atomic_dec(sctp_conn_tracked);
-		shm_free(e);
-	}
-	else
-		DBG("del assoc post-deref (kept): ser id %d, assoc_id %d,"
-				" post-refcnt %d, deref %d, post-tracked %d\n",
-				e->con.id, e->con.assoc_id, atomic_get(&e->refcnt), deref,
-				atomic_get(sctp_conn_tracked));
-	return locked;
-}
-#endif /* SCTP_ADDR_HASH */
-
-
-
-/** delete all tracked associations entries.
- */
-void sctp_con_tracking_flush()
-{
-	unsigned h;
-	struct sctp_con_elem* e;
-	struct sctp_con_elem* tmp;
-	
-	for (h=0; h<SCTP_ID_HASH_SIZE; h++){
-again:
-		LOCK_SCTP_ID_H(h);
-			clist_foreach_safe(&sctp_con_id_hash[h], e, tmp, l.next_id) {
-				if (_sctp_con_del_id_locked(h, e)==0){
-					/* unlocked, need to lock again and restart the list */
-					goto again;
-				}
-			}
-		UNLOCK_SCTP_ID_H(h);
-	}
-}
-
-
-
-/** using id, get the corresponding sctp assoc & socket. 
- *  @param id - ser unique assoc id
- *  @param si  - result parameter, filled with the socket info on success
- *  @param remote - result parameter, filled with the address and port
- *  @param del - if 1 delete the entry,
- *  @return assoc_id (!=0) on success & sets si, 0 on not found
- * si and remote will not be touched on failure.
- *
- */
-int sctp_con_get_assoc(unsigned int id, struct socket_info** si, 
-								union sockaddr_union *remote, int del)
-{
-	unsigned h;
-	ticks_t now; 
-	struct sctp_con_elem* e;
-	struct sctp_con_elem* tmp;
-	int ret;
-	
-	ret=0;
-	now=get_ticks_raw();
-	h=get_sctp_con_id_hash(id);
-#if 0
-again:
-#endif
-	LOCK_SCTP_ID_H(h);
-		clist_foreach_safe(&sctp_con_id_hash[h], e, tmp, l.next_id){
-			if(e->con.id==id){
-				ret=e->con.assoc_id;
-				*si=e->con.si;
-				*remote=e->con.remote;
-				if (del){
-					if (_sctp_con_del_id_locked(h, e)==0)
-						goto skip_unlock;
-				}else
-					e->con.expire=now +
-								S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
-				break;
-			}
-#if 0
-			else if (TICKS_LT(e->con.expire, now)){
-				WARN("sctp con: found expired assoc %d, id %d (%d s ago)\n",
-						e->con.assoc_id, e->con.id,
-						TICKS_TO_S(now-e->con.expire));
-				if (_sctp_con_del_id_locked(h, e)==0)
-					goto again; /* if unlocked need to restart the list */
-			}
-#endif
-		}
-	UNLOCK_SCTP_ID_H(h);
-skip_unlock:
-	return ret;
-}
-
-
-
-/** using the assoc_id, remote addr. & socket, get the corresp. internal id.
- *  @param assoc_id - sctp assoc id
- *  @param si  - socket on which the packet was received
- *  @param del - if 1 delete the entry,
- *  @return assoc_id (!=0) on success, 0 on not found
- */
-int sctp_con_get_id(unsigned int assoc_id, union sockaddr_union* remote,
-					struct socket_info* si, int del)
-{
-	unsigned h;
-	ticks_t now; 
-	struct sctp_con_elem* e;
-	struct sctp_con_elem* tmp;
-	int ret;
-	
-	ret=0;
-	now=get_ticks_raw();
-	h=get_sctp_con_assoc_hash(assoc_id);
-#if 0
-again:
-#endif
-	LOCK_SCTP_ASSOC_H(h);
-		clist_foreach_safe(&sctp_con_assoc_hash[h], e, tmp, l.next_assoc){
-			if(e->con.assoc_id==assoc_id && e->con.si==si &&
-					su_cmp(remote, &e->con.remote)){
-				ret=e->con.id;
-				if (del){
-					if (_sctp_con_del_assoc_locked(h, e)==0)
-						goto skip_unlock;
-				}else
-					e->con.expire=now +
-								S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
-				break;
-			}
-#if 0
-			else if (TICKS_LT(e->con.expire, now)){
-				WARN("sctp con: found expired assoc %d, id %d (%d s ago)\n",
-						e->con.assoc_id, e->con.id,
-						TICKS_TO_S(now-e->con.expire));
-				if (_sctp_con_del_assoc_locked(h, e)==0)
-					goto again; /* if unlocked need to restart the list */
-			}
-#endif
-		}
-	UNLOCK_SCTP_ASSOC_H(h);
-skip_unlock:
-	return ret;
-}
-
-
-
-#ifdef SCTP_ADDR_HASH
-/** using the dest. & source socket, get the corresponding id and assoc_id 
- *  @param remote   - peer address & port
- *  @param si       - local source socket
- *  @param assoc_id - result, filled with the sctp assoc_id
- *  @param del - if 1 delete the entry,
- *  @return ser id (!=0) on success, 0 on not found
- */
-int sctp_con_addr_get_id_assoc(union sockaddr_union* remote,
-								struct socket_info* si,
-								int* assoc_id, int del)
-{
-	unsigned h;
-	ticks_t now; 
-	struct sctp_con_elem* e;
-	struct sctp_con_elem* tmp;
-	int ret;
-	
-	ret=0;
-	*assoc_id=0;
-	now=get_ticks_raw();
-	h=get_sctp_con_addr_hash(remote, si);
-again:
-	LOCK_SCTP_ADDR_H(h);
-		clist_foreach_safe(&sctp_con_addr_hash[h], e, tmp, l.next_addr){
-			if(su_cmp(remote, &e->con.remote) && e->con.si==si){
-				ret=e->con.id;
-				*assoc_id=e->con.assoc_id;
-				if (del){
-					if (_sctp_con_del_addr_locked(h, e)==0)
-						goto skip_unlock;
-				}else
-					e->con.expire=now +
-								S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
-				break;
-			}
-#if 0
-			else if (TICKS_LT(e->con.expire, now)){
-				WARN("sctp con: found expired assoc %d, id %d (%d s ago)\n",
-						e->con.assoc_id, e->con.id,
-						TICKS_TO_S(now-e->con.expire));
-				if (_sctp_con_del_addr_locked(h, e)==0)
-					goto again; /* if unlocked need to restart the list */
-			}
-#endif
-		}
-	UNLOCK_SCTP_ADDR_H(h);
-skip_unlock:
-	return ret;
-}
-#endif /* SCTP_ADDR_HASH */
-
-
-
-/** del con tracking for (assod_id, si).
- * @return 0 on success, -1 on error (not found)
- */
-#define sctp_con_del_assoc(assoc_id, si) \
-	(-(sctp_con_get_id((assoc_id), (si), 1)==0))
-
-
-
-/** create a new sctp con elem.
-  * @param id - ser connection id
-  * @param assoc_id - sctp assoc id
-  * @param si - corresp. socket
-  * @param remote - remote side
-  * @return pointer to shm allocated sctp_con_elem on success, 0 on error
-  */
-struct sctp_con_elem* sctp_con_new(unsigned id, unsigned assoc_id, 
-									struct socket_info* si,
-									union sockaddr_union* remote)
-{
-	struct sctp_con_elem* e;
-	
-	e=shm_malloc(sizeof(*e));
-	if (unlikely(e==0))
-		goto error;
-	e->l.next_id=e->l.prev_id=0;
-	e->l.next_assoc=e->l.prev_assoc=0;
-	atomic_set(&e->refcnt, 0);
-	e->con.id=id;
-	e->con.assoc_id=assoc_id;
-	e->con.si=si;
-	e->con.flags=0;
-	if (likely(remote))
-		e->con.remote=*remote;
-	else
-		memset(&e->con.remote, 0, sizeof(e->con.remote));
-	e->con.start=get_ticks_raw();
-	e->con.expire=e->con.start +
-				S_TO_TICKS(cfg_get(sctp, sctp_cfg, autoclose));
-	return e;
-error:
-	return 0;
-}
-
-
-
-/** handles every ev on sctp assoc_id.
-  * @return ser id on success (!=0) or 0 on not found/error
-  */
-static int sctp_con_track(int assoc_id, struct socket_info* si,
-							union sockaddr_union* remote, int ev)
-{
-	int id;
-	unsigned hash;
-	unsigned assoc_hash;
-	struct sctp_con_elem* e;
-	struct sctp_con_elem* tmp;
-	
-	id=0;
-	DBG("sctp_con_track(%d, %p, %d) \n", assoc_id, si, ev);
-	
-	/* search for (assoc_id, si) */
-	assoc_hash=get_sctp_con_assoc_hash(assoc_id);
-	LOCK_SCTP_ASSOC_H(assoc_hash);
-		clist_foreach_safe(&sctp_con_assoc_hash[assoc_hash], e, tmp,
-								l.next_assoc){
-			/* we need to use the remote side address, because at least
-			   on linux assoc_id are immediately reused (even if sctp
-			   autoclose is off) and so it's possible that the association
-			   id we saved is already closed and assigned to another
-			   association by the time we search for it) */
-			if(e->con.assoc_id==assoc_id && e->con.si==si &&
-					su_cmp(remote, &e->con.remote)){
-				if (ev==SCTP_CON_DOWN_SEEN){
-					if (e->con.flags & SCTP_CON_UP_SEEN){
-						/* DOWN after UP => delete */
-						id=e->con.id;
-						/* do delete */
-						if (_sctp_con_del_assoc_locked(assoc_hash, e)==0)
-							goto found; /* skip unlock */
-					}else{
-						/* DOWN after DOWN => error
-						   DOWN after RCV w/ no UP -> not possible
-						    since we never create a tracking entry on RCV
-							only */
-						BUG("unexpected flags: %x for assoc_id %d, id %d"
-								", sctp con %p\n", e->con.flags, assoc_id,
-								e->con.id, e);
-						/* do delete */
-						if (_sctp_con_del_assoc_locked(assoc_hash, e)==0)
-							goto found; /* skip unlock */
-					}
-				}else if (ev==SCTP_CON_RCV_SEEN){
-					/* RCV after UP or DOWN => just mark RCV as seen */
-					id=e->con.id;
-					e->con.flags |= SCTP_CON_RCV_SEEN;
-				}else{
-					/* SCTP_CON_UP */
-					if (e->con.flags & SCTP_CON_DOWN_SEEN){
-						/* UP after DOWN => delete */
-						id=e->con.id;
-						/* do delete */
-						if (_sctp_con_del_assoc_locked(assoc_hash, e)==0)
-							goto found; /* skip unlock */
-					}else{
-						/* UP after UP or after RCVD => BUG */
-						BUG("connection with same assoc_id (%d) already"
-								" present, flags %x\n",
-								assoc_id, e->con.flags);
-					}
-				}
-				UNLOCK_SCTP_ASSOC_H(assoc_hash);
-				goto found;
-			}
-		}
-		/* not found */
-		if (unlikely(ev!=SCTP_CON_RCV_SEEN)){
-			/* UP or DOWN and no tracking entry => create new tracking entry
-			   for both of them (because we can have a re-ordered DOWN before
-			   the UP) */
-again:
-				id=atomic_add(sctp_id, 1);
-				if (unlikely(id==0)){
-					/* overflow  and 0 is not a valid id */
-					goto again;
-				}
-				e=sctp_con_new(id, assoc_id, si, remote);
-				if (likely(e)){
-					e->con.flags=ev;
-					e->l.next_id=e->l.prev_id=0;
-					e->l.next_assoc=e->l.prev_assoc=0;
-#ifdef SCTP_ADDR_HASH
-					e->l.next_addr=e->l.prev_addr=0;
-					e->refcnt.val+=3; /* account for the 3 lists */
-#else /* SCTP_ADDR_HASH */
-					e->refcnt.val+=2; /* account for the 2 lists */
-#endif /* SCTP_ADDR_HASH */
-					/* already locked */
-					clist_insert(&sctp_con_assoc_hash[assoc_hash], e,
-									l.next_assoc, l.prev_assoc);
-					hash=get_sctp_con_id_hash(e->con.id);
-					LOCK_SCTP_ID_H(hash);
-						clist_insert(&sctp_con_id_hash[hash], e,
-									l.next_id, l.prev_id);
-					UNLOCK_SCTP_ID_H(hash);
-#ifdef SCTP_ADDR_HASH
-					hash=get_sctp_con_addr_hash(&e->con.remote, e->con.si);
-					LOCK_SCTP_ADDR_H(hash);
-						clist_insert(&sctp_con_addr_hash[hash], e,
-									l.next_addr, l.prev_addr);
-					UNLOCK_SCTP_ADDR_H(hash);
-#endif /* SCTP_ADDR_HASH */
-					atomic_inc(sctp_conn_tracked);
-				}
-		} /* else not found and RCV -> ignore
-			 We cannot create a new entry because we don't know when to
-			 delete it (we can have UP DOWN RCV which would result in a
-			 tracking entry living forever). This means that if we receive
-			 a msg. on an assoc. before it's UP notification we won't know
-			 the id for connection reuse, but since happens very rarely it's
-			 an acceptable tradeoff */
-	UNLOCK_SCTP_ASSOC_H(assoc_hash);
-	if (unlikely(e==0)){
-		ERR("memory allocation failure\n");
-		goto error;
-	}
-found:
-	return id;
-error:
-	return 0;
-}
-
-
-
-#else /* SCTP_CONN_REUSE */
-void sctp_con_tracking_flush() {}
-#endif /* SCTP_CONN_REUSE */
-
-
-int init_sctp()
-{
-	int ret;
-	
-	ret=0;
-	if (INIT_SCTP_STATS()!=0){
-		ERR("sctp init: failed to intialize sctp stats\n");
-		goto error;
-	}
-	/* sctp options must be initialized before  calling this function */
-	sctp_conn_no=shm_malloc(sizeof(*sctp_conn_tracked));
-	if ( sctp_conn_no==0){
-		ERR("sctp init: memory allocation error\n");
-		ret=E_OUT_OF_MEM;
-		goto error;
-	}
-	atomic_set(sctp_conn_no, 0);
-#ifdef SCTP_CONN_REUSE
-	return init_sctp_con_tracking();
-#endif
-error:
-	return ret;
-}
-
-
-
-void destroy_sctp()
-{
-	if (sctp_conn_no){
-		shm_free(sctp_conn_no);
-		sctp_conn_no=0;
-	}
-#ifdef SCTP_CONN_REUSE
-	destroy_sctp_con_tracking();
-#endif
-	DESTROY_SCTP_STATS();
-}
-
-
-
-static int sctp_msg_send_ext(struct dest_info* dst, char* buf, unsigned len,
-						struct sctp_sndrcvinfo* sndrcv_info);
-#define SCTP_SEND_FIRST_ASSOCID 1  /* sctp_raw_send flag */
-static int sctp_raw_send(int socket, char* buf, unsigned len,
-						union sockaddr_union* to,
-						struct sctp_sndrcvinfo* sndrcv_info,
-						int flags);
-
-
-
-/* debugging: return a string name for SCTP_ASSOC_CHANGE state */
-static char* sctp_assoc_change_state2s(short int state)
-{
-	char* s;
-	
-	switch(state){
-		case SCTP_COMM_UP:
-			s="SCTP_COMM_UP";
-			break;
-		case SCTP_COMM_LOST:
-			s="SCTP_COMM_LOST";
-			break;
-		case SCTP_RESTART:
-			s="SCTP_RESTART";
-			break;
-		case SCTP_SHUTDOWN_COMP:
-			s="SCTP_SHUTDOWN_COMP";
-			break;
-		case SCTP_CANT_STR_ASSOC:
-			s="SCTP_CANT_STR_ASSOC";
-			break;
-		default:
-			s="UNKNOWN";
-			break;
-	};
-	return s;
-}
-
-
-
-/* debugging: return a string name for a SCTP_PEER_ADDR_CHANGE state */
-static char* sctp_paddr_change_state2s(unsigned int state)
-{
-	char* s;
-	
-	switch (state){
-		case SCTP_ADDR_AVAILABLE:
-			s="SCTP_ADDR_AVAILABLE";
-			break;
-		case SCTP_ADDR_UNREACHABLE:
-			s="SCTP_ADDR_UNREACHABLE";
-			break;
-		case SCTP_ADDR_REMOVED:
-			s="SCTP_ADDR_REMOVED";
-			break;
-		case SCTP_ADDR_ADDED:
-			s="SCTP_ADDR_ADDED";
-			break;
-		case SCTP_ADDR_MADE_PRIM:
-			s="SCTP_ADDR_MADE_PRIM";
-			break;
-	/* not supported by lksctp 1.0.6 
-		case SCTP_ADDR_CONFIRMED:
-			s="SCTP_ADDR_CONFIRMED";
-			break;
-	*/
-		default:
-			s="UNKNOWN";
-			break;
-	}
-	return s;
-}
-
-
-
-/* handle SCTP_SEND_FAILED notifications: if packet marked for retries
- * retry the send (with 0 assoc_id)
- * returns 0 on success, -1 on failure
- */
-static int sctp_handle_send_failed(struct socket_info* si,
-									union sockaddr_union* su,
-									char* buf, unsigned len)
-{
-	union sctp_notification* snp;
-	struct sctp_sndrcvinfo sinfo;
-	struct dest_info dst;
-	char* data;
-	unsigned data_len;
-	int retries;
-	int ret;
-#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
-	int send_ttl;
-#endif
-	
-	ret=-1;
-	SCTP_STATS_SEND_FAILED();
-	snp=(union sctp_notification*) buf;
-	retries=snp->sn_send_failed.ssf_info.sinfo_context;
-	
-	/* don't retry on explicit remote error
-	 * (unfortunately we can't be more picky than this, we get no 
-	 * indication in the SEND_FAILED notification for other error
-	 * reasons (e.g. ABORT received, INIT timeout a.s.o)
-	 */
-	if (retries && (snp->sn_send_failed.ssf_error==0)) {
-		DBG("sctp: RETRY-ing (%d)\n", retries);
-		SCTP_STATS_SEND_FORCE_RETRY();
-		retries--;
-		data=(char*)snp->sn_send_failed.ssf_data;
-		data_len=snp->sn_send_failed.ssf_length - 
-					sizeof(struct sctp_send_failed);
-		
-		memset(&sinfo, 0, sizeof(sinfo));
-		sinfo.sinfo_flags=SCTP_UNORDERED;
-#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
-		if ((send_ttl=cfg_get(sctp, sctp_cfg, send_ttl))){
-			sinfo.sinfo_pr_policy=SCTP_PR_SCTP_TTL;
-			sinfo.sinfo_pr_value=send_ttl;
-		}else
-			sinfo.info_pr_policy=SCTP_PR_SCTP_NONE;
-#else
-		sinfo.sinfo_timetolive=cfg_get(sctp, sctp_cfg, send_ttl);
-#endif
-		sinfo.sinfo_context=retries;
-		
-		dst.to=*su;
-		dst.send_sock=si;
-		dst.id=0;
-		dst.proto=PROTO_SCTP;
-#ifdef USE_COMP
-		dst.comp=COMP_NONE;
-#endif
-		
-		ret=sctp_msg_send_ext(&dst, data, data_len, &sinfo);
-	}
-#ifdef USE_DST_BLACKLIST
-	 else if (cfg_get(sctp, sctp_cfg, send_retries)) {
-		/* blacklist only if send_retries is on, if off we blacklist
-		   from SCTP_ASSOC_CHANGE: SCTP_COMM_LOST/SCTP_CANT_STR_ASSOC
-		   which is better (because we can tell connect errors from send
-		   errors and we blacklist a failed dst only once) */
-		dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
-	}
-#endif /* USE_DST_BLACKLIST */
-	
-	return (ret>0)?0:ret;
-}
-
-
-
-/* handle SCTP_ASOC_CHANGE notifications: map ser global sctp ids
- * to kernel asoc_ids. The global ids are needed because the kernel ones
- * might get reused after a close and so they are not unique for ser's
- * lifetime. We need a unique id to match replies to the association on
- * which we received the corresponding request (so that we can send them
- * back on the same asoc & socket if still opened).
- * returns 0 on success, -1 on failure
- */
-static int sctp_handle_assoc_change(struct socket_info* si,
-									union sockaddr_union* su,
-									union sctp_notification* snp
-									)
-{
-	int ret;
-	int state;
-	int assoc_id;
-	struct sctp_sndrcvinfo sinfo;
-	struct ip_addr ip; /* used only on error, for debugging */
-	
-	state=snp->sn_assoc_change.sac_state;
-	assoc_id=snp->sn_assoc_change.sac_assoc_id;
-	
-	ret=-1;
-	switch(state){
-		case SCTP_COMM_UP:
-			SCTP_STATS_ESTABLISHED();
-			atomic_inc(sctp_conn_no);
-#ifdef SCTP_CONN_REUSE
-			/* new connection, track it */
-			if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking)))
-					sctp_con_track(assoc_id, si, su, SCTP_CON_UP_SEEN);
-#if 0
-again:
-			id=atomic_add(sctp_id, 1);
-			if (unlikely(id==0)){
-				/* overflow  and 0 is not a valid id */
-				goto again;
-			}
-			e=sctp_con_new(id, assoc_id, si, su);
-			if (unlikely(e==0)){
-				ERR("memory allocation failure\n");
-			}else{
-				sctp_con_add(e);
-				ret=0;
-			}
-#endif
-#endif /* SCTP_CONN_REUSE */
-			if (unlikely((unsigned)atomic_get(sctp_conn_no) >
-							(unsigned)cfg_get(sctp, sctp_cfg, max_assocs))){
-				/* maximum assoc exceeded => we'll have to immediately 
-				   close it */
-				memset(&sinfo, 0, sizeof(sinfo));
-				sinfo.sinfo_flags=SCTP_UNORDERED | SCTP_ABORT;
-				sinfo.sinfo_assoc_id=assoc_id;
-				ret=sctp_raw_send(si->socket, ABORT_REASON_MAX_ASSOCS,
-											sizeof(ABORT_REASON_MAX_ASSOCS)-1,
-											su, &sinfo, 0);
-				if (ret<0){
-					su2ip_addr(&ip, su);
-					WARN("failed to ABORT new sctp association %d (%s:%d):"
-							" %s (%d)\n", assoc_id, ip_addr2a(&ip),
-							su_getport(su), strerror(errno), errno);
-				}else{
-					SCTP_STATS_LOCAL_REJECT();
-				}
-			}
-			break;
-		case SCTP_COMM_LOST:
-			SCTP_STATS_COMM_LOST();
-#ifdef USE_DST_BLACKLIST
-			/* blacklist only if send_retries is turned off (if on we don't
-			   know here if we did retry or we are at the first error) */
-			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
-						dst_blacklist_su(BLST_ERR_SEND, PROTO_SCTP, su, 0, 0);
-#endif /* USE_DST_BLACKLIST */
-			/* no break */
-			goto comm_lost_cont;	/* do not increment counters for
-									   SCTP_SHUTDOWN_COMP */
-		case SCTP_SHUTDOWN_COMP:
-			SCTP_STATS_ASSOC_SHUTDOWN();
-comm_lost_cont:
-			atomic_dec(sctp_conn_no);
-#ifdef SCTP_CONN_REUSE
-			/* connection down*/
-			if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking)))
-				sctp_con_track(assoc_id, si, su, SCTP_CON_DOWN_SEEN);
-#if 0
-			if (unlikely(sctp_con_del_assoc(assoc_id, si)!=0))
-				WARN("sctp con: tried to remove inexistent connection\n");
-			else
-				ret=0;
-#endif
-#endif /* SCTP_CONN_REUSE */
-			break;
-		case SCTP_RESTART:
-			/* do nothing on restart */
-			break;
-		case SCTP_CANT_STR_ASSOC:
-			SCTP_STATS_CONNECT_FAILED();
-			/* do nothing when failing to start an assoc
-			  (in this case we never see SCTP_COMM_UP so we never 
-			  track the assoc) */
-#ifdef USE_DST_BLACKLIST
-			/* blacklist only if send_retries is turned off (if on we don't 
-			   know here if we did retry or we are at the first error) */
-			if (cfg_get(sctp, sctp_cfg, send_retries)==0)
-					dst_blacklist_su(BLST_ERR_CONNECT, PROTO_SCTP, su, 0, 0);
-#endif /* USE_DST_BLACKLIST */
-			break;
-		default:
-			break;
-	}
-	return ret;
-}
-
-
-
-static int sctp_handle_notification(struct socket_info* si,
-									union sockaddr_union* su,
-									char* buf, unsigned len)
-{
-	union sctp_notification* snp;
-	char su_buf[SU2A_MAX_STR_SIZE];
-	
-	#define SNOT DBG
-	#define ERR_LEN_TOO_SMALL(length, val, bind_addr, from_su, text) \
-		if (unlikely((length)<(val))){\
-			SNOT("ERROR: sctp notification from %s on %.*s:%d: " \
-						text " too short (%d bytes instead of %d bytes)\n", \
-						su2a((from_su), sizeof(*(from_su))), \
-						(bind_addr)->name.len, (bind_addr)->name.s, \
-						(bind_addr)->port_no, (int)(length), (int)(val)); \
-			goto error; \
-		}
-
-	if (len < sizeof(snp->sn_header)){
-		LOG(L_ERR, "ERROR: sctp_handle_notification: invalid length %d "
-					"on %.*s:%d, from %s\n",
-					len, si->name.len, si->name.s, si->port_no,
-					su2a(su, sizeof(*su)));
-		goto error;
-	}
-	snp=(union sctp_notification*) buf;
-	switch(snp->sn_header.sn_type){
-		case SCTP_REMOTE_ERROR:
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_remote_error), si, su,
-								"SCTP_REMOTE_ERROR");
-			SCTP_EV_REMOTE_ERROR(&si->address, si->port_no, su, 
-									ntohs(snp->sn_remote_error.sre_error) );
-			SNOT("sctp notification from %s on %.*s:%d: SCTP_REMOTE_ERROR:"
-					" %d, len %d\n, assoc_id %d",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no,
-					ntohs(snp->sn_remote_error.sre_error),
-					ntohs(snp->sn_remote_error.sre_length),
-					snp->sn_remote_error.sre_assoc_id
-				);
-			break;
-		case SCTP_SEND_FAILED:
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_send_failed), si, su,
-								"SCTP_SEND_FAILED");
-			SCTP_EV_SEND_FAILED(&si->address, si->port_no, su, 
-									snp->sn_send_failed.ssf_error);
-			SNOT("sctp notification from %s on %.*s:%d: SCTP_SEND_FAILED:"
-					" error %d, assoc_id %d, flags %x\n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no, snp->sn_send_failed.ssf_error,
-					snp->sn_send_failed.ssf_assoc_id,
-					snp->sn_send_failed.ssf_flags);
-			sctp_handle_send_failed(si, su, buf, len);
-			break;
-		case SCTP_PEER_ADDR_CHANGE:
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_paddr_change), si, su,
-								"SCTP_PEER_ADDR_CHANGE");
-			SCTP_EV_PEER_ADDR_CHANGE(&si->address, si->port_no, su, 
-					sctp_paddr_change_state2s(snp->sn_paddr_change.spc_state),
-					snp->sn_paddr_change.spc_state,
-					&snp->sn_paddr_change.spc_aaddr);
-			strcpy(su_buf, su2a((union sockaddr_union*)
-									&snp->sn_paddr_change.spc_aaddr, 
-									sizeof(snp->sn_paddr_change.spc_aaddr)));
-			SNOT("sctp notification from %s on %.*s:%d: SCTP_PEER_ADDR_CHANGE"
-					": %s: %s: assoc_id %d \n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no, su_buf,
-					sctp_paddr_change_state2s(snp->sn_paddr_change.spc_state),
-					snp->sn_paddr_change.spc_assoc_id
-					);
-			break;
-		case SCTP_SHUTDOWN_EVENT:
-			SCTP_STATS_REMOTE_SHUTDOWN();
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_shutdown_event), si, su,
-								"SCTP_SHUTDOWN_EVENT");
-			SCTP_EV_SHUTDOWN_EVENT(&si->address, si->port_no, su);
-			SNOT("sctp notification from %s on %.*s:%d: SCTP_SHUTDOWN_EVENT:"
-					" assoc_id %d\n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no, snp->sn_shutdown_event.sse_assoc_id);
-			break;
-		case SCTP_ASSOC_CHANGE:
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_assoc_change), si, su,
-								"SCTP_ASSOC_CHANGE");
-			SCTP_EV_ASSOC_CHANGE(&si->address, si->port_no, su, 
-					sctp_assoc_change_state2s(snp->sn_assoc_change.sac_state),
-					snp->sn_assoc_change.sac_state);
-			SNOT("sctp notification from %s on %.*s:%d: SCTP_ASSOC_CHANGE"
-					": %s: assoc_id %d, ostreams %d, istreams %d\n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no,
-					sctp_assoc_change_state2s(snp->sn_assoc_change.sac_state),
-					snp->sn_assoc_change.sac_assoc_id,
-					snp->sn_assoc_change.sac_outbound_streams,
-					snp->sn_assoc_change.sac_inbound_streams
-					);
-			sctp_handle_assoc_change(si, su, snp);
-			break;
-#ifdef SCTP_ADAPTION_INDICATION
-		case SCTP_ADAPTION_INDICATION:
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_adaption_event), si, su,
-								"SCTP_ADAPTION_INDICATION");
-			SNOT("sctp notification from %s on %.*s:%d: "
-					"SCTP_ADAPTION_INDICATION \n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no);
-			break;
-#endif /* SCTP_ADAPTION_INDICATION */
-		case SCTP_PARTIAL_DELIVERY_EVENT:
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_pdapi_event), si, su,
-								"SCTP_PARTIAL_DELIVERY_EVENT");
-			ERR("sctp notification from %s on %.*s:%d: "
-					"SCTP_PARTIAL_DELIVERY_EVENT not supported: %d %s,"
-					"assoc_id %d\n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no, snp->sn_pdapi_event.pdapi_indication,
-					(snp->sn_pdapi_event.pdapi_indication==
-					 	SCTP_PARTIAL_DELIVERY_ABORTED)? " PD ABORTED":"",
-					snp->sn_pdapi_event.pdapi_assoc_id);
-			break;
-#ifdef SCTP_SENDER_DRY_EVENT /* new, not yet supported */
-		case SCTP_SENDER_DRY_EVENT:
-			ERR_LEN_TOO_SMALL(len, sizeof(struct sctp_sender_dry_event),
-								si, su, "SCTP_SENDER_DRY_EVENT");
-			SCTP_EV_REMOTE_ERROR(&si->address, si->port_no, su);
-			SNOT("sctp notification from %s on %.*s:%d: "
-					"SCTP_SENDER_DRY_EVENT on %d\n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no, snp->sn_sender_dry_event.sender_dry_assoc_id);
-			break;
-#endif /* SCTP_SENDER_DRY_EVENT */
-		default:
-			SNOT("sctp notification from %s on %.*s:%d: UNKNOWN (%d)\n",
-					su2a(su, sizeof(*su)), si->name.len, si->name.s,
-					si->port_no, snp->sn_header.sn_type);
-	}
-	return 0;
-error:
-	return -1;
-	#undef ERR_LEN_TOO_SMALL
-}
-
-
-
-int sctp_rcv_loop()
-{
-	unsigned len;
-	static char buf [BUF_SIZE+1];
-	char *tmp;
-	struct receive_info ri;
-	struct sctp_sndrcvinfo* sinfo;
-	struct msghdr msg;
-	struct iovec iov[1];
-	struct cmsghdr* cmsg;
-	/* use a larger buffer then needed in case some other ancillary info
-	 * is enabled */
-	char cbuf[CMSG_SPACE(sizeof(*sinfo))+CMSG_SPACE(1024)];
-
-	
-	ri.bind_address=bind_address; /* this will not change */
-	ri.dst_port=bind_address->port_no;
-	ri.dst_ip=bind_address->address;
-	ri.proto=PROTO_SCTP;
-	ri.proto_reserved2=0;
-	
-	iov[0].iov_base=buf;
-	iov[0].iov_len=BUF_SIZE;
-	msg.msg_iov=iov;
-	msg.msg_iovlen=1;
-	msg.msg_flags=0;
-	
-
-	/* initialize the config framework */
-	if (cfg_child_init()) goto error;
-	
-	for(;;){
-		msg.msg_name=&ri.src_su.s;
-		msg.msg_namelen=sockaddru_len(bind_address->su);
-		msg.msg_control=cbuf;
-		msg.msg_controllen=sizeof(cbuf);
-		sinfo=0;
-
-		len=recvmsg(bind_address->socket, &msg, 0);
-		if (len==-1){
-			if (errno==EAGAIN){
-				DBG("sctp_rcv_loop: EAGAIN on sctp socket\n");
-				continue;
-			}
-			LOG(L_ERR, "ERROR: sctp_rcv_loop: sctp_recvmsg on %d (%p):"
-						"[%d] %s\n", bind_address->socket, bind_address,
-						errno, strerror(errno));
-			if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
-				continue; /* goto skip;*/
-			else goto error;
-		}
-		/* update the local config */
-		cfg_update();
-		
-		if (unlikely(msg.msg_flags & MSG_NOTIFICATION)){
-			/* intercept useful notifications */
-			sctp_handle_notification(bind_address, &ri.src_su, buf, len);
-			continue;
-		}else if (unlikely(!(msg.msg_flags & MSG_EOR))){
-			LOG(L_ERR, "ERROR: sctp_rcv_loop: partial delivery not"
-						"supported\n");
-			continue;
-		}
-		
-		su2ip_addr(&ri.src_ip, &ri.src_su);
-		ri.src_port=su_getport(&ri.src_su);
-		
-		/* get ancillary data */
-		for (cmsg=CMSG_FIRSTHDR(&msg); cmsg; cmsg=CMSG_NXTHDR(&msg, cmsg)){
-#ifdef SCTP_EXT
-			if (likely((cmsg->cmsg_level==IPPROTO_SCTP) &&
-						((cmsg->cmsg_type==SCTP_SNDRCV)
-						 || (cmsg->cmsg_type==SCTP_EXTRCV)
-						) && (cmsg->cmsg_len>=CMSG_LEN(sizeof(*sinfo)))) )
-#else  /* !SCTP_EXT -- same as above but w/o SCTP_EXTRCV */
-			if (likely((cmsg->cmsg_level==IPPROTO_SCTP) &&
-						((cmsg->cmsg_type==SCTP_SNDRCV)
-						) && (cmsg->cmsg_len>=CMSG_LEN(sizeof(*sinfo)))) )
-#endif /*SCTP_EXT */
-			{
-				sinfo=(struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
-				DBG("sctp recv: message from %s:%d stream %d  ppid %x"
-						" flags %x%s tsn %u" " cumtsn %u assoc_id %d\n",
-						ip_addr2a(&ri.src_ip), ri.src_port,
-						sinfo->sinfo_stream, sinfo->sinfo_ppid,
-						sinfo->sinfo_flags,
-						(sinfo->sinfo_flags&SCTP_UNORDERED)?
-							" (SCTP_UNORDERED)":"",
-						sinfo->sinfo_tsn, sinfo->sinfo_cumtsn, 
-						sinfo->sinfo_assoc_id);
-				break;
-			}
-		}
-		/* we  0-term the messages for debugging */
-		buf[len]=0; /* no need to save the previous char */
-
-		/* sanity checks */
-		if (len<MIN_SCTP_PACKET) {
-			tmp=ip_addr2a(&ri.src_ip);
-			DBG("sctp_rcv_loop: probing packet received from %s:%d\n",
-					tmp, ri.src_port);
-			continue;
-		}
-		if (ri.src_port==0){
-			tmp=ip_addr2a(&ri.src_ip);
-			LOG(L_INFO, "sctp_rcv_loop: dropping 0 port packet from %s:0\n",
-						tmp);
-			continue;
-		}
-#ifdef USE_COMP
-		ri.comp=COMP_NONE;
-#endif
-#ifdef SCTP_CONN_REUSE
-		if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking) && sinfo)){
-			ri.proto_reserved1 = sctp_con_track(sinfo->sinfo_assoc_id,
-												ri.bind_address, 
-												&ri.src_su,
-												SCTP_CON_RCV_SEEN);
-			/* debugging */
-			if (unlikely(ri.proto_reserved1==0))
-				DBG("no tracked assoc. found for assoc_id %d, from %s\n",
-						sinfo->sinfo_assoc_id, 
-						su2a(&ri.src_su, sizeof(ri.src_su)));
-#if 0
-			ri.proto_reserved1=
-				sctp_con_get_id(sinfo->sinfo_assoc_id, ri.bind_address, 0);
-#endif
-		}else
-			ri.proto_reserved1=0;
-#else /* SCTP_CONN_REUSE */
-		ri.proto_received1=0;
-#endif /* SCTP_CONN_REUSE */
-		receive_msg(buf, len, &ri);
-	}
-error:
-	return -1;
-}
-
-
-
-/** low level sctp non-blocking send.
- * @param socket - sctp socket to send on.
- * @param buf   - data.
- * @param len   - lenght of the data.
- * @param to    - destination in ser sockaddr_union format.
- * @param sndrcv_info - sctp_sndrcvinfo structure pointer, pre-filled.
- * @param flags - can have one of the following values (or'ed):
- *                SCTP_SEND_FIRST_ASSOCID - try to send first to assoc_id
- *                and only if that fails use "to".
- * @return the numbers of bytes sent on success (>=0) and -1 on error.
- * On error errno is set too.
- */
-static int sctp_raw_send(int socket, char* buf, unsigned len,
-						union sockaddr_union* to,
-						struct sctp_sndrcvinfo* sndrcv_info,
-						int flags)
-{
-	int n;
-	int tolen;
-	int try_assoc_id;
-#if 0
-	struct ip_addr ip; /* used only on error, for debugging */
-#endif
-	struct msghdr msg;
-	struct iovec iov[1];
-	struct sctp_sndrcvinfo* sinfo;
-	struct cmsghdr* cmsg;
-	/* make sure msg_control will point to properly aligned data */
-	union {
-		struct cmsghdr cm;
-		char cbuf[CMSG_SPACE(sizeof(*sinfo))];
-	}ctrl_un;
-	
-	iov[0].iov_base=buf;
-	iov[0].iov_len=len;
-	msg.msg_iov=iov;
-	msg.msg_iovlen=1;
-	msg.msg_flags=0; /* not used on send (use instead sinfo_flags) */
-	msg.msg_control=ctrl_un.cbuf;
-	msg.msg_controllen=sizeof(ctrl_un.cbuf);
-	cmsg=CMSG_FIRSTHDR(&msg);
-	cmsg->cmsg_level=IPPROTO_SCTP;
-	cmsg->cmsg_type=SCTP_SNDRCV;
-	cmsg->cmsg_len=CMSG_LEN(sizeof(*sinfo));
-	sinfo=(struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
-	*sinfo=*sndrcv_info;
-	/* some systems need msg_controllen set to the actual size and not
-	 * something bigger (e.g. openbsd) */
-	msg.msg_controllen=cmsg->cmsg_len;
-	try_assoc_id= ((flags & SCTP_SEND_FIRST_ASSOCID) && sinfo->sinfo_assoc_id);
-	/* if assoc_id is set it means we want to send on association assoc_id
-	   and only if it's not opened any longer use the addresses */
-	if (try_assoc_id){
-		/* on linux msg->name has priority over assoc_id. To try first assoc_id
-		 * and then "to", one has to call first sendmsg() with msg->name==0 and
-		 * sinfo->assoc_id set. If it returns EPIPE => association is no longer
-		 * open => call again sendmsg() this time with msg->name!=0.
-		 * on freebsd assoc_id has priority over msg->name and moreover the
-		 * send falls back automatically to the address if the assoc_id is
-		 * closed, so a single call to sendmsg(msg->name, sinfo->assoc_id ) is
-		 * enough.  If one tries calling with msg->name==0 and the association
-		 * is no longer open send will return ENOENT.
-		 * on solaris it seems one must always use a dst address (assoc_id
-		 * will be ignored).
-		 */
-#ifdef __OS_linux
-		msg.msg_name=0;
-		msg.msg_namelen=0;
-#elif defined __OS_freebsd
-		tolen=sockaddru_len(*to);
-		msg.msg_name=&to->s;
-		msg.msg_namelen=tolen;
-#else /* __OS_* */
-		/* fallback for solaris and others, sent back to
-		  the address recorded (not exactly what we want, but there's
-		  no way to fallback to "to") */
-		tolen=sockaddru_len(*to);
-		msg.msg_name=&to->s;
-		msg.msg_namelen=tolen;
-#endif /* __OS_* */
-	}else{
-		tolen=sockaddru_len(*to);
-		msg.msg_name=&to->s;
-		msg.msg_namelen=tolen;
-	}
-	
-again:
-	n=sendmsg(socket, &msg, MSG_DONTWAIT);
-	if (n==-1){
-#ifdef __OS_linux
-		if ((errno==EPIPE) && try_assoc_id){
-			/* try again, this time with null assoc_id and non-null msg.name */
-			DBG("sctp raw sendmsg: assoc already closed (EPIPE), retrying with"
-					" assoc_id=0\n");
-			tolen=sockaddru_len(*to);
-			msg.msg_name=&to->s;
-			msg.msg_namelen=tolen;
-			sinfo->sinfo_assoc_id=0;
-			try_assoc_id=0;
-			goto again;
-		}
-#elif defined __OS_freebsd
-		if ((errno==ENOENT)){
-			/* it didn't work, no retrying */
-			WARN("unexpected sendmsg() failure (ENOENT),"
-					" assoc_id %d\n", sinfo->sinfo_assoc_id);
-		}
-#else /* __OS_* */
-		if ((errno==ENOENT || errno==EPIPE) && try_assoc_id){
-			/* in case the sctp stack prioritises assoc_id over msg->name,
-			   try again with 0 assoc_id and msg->name set to "to" */
-			WARN("unexpected ENOENT or EPIPE (assoc_id %d),"
-					"trying automatic recovery... (please report along with"
-					"your OS version)\n", sinfo->sinfo_assoc_id);
-			tolen=sockaddru_len(*to);
-			msg.msg_name=&to->s;
-			msg.msg_namelen=tolen;
-			sinfo->sinfo_assoc_id=0;
-			try_assoc_id=0;
-			goto again;
-		}
-#endif /* __OS_* */
-#if 0
-		if (errno==EINTR) goto again;
-		su2ip_addr(&ip, to);
-		LOG(L_ERR, "ERROR: sctp_raw_send: sendmsg(sock,%p,%d,0,%s:%d,...):"
-				" %s(%d)\n", buf, len, ip_addr2a(&ip), su_getport(to),
-				strerror(errno), errno);
-		if (errno==EINVAL) {
-			LOG(L_CRIT,"CRITICAL: invalid sendmsg parameters\n"
-			"one possible reason is the server is bound to localhost and\n"
-			"attempts to send to the net\n");
-		}else if (errno==EAGAIN || errno==EWOULDBLOCK){
-			SCTP_STATS_SENDQ_FULL();
-			LOG(L_ERR, "ERROR: sctp_msg_send: failed to send, send buffers"
-						" full\n");
-		}
-#endif
-	}
-	return n;
-}
-
-
-
-/* send buf:len over sctp to dst using sndrcv_info (uses send_sock,
- * to and id from dest_info)
- * returns the numbers of bytes sent on success (>=0) and -1 on error
- */
-static int sctp_msg_send_ext(struct dest_info* dst, char* buf, unsigned len,
-						struct sctp_sndrcvinfo* sndrcv_info)
-{
-	int n;
-	int tolen;
-	struct ip_addr ip; /* used only on error, for debugging */
-	struct msghdr msg;
-	struct iovec iov[1];
-	struct socket_info* si;
-	struct sctp_sndrcvinfo* sinfo;
-	struct cmsghdr* cmsg;
-	/* make sure msg_control will point to properly aligned data */
-	union {
-		struct cmsghdr cm;
-		char cbuf[CMSG_SPACE(sizeof(*sinfo))];
-	}ctrl_un;
-#ifdef SCTP_CONN_REUSE
-	int assoc_id;
-	union sockaddr_union to;
-#ifdef SCTP_ADDR_HASH
-	int tmp_id, tmp_assoc_id;
-#endif /* SCTP_ADDR_HASH */
-#endif /* SCTP_CONN_REUSE */
-	
-	iov[0].iov_base=buf;
-	iov[0].iov_len=len;
-	msg.msg_iov=iov;
-	msg.msg_iovlen=1;
-	msg.msg_flags=0; /* not used on send (use instead sinfo_flags) */
-	msg.msg_control=ctrl_un.cbuf;
-	msg.msg_controllen=sizeof(ctrl_un.cbuf);
-	cmsg=CMSG_FIRSTHDR(&msg);
-	cmsg->cmsg_level=IPPROTO_SCTP;
-	cmsg->cmsg_type=SCTP_SNDRCV;
-	cmsg->cmsg_len=CMSG_LEN(sizeof(*sinfo));
-	sinfo=(struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
-	*sinfo=*sndrcv_info;
-	/* some systems need msg_controllen set to the actual size and not
-	 * something bigger (e.g. openbsd) */
-	msg.msg_controllen=cmsg->cmsg_len;
-	si=dst->send_sock;
-#ifdef SCTP_CONN_REUSE
-	/* if dst->id is set it means we want to send on association with
-	   ser id dst->id if still opened and only if closed use dst->to */
-	assoc_id=0;
-	if ((dst->id) && cfg_get(sctp, sctp_cfg, assoc_reuse) &&
-			cfg_get(sctp, sctp_cfg, assoc_tracking) &&
-			(assoc_id=sctp_con_get_assoc(dst->id, &si, &to, 0))){
-		DBG("sctp: sending on sctp assoc_id %d (ser id %d)\n",
-				assoc_id, dst->id);
-		sinfo->sinfo_assoc_id=assoc_id;
-		/* on linux msg->name has priority over assoc_id. To try first assoc_id
-		 * and then dst, one has to call first sendmsg() with msg->name==0 and
-		 * sinfo->assoc_id set. If it returns EPIPE => association is no longer
-		 * open => call again sendmsg() this time with msg->name!=0.
-		 * on freebsd assoc_id has priority over msg->name and moreover the
-		 * send falls back automatically to the address if the assoc_id is
-		 * closed, so a single call to sendmsg(msg->name, sinfo->assoc_id ) is
-		 * enough.  If one tries calling with msg->name==0 and the association
-		 * is no longer open send will return ENOENT.
-		 * on solaris it seems one must always use a dst address (assoc_id
-		 * will be ignored).
-		 */
-#ifdef __OS_linux
-		DBG("sctp: linux: trying with 0 msg_name\n");
-		msg.msg_name=0;
-		msg.msg_namelen=0;
-#elif defined __OS_freebsd
-		tolen=sockaddru_len(dst->to);
-		msg.msg_name=&dst->to.s;
-		msg.msg_namelen=tolen;
-#else /* __OS_* */
-		/* fallback for solaris and others, sent back to
-		  the address recorded (not exactly what we want, but there's 
-		  no way to fallback to dst->to) */
-		tolen=sockaddru_len(dst->to);
-		msg.msg_name=&dst->to.s;
-		msg.msg_namelen=tolen;
-#endif /* __OS_* */
-	}else{
-#ifdef SCTP_ADDR_HASH
-		/* update timeout for the assoc identified  by (dst->to, dst->si) */
-		if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking))){
-			tmp_id=sctp_con_addr_get_id_assoc(&dst->to, dst->send_sock,
-												&tmp_assoc_id, 0);
-			DBG("sctp send: timeout updated ser id %d, sctp assoc_id %d\n",
-					tmp_id, tmp_assoc_id);
-			if (tmp_id==0 /* not tracked/found */ &&
-					(unsigned)atomic_get(sctp_conn_tracked) >=
-						(unsigned)cfg_get(sctp, sctp_cfg, max_assocs)){
-				ERR("maximum number of sctp associations exceeded\n");
-				goto error;
-			}
-		}
-#endif /* SCTP_ADDR_HASH */
-		tolen=sockaddru_len(dst->to);
-		msg.msg_name=&dst->to.s;
-		msg.msg_namelen=tolen;
-	}
-#else /* SCTP_CONN_REUSE */
-	tolen=sockaddru_len(dst->to);
-	msg.msg_name=&dst->to.s;
-	msg.msg_namelen=tolen;
-#endif /* SCTP_CONN_REUSE */
-
-again:
-	n=sendmsg(si->socket, &msg, MSG_DONTWAIT);
-	if (n==-1){
-#ifdef SCTP_CONN_REUSE
-#ifdef __OS_linux
-		if ((errno==EPIPE) && assoc_id){
-			/* try again, this time with null assoc_id and non-null msg.name */
-			DBG("sctp sendmsg: assoc already closed (EPIPE), retrying with"
-					" assoc_id=0\n");
-			tolen=sockaddru_len(dst->to);
-			msg.msg_name=&dst->to.s;
-			msg.msg_namelen=tolen;
-			sinfo->sinfo_assoc_id=0;
-			goto again;
-		}
-#elif defined __OS_freebsd
-		if ((errno==ENOENT)){
-			/* it didn't work, no retrying */
-			WARN("sctp sendmsg: unexpected sendmsg() failure (ENOENT),"
-					" assoc_id %d\n", assoc_id);
-		}
-#else /* __OS_* */
-		if ((errno==ENOENT || errno==EPIPE) && assoc_id){
-			/* in case the sctp stack prioritises assoc_id over msg->name,
-			   try again with 0 assoc_id and msg->name set to dst->to */
-			WARN("sctp sendmsg: unexpected ENOENT or EPIPE (assoc_id %d),"
-					"trying automatic recovery... (please report along with"
-					"your OS version)\n", assoc_id);
-			tolen=sockaddru_len(dst->to);
-			msg.msg_name=&dst->to.s;
-			msg.msg_namelen=tolen;
-			sinfo->sinfo_assoc_id=0;
-			goto again;
-		}
-#endif /* __OS_* */
-#endif /* SCTP_CONN_REUSE */
-		su2ip_addr(&ip, &dst->to);
-		LOG(L_ERR, "ERROR: sctp_msg_send: sendmsg(sock,%p,%d,0,%s:%d,...):"
-				" %s(%d)\n", buf, len, ip_addr2a(&ip), su_getport(&dst->to),
-				strerror(errno), errno);
-		if (errno==EINTR) goto again;
-		if (errno==EINVAL) {
-			LOG(L_CRIT,"CRITICAL: invalid sendmsg parameters\n"
-			"one possible reason is the server is bound to localhost and\n"
-			"attempts to send to the net\n");
-		}else if (errno==EAGAIN || errno==EWOULDBLOCK){
-			SCTP_STATS_SENDQ_FULL();
-			LOG(L_ERR, "ERROR: sctp_msg_send: failed to send, send buffers"
-						" full\n");
-		}
-	}
-	return n;
-#ifdef SCTP_CONN_REUSE
-#ifdef SCTP_ADDR_HASH
-error:
-	return -1;
-#endif /* SCTP_ADDR_HASH */
-#endif /* SCTP_CONN_REUSE */
-}
-
-
-
-/* wrapper around sctp_msg_send_ext():
- * send buf:len over udp to dst (uses only the to, send_sock and id members
- * from dst)
- * returns the numbers of bytes sent on success (>=0) and -1 on error
- */
-int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len)
-{
-	struct sctp_sndrcvinfo sinfo;
-#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
-	int send_ttl;
-#endif
-	
-	memset(&sinfo, 0, sizeof(sinfo));
-	sinfo.sinfo_flags=SCTP_UNORDERED;
-#ifdef HAVE_SCTP_SNDRCVINFO_PR_POLICY
-	if ((send_ttl=cfg_get(sctp, sctp_cfg, send_ttl))){
-		sinfo.sinfo_pr_policy=SCTP_PR_SCTP_TTL;
-		sinfo.sinfo_pr_value=send_ttl;
-	}else
-		sinfo->sinfo_pr_policy=SCTP_PR_SCTP_NONE;
-#else
-		sinfo.sinfo_timetolive=cfg_get(sctp, sctp_cfg, send_ttl);
-#endif
-	sinfo.sinfo_context=cfg_get(sctp, sctp_cfg, send_retries);
-	return sctp_msg_send_ext(dst, buf, len, &sinfo);
-}
-
-
-
-/** generic sctp info (basic stats).*/
-void sctp_get_info(struct sctp_gen_info* i)
-{
-	if (i){
-		i->sctp_connections_no=atomic_get(sctp_conn_no);
-#ifdef SCTP_CONN_REUSE
-		if (likely(cfg_get(sctp, sctp_cfg, assoc_tracking)))
-			i->sctp_tracked_no=atomic_get(sctp_conn_tracked);
-		else
-			i->sctp_tracked_no=-1;
-#else /* SCTP_CONN_REUSE */
-		i->sctp_tracked_no=-1;
-#endif /* SCTP_CONN_REUSE */
-		i->sctp_total_connections=atomic_get(sctp_id);
-	}
-}
-
-
-#endif /* USE_SCTP */
diff --git a/sctp_server.h b/sctp_server.h
deleted file mode 100644
index 113c409..0000000
--- a/sctp_server.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* 
- * $Id$
- * 
- * Copyright (C) 2008 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/* 
- * sctp one to many 
- */
-/*
- * History:
- * --------
- *  2008-08-07  initial version (andrei)
- */
-
-#ifndef _sctp_server_h
-#define _sctp_server_h
-
-#include "ip_addr.h"
-
-struct sctp_gen_info{
-	int sctp_connections_no;
-	int sctp_tracked_no;
-	int sctp_total_connections;
-};
-
-int init_sctp(void);
-void destroy_sctp(void);
-int sctp_check_compiled_sockopts(char* buf, int size);
-int sctp_check_support(void);
-int sctp_init_sock(struct socket_info* sock_info);
-int sctp_rcv_loop(void);
-int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len);
-
-/* generic sctp information (stats a.s.o) */
-void sctp_get_info(struct sctp_gen_info* sinf);
-
-void destroy_sctp(void);
-
-int sctp_setsockopt(int s, int level, int optname,
-					void* optval, socklen_t optlen, char* err_prefix);
-
-void sctp_con_tracking_flush(void);
-#endif /* _sctp_server_h */
diff --git a/sctp_stats.c b/sctp_stats.c
deleted file mode 100644
index e024811..0000000
--- a/sctp_stats.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* 
- * $Id$
- * 
- * Copyright (C) 2010 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/** sctp statistics.
- * @file sctp_stats.c
- * @ingroup:  core (sctp)
- */
-/*
- * History:
- * --------
- *  2010-08-09  initial version (andrei)
-*/
-
-#ifdef USE_SCTP
-
-#include "sctp_stats.h"
-
-#ifdef USE_SCTP_STATS
-
-#include "counters.h"
-#include "sctp_server.h"
-
-struct sctp_counters_h sctp_cnts_h;
-
-
-enum sctp_info_req { SCTP_INFO_NONE, SCTP_INFO_CONN_NO, SCTP_INFO_TRACKED_NO };
-static counter_val_t sctp_info(counter_handle_t h, void* what);
-
-
-
-/* sctp counters definitions */
-counter_def_t sctp_cnt_defs[] =  {
-	{&sctp_cnts_h.established, "established", 0, 0, 0,
-		"incremented each time a new association is established."},
-	{&sctp_cnts_h.connect_failed, "connect_failed", 0, 0, 0,
-		"incremented each time a new outgoing connection fails."},
-	{&sctp_cnts_h.local_reject, "local_reject", 0, 0, 0,
-		"number of rejected incoming connections."},
-	{&sctp_cnts_h.remote_shutdown, "remote_shutdown", 0, 0, 0,
-		"incremented each time an association is closed by the peer."},
-	{&sctp_cnts_h.assoc_shutdown, "assoc_shutdown", 0, 0, 0,
-		"incremented each time an association is shutdown."},
-	{&sctp_cnts_h.comm_lost, "comm_lost", 0, 0, 0,
-		"incremented each time an established connection is close due to"
-			"some error."},
-	{&sctp_cnts_h.sendq_full, "sendq_full", 0, 0, 0,
-		"number of failed send attempt due to exceeded buffering capacity"
-	    " (full kernel buffers)."},
-	{&sctp_cnts_h.send_failed, "send_failed", 0, 0, 0,
-		"number of failed send attempt for any reason except full buffers."},
-	{&sctp_cnts_h.send_force_retry, "send_force_retry", 0, 0, 0,
-		"incremented each time a failed send is force-retried"
-			"(possible only if sctp_send_retries ! = 0"},
-	{0, "current_opened_connections", 0,
-		sctp_info, (void*)(long)SCTP_INFO_CONN_NO,
-		"number of currently opened associations."},
-	{0, "current_tracked_connections", 0,
-		sctp_info, (void*)(long)SCTP_INFO_TRACKED_NO,
-		"number of currently tracked associations."},
-	{0, 0, 0, 0, 0, 0 }
-};
-
-
-
-/** helper function for some stats (which are kept internally inside sctp).
- */
-static counter_val_t sctp_info(counter_handle_t h, void* what)
-{
-	enum sctp_info_req w;
-	struct sctp_gen_info i;
-
-	if (sctp_disable)
-		return 0;
-	w = (int)(long)what;
-	sctp_get_info(&i);
-	switch(w) {
-		case SCTP_INFO_CONN_NO:
-			return i.sctp_connections_no;
-		case SCTP_INFO_TRACKED_NO:
-			return i.sctp_tracked_no;
-		case SCTP_INFO_NONE:
-			break;
-	};
-	return 0;
-}
-
-/** intialize sctp statistics.
- *  Must be called before forking.
- * @return < 0 on errror, 0 on success.
- */
-int sctp_stats_init()
-{
-	if (counter_register_array("sctp", sctp_cnt_defs) < 0)
-		goto error;
-	return 0;
-error:
-	return -1;
-}
-
-
-void sctp_stats_destroy()
-{
-	/* do nothing */
-}
-
-#endif /* USE_SCTP_STATS */
-#endif /* USE_SCTP */
-
-/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/sctp_stats.h b/sctp_stats.h
deleted file mode 100644
index 1ce6f8d..0000000
--- a/sctp_stats.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* 
- * $Id$
- * 
- * Copyright (C) 2009 iptelorg GmbH
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * sctp_stats.h - sctp statistics macros
- */
-/*
- * History:
- * --------
- *  2009-04-28  initial version (andrei)
-*/
-
-#ifndef __sctp_stats_h
-#define __sctp_stats_h
-
-
-/* enable sctp stats by default */
-#ifndef NO_SCTP_STATS
-#define USE_SCTP_STATS
-#endif
-
-#ifndef USE_SCTP_STATS
-
-#define INIT_SCTP_STATS() 0 /* success */
-#define DESTROY_SCTP_STATS()
-
-#define SCTP_STATS_ESTABLISHED()
-#define SCTP_STATS_CONNECT_FAILED()
-#define SCTP_STATS_LOCAL_REJECT()
-#define SCTP_STATS_REMOTE_SHUTDOWN()
-#define SCTP_STATS_ASSOC_SHUTDOWN()
-#define SCTP_STATS_COMM_LOST()
-#define SCTP_STATS_SENDQ_FULL()
-#define SCTP_STATS_SEND_FAILED()
-#define SCTP_STATS_SEND_FORCE_RETRY()
-
-#else /* USE_SCTP_STATS */
-
-#include "counters.h"
-
-struct sctp_counters_h {
-	counter_handle_t established;
-	counter_handle_t connect_failed;
-	counter_handle_t local_reject;
-	counter_handle_t remote_shutdown;
-	counter_handle_t assoc_shutdown;
-	counter_handle_t comm_lost;
-	counter_handle_t sendq_full;
-	counter_handle_t send_failed;
-	counter_handle_t send_force_retry;
-};
-
-extern struct sctp_counters_h sctp_cnts_h;
-
-int sctp_stats_init();
-void sctp_stats_destroy();
-
-#define INIT_SCTP_STATS() sctp_stats_init() /* success */
-
-#define DESTROY_SCTP_STATS() sctp_stats_destroy()
-
-
-/** called each time a new sctp assoc. is established.
- * sctp notification: SCTP_COMM_UP.
- */
-#define SCTP_STATS_ESTABLISHED() \
-	counter_inc(sctp_cnts_h.established)
-
-/** called each time a new outgoing connection/assoc open fails.
- *  sctp notification: SCTP_CANT_STR_ASSOC
- */
-#define SCTP_STATS_CONNECT_FAILED() \
-	counter_inc(sctp_cnts_h.connect_failed)
-
-/** called each time a new incoming connection is rejected.  */
-#define SCTP_STATS_LOCAL_REJECT() \
-	counter_inc(sctp_cnts_h.local_reject)
-
-
-/** called each time a connection is closed by the peer.
-  * sctp notification: SCTP_SHUTDOWN_EVENT
-  */
-#define SCTP_STATS_REMOTE_SHUTDOWN() \
-	counter_inc(sctp_cnts_h.remote_shutdown)
-
-
-/** called each time a connection is shutdown.
-  * sctp notification: SCTP_SHUTDOWN_COMP
-  */
-#define SCTP_STATS_ASSOC_SHUTDOWN() \
-	counter_inc(sctp_cnts_h.assoc_shutdown)
-
-
-/** called each time an established connection is closed due to some error.
-  * sctp notification: SCTP_COMM_LOST
-  */
-#define SCTP_STATS_COMM_LOST() \
-	counter_inc(sctp_cnts_h.comm_lost)
-
-
-/** called each time a send fails due to the buffering capacity being exceeded.
-  * (send fails due to full kernel buffers)
-  */
-#define SCTP_STATS_SENDQ_FULL() \
-	counter_inc(sctp_cnts_h.sendq_full)
-
-
-/** called each time a send fails.
-  * (send fails for any reason except buffers full)
-  * sctp notification: SCTP_SEND_FAILED
-  */
-#define SCTP_STATS_SEND_FAILED() \
-	counter_inc(sctp_cnts_h.send_failed)
-
-/** called each time a failed send is force-retried.
-  * (possible only if sctp_send_retries is != 0)
-  */
-#define SCTP_STATS_SEND_FORCE_RETRY() \
-	counter_inc(sctp_cnts_h.send_force_retry)
-
-#endif /* USE_SCTP_STATS */
-
-#endif /*__sctp_stats_h*/
-
-/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/select_core.c b/select_core.c
index 4c0ae9f..4d8fe06 100644
--- a/select_core.c
+++ b/select_core.c
@@ -1621,7 +1621,7 @@ int select_branch_uri(str* res, select_t* s, struct sip_msg* msg) {
 		char *c;
 		init_branch_iterator();
 		len = 0;
-		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0))) {
+		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0, 0, 0))) {
 
 			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
 				l = dst_uri.len;
@@ -1645,7 +1645,7 @@ int select_branch_uri(str* res, select_t* s, struct sip_msg* msg) {
 		init_branch_iterator();
 		res->len = 0;
 		n = 0;
-		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0))) {
+		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0, 0, 0))) {
 			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
 				l = dst_uri.len;
 				c = dst_uri.s;
@@ -1687,7 +1687,7 @@ int select_branch_uri(str* res, select_t* s, struct sip_msg* msg) {
 		if (n < 0 || n >= nr_branches) 
 			return -1;
 		init_branch_iterator();
-		for (; (c = next_branch(&l, &q, &dst_uri, 0, 0, 0)) && n; n--);
+		for (; (c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0, 0, 0)) && n; n--);
 		if (!c) return 1;
 		
 		if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
diff --git a/ser_stun.c b/ser_stun.c
deleted file mode 100644
index 86eab5a..0000000
--- a/ser_stun.c
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info at iptel.org
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * History
- * --------
- *  2006-10-13  created (vlada)
- *  2006-12-14  fixed calculation of body length (vlada) 
- */
-
-/*!
- * \file
- * \brief SIP-router core :: 
- * \ingroup core
- * Module: \ref core
- */
-
-#ifdef USE_STUN 
- 
-#include <arpa/inet.h>
-#include <openssl/sha.h>
-#include "ser_stun.h"
-#include "forward.h"
-
-/*
- * ****************************************************************************
- *                     Declaration of functions                               *
- * ****************************************************************************
- */
-int stun_parse_header(struct stun_msg* req, USHORT_T* error_code);
-int stun_parse_body(
-				struct stun_msg* req,
-				struct stun_unknown_att** unknown,
-				USHORT_T* error_code);
-void stun_delete_unknown_attrs(struct stun_unknown_att* unknown);
-struct stun_unknown_att* stun_alloc_unknown_attr(USHORT_T type);
-int stun_add_address_attr(struct stun_msg* res, 
-						UINT_T		af,
-						USHORT_T	port,
-						UINT_T*		ip_addr,
-						USHORT_T	type,
-						int do_xor);
-int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown);
-int add_error_code(struct stun_msg* res, USHORT_T error_code);
-int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad);
-int reallock_buffer(struct stun_buffer* buffer, UINT_T len);
-int buf_copy(struct stun_buffer* msg, void* source, UINT_T len);
-void clean_memory(struct stun_msg* req,
-				struct stun_msg* res,	struct stun_unknown_att* unknown);
-int stun_create_response(
-						struct stun_msg* req,
-						struct stun_msg* res,
-						struct receive_info* ri,
-						struct stun_unknown_att* unknown, 
-						UINT_T error_code);
-int stun_add_common_integer_attr(struct stun_msg* res, USHORT_T type, UINT_T value);
-int stun_add_common_text_attr(struct stun_msg* res, USHORT_T type, char* value, 
-							USHORT_T pad);
-
-
-/*
- * ****************************************************************************
- *                      Definition of functions                               *
- * ****************************************************************************
- */
- 
-/* 
- * stun_process_msg(): 
- * 			buf - incoming message
- * 			len - length of incoming message
- * 			ri  - information about socket that received a message and 
- *                also information about sender (its IP, port, protocol)
- * 
- * This function ensures processing of incoming message. It's common for both
- * TCP and UDP protocol. There is no other function as an interface.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- * 
- */
-int stun_process_msg(char* buf, unsigned len, struct receive_info* ri)
-{
-	struct stun_msg 			msg_req;
-	struct stun_msg 			msg_res;
-	struct dest_info			dst;
-	struct stun_unknown_att*	unknown;
-	USHORT_T					error_code;
-	 
-	memset(&msg_req, 0, sizeof(msg_req));
-	memset(&msg_res, 0, sizeof(msg_res));
-	
-	msg_req.msg.buf.s = buf;
-	msg_req.msg.buf.len = len;	
-	unknown = NULL;
-	error_code = RESPONSE_OK;
-	
-	if (stun_parse_header(&msg_req, &error_code) != 0) {
-		goto error;
-	}
-	
-	if (error_code == RESPONSE_OK) {
-		if (stun_parse_body(&msg_req, &unknown, &error_code) != 0) {
-			goto error;
-		}
-	}
-	
-	if (stun_create_response(&msg_req, &msg_res, ri,  
-							unknown, error_code) != 0) {
-		goto error;
-	}
-	
-	init_dst_from_rcv(&dst, ri);
-
-#ifdef EXTRA_DEBUG	
-	struct ip_addr ip;
-	su2ip_addr(&ip, &dst.to);
-	LOG(L_DBG, "DEBUG: stun_process_msg: decoded request from (%s:%d)\n", ip_addr2a(&ip), 
-		su_getport(&dst.to));
-#endif
-	
-	/* send STUN response */
-	if (msg_send(&dst, msg_res.msg.buf.s, msg_res.msg.buf.len) != 0) {
-		goto error;
-	}
-	
-#ifdef EXTRA_DEBUG
-	LOG(L_DBG, "DEBUG: stun_process_msg: send response\n");
-#endif
-	clean_memory(&msg_req, &msg_res, unknown);
-	return 0;
-	
-error:
-#ifdef EXTRA_DEBUG
-	LOG(L_DBG, "DEBUG: stun_process_msg: failed to decode request\n");
-#endif
-	clean_memory(&msg_req, &msg_res, unknown);
-	return FATAL_ERROR;
-}
-
-/*
- * stun_parse_header():
- * 			- req: request from host that should be processed
- * 			- error_code: indication of any protocol error
- * 
- * This function ensures parsing of incoming header.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-
-int stun_parse_header(struct stun_msg* req, USHORT_T* error_code)
-{
-	
-	if (sizeof(req->hdr) > req->msg.buf.len) {
-		/* the received message does not contain whole header */
-		LOG(L_INFO, "INFO: stun_parse_header: incomplete header of STUN message\n");
-		/* Any better solution? IMHO it's not possible to send error response
-		 * because the transaction ID is not available.
-		 */
-		return FATAL_ERROR;
-	}
-	
-	memcpy(&req->hdr, req->msg.buf.s, sizeof(struct stun_hdr));
-	req->hdr.type = ntohs(req->hdr.type);
-	
-	/* the SER supports only Binding Request right now */ 
-	if (req->hdr.type != BINDING_REQUEST) {
-		LOG(L_INFO, "INFO: stun_parse_header: unsupported type of STUN message: %x\n", 
-					req->hdr.type);
-		/* resending of same message is not welcome */
-		*error_code = GLOBAL_FAILURE_ERR;
-	}
-	
-	req->hdr.len = ntohs(req->hdr.len);
-	
-	/* check if there is correct magic cookie */
-	req->old = (req->hdr.id.magic_cookie == htonl(MAGIC_COOKIE)) ? 0 : 1;
-
-#ifdef EXTRA_DEBUG
-	LOG(L_DBG, "DEBUG: stun_parse_header: request is old: %i\n", req->old);
-#endif
-	return 0;
-}
-
-/*
- * stun_parse_body():
- * 			- req: request from host that should be processed
- * 			- unknown: this is a link list header of attributes 
- * 					   that are unknown to SER; defaul value is NULL
- * 			- error_code: indication of any protocol error
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int stun_parse_body(
-				struct stun_msg* req,
-				struct stun_unknown_att** unknown,
-				USHORT_T* error_code)
-{
-	int not_parsed;
-	struct stun_attr attr;
-	USHORT_T attr_size;
-	UINT_T padded_len;
-	struct stun_unknown_att*	tmp_unknown;
-	struct stun_unknown_att*	body;
-	char*	buf;
-	
-	attr_size = sizeof(struct stun_attr);
-	buf = &req->msg.buf.s[sizeof(struct stun_hdr)];
-	
-	/* 
-	 * Mark the body lenght as unparsed.
-	 */
-	not_parsed = req->msg.buf.len - sizeof(struct stun_hdr);
-	
-	if (not_parsed != req->hdr.len) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: stun_parse_body: body too short to be valid\n");
-#endif
-		*error_code = BAD_REQUEST_ERR;
-		return 0; 
-	}
-	
-	tmp_unknown = *unknown;
-	body = NULL;
-	
-	while (not_parsed > 0 && *error_code == RESPONSE_OK) {
-		memset(&attr, 0, attr_size);
-		
-		/* check if there are 4 bytes for attribute type and its value */
-		if (not_parsed < 4) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_parse_body: attribute header short to be valid\n");
-#endif
-			*error_code = BAD_REQUEST_ERR;
-			continue;
-		}
-		
-		memcpy(&attr, buf, attr_size);
-		
-		buf += attr_size;
-		not_parsed -= attr_size;
-		
-		/* check if there is enought unparsed space for attribute's value */
-		if (not_parsed < ntohs(attr.len)) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_parse_body: remaining message is shorter then attribute length\n");
-#endif
-			*error_code = BAD_REQUEST_ERR;
-			continue;
-		}
-		
-		/* check if the attribute is known to the server */
-		switch (ntohs(attr.type)) {			
-			case REALM_ATTR:
-			case NONCE_ATTR:
-			case MAPPED_ADDRESS_ATTR:
-			case XOR_MAPPED_ADDRESS_ATTR:
-			case ALTERNATE_SERVER_ATTR:
-			case RESPONSE_ADDRESS_ATTR:
-			case SOURCE_ADDRESS_ATTR:
-			case REFLECTED_FROM_ATTR:		
-			case CHANGE_REQUEST_ATTR:
-			case CHANGED_ADDRESS_ATTR:
-				padded_len = ntohs(attr.len);
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_parse_body: known attributes\n");
-#endif
-				break;
-			
-			/* following attributes must be padded to 4 bytes */
-			case USERNAME_ATTR:
-			case ERROR_CODE_ATTR:
-			case UNKNOWN_ATTRIBUTES_ATTR:
-			case SOFTWARE_ATTR:
-				padded_len = PADDED_TO_FOUR(ntohs(attr.len));
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_parse_body: padded to four\n");
-#endif
-				break;
-
-			/* MESSAGE_INTEGRITY must be padded to sixty four bytes*/
-			case MESSAGE_INTEGRITY_ATTR:
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_parse_body: message integrity attribute found\n");
-#endif
-				padded_len = PADDED_TO_SIXTYFOUR(ntohs(attr.len));
-				break;
-			
-			case FINGERPRINT_ATTR:
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint attribute found\n");
-#endif
-				padded_len = SHA_DIGEST_LENGTH;
-
-				if (not_parsed > SHA_DIGEST_LENGTH) {
-#ifdef EXTRA_DEBUG
-					LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is not the last attribute\n");
-#endif
-					/* fingerprint must be last parameter in request */
-					*error_code = BAD_REQUEST_ERR;
-					continue;
-				}
-				break;
-			
-			default:
-				/* 
-				 * the attribute is uknnown to the server
-				 * let see if it's necessary to generate error response 
-				 */
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: low endian: attr - 0x%x   const - 0x%x\n", ntohs(attr.type), MANDATORY_ATTR);
-		    LOG(L_DBG, "DEBUG: big endian: attr - 0x%x   const - 0x%x\n", attr.type, htons(MANDATORY_ATTR));
-#endif
-				if (ntohs(attr.type) <= MANDATORY_ATTR) {
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_parse_body: mandatory unknown attribute found - 0x%x\n", ntohs(attr.type));
-#endif		
-					tmp_unknown = stun_alloc_unknown_attr(attr.type);
-					if (tmp_unknown == NULL) {
-						return FATAL_ERROR;
-					}
-					if (*unknown == NULL) {
-						*unknown = body = tmp_unknown;
-					}
-					else { 
-						body->next = tmp_unknown;
-						body = body->next;
-					}
-				}
-#ifdef EXTRA_DEBUG
-        else {
-				  LOG(L_DBG, "DEBUG: stun_parse_body: optional unknown attribute found - 0x%x\n", ntohs(attr.type));
-        }
-#endif
-				padded_len = ntohs(attr.len);
-				break;
-		}
-		
-		/* check if there is enough unparsed space for the padded attribute
-		   (the padded length might be greater then the attribute length)
-		 */
-		if (not_parsed < padded_len) {
-			break;
-		}
-		buf += padded_len;
-		not_parsed -= padded_len;
-	}  /* while */
-	
-	/*
-	 * The unknown attribute error code must set after parsing of whole body
-	 * because it's necessary to obtain all of unknown attributes! 
-	 */
-	if (*error_code == RESPONSE_OK && *unknown != NULL) {
-		*error_code = UNKNOWN_ATTRIBUTE_ERR;
-	} 
-	
-	return 0;
-}
-
-/*
- * stun_create_response():
- * 			- req: original request from host
- * 			- res: this will represent response to host
- * 			- ri: information about request, necessary because of IP 
- * 				  address and port 
- *			- unknown: link list of unknown attributes
- * 			- error_code: indication of any protocol error
- * 
- * The function stun_create_response ensures creating response to a host.
- * The type of response depends on value of error_code parameter.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory  
- */
-
-int stun_create_response(
-						struct stun_msg* req,
-						struct stun_msg* res,
-						struct receive_info* ri,
-						struct stun_unknown_att* unknown, 
-						UINT_T error_code)
-{
-	/*
-	 * Alloc some space for response.
-	 * Optimalization? - maybe it would be better to use biggish static array.
-	 */
-	res->msg.buf.s = (char *) pkg_malloc(sizeof(char)*STUN_MSG_LEN);
-	if (res->msg.buf.s == NULL) {
-		LOG(L_ERR, "ERROR: STUN: out of memory\n");
-		return FATAL_ERROR;
-	}
-	
-	memset(res->msg.buf.s, 0, sizeof(char)*STUN_MSG_LEN); 
-	res->msg.buf.len = 0;
-	res->msg.empty = STUN_MSG_LEN;
-	
-	/* use magic cookie and transaction ID from request */
-	memcpy(&res->hdr.id, &req->hdr.id, sizeof(struct transaction_id));
-	/* the correct body length will be added ASAP it will be known */ 
-	res->hdr.len = htons(0);
-	
-	if (error_code == RESPONSE_OK) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: stun_create_response: creating normal response\n");
-#endif
-		res->hdr.type = htons(BINDING_RESPONSE);
-		
-		/* copy header into msg buffer */
-		if (buf_copy(&res->msg, (void *) &res->hdr, 
-					sizeof(struct stun_hdr)) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_create_response: failed to copy buffer\n");
-#endif
-			return FATAL_ERROR;
-		}
-
-		/* 
-		 * If the SER received message in old format, then the body will 
-		 * contain MAPPED-ADDRESS attribute instead of XOR-MAPPED-ADDRESS
-		 * attribute.
-		 */		
-		if (req->old == 0) {
-			if (stun_add_address_attr(res, ri->src_ip.af, ri->src_port, 
-						  ri->src_ip.u.addr32, XOR_MAPPED_ADDRESS_ATTR, 
-						  XOR) != 0) {
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
-#endif
-				return FATAL_ERROR;
-			}
-		}
-		else {
-			if (stun_add_address_attr(res, ri->src_ip.af, ri->src_port, 
-						ri->src_ip.u.addr32, MAPPED_ADDRESS_ATTR, !XOR) != 0) {
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
-#endif
-				return FATAL_ERROR;
-			}
-		}
-	}
-	else {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: stun_create_response: creating error response\n");
-#endif
-		res->hdr.type = htons(BINDING_ERROR_RESPONSE);
-		
-		if (buf_copy(&res->msg, (void *) &res->hdr, 
-								sizeof(struct stun_hdr)) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_create_response: failed to copy buffer\n");
-#endif
-			return FATAL_ERROR;
-		}
-		
-		if (add_error_code(res, error_code) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_create_response: failed to add error code\n");
-#endif
-			return FATAL_ERROR;
-		}
-		
-		if (unknown != NULL) {
-			if (add_unknown_attr(res, unknown) != 0) {
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_create_response: failed to add unknown attribute\n");
-#endif
-				return FATAL_ERROR;
-			}
-		} 
-	}
-	
-	if (req->old == 0) {
-		/* 
-		 * add optional information about server; attribute SOFTWARE is part of 
-		 * rfc5389.txt
-		 * */
-		if (stun_add_common_text_attr(res, SOFTWARE_ATTR, SERVER_HDR, PAD4)!=0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_create_response: failed to add common text attribute\n");
-#endif
-			return FATAL_ERROR;
-		}
-	}	
-	
-	res->hdr.len = htons(res->msg.buf.len - sizeof(struct stun_hdr));
-	memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
-	       sizeof(USHORT_T));
-	
-	return 0;
-}
-
-/*
- * add_unknown_attr()
- * 			- res: response representation
- * 			- unknown: link list of unknown attributes
- * 
- * The function add_unknown_attr ensures copy of link list of unknown 
- * attributes into response buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- * 
- */
-int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown)
-{
-	struct stun_attr attr;
-	struct stun_unknown_att* tmp_unknown;
-	UINT_T		counter;
-	USHORT_T	orig_len;
-
-	counter = 0;
-	orig_len = res->msg.buf.len;
-	tmp_unknown = unknown;
-	
-	attr.type = htons(UNKNOWN_ATTRIBUTES_ATTR);
-	attr.len = htons(0);
-	
-	if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: add_unknown_attr: failed to copy buffer\n");
-#endif
-		return FATAL_ERROR;
-	}
-	
-	while (tmp_unknown != NULL) {
-		if (buf_copy(&res->msg, (void *)&tmp_unknown->type, 
-								sizeof(USHORT_T)) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: add_unknown_attr: failed to copy unknown attribute\n");
-#endif
-			return FATAL_ERROR;
-		}
-		tmp_unknown = tmp_unknown->next;
-		++counter;
-	}
-	
-	attr.len = htons(res->msg.buf.len - orig_len);
-	memcpy(&res->msg.buf.s[orig_len], (void *)&attr, sizeof(struct stun_attr));
-	
-	/* check if there is an odd number of unknown attributes and if yes, 
-	 * repeat one of them because of padding to 32
-	 */
-	if (counter/2 != 0 && unknown != NULL) {
-		if (buf_copy(&res->msg, (void *)&unknown->type, sizeof(USHORT_T))!=0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: add_unknown_attr: failed to padd\n");
-#endif
-			return FATAL_ERROR;
-		}
-	}	
-	
-	return 0;
-}
-
-/*
- * add_error_code()
- * 			- res: response representation
- * 			- error_code: value of error type
- * 
- * The function add_error_code ensures copy of link list of unknown 
- * attributes into response buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int add_error_code(struct stun_msg* res, USHORT_T error_code)
-{
-	struct stun_attr attr;
-	USHORT_T	orig_len;
-	USHORT_T	two_bytes;
-	int			text_pad;
-	char		err[2];
-	
-	orig_len = res->msg.buf.len;
-	text_pad = 0;
-	
-	/* the type and length will be copy as last one because of unknown length*/
-	if (res->msg.buf.len < sizeof(struct stun_attr)) {
-		if (reallock_buffer(&res->msg, sizeof(struct stun_attr)) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: add_error_code: failed to reallocate buffer\n");
-#endif
-			return FATAL_ERROR;
-		}
-	}
-	res->msg.buf.len += sizeof(struct stun_attr);
-	res->msg.empty -= sizeof(struct stun_attr);
-	
-	/* first two bytes are empty */
-	two_bytes = 0x0000;
-	
-	if (buf_copy(&res->msg, (void *) &two_bytes, sizeof(USHORT_T)) != 0) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: add_error_code: failed to copy buffer\n");
-#endif
-		return FATAL_ERROR;
-	}
-	
-	err[0] = error_code / 100;
-	err[1] = error_code % 100;
-	if (buf_copy(&res->msg, (void *) err, sizeof(UCHAR_T)*2) != 0) {
-		return FATAL_ERROR;
-	}
-	
-	switch (error_code) {
-		case TRY_ALTERNATE_ERR:
-			text_pad = copy_str_to_buffer(res, TRY_ALTERNATE_TXT, PAD4); 
-			break;
-		case BAD_REQUEST_ERR:
-			text_pad = copy_str_to_buffer(res, BAD_REQUEST_TXT, PAD4); 
-			break;
-		case UNAUTHORIZED_ERR:
-			text_pad = copy_str_to_buffer(res, UNAUTHORIZED_TXT, PAD4); 
-			break;
-		case UNKNOWN_ATTRIBUTE_ERR:
-			text_pad = copy_str_to_buffer(res, UNKNOWN_ATTRIBUTE_TXT, PAD4);
-			break;
-		case STALE_CREDENTIALS_ERR:
-			text_pad = copy_str_to_buffer(res, STALE_CREDENTIALS_TXT, PAD4); 
-			break;
-		case INTEGRITY_CHECK_ERR:
-			text_pad = copy_str_to_buffer(res, INTEGRITY_CHECK_TXT, PAD4); 
-			break;
-		case MISSING_USERNAME_ERR:
-			text_pad = copy_str_to_buffer(res, MISSING_USERNAME_TXT, PAD4); 
-			break;
-		case USE_TLS_ERR:
-			text_pad = copy_str_to_buffer(res, USE_TLS_TXT, PAD4); 
-			break;
-		case MISSING_REALM_ERR:
-			text_pad = copy_str_to_buffer(res, MISSING_REALM_TXT, PAD4); 
-			break;
-		case MISSING_NONCE_ERR:
-			text_pad = copy_str_to_buffer(res, MISSING_NONCE_TXT, PAD4); 
-			break;
-		case UNKNOWN_USERNAME_ERR:
-			text_pad = copy_str_to_buffer(res, UNKNOWN_USERNAME_TXT, PAD4); 
-			break;
-		case STALE_NONCE_ERR:
-			text_pad = copy_str_to_buffer(res, STALE_NONCE_TXT, PAD4);
-			break;
-		case SERVER_ERROR_ERR:
-			text_pad = copy_str_to_buffer(res, SERVER_ERROR_TXT, PAD4); 
-			break;
-		case GLOBAL_FAILURE_ERR:
-			text_pad = copy_str_to_buffer(res, GLOBAL_FAILURE_TXT, PAD4); 
-			break;
-		default:
-			LOG(L_ERR, "ERROR: STUN: Unknown error code.\n");
-			break;
-	}
-	if (text_pad < 0) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: add_error_code: text_pad is negative\n");
-#endif
-		goto error;
-	}
-	attr.type = htons(ERROR_CODE_ATTR);
-	/* count length of "value" field -> without type and lehgth field */
-	attr.len = htons(res->msg.buf.len - orig_len - 
-					 text_pad - sizeof(struct stun_attr));
-	memcpy(&res->msg.buf.s[orig_len], (void *)&attr, sizeof(struct stun_attr));
-	
-	return 0;
-
-error:
-	return FATAL_ERROR;
-}
-
-/*
- * copy_str_to_buffer()
- * 			- res: response representation
- * 			- data: text data, in our case almost text representation of error
- * 			- pad: the size of pad (for how much bytes the string should be 
- * 				   padded
- * 
- * The function copy_str_to_buffer ensures copy of text buffer into response
- * buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad)
-{
-	USHORT_T	pad_len;
-	UINT_T		data_len;
-	UCHAR_T		empty[pad];
-	
-	data_len = strlen(data);
-	memset(&empty, 0, pad);
-	
-	pad_len = (pad - data_len%pad) % pad;
-	
-	if (buf_copy(&res->msg, (void *) data, sizeof(UCHAR_T)*data_len) != 0) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: copy_str_to_buffer: failed to copy buffer\n");
-#endif
-		return FATAL_ERROR;
-	}
-	
-	if (pad_len != 0) {
-		if (buf_copy(&res->msg, &empty, pad_len) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: copy_str_to_buffer: failed to pad\n");
-#endif
-			return FATAL_ERROR;
-		}	
-	}
-
-	return pad_len;	
-}
-
-/*
- * stun_add_address_attr()
- * 			- res: response representation
- * 			- af: address family
- * 			- port: port
- * 			- ip_addr: represent both IPv4 and IPv6, the differences is in 
- * 			length  
- * 			- type: type of attribute
- * 			- do_xor: if the port should be XOR-ed or not.
- * 
- * The function stun_add_address_attr ensures copy of any IP attribute into
- * response buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int stun_add_address_attr(struct stun_msg* res, 
-						UINT_T		af,
-						USHORT_T	port,
-						UINT_T*		ip_addr,
-						USHORT_T	type,
-						int do_xor)
-{
-	struct stun_attr attr;
-	int		 ip_struct_len;
-#ifdef USE_IPV6
-	UINT_T	 id[IP_ADDR];
-	int i;
-#endif /* USE_IPV6 */ 
-	
-	ip_struct_len = 0;
-	attr.type = htons(type);
-	res->ip_addr.port = htons((do_xor) ? (port ^ MAGIC_COOKIE_2B) : port);
-	switch(af) {
-		case AF_INET:
-			ip_struct_len = sizeof(struct stun_ip_addr) - 3*sizeof(UINT_T);
-			res->ip_addr.family = htons(IPV4_FAMILY);
-			memcpy(res->ip_addr.ip, ip_addr, IPV4_LEN);
-			res->ip_addr.ip[0] = (do_xor) ? 
-				res->ip_addr.ip[0] ^ htonl(MAGIC_COOKIE) : res->ip_addr.ip[0];
-			break;
-#ifdef USE_IPV6
-		case AF_INET6:
-			ip_struct_len = sizeof(struct stun_ip_addr);
-			res->ip_addr.family = htons(IPV6_FAMILY);
-			memcpy(&res->ip_addr.ip, ip_addr, IPV6_LEN);
-			memcpy(id, &res->hdr.id, sizeof(struct transaction_id));
-			for (i=0; i<IP_ADDR; i++) {
-				res->ip_addr.ip[i] = (do_xor) ? 
-							res->ip_addr.ip[i] ^ id[i] : res->ip_addr.ip[i];
-			}
-			break;
-#endif /* USE_IPV6 */ 
-		default:
-			break;
-	}
-	
-	attr.len = htons(ip_struct_len);
-	
-	/* copy type and attribute's length */ 
-	if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
-		return FATAL_ERROR;
-	}
-	
-	/* copy family, port and IP */
-	if (buf_copy(&res->msg, (void *) &res->ip_addr, ip_struct_len) != 0) {
-		return FATAL_ERROR;
-	}
-
-	return 0;
-}
-
-/*
- * stun_alloc_unknown_attr()
- * 			- type: type of unknown attribute
- * 
- * The function stun_alloc_unknown_attr ensures allocationg new element for
- * the link list of unknown attributes.
- * 
- * Return value: pointer to new element of link list in positive case
- * 				 NULL if there is some enviroment error such as insufficiency
- * 						of memory
- */
-struct stun_unknown_att* stun_alloc_unknown_attr(USHORT_T type)
-{
-	struct stun_unknown_att* attr;
-
-	attr = (struct stun_unknown_att *) pkg_malloc(sizeof(struct stun_unknown_att));
-	if (attr == NULL) {
-		LOG(L_ERR, "ERROR: STUN: out of memory\n");
-		return NULL;
-	}
-	
-	attr->type = type;
-	attr->next = NULL;
-	
-	return attr;
-}
-
-/*
- * stun_delete_unknown_attrs()
- * 			- unknown: link list of unknown attributes
- * 
- * The function stun_delete_unknown_attrs ensures deleting of link list
- * 
- * Return value: none
- */
-void stun_delete_unknown_attrs(struct stun_unknown_att* unknown)
-{
-	struct stun_unknown_att* tmp_unknown;
-	
-	if (unknown == NULL) {
-		return;
-	}
-	
-	while(unknown->next) {
-		tmp_unknown = unknown->next;
-		unknown->next = tmp_unknown->next;
-		pkg_free(tmp_unknown);		
-	}
-	pkg_free(unknown);
-}
-
-/*
- * buf_copy()
- * 			- msg: buffer where the data will be copy to
- * 			- source: source data buffer
- * 			- len: number of bytes that should be copied
- * 
- * The function buf_copy copies "len" bytes from source into msg buffer
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int buf_copy(struct stun_buffer* msg, void* source, UINT_T len)
-{
-	if (msg->empty < len) {
-		if (reallock_buffer(msg, len) != 0) {
-			return FATAL_ERROR;
-		}
-	}
-	
-	memcpy(&msg->buf.s[msg->buf.len], source, len);
-	msg->buf.len += len;
-	msg->empty -= len;
-	
-	return 0;
-}
-
-/*
- * reallock_buffer()
- * 			- buffer: original buffer
- * 			- len: represents minimum of bytes that must be available after 
- * 					reallocation
- * 
- * The function reallock_buffer reallocks buffer. New buffer's length will be 
- * original length plus bigger from len and STUN_MSG_LEN constant.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int reallock_buffer(struct stun_buffer* buffer, UINT_T len)
-{
-	char*	tmp_buf;
-	UINT_T	new_len;
-	
-	new_len = (STUN_MSG_LEN < len) ? STUN_MSG_LEN+len : STUN_MSG_LEN;
-	
-	tmp_buf = (char *) pkg_realloc(buffer->buf.s, 
-								   buffer->buf.len + buffer->empty + new_len);
-	if (tmp_buf == 0) {
-		LOG(L_ERR, "ERROR: STUN: out of memory\n");
-		return FATAL_ERROR;
-	}
-	
-	buffer->buf.s = tmp_buf;
-	buffer->empty += new_len;
-
-	return 0;
-}
-
-/*
- * clean_memory()
- * 			- res: structure representing response message
- * 			- unknown: link list of unknown attributes
- * 
- * The function clean_memory should free dynamic allocated memory.
- * 
- * Return value: none
- */
-void clean_memory(struct stun_msg* req,
-				struct stun_msg* res,	struct stun_unknown_att* unknown)
-{
-#ifdef DYN_BUF
-	pkg_free(req->msg.buf.s);
-#endif
-
-	if (res->msg.buf.s != NULL) {
-		pkg_free(res->msg.buf.s);
-	}
-	stun_delete_unknown_attrs(unknown);
-}
-
-/*
- * stun_add_common_integer_attr()
- * 			- res: structure representing response
- * 			- type: type of attribute
- * 			- value: attribute's value
- * 
- * The function stun_add_common_integer_attr copy attribute with integer value 
- * into response buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int stun_add_common_integer_attr(struct stun_msg* res, 
-								 USHORT_T type, 
-								 UINT_T value)
-{
-	struct stun_attr attr;
-	
-	attr.type = htons(type);
-	attr.len = htons(sizeof(UINT_T));
-	
-	if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
-		return FATAL_ERROR;
-	}
-	
-	value = htonl(value);
-	if (buf_copy(&res->msg, (void *) &value, sizeof(UINT_T)) != 0) {
-		return FATAL_ERROR;
-	}
-	
-	return 0;
-}
-
-/*
- * stun_add_common_text_attr()
- * 			- res: structure representing response
- * 			- type: type of attribute
- * 			- value: attribute's value
- * 			- pad: size of pad
- * 
- * The function stun_add_common_text_attr copy attribute with string value 
- * into response buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int stun_add_common_text_attr(struct stun_msg* res, 
-							  USHORT_T type, 
-							  char* value, 
-							  USHORT_T pad)
-{
-	struct stun_attr attr;
-	
-	if (value == NULL) {
-		LOG(L_INFO, "INFO: stun_add_common_text_attr: value is NULL\n");
-		return 0;
-	}
-	
-	attr.type = htons(type);
-	attr.len = htons(strlen(value));
-	
-	if (buf_copy(&res->msg, (void *) &attr, sizeof(struct stun_attr)) != 0) {
-		return FATAL_ERROR;
-	}
-	
-	if (copy_str_to_buffer(res, value, pad) < 0) {
-		return FATAL_ERROR;
-	}
-	
-	return 0;
-	
-}
-
-#endif  /* USE_STUN */
diff --git a/ser_stun.h b/ser_stun.h
deleted file mode 100644
index 55e8145..0000000
--- a/ser_stun.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- *    info at iptel.org
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- *
- * History:
- * --------
- *  2006-10-13  created (vlada)
- */
-
-
-#ifndef _ser_stun_h
-#define _ser_stun_h
-
-#ifdef USE_STUN
-
-#include <openssl/sha.h>
-
-#include "str.h"
-#include "tcp_conn.h"
-#include "ip_addr.h"
-
-/* type redefinition */
-typedef unsigned char	UCHAR_T;
-typedef unsigned short USHORT_T;
-typedef unsigned int	UINT_T;
-typedef unsigned long	ULONG_T;
-
-/* STUN message types supported by SER */
-#define BINDING_REQUEST			0x0001
-#define BINDING_RESPONSE		0x0101
-#define BINDING_ERROR_RESPONSE	0x0111
-
-/* common STUN attributes */
-#define MAPPED_ADDRESS_ATTR		0x0001
-#define USERNAME_ATTR			0x0006
-#define MESSAGE_INTEGRITY_ATTR	0x0008
-#define ERROR_CODE_ATTR			0x0009
-#define UNKNOWN_ATTRIBUTES_ATTR	0x000A
-
-/* STUN attributes defined by rfc5389 */
-#define REALM_ATTR				0x0014
-#define NONCE_ATTR				0x0015
-#define XOR_MAPPED_ADDRESS_ATTR	0x0020 
-#define FINGERPRINT_ATTR		0x8028
-#define SOFTWARE_ATTR				0x8022
-#define ALTERNATE_SERVER_ATTR	0x8023
-
-/* STUN attributes defined by rfc3489 */
-#define RESPONSE_ADDRESS_ATTR	0x0002
-#define CHANGE_REQUEST_ATTR		0x0003
-#define SOURCE_ADDRESS_ATTR		0x0004
-#define CHANGED_ADDRESS_ATTR	0x0005
-#define REFLECTED_FROM_ATTR		0x000b
-
-/* STUN error codes supported by SER */
-#define RESPONSE_OK				200
-#define TRY_ALTERNATE_ERR		300
-#define BAD_REQUEST_ERR			400
-#define UNAUTHORIZED_ERR		401
-#define UNKNOWN_ATTRIBUTE_ERR	420
-#define STALE_CREDENTIALS_ERR	430
-#define INTEGRITY_CHECK_ERR		431
-#define MISSING_USERNAME_ERR	432
-#define USE_TLS_ERR				433
-#define MISSING_REALM_ERR		434
-#define MISSING_NONCE_ERR		435
-#define UNKNOWN_USERNAME_ERR	436
-#define STALE_NONCE_ERR			438
-#define SERVER_ERROR_ERR		500
-#define GLOBAL_FAILURE_ERR		600
-
-#define TRY_ALTERNATE_TXT      "Try Alternate"
-#define BAD_REQUEST_TXT        "Bad Request"
-#define UNAUTHORIZED_TXT       "Unauthorized"
-#define UNKNOWN_ATTRIBUTE_TXT  "Unknown Attribute"
-#define STALE_CREDENTIALS_TXT  "Stale Credentials"
-#define INTEGRITY_CHECK_TXT    "Integrity Check Failure"
-#define MISSING_USERNAME_TXT   "Missing Username"
-#define USE_TLS_TXT            "Use TLS"
-#define MISSING_REALM_TXT      "Missing Realm"
-#define MISSING_NONCE_TXT      "Missing Nonce"
-#define UNKNOWN_USERNAME_TXT   "Unknown Username"
-#define STALE_NONCE_TXT        "Stale Nonce"
-#define SERVER_ERROR_TXT       "Server Error"
-#define GLOBAL_FAILURE_TXT     "Global Failure"
-
-
-/* other stuff */
-#define MAGIC_COOKIE	0x2112A442
-#define MAGIC_COOKIE_2B 0x2112	/* because of XOR for port */
-#define MANDATORY_ATTR	0x7fff
-#define PAD4			4
-#define PAD64			64
-#define STUN_MSG_LEN	516
-#define IPV4_LEN		4
-#define IPV6_LEN		16
-#define IPV4_FAMILY		0x0001
-#define IPV6_FAMILY		0x0002
-#define	FATAL_ERROR		-1
-#define IP_ADDR			4
-#define XOR				1
-#define TRANSACTION_ID	12
-
-/** padd len to a multiple of sz.
- *  sz must be a power of the form 2^k (e.g. 2, 4, 8, 16 ...)
- */
-#define PADD_TO(len, sz)	(((len) + (sz)-1) & (~((sz) - 1)))
-
-#define PADDED_TO_FOUR(len) PADD_TO(len, 4)
-#define PADDED_TO_SIXTYFOUR(len) PADD_TO(len, 64)
-
-struct transaction_id {
-	UINT_T	magic_cookie;
-	UCHAR_T	id[TRANSACTION_ID];
-};
-
-struct stun_hdr {
-	USHORT_T				type;
-	USHORT_T				len;
-	struct transaction_id	id;
-};
-
-struct stun_ip_addr {
-	USHORT_T	family; /* 0x01: IPv4; 0x02: IPv6 */
-	USHORT_T	port;
-	UINT_T		ip[IP_ADDR];
-};
-
-struct stun_buffer {
-	str			buf;
-	USHORT_T	empty;	/* number of free bytes in buf before 
-						 * it'll be necessary to realloc the buf 
-						 */
-};
-
-struct stun_unknown_att {
-	USHORT_T					type;
-	struct stun_unknown_att*	next;
-};
-
-struct stun_attr {
-	USHORT_T	type;
-	USHORT_T	len;
-};
-
-struct stun_msg {
-	struct stun_hdr			hdr;
-	struct stun_ip_addr		ip_addr;		/* XOR values for rfc3489bis, 
-											normal values for rfc3489 */
-	struct stun_buffer		msg;
-	UCHAR_T					old;		/* true: the format of message is in 
-										accordance with rfc3489 */ 
-};
-
-
-/*
- * stun functions called from ser
- */
-int stun_process_msg(char* buf, unsigned len, struct receive_info* ri);
-
-#endif /* USE_STUN */
-
-#endif  /* _ser_stun_h */
diff --git a/sip_msg_clone.c b/sip_msg_clone.c
index 13bc9cd..1bb55ee 100644
--- a/sip_msg_clone.c
+++ b/sip_msg_clone.c
@@ -542,8 +542,16 @@ struct sip_msg*  sip_msg_shm_clone( struct sip_msg *org_msg, int *sip_msg_len,
 	/* instance is not cloned (it's reset instead) */
 	new_msg->instance.s=0;
 	new_msg->instance.len=0;
+	/* ruid is not cloned (it's reset instead) */
+	new_msg->ruid.s=0;
+	new_msg->ruid.len=0;
+	/* location ua is not cloned (it's reset instead) */
+	new_msg->location_ua.s=0;
+	new_msg->location_ua.len=0;
 	/* reg_id is not cloned (it's reset instead) */
 	new_msg->reg_id=0;
+	/* local data struct is not cloned (it's reset instead) */
+	memset(&new_msg->ldv, 0, sizeof(msg_ldata_t));
 	/* message buffers(org and scratch pad) */
 	memcpy( p , org_msg->buf, org_msg->len);
 	/* ZT to be safer */
diff --git a/socket_info.c b/socket_info.c
index f865f43..3314014 100644
--- a/socket_info.c
+++ b/socket_info.c
@@ -513,9 +513,7 @@ struct socket_info** get_sock_info_list(unsigned short proto)
 inline static int si_hname_cmp(str* host, str* name, str* addr_str, 
 								struct ip_addr* ip_addr, int flags)
 {
-#ifdef USE_IPV6
 	struct ip_addr* ip6;
-#endif
 	
 	if ( (host->len==name->len) && 
 		(strncasecmp(host->s, name->s, name->len)==0) /*slower*/)
@@ -524,7 +522,6 @@ inline static int si_hname_cmp(str* host, str* name, str* addr_str,
 		 * ipv6 addresses if we are lucky*/
 		goto found;
 	/* check if host == ip address */
-#ifdef USE_IPV6
 	/* ipv6 case is uglier, host can be [3ffe::1] */
 	ip6=str2ip6(host);
 	if (ip6){
@@ -534,7 +531,6 @@ inline static int si_hname_cmp(str* host, str* name, str* addr_str,
 			return -1; /* no match, but this is an ipv6 address
 						 so no point in trying ipv4 */
 	}
-#endif
 	/* ipv4 */
 	if ( (!(flags&SI_IS_IP)) && (host->len==addr_str->len) && 
 			(memcmp(host->s, addr_str->s, addr_str->len)==0) )
@@ -563,13 +559,11 @@ struct socket_info* grep_sock_info(str* host, unsigned short port,
 	unsigned short c_proto;
 	
 	hname=*host;
-#ifdef USE_IPV6
 	if ((hname.len>2)&&((*hname.s)=='[')&&(hname.s[hname.len-1]==']')){
 		/* ipv6 reference, skip [] */
 		hname.s++;
 		hname.len-=2;
 	}
-#endif
 
 	c_proto=(proto!=PROTO_NONE)?proto:PROTO_UDP;
 retry:
@@ -1275,12 +1269,8 @@ int add_interfaces(char* if_name, int family, unsigned short port,
 				#else
 					( (ifr.ifr_addr.sa_family==AF_INET)?
 						sizeof(struct sockaddr_in):
-					#ifdef USE_IPV6
 						((ifr.ifr_addr.sa_family==AF_INET6)?
 						sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) )
-					#else /* USE_IPV6 */
-						sizeof(struct sockaddr) )
-					#endif /* USE_IPV6 */
 				#endif
 				)
 			#endif
@@ -1843,13 +1833,11 @@ int fix_all_socket_lists()
 		){
 		/* get all listening ipv4/ipv6 interfaces */
 		if ( ( (add_interfaces(0, AF_INET, 0,  PROTO_UDP, &ai_lst)==0)
-#ifdef USE_IPV6
 #ifdef __OS_linux
 		&&  (!auto_bind_ipv6 || add_interfaces_via_netlink(0, AF_INET6, 0, PROTO_UDP, &ai_lst) == 0)
 #else
 		&& ( !auto_bind_ipv6 || add_interfaces(0, AF_INET6, 0,  PROTO_UDP, &ai_lst) !=0 ) /* add_interface does not work for IPv6 on Linux */
 #endif /* __OS_linux */
-#endif /* USE_IPV6 */
 			 ) && (addr_info_to_si_lst(ai_lst, 0, PROTO_UDP, 0, &udp_listen)==0)){
 			free_addr_info_lst(&ai_lst);
 			ai_lst=0;
@@ -1857,13 +1845,11 @@ int fix_all_socket_lists()
 #ifdef USE_TCP
 			if (!tcp_disable){
 				if ( ((add_interfaces(0, AF_INET, 0,  PROTO_TCP, &ai_lst)!=0)
-#ifdef USE_IPV6
 #ifdef __OS_linux
     				|| (auto_bind_ipv6 && add_interfaces_via_netlink(0, AF_INET6, 0, PROTO_TCP, &ai_lst) != 0)
 #else
 				|| (auto_bind_ipv6 && add_interfaces(0, AF_INET6, 0,  PROTO_TCP, &ai_lst) !=0 )
 #endif /* __OS_linux */
-#endif /* USE_IPV6 */
 				) || (addr_info_to_si_lst(ai_lst, 0, PROTO_TCP, 0,
 										 				&tcp_listen)!=0))
 					goto error;
@@ -1873,13 +1859,11 @@ int fix_all_socket_lists()
 				if (!tls_disable){
 					if (((add_interfaces(0, AF_INET, 0, PROTO_TLS,
 										&ai_lst)!=0)
-#ifdef USE_IPV6
 #ifdef __OS_linux
     				|| (auto_bind_ipv6 && add_interfaces_via_netlink(0, AF_INET6, 0, PROTO_TLS, &ai_lst) != 0)
 #else
 				|| (auto_bind_ipv6 && add_interfaces(0, AF_INET6, 0,  PROTO_TLS, &ai_lst)!=0)
 #endif /* __OS_linux */
-#endif /* USE_IPV6 */
 					) || (addr_info_to_si_lst(ai_lst, 0, PROTO_TLS, 0,
 										 				&tls_listen)!=0))
 						goto error;
@@ -1892,13 +1876,11 @@ int fix_all_socket_lists()
 #ifdef USE_SCTP
 			if (!sctp_disable){
 				if (((add_interfaces(0, AF_INET, 0,  PROTO_SCTP, &ai_lst)!=0)
-#ifdef USE_IPV6
 #ifdef __OS_linux
     				|| (auto_bind_ipv6 && add_interfaces_via_netlink(0, AF_INET6, 0, PROTO_SCTP, &ai_lst) != 0)
 #else
 				|| (auto_bind_ipv6 && add_interfaces(0, AF_INET6, 0,  PROTO_SCTP, &ai_lst) != 0)
 #endif /* __OS_linux */
-#endif /* USE_IPV6 */
 					) || (addr_info_to_si_lst(ai_lst, 0, PROTO_SCTP, 0,
 							 				&sctp_listen)!=0))
 					goto error;
@@ -2075,3 +2057,97 @@ void init_proto_order()
 }
 
 
+/**
+ * parse '[port:]host[:port]' string to a broken down structure
+ */
+int parse_protohostport(str* ins, sr_phostp_t *r)
+{
+	char* first; /* first ':' occurrence */
+	char* second; /* second ':' occurrence */
+	char* p;
+	int bracket;
+	char* tmp;
+
+	first=second=0;
+	bracket=0;
+	memset(r, 0, sizeof(sr_phostp_t));
+
+	/* find the first 2 ':', ignoring possible ipv6 addresses
+	 * (substrings between [])
+	 */
+	for(p=ins->s; p<ins->s+ins->len; p++){
+		switch(*p){
+			case '[':
+				bracket++;
+				if (bracket>1) goto error_brackets;
+				break;
+			case ']':
+				bracket--;
+				if (bracket<0) goto error_brackets;
+				break;
+			case ':':
+				if (bracket==0){
+					if (first==0) first=p;
+					else if( second==0) second=p;
+					else goto error_colons;
+				}
+				break;
+		}
+	}
+	if (p==ins->s) return -1;
+	if (*(p-1)==':') goto error_colons;
+
+	if (first==0) { /* no ':' => only host */
+		r->host.s=ins->s;
+		r->host.len=(int)(p-ins->s);
+		goto end;
+	}
+	if (second) { /* 2 ':' found => check if valid */
+		if (parse_proto((unsigned char*)ins->s, first-ins->s, &r->proto)<0)
+			goto error_proto;
+		r->port=strtol(second+1, &tmp, 10);
+		if ((tmp==0)||(*tmp)||(tmp==second+1)) goto error_port;
+		r->host.s=first+1;
+		r->host.len=(int)(second-r->host.s);
+		goto end;
+	}
+	/* only 1 ':' found => it's either proto:host or host:port */
+	r->port=strtol(first+1, &tmp, 10);
+	if ((tmp==0)||(*tmp)||(tmp==first+1)){
+		/* invalid port => it's proto:host */
+		if (parse_proto((unsigned char*)ins->s, first-ins->s, &r->proto)<0)
+			goto error_proto;
+		r->host.s=first+1;
+		r->host.len=(int)(p-r->host.s);
+	}else{
+		/* valid port => its host:port */
+		r->host.s=ins->s;
+		r->host.len=(int)(first-r->host.s);
+	}
+end:
+	return 0;
+error_brackets:
+	LOG(L_ERR, "too many brackets in %.*s\n", ins->len, ins->s);
+	return -1;
+error_colons:
+	LOG(L_ERR, "too many colons in %.*s\n", ins->len, ins->s);
+	return -1;
+error_proto:
+	LOG(L_ERR, "bad protocol in %.*s\n", ins->len, ins->s);
+	return -1;
+error_port:
+	LOG(L_ERR, "bad port number in %.*s\n", ins->len, ins->s);
+	return -1;
+}
+
+/**
+ * lookup a local socket by '[port:]host[:port]' string
+ */
+struct socket_info* lookup_local_socket(str *phostp)
+{
+	sr_phostp_t r;
+	if(parse_protohostport(phostp, &r)<0)
+		return NULL;
+	return grep_sock_info(&r.host, (unsigned short)r.port,
+			(unsigned short)r.proto);
+}
diff --git a/socket_info.h b/socket_info.h
index 926b317..ea0ab8b 100644
--- a/socket_info.h
+++ b/socket_info.h
@@ -105,6 +105,8 @@ struct socket_info** get_sock_info_list(unsigned short proto);
 int parse_phostport(char* s, char** host, int* hlen,
 								 int* port, int* proto);
 
+int parse_proto(unsigned char* s, long len, int* proto);
+
 char* get_valid_proto_name(unsigned short proto);
 
 /* helper function:
@@ -142,5 +144,13 @@ inline static struct socket_info* get_first_socket(void)
 	return 0;
 }
 
+/* structure to break down 'proto:host:port' */
+typedef struct _sr_phostp {
+	int proto;
+	str host;
+	int port;
+} sr_phostp_t;
+
+struct socket_info* lookup_local_socket(str *phostp);
 
 #endif
diff --git a/sr_module.c b/sr_module.c
index 485f975..e169291 100644
--- a/sr_module.c
+++ b/sr_module.c
@@ -64,6 +64,7 @@
 #include "globals.h"
 #include "rpc_lookup.h"
 #include "sr_compat.h"
+#include "ppcfg.h"
 
 #include <sys/stat.h>
 #include <regex.h>
@@ -119,6 +120,17 @@ struct sr_module* modules=0;
 int mod_response_cbk_no=0;
 response_function* mod_response_cbks=0;
 
+/* number of usec to wait before initializing a module */
+static unsigned int modinit_delay = 0;
+
+unsigned int set_modinit_delay(unsigned int v)
+{
+	unsigned int r;
+	r =  modinit_delay;
+	modinit_delay = v;
+	return r;
+}
+
 /**
  * if bit 1 set, SIP worker processes handle RPC commands as well
  * if bit 2 set, RPC worker processes handle SIP commands as well
@@ -271,6 +283,7 @@ static int register_module(unsigned ver, union module_exports_u* e,
 {
 	int ret, i;
 	struct sr_module* mod;
+	char defmod[64];
 
 	ret=-1;
 
@@ -366,6 +379,20 @@ static int register_module(unsigned ver, union module_exports_u* e,
 		/* i==0 => success */
 	}
 
+	/* add cfg define for each module: MOD_modulename */
+	if(strlen(mod->exports.name)>=60) {
+		LM_ERR("too long module name: %s\n", mod->exports.name);
+		goto error;
+	}
+	strcpy(defmod, "MOD_");
+	strcat(defmod, mod->exports.name);
+	pp_define_set_type(0);
+	if(pp_define(strlen(defmod), defmod)<0) {
+		LM_ERR("unable to set cfg define for module: %s\n",
+				mod->exports.name);
+		goto error;
+	}
+
 	/* link module in the list */
 	mod->next=modules;
 	modules=mod;
@@ -816,12 +843,16 @@ int init_modules(void)
 	struct sr_module* t;
 
 	for(t = modules; t; t = t->next) {
-		if (t->exports.init_f)
+		if (t->exports.init_f) {
 			if (t->exports.init_f() != 0) {
 				LOG(L_ERR, "init_modules(): Error while"
 						" initializing module %s\n", t->exports.name);
 				return -1;
 			}
+			/* delay next module init, if configured */
+			if(unlikely(modinit_delay>0))
+				sleep_us(modinit_delay);
+		}
 		if (t->exports.response_f)
 			mod_response_cbk_no++;
 	}
diff --git a/sr_module.h b/sr_module.h
index 810008f..14f9936 100644
--- a/sr_module.h
+++ b/sr_module.h
@@ -670,4 +670,6 @@ void set_child_rpc_sip_mode(void);
 int is_sip_worker(int rank);
 int is_rpc_worker(int rank);
 
+unsigned int set_modinit_delay(unsigned int v);
+
 #endif /* sr_module_h */
diff --git a/stun.c b/stun.c
new file mode 100644
index 0000000..31da8b5
--- /dev/null
+++ b/stun.c
@@ -0,0 +1,46 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "events.h"
+#include "ip_addr.h"
+#include "stun.h"
+
+int stun_process_msg(char* buf, unsigned int len, struct receive_info* ri)
+{
+        int ret;
+	stun_event_info_t sev;
+
+        ret = 0;
+        LM_DBG("STUN Message: [[>>>\n%.*s<<<]]\n", len, buf);
+        if(likely(sr_event_enabled(SREV_STUN_IN))) {
+		memset(&sev, 0, sizeof(stun_event_info_t));
+		sev.buf = buf;
+		sev.len = len;
+		sev.rcv = ri;
+                ret = sr_event_exec(SREV_STUN_IN, (void *) &sev);
+        } else {
+                LM_DBG("no callback registering for handling STUN -"
+			" dropping!\n");
+        }
+        return ret;
+}
diff --git a/stun.h b/stun.h
new file mode 100644
index 0000000..b1aef60
--- /dev/null
+++ b/stun.h
@@ -0,0 +1,64 @@
+/*
+ * $Id$
+ *
+ * Portions Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * Based on "ser_stun.h". Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _STUN_H
+#define _STUN_H
+
+#include "ip_addr.h"
+
+/* type redefinition */
+typedef unsigned char UCHAR_T;
+typedef unsigned short USHORT_T;
+typedef unsigned int UINT_T;
+typedef unsigned long ULONG_T;
+
+#define MAGIC_COOKIE	0x2112A442
+#define TRANSACTION_ID	12
+
+struct transaction_id {
+        UINT_T magic_cookie;
+        UCHAR_T id[TRANSACTION_ID];
+};
+
+struct stun_hdr {
+        USHORT_T type;
+        USHORT_T len;
+        struct transaction_id id;
+};
+
+struct stun_attr {
+        USHORT_T type;
+        USHORT_T len;
+};
+
+typedef struct stun_event_info {
+	char *buf;
+	unsigned int len;
+	struct receive_info *rcv;
+} stun_event_info_t;
+
+int stun_process_msg(char* buf, unsigned int len, struct receive_info* ri);
+
+#endif /* _STUN_H */
diff --git a/tcp_main.c b/tcp_main.c
index 8a650a1..0c5a333 100644
--- a/tcp_main.c
+++ b/tcp_main.c
@@ -254,10 +254,8 @@ int tls_max_connections=DEFAULT_TLS_MAX_CONNECTIONS;
 
 static union sockaddr_union tcp_source_ipv4_addr; /* saved bind/srv v4 addr. */
 static union sockaddr_union* tcp_source_ipv4=0;
-#ifdef USE_IPV6
 static union sockaddr_union tcp_source_ipv6_addr; /* saved bind/src v6 addr. */
 static union sockaddr_union* tcp_source_ipv6=0;
-#endif
 
 static int* tcp_connections_no=0; /* current tcp (+tls) open connections */
 static int* tls_connections_no=0; /* current tls open connections */
@@ -308,12 +306,10 @@ int tcp_set_src_addr(struct ip_addr* ip)
 			ip_addr2su(&tcp_source_ipv4_addr, ip, 0);
 			tcp_source_ipv4=&tcp_source_ipv4_addr;
 			break;
-		#ifdef USE_IPV6
 		case AF_INET6:
 			ip_addr2su(&tcp_source_ipv6_addr, ip, 0);
 			tcp_source_ipv6=&tcp_source_ipv6_addr;
 			break;
-		#endif
 		default:
 			return -1;
 	}
@@ -395,7 +391,6 @@ static int init_sock_opt(int s, int af)
 					strerror(errno));
 			/* continue since this is not critical */
 		}
-#ifdef USE_IPV6
 	} else if(af==AF_INET6){
 		if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS,
 					(void*)&optval, sizeof(optval)) ==-1) {
@@ -403,7 +398,6 @@ static int init_sock_opt(int s, int af)
 					strerror(errno));
 			/* continue since this is not critical */
 		}
-#endif
 	}
 
 #if  !defined(TCP_DONT_REUSEADDR) 
@@ -1250,9 +1244,7 @@ find_socket:
 				" listening socket for %s, using default...\n",
 					su2a(server, sizeof(*server)), ip_addr2a(&ip));
 		if (server->s.sa_family==AF_INET) *res_si=sendipv4_tcp;
-#ifdef USE_IPV6
 		else *res_si=sendipv6_tcp;
-#endif
 	}
 	*res_local_addr=*from;
 	return s;
@@ -1862,11 +1854,9 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
 				case AF_INET:
 						from = tcp_source_ipv4;
 					break;
-#ifdef USE_IPV6
 				case AF_INET6:
 						from = tcp_source_ipv6;
 					break;
-#endif
 				default:
 					/* error, bad af, ignore ... */
 					break;
diff --git a/tcp_options.c b/tcp_options.c
index ce3a381..5069948 100644
--- a/tcp_options.c
+++ b/tcp_options.c
@@ -115,7 +115,7 @@ static cfg_def_t tcp_cfg_def[] = {
 	{ "new_conn_alias_flags", CFG_VAR_INT | CFG_ATOMIC, 0,    2,  0,         0,
 		"flags for the def. aliases for a new conn. (FORCE_ADD:1, REPLACE:2 "},
 	{ "accept_no_cl",   CFG_VAR_INT | CFG_ATOMIC,   0,        1,  0,         0,
-		"accept TCP messges without Content-Lenght "},
+		"accept TCP messges without Content-Length "},
 	/* internal and/or "fixed" versions of some vars
 	   (not supposed to be writeable, read will provide only debugging value*/
 	{ "rd_buf_size", CFG_VAR_INT | CFG_ATOMIC,    512,    16777216,  0,         0,
diff --git a/tcp_options.h b/tcp_options.h
index 49a3e34..ba9dd4b 100644
--- a/tcp_options.h
+++ b/tcp_options.h
@@ -139,7 +139,7 @@ struct cfg_group_tcp{
 	int accept_aliases;
 	int alias_flags;
 	int new_conn_alias_flags;
-	int accept_no_cl;  /* on/off - accpet messages without content-lenght */
+	int accept_no_cl;  /* on/off - accept messages without content-length */
 
 	/* internal, "fixed" vars */
 	unsigned int rd_buf_size; /* read buffer size (should be > max. datagram)*/
diff --git a/tcp_read.c b/tcp_read.c
index 618e05a..37b577f 100644
--- a/tcp_read.c
+++ b/tcp_read.c
@@ -97,16 +97,10 @@
 #include "tsend.h"
 #include "forward.h"
 #include "events.h"
-
-#ifdef USE_STUN
-#include "ser_stun.h"
-
-int is_msg_complete(struct tcp_req* r);
-
-#endif /* USE_STUN */
+#include "stun.h"
 
 #ifdef READ_HTTP11
-#define HTTP11CONTINUE	"HTTP/1.1 100 Continue\r\nContent-Lenght: 0\r\n\r\n"
+#define HTTP11CONTINUE	"HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n"
 #define HTTP11CONTINUE_LEN	(sizeof(HTTP11CONTINUE)-1)
 #endif
 
@@ -123,6 +117,8 @@ static int tcpmain_sock=-1;
 static struct local_timer tcp_reader_ltimer;
 static ticks_t tcp_reader_prev_ticks;
 
+int is_msg_complete(struct tcp_req* r);
+
 /**
  * control cloning of TCP receive buffer
  * - needed for operations working directly inside the buffer
@@ -373,11 +369,8 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 	int bytes, remaining;
 	char *p;
 	struct tcp_req* r;
-
-#ifdef USE_STUN
 	unsigned int mc;   /* magic cookie */
 	unsigned short body_len;
-#endif
 
 #ifdef READ_MSRP
 	char *mfline;
@@ -610,18 +603,16 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 						r->start=p;
 						break;
 					default:
-#ifdef USE_STUN
-						/* STUN support can be switched off even if it's compiled */
 						/* stun test */						
-						if (stun_allow_stun && (unsigned char)*p == 0x00) {
+						if (unlikely(sr_event_enabled(SREV_STUN_IN)) && (unsigned char)*p == 0x00) {
 							r->state=H_STUN_MSG;
 						/* body will used as pointer to the last used byte */
 							r->body=p;
 							r->content_len = 0;
 							DBG("stun msg detected\n");
-						}else
-#endif
-						r->state=H_SKIP;
+						} else {
+							r->state=H_SKIP;
+						}
 						r->start=p;
 				};
 				p++;
@@ -656,7 +647,7 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 					r->state = H_SKIP_EMPTY;
 				}
 				break;
-#ifdef USE_STUN
+
 			case H_STUN_MSG:
 				if ((r->pos - r->body) >= sizeof(struct stun_hdr)) {
 					/* copy second short from buffer where should be body 
@@ -688,8 +679,8 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 						}
 						else {
 							/* set content_len to length of fingerprint */
-							body_len = sizeof(struct stun_attr) + 
-									   SHA_DIGEST_LENGTH;
+							body_len = sizeof(struct stun_attr) + 20;
+							/* 20 is SHA_DIGEST_LENGTH from openssl/sha.h */
 						}
 					}
 					r->content_len=body_len;
@@ -711,7 +702,8 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 					}
 					else {
 						/* set content_len to length of fingerprint */
-						body_len = sizeof(struct stun_attr)+SHA_DIGEST_LENGTH;
+						body_len = sizeof(struct stun_attr) + 20;
+						/* 20 is SHA_DIGEST_LENGTH from openssl/sha.h */
 						r->content_len=body_len;
 					}
 				}
@@ -736,7 +728,7 @@ int tcp_read_headers(struct tcp_connection *c, int* read_flags)
 					p = r->pos;
 				}
 				break;
-#endif /* USE_STUN */
+
 			change_state_case(H_CONT_LEN1,  'O', 'o', H_CONT_LEN2);
 			change_state_case(H_CONT_LEN2,  'N', 'n', H_CONT_LEN3);
 			change_state_case(H_CONT_LEN3,  'T', 't', H_CONT_LEN4);
@@ -1364,14 +1356,11 @@ again:
 					LOG(L_ERR, "CRLF ping: tcp_send() failed\n");
 				}
 				ret = 0;
-			}else
-#ifdef USE_STUN
-			if (unlikely(req->state==H_STUN_END)){
+			} else if (unlikely(req->state==H_STUN_END)) {
 				/* stun request */
 				ret = stun_process_msg(req->start, req->parsed-req->start,
 									 &con->rcv);
-			}else
-#endif
+			} else
 #ifdef READ_MSRP
 			// if (unlikely(req->flags&F_TCP_REQ_MSRP_FRAME)){
 			if (unlikely(req->state==H_MSRP_FINISH)){
@@ -1776,8 +1765,6 @@ error:
 }
 
 
-
-#ifdef USE_STUN
 int is_msg_complete(struct tcp_req* r)
 {
 	if (TCP_REQ_HAS_CLEN(r)) {
@@ -1792,6 +1779,5 @@ int is_msg_complete(struct tcp_req* r)
 		return 1;
 	}
 }
-#endif
 
 #endif /* USE_TCP */
diff --git a/timer_funcs.h b/timer_funcs.h
index 8e17b8a..28c223d 100644
--- a/timer_funcs.h
+++ b/timer_funcs.h
@@ -157,6 +157,8 @@ static inline void timer_redist(ticks_t t, struct timer_head *h)
 
 static inline void timer_run(ticks_t t)
 {
+	struct timer_head *thp;
+
 	/* trust the compiler for optimizing */
 	if ((t & H0_MASK)==0){              /*r1*/
 		if ((t & H1_H0_MASK)==0){        /*r2*/
@@ -168,7 +170,8 @@ static inline void timer_run(ticks_t t)
 	/*
 	DBG("timer_run: ticks %u, expire h0[%u]\n",
 						(unsigned ) t, (unsigned)(t & H0_MASK));*/
-	_timer_mv_expire(&timer_lst->h0[t & H0_MASK]);  /*r1*/
+	thp = &timer_lst->h0[t & H0_MASK];
+	_timer_mv_expire(thp);  /*r1*/
 }
 #else
 
diff --git a/udp_server.c b/udp_server.c
index d4efe13..ea88f10 100644
--- a/udp_server.c
+++ b/udp_server.c
@@ -76,15 +76,12 @@
 #include "ip_addr.h"
 #include "cfg/cfg_struct.h"
 #include "events.h"
+#include "stun.h"
 #ifdef USE_RAW_SOCKS
 #include "raw_sock.h"
 #endif /* USE_RAW_SOCKS */
 
 
-#ifdef USE_STUN
-  #include "ser_stun.h"
-#endif
-
 #ifdef DBG_MSG_QA
 /* message quality assurance -- frequently, bugs in ser have
    been indicated by zero characters or long whitespaces
@@ -243,9 +240,7 @@ int probe_max_receive_buffer( int udp_sock )
 static int setup_mcast_rcvr(int sock, union sockaddr_union* addr)
 {
 	struct ip_mreq mreq;
-#ifdef USE_IPV6
 	struct ipv6_mreq mreq6;
-#endif /* USE_IPV6 */
 	
 	if (addr->s.sa_family==AF_INET){
 		memcpy(&mreq.imr_multiaddr, &addr->sin.sin_addr, 
@@ -259,7 +254,6 @@ static int setup_mcast_rcvr(int sock, union sockaddr_union* addr)
 			return -1;
 		}
 		
-#ifdef USE_IPV6
 	} else if (addr->s.sa_family==AF_INET6){
 		memcpy(&mreq6.ipv6mr_multiaddr, &addr->sin6.sin6_addr, 
 		       sizeof(struct in6_addr));
@@ -275,7 +269,6 @@ static int setup_mcast_rcvr(int sock, union sockaddr_union* addr)
 			return -1;
 		}
 		
-#endif /* USE_IPV6 */
 	} else {
 		LOG(L_ERR, "ERROR: setup_mcast_rcvr: Unsupported protocol family\n");
 		return -1;
@@ -328,7 +321,6 @@ int udp_init(struct socket_info* sock_info)
 					strerror(errno));
 			/* continue since this is not critical */
 		}
-#ifdef USE_IPV6
 	} else if (addr->s.sa_family==AF_INET6){
 		if (setsockopt(sock_info->socket, IPPROTO_IPV6, IPV6_TCLASS,
 					(void*)&optval, sizeof(optval)) ==-1) {
@@ -336,7 +328,6 @@ int udp_init(struct socket_info* sock_info)
 					strerror(errno));
 			/* continue since this is not critical */
 		}
-#endif
 	}
 
 #if defined (__OS_linux) && defined(UDP_ERRORS)
@@ -382,7 +373,6 @@ int udp_init(struct socket_info* sock_info)
 						" %s\n", strerror(errno));
 			}
 		}
-#ifdef USE_IPV6
 	} else if (addr->s.sa_family==AF_INET6){
 		if (setsockopt(sock_info->socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 
 						&mcast_loopback, sizeof(mcast_loopback))==-1){
@@ -396,7 +386,6 @@ int udp_init(struct socket_info* sock_info)
 						"(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
 			}
 		}
-#endif /* USE_IPV6*/
 	} else {
 		LOG(L_ERR, "ERROR: udp_init: Unsupported protocol family %d\n",
 					addr->s.sa_family);
@@ -412,11 +401,9 @@ int udp_init(struct socket_info* sock_info)
 				(unsigned)sockaddru_len(*addr),
 				sock_info->address_str.s,
 				strerror(errno));
-	#ifdef USE_IPV6
 		if (addr->s.sa_family==AF_INET6)
 			LOG(L_ERR, "ERROR: udp_init: might be caused by using a link "
 					" local address, try site local or global\n");
-	#endif
 		goto error;
 	}
 
@@ -501,19 +488,14 @@ int udp_rcv_loop()
 			}
 		}
 #ifndef NO_ZERO_CHECKS
-#ifdef USE_STUN
-		/* STUN support can be switched off even if it's compiled */
-		if (stun_allow_stun == 0 || (unsigned char)*buf != 0x00) {
-#endif
-		  if (len<MIN_UDP_PACKET) {
-			  tmp=ip_addr2a(&ri.src_ip);
-			  DBG("udp_rcv_loop: probing packet received from %s %d\n",
-				  	tmp, htons(ri.src_port));
-			  continue;
-		  }
-#ifdef USE_STUN
+		if (!unlikely(sr_event_enabled(SREV_STUN_IN)) || (unsigned char)*buf != 0x00) {
+			if (len<MIN_UDP_PACKET) {
+				tmp=ip_addr2a(&ri.src_ip);
+				DBG("udp_rcv_loop: probing packet received from %s %d\n",
+					tmp, htons(ri.src_port));
+				continue;
+			}
 		}
-#endif
 /* historically, zero-terminated packets indicated a bug in clients
  * that calculated wrongly packet length and included string-terminating
  * zero; today clients exist with legitimate binary payloads and we
@@ -544,17 +526,15 @@ int udp_rcv_loop()
 		
 		/* update the local config */
 		cfg_update();
-#ifdef USE_STUN
-			/* STUN support can be switched off even if it's compiled */
-			if (stun_allow_stun && (unsigned char)*buf == 0x00) {
-			    /* stun_process_msg releases buf memory if necessary */
-				if ((stun_process_msg(buf, len, &ri)) != 0) {
-					continue; /* some error occurred */
-				}
-			} else
-#endif
-		/* receive_msg must free buf too!*/
-		receive_msg(buf, len, &ri);
+		if (unlikely(sr_event_enabled(SREV_STUN_IN)) && (unsigned char)*buf == 0x00) {
+			/* stun_process_msg releases buf memory if necessary */
+			if ((stun_process_msg(buf, len, &ri)) != 0) {
+				continue; /* some error occurred */
+			}
+		} else {
+			/* receive_msg must free buf too!*/
+			receive_msg(buf, len, &ri);
+		}
 		
 	/* skip: do other stuff */
 		
diff --git a/utils/kamctl/db_berkeley/kamailio/acc_cdrs b/utils/kamctl/db_berkeley/kamailio/acc_cdrs
new file mode 100644
index 0000000..32fb63b
--- /dev/null
+++ b/utils/kamctl/db_berkeley/kamailio/acc_cdrs
@@ -0,0 +1,10 @@
+METADATA_COLUMNS
+id(int) start_time(str) end_time(str) duration(str)
+METADATA_KEY
+
+METADATA_READONLY
+0
+METADATA_LOGFLAGS
+0
+METADATA_DEFAULTS
+NIL|''|''|''
diff --git a/utils/kamctl/db_berkeley/kamailio/mohqcalls b/utils/kamctl/db_berkeley/kamailio/mohqcalls
new file mode 100644
index 0000000..3cb22c7
--- /dev/null
+++ b/utils/kamctl/db_berkeley/kamailio/mohqcalls
@@ -0,0 +1,10 @@
+METADATA_COLUMNS
+id(int) mohq_id(int) call_id(str) call_status(int) call_from(str) call_contact(str) call_time(datetime)
+METADATA_KEY
+
+METADATA_READONLY
+0
+METADATA_LOGFLAGS
+0
+METADATA_DEFAULTS
+NIL|NIL|NIL|NIL|NIL|NIL|NIL
diff --git a/utils/kamctl/db_berkeley/kamailio/mohqueues b/utils/kamctl/db_berkeley/kamailio/mohqueues
new file mode 100644
index 0000000..eafd9ce
--- /dev/null
+++ b/utils/kamctl/db_berkeley/kamailio/mohqueues
@@ -0,0 +1,10 @@
+METADATA_COLUMNS
+id(int) name(str) uri(str) mohdir(str) mohfile(str) debug(int)
+METADATA_KEY
+
+METADATA_READONLY
+0
+METADATA_LOGFLAGS
+0
+METADATA_DEFAULTS
+NIL|NIL|NIL|NIL|NIL|NIL
diff --git a/utils/kamctl/db_berkeley/kamailio/rtpproxy b/utils/kamctl/db_berkeley/kamailio/rtpproxy
new file mode 100644
index 0000000..09ba958
--- /dev/null
+++ b/utils/kamctl/db_berkeley/kamailio/rtpproxy
@@ -0,0 +1,10 @@
+METADATA_COLUMNS
+id(int) setid(str) url(str) flags(int) weight(int) description(str)
+METADATA_KEY
+3 4 
+METADATA_READONLY
+0
+METADATA_LOGFLAGS
+0
+METADATA_DEFAULTS
+NIL|00|''|0|1|''
diff --git a/utils/kamctl/db_berkeley/kamailio/version b/utils/kamctl/db_berkeley/kamailio/version
index ef9cac4..e9e350b 100644
--- a/utils/kamctl/db_berkeley/kamailio/version
+++ b/utils/kamctl/db_berkeley/kamailio/version
@@ -10,6 +10,8 @@ METADATA_DEFAULTS
 NIL|0
 acc|
 acc|4
+acc_cdrs|
+acc_cdrs|1
 active_watchers|
 active_watchers|11
 address|
@@ -74,6 +76,10 @@ matrix|
 matrix|1
 missed_calls|
 missed_calls|3
+mohqcalls|
+mohqcalls|1
+mohqueues|
+mohqueues|1
 mtree|
 mtree|1
 mtrees|
@@ -94,6 +100,8 @@ rls_presentity|
 rls_presentity|1
 rls_watchers|
 rls_watchers|3
+rtpproxy|
+rtpproxy|1
 sca_subscriptions|
 sca_subscriptions|1
 silo|
diff --git a/utils/kamctl/db_sqlite/acc-create.sql b/utils/kamctl/db_sqlite/acc-create.sql
index 103014a..43d3355 100644
--- a/utils/kamctl/db_sqlite/acc-create.sql
+++ b/utils/kamctl/db_sqlite/acc-create.sql
@@ -12,6 +12,16 @@ CREATE TABLE acc (
 
 CREATE INDEX acc_callid_idx ON acc (callid);
 
+INSERT INTO version (table_name, table_version) values ('acc_cdrs','1');
+CREATE TABLE acc_cdrs (
+    id INTEGER PRIMARY KEY NOT NULL,
+    start_time VARCHAR(32) DEFAULT '' NOT NULL,
+    end_time VARCHAR(32) DEFAULT '' NOT NULL,
+    duration VARCHAR(32) DEFAULT '' NOT NULL
+);
+
+CREATE INDEX acc_cdrs_start_time_idx ON acc_cdrs (start_time);
+
 INSERT INTO version (table_name, table_version) values ('missed_calls','3');
 CREATE TABLE missed_calls (
     id INTEGER PRIMARY KEY NOT NULL,
diff --git a/utils/kamctl/db_sqlite/alias_db-create.sql b/utils/kamctl/db_sqlite/alias_db-create.sql
index 90656e9..f9975de 100644
--- a/utils/kamctl/db_sqlite/alias_db-create.sql
+++ b/utils/kamctl/db_sqlite/alias_db-create.sql
@@ -4,9 +4,10 @@ CREATE TABLE dbaliases (
     alias_username VARCHAR(64) DEFAULT '' NOT NULL,
     alias_domain VARCHAR(64) DEFAULT '' NOT NULL,
     username VARCHAR(64) DEFAULT '' NOT NULL,
-    domain VARCHAR(64) DEFAULT '' NOT NULL,
-    CONSTRAINT dbaliases_alias_idx UNIQUE (alias_username, alias_domain)
+    domain VARCHAR(64) DEFAULT '' NOT NULL
 );
 
+CREATE INDEX dbaliases_alias_user_idx ON dbaliases (alias_username);
+CREATE INDEX dbaliases_alias_idx ON dbaliases (alias_username, alias_domain);
 CREATE INDEX dbaliases_target_idx ON dbaliases (username, domain);
 
diff --git a/utils/kamctl/db_sqlite/mohqueue-create.sql b/utils/kamctl/db_sqlite/mohqueue-create.sql
new file mode 100644
index 0000000..3989fe8
--- /dev/null
+++ b/utils/kamctl/db_sqlite/mohqueue-create.sql
@@ -0,0 +1,24 @@
+INSERT INTO version (table_name, table_version) values ('mohqcalls','1');
+CREATE TABLE mohqcalls (
+    id INTEGER PRIMARY KEY NOT NULL,
+    mohq_id INTEGER NOT NULL,
+    call_id VARCHAR(100) NOT NULL,
+    call_status INTEGER NOT NULL,
+    call_from VARCHAR(100) NOT NULL,
+    call_contact VARCHAR(100),
+    call_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
+    CONSTRAINT mohqcalls_mohqcalls_idx UNIQUE (call_id)
+);
+
+INSERT INTO version (table_name, table_version) values ('mohqueues','1');
+CREATE TABLE mohqueues (
+    id INTEGER PRIMARY KEY NOT NULL,
+    name VARCHAR(25) NOT NULL,
+    uri VARCHAR(100) NOT NULL,
+    mohdir VARCHAR(100),
+    mohfile VARCHAR(100) NOT NULL,
+    debug INTEGER NOT NULL,
+    CONSTRAINT mohqueues_mohqueue_uri_idx UNIQUE (uri),
+    CONSTRAINT mohqueues_mohqueue_name_idx UNIQUE (name)
+);
+
diff --git a/utils/kamctl/db_sqlite/rtpproxy-create.sql b/utils/kamctl/db_sqlite/rtpproxy-create.sql
new file mode 100644
index 0000000..9076577
--- /dev/null
+++ b/utils/kamctl/db_sqlite/rtpproxy-create.sql
@@ -0,0 +1,10 @@
+INSERT INTO version (table_name, table_version) values ('rtpproxy','1');
+CREATE TABLE rtpproxy (
+    id INTEGER PRIMARY KEY NOT NULL,
+    setid VARCHAR(32) DEFAULT 00 NOT NULL,
+    url VARCHAR(64) DEFAULT '' NOT NULL,
+    flags INTEGER DEFAULT 0 NOT NULL,
+    weight INTEGER DEFAULT 1 NOT NULL,
+    description VARCHAR(64) DEFAULT '' NOT NULL
+);
+
diff --git a/utils/kamctl/dbtext/kamailio/acc_cdrs b/utils/kamctl/dbtext/kamailio/acc_cdrs
new file mode 100644
index 0000000..df44e95
--- /dev/null
+++ b/utils/kamctl/dbtext/kamailio/acc_cdrs
@@ -0,0 +1 @@
+id(int,auto) start_time(string) end_time(string) duration(string) 
diff --git a/utils/kamctl/dbtext/kamailio/mohqcalls b/utils/kamctl/dbtext/kamailio/mohqcalls
new file mode 100644
index 0000000..c5454dc
--- /dev/null
+++ b/utils/kamctl/dbtext/kamailio/mohqcalls
@@ -0,0 +1 @@
+id(int,auto) mohq_id(int) call_id(string) call_status(int) call_from(string) call_contact(string,null) call_time(int) 
diff --git a/utils/kamctl/dbtext/kamailio/mohqueues b/utils/kamctl/dbtext/kamailio/mohqueues
new file mode 100644
index 0000000..a44840b
--- /dev/null
+++ b/utils/kamctl/dbtext/kamailio/mohqueues
@@ -0,0 +1 @@
+id(int,auto) name(string) uri(string) mohdir(string,null) mohfile(string) debug(int) 
diff --git a/utils/kamctl/dbtext/kamailio/rtpproxy b/utils/kamctl/dbtext/kamailio/rtpproxy
new file mode 100644
index 0000000..23b9dfb
--- /dev/null
+++ b/utils/kamctl/dbtext/kamailio/rtpproxy
@@ -0,0 +1 @@
+id(int,auto) setid(string) url(string) flags(int) weight(int) description(string) 
diff --git a/utils/kamctl/dbtext/kamailio/version b/utils/kamctl/dbtext/kamailio/version
index f76df16..c3ca5ad 100644
--- a/utils/kamctl/dbtext/kamailio/version
+++ b/utils/kamctl/dbtext/kamailio/version
@@ -1,5 +1,6 @@
 table_name(string) table_version(int) 
 acc:4
+acc_cdrs:1
 active_watchers:11
 address:6
 aliases:6
@@ -32,6 +33,8 @@ location:6
 location_attrs:1
 matrix:1
 missed_calls:3
+mohqcalls:1
+mohqueues:1
 mtree:1
 mtrees:2
 pdt:1
@@ -42,6 +45,7 @@ purplemap:1
 re_grp:1
 rls_presentity:1
 rls_watchers:3
+rtpproxy:1
 sca_subscriptions:1
 silo:7
 sip_trace:3
diff --git a/utils/kamctl/kamctl b/utils/kamctl/kamctl
index 9e6b0ba..b286d55 100755
--- a/utils/kamctl/kamctl
+++ b/utils/kamctl/kamctl
@@ -7,7 +7,7 @@
 #===================================================================
 
 ### version for this script
-VERSION='3.3.0'
+VERSION='4.1.0'
 
 PATH=$PATH:/usr/local/sbin/
 
@@ -343,7 +343,7 @@ acl() {
 
 				QUERY="insert into $ACL_TABLE ($ACL_USER_COLUMN,\
 $ACL_GROUP_COLUMN,$ACL_MODIFIED_COLUMN,$ACL_DOMAIN_COLUMN ) values \
-('$OSERUSER','$1', now(), '$OSERDOMAIN' );"
+('$OSERUSER','$1', $DBFNOW, '$OSERDOMAIN' );"
 				$DBCMD "$QUERY"
 				if [ $? -ne 0 ] ; then
 					merr "acl - SQL Error"
@@ -795,7 +795,7 @@ FROM $AVP_TABLE $CLAUSE;"
 			QUERY="INSERT INTO $AVP_TABLE \
 ($AVP_UUID_COLUMN,$AVP_USER_COLUMN,$AVP_DOMAIN_COLUMN,$AVP_ATTRIBUTE_COLUMN,\
 $AVP_TYPE_COLUMN,$AVP_VALUE_COLUMN,$AVP_MODIFIED_COLUMN) \
-VALUES ('$AVP_UUID','$OSERUSER','$OSERDOMAIN','$2',$3,'$4',NOW());"
+VALUES ('$AVP_UUID','$OSERUSER','$OSERDOMAIN','$2',$3,'$4',$DBFNOW);"
 			# echo "Query: $QUERY"
 			$DBCMD "$QUERY"
 			if [ $? -ne 0 ] ; then
@@ -992,6 +992,24 @@ db_ops() {
 			QUERY="select * FROM $1\\G;"
 			$DBROCMD "$QUERY"
 			;;
+		smatch)
+			shift
+			if [ $# -ne 3 ] ; then
+				merr "missing parameters"
+				exit 1
+			fi
+			QUERY="SELECT * FROM $1 WHERE $2='$3'\\G;"
+			$DBROCMD "$QUERY"
+			;;
+		nmatch)
+			shift
+			if [ $# -ne 3 ] ; then
+				merr "missing parameters"
+				exit 1
+			fi
+			QUERY="SELECT * FROM $1 WHERE $2=$3\\G;"
+			$DBROCMD "$QUERY"
+			;;
 		*)
 			usage_db_ops
 			exit 1
@@ -1029,7 +1047,7 @@ domain() {
 				exit 0
 			fi
 			QUERY="insert into $DOMAIN_TABLE ($DO_DOMAIN_COLUMN, \
-			$DO_LAST_MODIFIED_COLUMN) VALUES ('$1',now());"
+			$DO_LAST_MODIFIED_COLUMN) VALUES ('$1',$DBFNOW);"
 			$DBCMD "$QUERY"
 			if [ $? -ne 0 ] ; then
 				merr "domain - SQL Error"
@@ -1532,7 +1550,6 @@ cr() {
 	esac
 }
 
-
 #
 ##### ------------------------------------------------ #####
 ### DISPATCHER management
@@ -1546,27 +1563,44 @@ dispatcher() {
 			QUERY="select * FROM $DISPATCHER_TABLE ORDER BY $DISPATCHER_SETID_COLUMN; "
 			$DBROCMD "$QUERY"
 			;;
-		addgw)
+		addgw|add)
 			shift
-			if [ $# -lt 3 ] ; then
+			if [ $# -lt 2 ] ; then
 				merr "too few parameters"
 				usage_dispatcher
 				exit 1
 			fi
 
+			DISPATCHER_SETID=$1
+			DISPATCHER_DESTINATION=$2
+
+			if [ $# -gt 2 ] ; then
+				DISPATCHER_FLAGS=$3
+			else
+				DISPATCHER_FLAGS=0
+			fi
+
 			if [ $# -gt 3 ] ; then
-				DISPATCHER_DESCRIPTION=$4
+				DISPATCHER_PRIORITY=$4
 			else
-				DISPATCHER_DESCRIPTION=""
-			fi 
+				DISPATCHER_PRIORITY=0
+			fi
 
-			DISPATCHER_SETID=$1
-			DISPATCHER_DESTINATION=$2
-			DISPATCHER_FLAGS=$3
+			if [ $# -gt 4 ] ; then
+				DISPATCHER_ATTRS=$5
+			else
+				DISPATCHER_ATTRS=""
+			fi
+
+			if [ $# -gt 5 ] ; then
+				DISPATCHER_DESCRIPTION=$6
+			else
+				DISPATCHER_DESCRIPTION=""
+			fi
 
 			QUERY="insert into $DISPATCHER_TABLE \
-				( $DISPATCHER_SETID_COLUMN, $DISPATCHER_DESTINATION_COLUMN, $DISPATCHER_FLAGS_COLUMN, $DISPATCHER_DESCRIPTION_COLUMN ) \
-				VALUES ($DISPATCHER_SETID,'$DISPATCHER_DESTINATION',$DISPATCHER_FLAGS,'$DISPATCHER_DESCRIPTION');"
+				( $DISPATCHER_SETID_COLUMN, $DISPATCHER_DESTINATION_COLUMN, $DISPATCHER_FLAGS_COLUMN, $DISPATCHER_PRIORITY_COLUMN, $DISPATCHER_ATTRS_COLUMN, $DISPATCHER_DESCRIPTION_COLUMN ) \
+				VALUES ($DISPATCHER_SETID,'$DISPATCHER_DESTINATION',$DISPATCHER_FLAGS,$DISPATCHER_PRIORITY,'$DISPATCHER_ATTRS','$DISPATCHER_DESCRIPTION');"
 			$DBCMD "$QUERY"
 
 			if [ $? -ne 0 ] ; then
@@ -1574,9 +1608,8 @@ dispatcher() {
 				exit 1
 			fi
 
-			$CTLCMD ds_reload
 			;;
-		rmgw)
+		rmgw|rm)
 			shift
 			if [ $# -ne 1 ] ; then
 				merr "missing gateway id to be removed"
@@ -1591,7 +1624,6 @@ dispatcher() {
 				exit 1
 			fi
 
-			$CTLCMD ds_reload
 			;;
 		reload)
 			$CTLCMD ds_reload
@@ -1610,6 +1642,30 @@ dispatcher() {
 
 #
 ##### ------------------------------------------------ #####
+### DIALOG management
+#
+dialog() {
+	case $1 in
+		show|list)
+			require_ctlengine
+			mecho "dialog memory records"
+			$CTLCMD dlg_list
+			;;
+		showdb)
+			require_dbengine
+			mecho "dialog database records"
+			QUERY="select * FROM $DIALOG_TABLE ORDER BY id; "
+			$DBROCMD "$QUERY"
+			;;
+		*)
+			usage_dialog
+			exit 1
+
+	esac
+}
+
+#
+##### ------------------------------------------------ #####
 ### DIALPLAN management
 #
 dialplan() {
@@ -2151,6 +2207,28 @@ subscriber() {
 			fi
 			;;
 
+		show)
+			if [ $# -ne 2 ] ; then
+				usage_subscriber
+				exit 1
+			fi
+			shift
+
+			set_user $1
+
+			case $DBENGINE in
+				MYSQL|mysql|MySQL)
+					QUERY="SELECT * FROM $SUB_TABLE \
+WHERE $SUBSCRIBER_COLUMN='$OSERUSER' AND $REALM_COLUMN='$OSERDOMAIN'\G"
+				;;
+				*)
+					QUERY="SELECT * FROM $SUB_TABLE \
+WHERE $SUBSCRIBER_COLUMN='$OSERUSER' AND $REALM_COLUMN='$OSERDOMAIN';"
+				;;
+			esac
+			$DBROCMD "$QUERY"
+			;;
+
 		passwd)
 			if [ $# -ne 3 ] ; then
 				usage_subscriber
@@ -2214,6 +2292,51 @@ and $REALM_COLUMN='$OSERDOMAIN';"
 			# and also all his contacts
 			$0 ul rm $1   > /dev/null 2>&1
 			;;
+		sets)
+			if [ $# -ne 4 ] ; then
+				usage_subscriber
+				exit 1
+			fi
+			shift
+
+			is_user $1
+			if [ $? -ne 0 ] ; then
+				merr "non-existent user '$1'"
+				exit 1
+			fi
+
+			QUERY="update $SUB_TABLE set $2='$3' \
+WHERE $SUBSCRIBER_COLUMN='$OSERUSER' and $REALM_COLUMN='$OSERDOMAIN';"
+			$DBCMD "$QUERY"
+			if [ $? -ne 0 ] ; then
+				merr "attribute change failed"
+			else
+				minfo "attribute change succeeded"
+			fi
+			;;
+		setn)
+			if [ $# -ne 4 ] ; then
+				usage_subscriber
+				exit 1
+			fi
+			shift
+
+			is_user $1
+			if [ $? -ne 0 ] ; then
+				merr "non-existent user '$1'"
+				exit 1
+			fi
+
+			QUERY="update $SUB_TABLE set $2=$3 \
+WHERE $SUBSCRIBER_COLUMN='$OSERUSER' and $REALM_COLUMN='$OSERDOMAIN';"
+			$DBCMD "$QUERY"
+			if [ $? -ne 0 ] ; then
+				merr "attribute change failed"
+			else
+				minfo "attribute change succeeded"
+			fi
+			;;
+
 	esac
 
 }
@@ -2281,10 +2404,17 @@ usrloc() {
 				UL_EXPIRES=0
 				UL_FLAGS=0
 				BR_FLAGS=0
+				UL_PATH=0
 			elif [ $# -eq 4 ] ; then
 				UL_EXPIRES=$4
 				UL_FLAGS=0
 				BR_FLAGS=0
+				UL_PATH=0
+			elif [ $# -eq 5 ] ; then
+				UL_EXPIRES=$4
+				UL_FLAGS=0
+				BR_FLAGS=0
+				UL_PATH="$5"
 			else
 				usage_usrloc
 				exit 1
@@ -2317,7 +2447,7 @@ usrloc() {
 			fi
 
 			$CTLCMD ul_add "$USRLOC_TABLE" "$OSERUSER@$OSERDOMAIN" "$2" \
-"$UL_EXPIRES" "1.00" "0" "$UL_FLAGS" "$BR_FLAGS" "$ALL_METHODS"
+"$UL_EXPIRES" "1.00" "$UL_PATH" "$UL_FLAGS" "$BR_FLAGS" "$ALL_METHODS"
 			exit $?
 			;;
 		rm)
@@ -2495,6 +2625,25 @@ tls_ca() {
 	fi
 }
 
+extcmd() {
+	if [ -f $ETCDIR/kamctl.${1}.ext ]; then
+		. $ETCDIR/kamctl.${1}.ext
+	else
+		if [ -f ~/.kamctl/kamctl.${1}.ext ]; then
+			. ~/.kamctl/kamctl.${1}.ext
+		else
+			return
+		fi
+	fi
+
+	XCMD=cmd_${1}
+
+	shift
+	$XCMD "$@"
+
+	exit 1
+}
+
 #
 ##### ================================================ #####
 ### main command switch
@@ -2509,6 +2658,10 @@ case $1 in
 		subscriber "$@"
 		;;
 
+	show)
+		subscriber "$@"
+		;;
+
 	passwd)
 		subscriber "$@"
 		;;
@@ -2517,6 +2670,14 @@ case $1 in
 		subscriber "$@"
 		;;
 
+	sets)
+		subscriber "$@"
+		;;
+
+	setn)
+		subscriber "$@"
+		;;
+
 	alias|ul|usrloc)
 		usrloc "$@"
 		;;
@@ -2594,6 +2755,11 @@ case $1 in
 		dispatcher "$@"
 		;;
 
+	dialog)
+		shift
+		dialog "$@"
+		;;
+
 	dialplan)
 		shift
 		dialplan "$@"
@@ -2672,6 +2838,8 @@ case $1 in
 		;;
 		
 	*)
+		extcmd "$@"
+
 		usage
 		exit 1
 		;;
diff --git a/utils/kamctl/kamctl.8 b/utils/kamctl/kamctl.8
index 61fc55f..f0d225e 100644
--- a/utils/kamctl/kamctl.8
+++ b/utils/kamctl/kamctl.8
@@ -43,7 +43,7 @@ Ping <uri> with SIP OPTIONS
 
 
 .TP 16
-.I Access control list (acl)  managment commands:
+.I Access control list (acl)  management commands:
 .TP
 .B acl show [<username>]
 Show user membership
@@ -55,7 +55,7 @@ Grant user membership (*)
 Grant user membership(s) (*)
 
 .TP 16
-.I  Least cost routes (lcr) managment command:
+.I  Least cost routes (lcr) management command:
 .TP             
 .B lcr dump
 Show in memory gateways and routes tables
@@ -64,7 +64,7 @@ Show in memory gateways and routes tables
 Reload lcr gateways and routes
 
 .TP 16
-.I Carrierroute tables('cr') managment commands:
+.I Carrierroute tables('cr') management commands:
 .TP
 .B cr show 
 Show tables
@@ -88,7 +88,7 @@ Add a carrier (prob, strip, rewrite_prefix, rewrite_suffix, flags, mask and comm
 Remove a carrier
 
 .TP 16
-.I Remote-Party-ID (RPID) managment commands:
+.I Remote-Party-ID (RPID) management commands:
 .TP
 .B rpid add <username> <rpid>
 Add rpid for a user (*)
@@ -100,7 +100,7 @@ Set rpid to NULL for a user (*)
 Show rpid of a user
 
 .TP 16
-.I Subscriber managment commands:
+.I Subscriber management commands:
 .TP
 .B add <username> <password> 
  Add a new subscriber (*)
@@ -130,7 +130,7 @@ Add a new entry (from_pattern and tag are optional arguments)
 Remove all entres for the given src_ip
 
 .TP 16
-.I Dispatcher managment commands:
+.I Dispatcher management commands:
 .TP
 .B dispatcher show 
 Show dispatcher gateways
@@ -154,7 +154,7 @@ Delete gateway
 Restart phone configured for <uri>
 
 .TP 16
-.I User location('ul') or aliases managment commands:
+.I User location('ul') or aliases management commands:
 .B ul show [<username>]
 Show in-RAM online users
 .TP
@@ -169,6 +169,9 @@ Introduce a permanent usrloc entry
 .TP
 .B ul add <username> <uri> <expires>
 Introduce a temporary usrloc entry
+.TP
+.B ul add <username> <uri> <expires> <path>
+Introduce a temporary usrloc entry including a path
 
 .TP 16
 .I Fifo commands:
diff --git a/utils/kamctl/kamctl.base b/utils/kamctl/kamctl.base
index 589e0a0..27532a3 100644
--- a/utils/kamctl/kamctl.base
+++ b/utils/kamctl/kamctl.base
@@ -310,8 +310,15 @@ DISPATCHER_ID_COLUMN=id
 DISPATCHER_SETID_COLUMN=setid
 DISPATCHER_DESTINATION_COLUMN=destination
 DISPATCHER_FLAGS_COLUMN=flags
+DISPATCHER_PRIORITY_COLUMN=priority
+DISPATCHER_ATTRS_COLUMN=attrs
 DISPATCHER_DESCRIPTION_COLUMN=description
 
+# dialog tables
+if [ -z "$DIALOG_TABLE" ] ; then
+	DIALOG_TABLE=dialog
+fi
+
 # dialplan tables
 if [ -z "$DIALPLAN_TABLE" ] ; then
 	DIALPLAN_TABLE=dialplan
@@ -422,8 +429,11 @@ usage_subscriber() {
 	echo
 cat <<EOF
  add <username> <password> .......... add a new subscriber (*)
+ show <username> .................... show subscriber attributes (*)
  passwd <username> <passwd> ......... change user's password (*)
  rm <username> ...................... delete a user (*)
+ sets <username> <attr> <val> ....... set string attribute (column value)
+ setn <username> <attr> <val> ....... set numeric attribute (column value)
 EOF
 }
 USAGE_FUNCTIONS="$USAGE_FUNCTIONS usage_subscriber"
@@ -465,19 +475,32 @@ usage_dispatcher() {
 	mecho " -- command 'dispatcher' - manage dispatcher"
 	echo
 cat <<EOF
-   * Examples:  dispatcher addgw 1 sip:1.2.3.1:5050 1 'outbound gateway'
-   *            dispatcher addgw 2 sip:1.2.3.4:5050 3 ''
-   *            dispatcher rmgw 4
+   * Examples: dispatcher add 1 sip:1.2.3.1:5050 1 5 'prefix=123' 'gw one'
+   *           dispatcher add 2 sip:1.2.3.4:5050 3 0
+   *           dispatcher rm 4
  dispatcher show ..................... show dispatcher gateways
  dispatcher reload ................... reload dispatcher gateways
  dispatcher dump ..................... show in memory dispatcher gateways
- dispatcher addgw <setid> <destination> <flags> <description>
+ dispatcher add <setid> <destination> [flags] [priority] [attrs] [description]
             .......................... add gateway
- dispatcher rmgw <id> ................ delete gateway
+ dispatcher rm <id> .................. delete gateway
 EOF
 }
 USAGE_FUNCTIONS="$USAGE_FUNCTIONS usage_dispatcher"
 
+usage_dialog() {
+	echo
+	mecho " -- command 'dialog' - manage dialog records"
+	echo
+cat <<EOF
+   * Examples: dialog show
+   *           dialog showdb
+ dialog show ..................... show in-memory dialog records
+ dialog showdb ................... show database dialog records
+EOF
+}
+USAGE_FUNCTIONS="$USAGE_FUNCTIONS usage_dialog"
+
 usage_dialplan() {
 	echo
 	mecho " -- command 'dialplan' - manage dialplans"
diff --git a/utils/kamctl/kamctl.ctlbase b/utils/kamctl/kamctl.ctlbase
index a5ddf72..a605b10 100644
--- a/utils/kamctl/kamctl.ctlbase
+++ b/utils/kamctl/kamctl.ctlbase
@@ -67,11 +67,12 @@ usage_usrloc() {
 	mecho " -- command 'ul|alias' - manage user location or aliases"
 	echo
 cat <<EOF
- ul show [<username>]................ show in-RAM online users
- ul show --brief..................... show in-RAM online users in short format
- ul rm <username> [<contact URI>].... delete user's usrloc entries
- ul add <username> <uri> ............ introduce a permanent usrloc entry
- ul add <username> <uri> <expires> .. introduce a temporary usrloc entry
+ ul show [<username>]................... show in-RAM online users
+ ul show --brief........................ show in-RAM online users in short format
+ ul rm <username> [<contact URI>]....... delete user's usrloc entries
+ ul add <username> <uri> ............... introduce a permanent usrloc entry
+ ul add <username> <uri> <expires> ..... introduce a temporary usrloc entry
+ ul add <user> <uri> <expires> <path> .. introduce a temporary usrloc entry
 EOF
 }
 USAGE_FUNCTIONS="$USAGE_FUNCTIONS usage_usrloc"
diff --git a/utils/kamctl/kamctl.fifo b/utils/kamctl/kamctl.fifo
index fead9de..50c8e92 100644
--- a/utils/kamctl/kamctl.fifo
+++ b/utils/kamctl/kamctl.fifo
@@ -23,8 +23,12 @@ fi
 ##### ----------------------------------------------- #####
 ### parameters
 #
-if [ -z "$OSER_FIFO" ]; then
-	OSER_FIFO=/tmp/kamailio_fifo
+if [ -z "$FIFOPATH" ]; then
+	if [ -z "$OSER_FIFO" ]; then
+		FIFOPATH=/tmp/kamailio_fifo
+	else
+		FIFOPATH=$OSER_FIFO
+	fi
 fi
 
 #
@@ -53,12 +57,12 @@ fifo_cmd()
 	fi
 	name=kamailio_receiver_$$
 	path=$CHROOT_DIR/tmp/$name
-	if [ ! -w $OSER_FIFO ]; then
-		merr "Error opening Kamailio's FIFO $OSER_FIFO"
-		merr "Make sure you have the line 'modparam(\"mi_fifo\", \"fifo_name\", \"$OSER_FIFO\")' in your config"
+	if [ ! -w $FIFOPATH ]; then
+		merr "Error opening Kamailio's FIFO $FIFOPATH"
+		merr "Make sure you have the line 'modparam(\"mi_fifo\", \"fifo_name\", \"$FIFOPATH\")' in your config"
 		merr "and also have loaded the mi_fifo module."
 		if [ ! -z $CHROOT_DIR ]; then
-			merr "[chrooted environment] Check that $OSER_FIFO is symlinked to ${CHROOT_DIR}${OSER_FIFO}"
+			merr "[chrooted environment] Check that $FIFOPATH is symlinked to ${CHROOT_DIR}${FIFOPATH}"
 		fi
 		exit 2
 	fi
@@ -87,7 +91,7 @@ fifo_cmd()
 	cat < $path | filter_fl &
 
 	# issue FIFO request (printf taken to deal with \n)
-	printf "$CMD" > $OSER_FIFO
+	printf "$CMD" > $FIFOPATH
 
 	# wait for the reader to complete
 	wait
@@ -102,9 +106,9 @@ CTLCMD=fifo_cmd
 fifo_kamailio_monitor() {
 	name=kamailio_receiver_$$
 	path=$CHROOT_DIR/tmp/$name
-	if [ ! -w $OSER_FIFO ]; then
-		merr "Error opening Kamailio's FIFO $OSER_FIFO"
-		merr "Make sure you have the line 'modparam(\"mi_fifo\", \"fifo_name\", \"$OSER_FIFO\")' in your config"
+	if [ ! -w $FIFOPATH ]; then
+		merr "Error opening Kamailio's FIFO $FIFOPATH"
+		merr "Make sure you have the line 'modparam(\"mi_fifo\", \"fifo_name\", \"$FIFOPATH\")' in your config"
 		merr "and also have loaded the mi_fifo module."
 		exit 1
 	fi
@@ -133,14 +137,14 @@ fifo_kamailio_monitor() {
 		mecho "[cycle #: $attempt; if constant make sure server lives]"
 
 		cat < $path | filter_fl &
-		cat > $OSER_FIFO <<EOF
+		cat > $FIFOPATH <<EOF
 :version:$name
 
 EOF
 		wait
 
 		cat < $path | filter_fl &
-		cat > $OSER_FIFO << EOF
+		cat > $FIFOPATH << EOF
 :uptime:$name
 
 EOF
@@ -149,7 +153,7 @@ EOF
 
 		mecho "Transaction Statistics: "
 		cat < $path | filter_fl &
-		cat > $OSER_FIFO <<EOF
+		cat > $FIFOPATH <<EOF
 :get_statistics:$name
 UAS_transactions
 UAC_transactions
@@ -161,7 +165,7 @@ EOF
 
 		mecho "Stateless Server Statistics: "
 		cat < $path | filter_fl &
-		cat > $OSER_FIFO <<EOF
+		cat > $FIFOPATH <<EOF
 :get_statistics:$name
 sent_replies
 sent_err_replies
@@ -173,7 +177,7 @@ EOF
 
 		mecho "UsrLoc Stats: "
 		cat < $path | filter_fl &
-		cat > $OSER_FIFO <<EOF
+		cat > $FIFOPATH <<EOF
 :get_statistics:$name
 usrloc:
 
diff --git a/utils/kamctl/kamctl.sqlbase b/utils/kamctl/kamctl.sqlbase
index f07705f..53d32f9 100644
--- a/utils/kamctl/kamctl.sqlbase
+++ b/utils/kamctl/kamctl.sqlbase
@@ -31,6 +31,8 @@ if [ -z "$DBROOTUSER" ]; then
 	DBROOTUSER="root"
 fi
 
+DBFNOW="now()"
+
 #params: none
 # output: DBRWPW
 prompt_pw() {
@@ -61,6 +63,10 @@ cat <<EOF
                                        \$id variable
  db show <table> ..................... display table content
  db showg <table> .................... display formatted table content
+ db smatch <table> <key> <value>...... display record from table that has
+           ........................... column key equal to value as string
+ db nmatch <table> <key> <value>...... display record from table that has
+           ........................... column key equal to value as non-string
 EOF
 }
 USAGE_FUNCTIONS="$USAGE_FUNCTIONS usage_db_ops"
diff --git a/utils/kamctl/kamctl.sqlite b/utils/kamctl/kamctl.sqlite
index 8c3eb21..35cf45a 100644
--- a/utils/kamctl/kamctl.sqlite
+++ b/utils/kamctl/kamctl.sqlite
@@ -21,6 +21,9 @@ fi
 
 DBNAME=$DB_PATH
 
+DATENOW=`date`
+DBFNOW="'$DATENOW'"
+
 ##### ----------------------------------------------- #####
 ### binaries
 if [ -z "$SQLITE" ] ; then
diff --git a/utils/kamctl/kamctlrc b/utils/kamctl/kamctlrc
index e5d8311..472d991 100644
--- a/utils/kamctl/kamctlrc
+++ b/utils/kamctl/kamctlrc
@@ -122,7 +122,7 @@
 # CTLENGINE="FIFO"
 
 ## path to FIFO file
-# OSER_FIFO="FIFO"
+# FIFOPATH="/tmp/kamailio_fifo"
 
 ## check ACL names; default on (1); off (0)
 # VERIFY_ACL=1
diff --git a/utils/kamctl/kamdbctl b/utils/kamctl/kamdbctl
index 935e106..e9249d8 100755
--- a/utils/kamctl/kamdbctl
+++ b/utils/kamctl/kamdbctl
@@ -444,6 +444,23 @@ case $1 in
 		kamailio_db_revoke $DBNAME
 		exit $?
 		;;
+	add-tables)
+		if [ "$USED_DBENGINE" != "mysql" ] ; then
+			merr "$USED_DBENGINE don't support add-tables operation"
+			exit 1
+		fi
+		if [ $# -ne 2 ] ; then
+			merr "add-tables requires 1 parameter: group id of tables"
+			exit 1
+		fi
+		if [ -z "$DBNAME" ] ; then
+			merr "DBNAME is not set"
+			exit 1
+		fi
+
+		kamailio_add_tables $DBNAME $2
+		exit $?
+		;;
 	bdb|db_berkeley)
 		shift
 		kamailio_berkeley "$@"
diff --git a/utils/kamctl/kamdbctl.base b/utils/kamctl/kamdbctl.base
index ab4dc87..c4e0307 100644
--- a/utils/kamctl/kamdbctl.base
+++ b/utils/kamctl/kamdbctl.base
@@ -36,11 +36,12 @@ INSTALL_DBUID_TABLES=${INSTALL_DBUID_TABLES:-ask}
 STANDARD_TABLES=${STANDARD_TABLES:-version acc dbaliases domain domain_attrs
 		grp uri speed_dial lcr_gw lcr_rule lcr_rule_target pdt subscriber
 		location location_attrs re_grp trusted address missed_calls
-		usr_preferences aliases silo dialog dialog_vars dispatcher dialplan}
+		usr_preferences aliases silo dialog dialog_vars dispatcher dialplan
+		acc_cdrs}
 EXTRA_TABLES=${EXTRA_TABLES:-imc_members imc_rooms cpl sip_trace domainpolicy
 		carrierroute carrier_name domain_name carrierfailureroute userblacklist
 		globalblacklist htable purplemap uacreg pl_pipes mtree mtrees
-		sca_subscriptions}
+		sca_subscriptions mohqcalls mohqueues}
 PRESENCE_TABLES=${PRESENCE_TABLES:-presentity active_watchers watchers xcap 
 		pua rls_presentity rls_watchers}
 DBUID_TABLES=${UID_TABLES:-uid_credentials uid_domain uid_domain_attrs
@@ -80,7 +81,7 @@ STANDARD_MODULES=${STANDARD_MODULES:-standard acc lcr domain group
 PRESENCE_MODULES=${PRESENCE_MODULES:-presence rls}
 
 EXTRA_MODULES=${EXTRA_MODULES:-imc cpl siptrace domainpolicy carrierroute
-		userblacklist htable purple uac pipelimit mtree sca}
+		userblacklist htable purple uac pipelimit mtree sca mohqueue}
 
 DBUID_MODULES=${UID_MODULES:-uid_auth_db uid_avp_db uid_domain uid_gflags
 		uid_uri_db}
@@ -107,6 +108,7 @@ usage: $COMMAND create <db name or db_path, optional> ...(creates a new database
        $COMMAND dbonly ..................................(creates empty database)
        $COMMAND grant ...................................(grant privileges to database)
        $COMMAND revoke ..................................(revoke privileges to database)
+       $COMMAND add-tables <gid> ........................(creates only tables groupped in gid)
 
        if you want to manipulate database as other database user than
        root, want to change database name from default value "$DBNAME",
diff --git a/utils/kamctl/kamdbctl.mysql b/utils/kamctl/kamdbctl.mysql
index e4825ab..0c6d5d3 100644
--- a/utils/kamctl/kamdbctl.mysql
+++ b/utils/kamctl/kamdbctl.mysql
@@ -345,6 +345,28 @@ dbuid_create () # pars: <database name>
 }  # end uid_create
 
 
+kamailio_add_tables () # params: <database name> <tables group name>
+{
+	if [ $# -ne 2 ] ; then
+		merr "kamailio_add_tables function takes two params"
+		exit 1
+	fi
+
+	minfo "creating group of tables [$2] into database [$1] ..."
+
+	if [ -e $DB_SCHEMA/$2-create.sql ]
+	then
+		sql_query $1 < $DB_SCHEMA/$2-create.sql
+		if [ $? -ne 0 ] ; then
+			merr "Creating group of tables [$2] failed"
+			exit 1
+		fi
+	else
+		merr "Script for creating group of tables [$2] not found"
+		exit 1
+	fi
+}  # end kamailio_add_tables
+
 migrate_table () # 4 paremeters (dst_table, dst_cols, src_table, src_cols)
 {
 	if [ $# -ne 4 ] ; then
diff --git a/utils/kamctl/mysql/acc-create.sql b/utils/kamctl/mysql/acc-create.sql
index 54071dc..c0193f5 100644
--- a/utils/kamctl/mysql/acc-create.sql
+++ b/utils/kamctl/mysql/acc-create.sql
@@ -8,10 +8,20 @@ CREATE TABLE acc (
     sip_code VARCHAR(3) DEFAULT '' NOT NULL,
     sip_reason VARCHAR(32) DEFAULT '' NOT NULL,
     time DATETIME NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX callid_idx ON acc (callid);
 
+INSERT INTO version (table_name, table_version) values ('acc_cdrs','1');
+CREATE TABLE acc_cdrs (
+    id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
+    start_time VARCHAR(32) DEFAULT '' NOT NULL,
+    end_time VARCHAR(32) DEFAULT '' NOT NULL,
+    duration VARCHAR(32) DEFAULT '' NOT NULL
+);
+
+CREATE INDEX start_time_idx ON acc_cdrs (start_time);
+
 INSERT INTO version (table_name, table_version) values ('missed_calls','3');
 CREATE TABLE missed_calls (
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
@@ -22,7 +32,7 @@ CREATE TABLE missed_calls (
     sip_code VARCHAR(3) DEFAULT '' NOT NULL,
     sip_reason VARCHAR(32) DEFAULT '' NOT NULL,
     time DATETIME NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX callid_idx ON missed_calls (callid);
 
diff --git a/utils/kamctl/mysql/alias_db-create.sql b/utils/kamctl/mysql/alias_db-create.sql
index 8da6df4..86fe793 100644
--- a/utils/kamctl/mysql/alias_db-create.sql
+++ b/utils/kamctl/mysql/alias_db-create.sql
@@ -4,9 +4,10 @@ CREATE TABLE dbaliases (
     alias_username VARCHAR(64) DEFAULT '' NOT NULL,
     alias_domain VARCHAR(64) DEFAULT '' NOT NULL,
     username VARCHAR(64) DEFAULT '' NOT NULL,
-    domain VARCHAR(64) DEFAULT '' NOT NULL,
-    CONSTRAINT alias_idx UNIQUE (alias_username, alias_domain)
-) ENGINE=MyISAM;
+    domain VARCHAR(64) DEFAULT '' NOT NULL
+);
 
+CREATE INDEX alias_user_idx ON dbaliases (alias_username);
+CREATE INDEX alias_idx ON dbaliases (alias_username, alias_domain);
 CREATE INDEX target_idx ON dbaliases (username, domain);
 
diff --git a/utils/kamctl/mysql/auth_db-create.sql b/utils/kamctl/mysql/auth_db-create.sql
index f09d330..cb83c52 100644
--- a/utils/kamctl/mysql/auth_db-create.sql
+++ b/utils/kamctl/mysql/auth_db-create.sql
@@ -9,7 +9,7 @@ CREATE TABLE subscriber (
     ha1b VARCHAR(64) DEFAULT '' NOT NULL,
     rpid VARCHAR(64) DEFAULT NULL,
     CONSTRAINT account_idx UNIQUE (username, domain)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX username_idx ON subscriber (username);
 
diff --git a/utils/kamctl/mysql/avpops-create.sql b/utils/kamctl/mysql/avpops-create.sql
index 82ec943..bcaaf72 100644
--- a/utils/kamctl/mysql/avpops-create.sql
+++ b/utils/kamctl/mysql/avpops-create.sql
@@ -8,7 +8,7 @@ CREATE TABLE usr_preferences (
     type INT(11) DEFAULT 0 NOT NULL,
     value VARCHAR(128) DEFAULT '' NOT NULL,
     last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX ua_idx ON usr_preferences (uuid, attribute);
 CREATE INDEX uda_idx ON usr_preferences (username, domain, attribute);
diff --git a/utils/kamctl/mysql/carrierroute-create.sql b/utils/kamctl/mysql/carrierroute-create.sql
index f52b800..f937bf0 100644
--- a/utils/kamctl/mysql/carrierroute-create.sql
+++ b/utils/kamctl/mysql/carrierroute-create.sql
@@ -12,7 +12,7 @@ CREATE TABLE carrierroute (
     rewrite_prefix VARCHAR(64) DEFAULT '' NOT NULL,
     rewrite_suffix VARCHAR(64) DEFAULT '' NOT NULL,
     description VARCHAR(255) DEFAULT NULL
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('carrierfailureroute','2');
 CREATE TABLE carrierfailureroute (
@@ -26,17 +26,17 @@ CREATE TABLE carrierfailureroute (
     mask INT(11) UNSIGNED DEFAULT 0 NOT NULL,
     next_domain INT(10) UNSIGNED DEFAULT 0 NOT NULL,
     description VARCHAR(255) DEFAULT NULL
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('carrier_name','1');
 CREATE TABLE carrier_name (
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
     carrier VARCHAR(64) DEFAULT NULL
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('domain_name','1');
 CREATE TABLE domain_name (
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
     domain VARCHAR(64) DEFAULT NULL
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/cpl-create.sql b/utils/kamctl/mysql/cpl-create.sql
index 893c256..7d06ed4 100644
--- a/utils/kamctl/mysql/cpl-create.sql
+++ b/utils/kamctl/mysql/cpl-create.sql
@@ -6,5 +6,5 @@ CREATE TABLE cpl (
     cpl_xml TEXT,
     cpl_bin TEXT,
     CONSTRAINT account_idx UNIQUE (username, domain)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/dialog-create.sql b/utils/kamctl/mysql/dialog-create.sql
index d4ec70a..ab9ba4b 100644
--- a/utils/kamctl/mysql/dialog-create.sql
+++ b/utils/kamctl/mysql/dialog-create.sql
@@ -24,7 +24,7 @@ CREATE TABLE dialog (
     toroute_name VARCHAR(32),
     req_uri VARCHAR(128) NOT NULL,
     xdata VARCHAR(512)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX hash_idx ON dialog (hash_entry, hash_id);
 
@@ -35,7 +35,7 @@ CREATE TABLE dialog_vars (
     hash_id INT(10) UNSIGNED NOT NULL,
     dialog_key VARCHAR(128) NOT NULL,
     dialog_value VARCHAR(512) NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX hash_idx ON dialog_vars (hash_entry, hash_id);
 
diff --git a/utils/kamctl/mysql/dialplan-create.sql b/utils/kamctl/mysql/dialplan-create.sql
index cc95d55..c6a56d6 100644
--- a/utils/kamctl/mysql/dialplan-create.sql
+++ b/utils/kamctl/mysql/dialplan-create.sql
@@ -9,5 +9,5 @@ CREATE TABLE dialplan (
     subst_exp VARCHAR(64) NOT NULL,
     repl_exp VARCHAR(32) NOT NULL,
     attrs VARCHAR(32) NOT NULL
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/dispatcher-create.sql b/utils/kamctl/mysql/dispatcher-create.sql
index f4729d2..4e82750 100644
--- a/utils/kamctl/mysql/dispatcher-create.sql
+++ b/utils/kamctl/mysql/dispatcher-create.sql
@@ -7,5 +7,5 @@ CREATE TABLE dispatcher (
     priority INT DEFAULT 0 NOT NULL,
     attrs VARCHAR(128) DEFAULT '' NOT NULL,
     description VARCHAR(64) DEFAULT '' NOT NULL
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/domain-create.sql b/utils/kamctl/mysql/domain-create.sql
index a037a68..7ab9e7d 100644
--- a/utils/kamctl/mysql/domain-create.sql
+++ b/utils/kamctl/mysql/domain-create.sql
@@ -5,7 +5,7 @@ CREATE TABLE domain (
     did VARCHAR(64) DEFAULT NULL,
     last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL,
     CONSTRAINT domain_idx UNIQUE (domain)
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('domain_attrs','1');
 CREATE TABLE domain_attrs (
@@ -16,5 +16,5 @@ CREATE TABLE domain_attrs (
     value VARCHAR(255) NOT NULL,
     last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL,
     CONSTRAINT domain_attrs_idx UNIQUE (did, name, value)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/domainpolicy-create.sql b/utils/kamctl/mysql/domainpolicy-create.sql
index 0dc55e6..e68ff88 100644
--- a/utils/kamctl/mysql/domainpolicy-create.sql
+++ b/utils/kamctl/mysql/domainpolicy-create.sql
@@ -7,7 +7,7 @@ CREATE TABLE domainpolicy (
     val VARCHAR(128),
     description VARCHAR(255) NOT NULL,
     CONSTRAINT rav_idx UNIQUE (rule, att, val)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX rule_idx ON domainpolicy (rule);
 
diff --git a/utils/kamctl/mysql/drouting-create.sql b/utils/kamctl/mysql/drouting-create.sql
index 8f72794..c53450d 100644
--- a/utils/kamctl/mysql/drouting-create.sql
+++ b/utils/kamctl/mysql/drouting-create.sql
@@ -7,7 +7,7 @@ CREATE TABLE dr_gateways (
     pri_prefix VARCHAR(64) DEFAULT NULL,
     attrs VARCHAR(255) DEFAULT NULL,
     description VARCHAR(128) DEFAULT '' NOT NULL
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('dr_rules','3');
 CREATE TABLE dr_rules (
@@ -19,14 +19,14 @@ CREATE TABLE dr_rules (
     routeid VARCHAR(64) NOT NULL,
     gwlist VARCHAR(255) NOT NULL,
     description VARCHAR(128) DEFAULT '' NOT NULL
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('dr_gw_lists','1');
 CREATE TABLE dr_gw_lists (
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
     gwlist VARCHAR(255) NOT NULL,
     description VARCHAR(128) DEFAULT '' NOT NULL
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('dr_groups','2');
 CREATE TABLE dr_groups (
@@ -35,5 +35,5 @@ CREATE TABLE dr_groups (
     domain VARCHAR(128) DEFAULT '' NOT NULL,
     groupid INT(11) UNSIGNED DEFAULT 0 NOT NULL,
     description VARCHAR(128) DEFAULT '' NOT NULL
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/group-create.sql b/utils/kamctl/mysql/group-create.sql
index 04a715b..8632a35 100644
--- a/utils/kamctl/mysql/group-create.sql
+++ b/utils/kamctl/mysql/group-create.sql
@@ -6,14 +6,14 @@ CREATE TABLE grp (
     grp VARCHAR(64) DEFAULT '' NOT NULL,
     last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL,
     CONSTRAINT account_group_idx UNIQUE (username, domain, grp)
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('re_grp','1');
 CREATE TABLE re_grp (
     id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
     reg_exp VARCHAR(128) DEFAULT '' NOT NULL,
     group_id INT(11) DEFAULT 0 NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX group_idx ON re_grp (group_id);
 
diff --git a/utils/kamctl/mysql/htable-create.sql b/utils/kamctl/mysql/htable-create.sql
index 79eb43b..afd3b13 100644
--- a/utils/kamctl/mysql/htable-create.sql
+++ b/utils/kamctl/mysql/htable-create.sql
@@ -6,5 +6,5 @@ CREATE TABLE htable (
     value_type INT DEFAULT 0 NOT NULL,
     key_value VARCHAR(128) DEFAULT '' NOT NULL,
     expires INT DEFAULT 0 NOT NULL
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/imc-create.sql b/utils/kamctl/mysql/imc-create.sql
index c0c5657..6ab767d 100644
--- a/utils/kamctl/mysql/imc-create.sql
+++ b/utils/kamctl/mysql/imc-create.sql
@@ -5,7 +5,7 @@ CREATE TABLE imc_rooms (
     domain VARCHAR(64) NOT NULL,
     flag INT(11) NOT NULL,
     CONSTRAINT name_domain_idx UNIQUE (name, domain)
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('imc_members','1');
 CREATE TABLE imc_members (
@@ -15,5 +15,5 @@ CREATE TABLE imc_members (
     room VARCHAR(64) NOT NULL,
     flag INT(11) NOT NULL,
     CONSTRAINT account_room_idx UNIQUE (username, domain, room)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/lcr-create.sql b/utils/kamctl/mysql/lcr-create.sql
index f6e2037..925a43b 100644
--- a/utils/kamctl/mysql/lcr-create.sql
+++ b/utils/kamctl/mysql/lcr-create.sql
@@ -14,7 +14,7 @@ CREATE TABLE lcr_gw (
     tag VARCHAR(64) DEFAULT NULL,
     flags INT UNSIGNED DEFAULT 0 NOT NULL,
     defunct INT UNSIGNED DEFAULT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX lcr_id_idx ON lcr_gw (lcr_id);
 
@@ -27,7 +27,7 @@ CREATE TABLE lcr_rule_target (
     priority TINYINT UNSIGNED NOT NULL,
     weight INT UNSIGNED DEFAULT 1 NOT NULL,
     CONSTRAINT rule_id_gw_id_idx UNIQUE (rule_id, gw_id)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX lcr_id_idx ON lcr_rule_target (lcr_id);
 
@@ -41,5 +41,5 @@ CREATE TABLE lcr_rule (
     stopper INT UNSIGNED DEFAULT 0 NOT NULL,
     enabled INT UNSIGNED DEFAULT 1 NOT NULL,
     CONSTRAINT lcr_id_prefix_from_uri_idx UNIQUE (lcr_id, prefix, from_uri)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/matrix-create.sql b/utils/kamctl/mysql/matrix-create.sql
index 2feb131..8fd87c5 100644
--- a/utils/kamctl/mysql/matrix-create.sql
+++ b/utils/kamctl/mysql/matrix-create.sql
@@ -3,7 +3,7 @@ CREATE TABLE matrix (
     first INT(10) NOT NULL,
     second SMALLINT(10) NOT NULL,
     res INT(10) NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX matrix_idx ON matrix (first, second);
 
diff --git a/utils/kamctl/mysql/mohqueue-create.sql b/utils/kamctl/mysql/mohqueue-create.sql
new file mode 100644
index 0000000..4326fe4
--- /dev/null
+++ b/utils/kamctl/mysql/mohqueue-create.sql
@@ -0,0 +1,24 @@
+INSERT INTO version (table_name, table_version) values ('mohqcalls','1');
+CREATE TABLE mohqcalls (
+    id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
+    mohq_id INT(10) UNSIGNED NOT NULL,
+    call_id VARCHAR(100) NOT NULL,
+    call_status INT UNSIGNED NOT NULL,
+    call_from VARCHAR(100) NOT NULL,
+    call_contact VARCHAR(100),
+    call_time DATETIME NOT NULL,
+    CONSTRAINT mohqcalls_idx UNIQUE (call_id)
+);
+
+INSERT INTO version (table_name, table_version) values ('mohqueues','1');
+CREATE TABLE mohqueues (
+    id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
+    name VARCHAR(25) NOT NULL,
+    uri VARCHAR(100) NOT NULL,
+    mohdir VARCHAR(100),
+    mohfile VARCHAR(100) NOT NULL,
+    debug INT NOT NULL,
+    CONSTRAINT mohqueue_uri_idx UNIQUE (uri),
+    CONSTRAINT mohqueue_name_idx UNIQUE (name)
+);
+
diff --git a/utils/kamctl/mysql/msilo-create.sql b/utils/kamctl/mysql/msilo-create.sql
index 0d879e9..58c0f5c 100644
--- a/utils/kamctl/mysql/msilo-create.sql
+++ b/utils/kamctl/mysql/msilo-create.sql
@@ -13,7 +13,7 @@ CREATE TABLE silo (
     extra_hdrs TEXT DEFAULT '' NOT NULL,
     callid VARCHAR(128) DEFAULT '' NOT NULL,
     status INT DEFAULT 0 NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX account_idx ON silo (username, domain);
 
diff --git a/utils/kamctl/mysql/mtree-create.sql b/utils/kamctl/mysql/mtree-create.sql
index 251ddea..785d60f 100644
--- a/utils/kamctl/mysql/mtree-create.sql
+++ b/utils/kamctl/mysql/mtree-create.sql
@@ -4,7 +4,7 @@ CREATE TABLE mtree (
     tprefix VARCHAR(32) DEFAULT '' NOT NULL,
     tvalue VARCHAR(128) DEFAULT '' NOT NULL,
     CONSTRAINT tprefix_idx UNIQUE (tprefix)
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('mtrees','2');
 CREATE TABLE mtrees (
@@ -13,5 +13,5 @@ CREATE TABLE mtrees (
     tprefix VARCHAR(32) DEFAULT '' NOT NULL,
     tvalue VARCHAR(128) DEFAULT '' NOT NULL,
     CONSTRAINT tname_tprefix_tvalue_idx UNIQUE (tname, tprefix, tvalue)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/pdt-create.sql b/utils/kamctl/mysql/pdt-create.sql
index 74cdf56..4069638 100644
--- a/utils/kamctl/mysql/pdt-create.sql
+++ b/utils/kamctl/mysql/pdt-create.sql
@@ -5,5 +5,5 @@ CREATE TABLE pdt (
     prefix VARCHAR(32) NOT NULL,
     domain VARCHAR(128) DEFAULT '' NOT NULL,
     CONSTRAINT sdomain_prefix_idx UNIQUE (sdomain, prefix)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/permissions-create.sql b/utils/kamctl/mysql/permissions-create.sql
index dfa158c..2e69fec 100644
--- a/utils/kamctl/mysql/permissions-create.sql
+++ b/utils/kamctl/mysql/permissions-create.sql
@@ -5,7 +5,7 @@ CREATE TABLE trusted (
     proto VARCHAR(4) NOT NULL,
     from_pattern VARCHAR(64) DEFAULT NULL,
     tag VARCHAR(64)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX peer_idx ON trusted (src_ip);
 
@@ -17,5 +17,5 @@ CREATE TABLE address (
     mask INT DEFAULT 32 NOT NULL,
     port SMALLINT(5) UNSIGNED DEFAULT 0 NOT NULL,
     tag VARCHAR(64)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/pipelimit-create.sql b/utils/kamctl/mysql/pipelimit-create.sql
index 86fd350..49c3ff7 100644
--- a/utils/kamctl/mysql/pipelimit-create.sql
+++ b/utils/kamctl/mysql/pipelimit-create.sql
@@ -4,5 +4,5 @@ CREATE TABLE pl_pipes (
     pipeid VARCHAR(64) DEFAULT '' NOT NULL,
     algorithm VARCHAR(32) DEFAULT '' NOT NULL,
     plimit INT DEFAULT 0 NOT NULL
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/presence-create.sql b/utils/kamctl/mysql/presence-create.sql
index 0976fef..c8b9e48 100644
--- a/utils/kamctl/mysql/presence-create.sql
+++ b/utils/kamctl/mysql/presence-create.sql
@@ -10,7 +10,7 @@ CREATE TABLE presentity (
     body BLOB NOT NULL,
     sender VARCHAR(128) NOT NULL,
     CONSTRAINT presentity_idx UNIQUE (username, domain, event, etag)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX presentity_expires ON presentity (expires);
 CREATE INDEX account_idx ON presentity (username, domain, event);
@@ -43,7 +43,7 @@ CREATE TABLE active_watchers (
     updated INT(11) NOT NULL,
     updated_winfo INT(11) NOT NULL,
     CONSTRAINT active_watchers_idx UNIQUE (callid, to_tag, from_tag)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX active_watchers_expires ON active_watchers (expires);
 CREATE INDEX active_watchers_pres ON active_watchers (presentity_uri, event);
@@ -61,7 +61,7 @@ CREATE TABLE watchers (
     reason VARCHAR(64),
     inserted_time INT(11) NOT NULL,
     CONSTRAINT watcher_idx UNIQUE (presentity_uri, watcher_username, watcher_domain, event)
-) ENGINE=MyISAM;
+);
 
 INSERT INTO version (table_name, table_version) values ('xcap','4');
 CREATE TABLE xcap (
@@ -75,7 +75,7 @@ CREATE TABLE xcap (
     doc_uri VARCHAR(255) NOT NULL,
     port INT(11) NOT NULL,
     CONSTRAINT doc_uri_idx UNIQUE (doc_uri)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX account_doc_type_idx ON xcap (username, domain, doc_type);
 CREATE INDEX account_doc_type_uri_idx ON xcap (username, domain, doc_type, doc_uri);
@@ -103,7 +103,7 @@ CREATE TABLE pua (
     version INT(11) NOT NULL,
     extra_headers TEXT NOT NULL,
     CONSTRAINT pua_idx UNIQUE (etag, tuple_id, call_id, from_tag)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX expires_idx ON pua (expires);
 CREATE INDEX dialog1_idx ON pua (pres_id, pres_uri);
diff --git a/utils/kamctl/mysql/purple-create.sql b/utils/kamctl/mysql/purple-create.sql
index 4367dec..afd55c3 100644
--- a/utils/kamctl/mysql/purple-create.sql
+++ b/utils/kamctl/mysql/purple-create.sql
@@ -5,5 +5,5 @@ CREATE TABLE purplemap (
     ext_user VARCHAR(128) NOT NULL,
     ext_prot VARCHAR(16) NOT NULL,
     ext_pass VARCHAR(64)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/registrar-create.sql b/utils/kamctl/mysql/registrar-create.sql
index 3cb5287..5d9254e 100644
--- a/utils/kamctl/mysql/registrar-create.sql
+++ b/utils/kamctl/mysql/registrar-create.sql
@@ -20,7 +20,7 @@ CREATE TABLE aliases (
     instance VARCHAR(255) DEFAULT NULL,
     reg_id INT(11) DEFAULT 0 NOT NULL,
     CONSTRAINT ruid_idx UNIQUE (ruid)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX alias_idx ON aliases (username, domain, contact);
 
diff --git a/utils/kamctl/mysql/rls-create.sql b/utils/kamctl/mysql/rls-create.sql
index 643d6fc..f165c57 100644
--- a/utils/kamctl/mysql/rls-create.sql
+++ b/utils/kamctl/mysql/rls-create.sql
@@ -10,7 +10,7 @@ CREATE TABLE rls_presentity (
     auth_state INT(11) NOT NULL,
     reason VARCHAR(64) NOT NULL,
     CONSTRAINT rls_presentity_idx UNIQUE (rlsubs_did, resource_uri)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX rlsubs_idx ON rls_presentity (rlsubs_did);
 CREATE INDEX updated_idx ON rls_presentity (updated);
@@ -43,7 +43,7 @@ CREATE TABLE rls_watchers (
     from_domain VARCHAR(64) NOT NULL,
     updated INT(11) NOT NULL,
     CONSTRAINT rls_watcher_idx UNIQUE (callid, to_tag, from_tag)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX rls_watchers_update ON rls_watchers (watcher_username, watcher_domain, event);
 CREATE INDEX rls_watchers_expires ON rls_watchers (expires);
diff --git a/utils/kamctl/mysql/rtpproxy-create.sql b/utils/kamctl/mysql/rtpproxy-create.sql
new file mode 100644
index 0000000..dcb6f08
--- /dev/null
+++ b/utils/kamctl/mysql/rtpproxy-create.sql
@@ -0,0 +1,10 @@
+INSERT INTO version (table_name, table_version) values ('rtpproxy','1');
+CREATE TABLE rtpproxy (
+    id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
+    setid VARCHAR(32) DEFAULT 00 NOT NULL,
+    url VARCHAR(64) DEFAULT '' NOT NULL,
+    flags INT DEFAULT 0 NOT NULL,
+    weight INT DEFAULT 1 NOT NULL,
+    description VARCHAR(64) DEFAULT '' NOT NULL
+);
+
diff --git a/utils/kamctl/mysql/sca-create.sql b/utils/kamctl/mysql/sca-create.sql
index b48d38b..db54472 100644
--- a/utils/kamctl/mysql/sca-create.sql
+++ b/utils/kamctl/mysql/sca-create.sql
@@ -14,7 +14,7 @@ CREATE TABLE sca_subscriptions (
     notify_cseq INT(11) NOT NULL,
     subscribe_cseq INT(11) NOT NULL,
     CONSTRAINT sca_subscriptions_idx UNIQUE (subscriber, call_id, from_tag, to_tag)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX sca_expires_idx ON sca_subscriptions (expires);
 CREATE INDEX sca_subscribers_idx ON sca_subscriptions (subscriber, event);
diff --git a/utils/kamctl/mysql/siptrace-create.sql b/utils/kamctl/mysql/siptrace-create.sql
index 9739287..28c50e3 100644
--- a/utils/kamctl/mysql/siptrace-create.sql
+++ b/utils/kamctl/mysql/siptrace-create.sql
@@ -12,7 +12,7 @@ CREATE TABLE sip_trace (
     toip VARCHAR(50) DEFAULT '' NOT NULL,
     fromtag VARCHAR(64) DEFAULT '' NOT NULL,
     direction VARCHAR(4) DEFAULT '' NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX traced_user_idx ON sip_trace (traced_user);
 CREATE INDEX date_idx ON sip_trace (time_stamp);
diff --git a/utils/kamctl/mysql/speeddial-create.sql b/utils/kamctl/mysql/speeddial-create.sql
index 3c3562f..1531013 100644
--- a/utils/kamctl/mysql/speeddial-create.sql
+++ b/utils/kamctl/mysql/speeddial-create.sql
@@ -10,5 +10,5 @@ CREATE TABLE speed_dial (
     lname VARCHAR(64) DEFAULT '' NOT NULL,
     description VARCHAR(64) DEFAULT '' NOT NULL,
     CONSTRAINT speed_dial_idx UNIQUE (username, domain, sd_domain, sd_username)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/standard-create.sql b/utils/kamctl/mysql/standard-create.sql
index d76d450..d029469 100644
--- a/utils/kamctl/mysql/standard-create.sql
+++ b/utils/kamctl/mysql/standard-create.sql
@@ -2,5 +2,5 @@ CREATE TABLE version (
     table_name VARCHAR(32) NOT NULL,
     table_version INT UNSIGNED DEFAULT 0 NOT NULL,
     CONSTRAINT table_name_idx UNIQUE (table_name)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/uac-create.sql b/utils/kamctl/mysql/uac-create.sql
index b72b5e6..5de67b9 100644
--- a/utils/kamctl/mysql/uac-create.sql
+++ b/utils/kamctl/mysql/uac-create.sql
@@ -12,5 +12,5 @@ CREATE TABLE uacreg (
     auth_proxy VARCHAR(64) DEFAULT '' NOT NULL,
     expires INT DEFAULT 0 NOT NULL,
     CONSTRAINT l_uuid_idx UNIQUE (l_uuid)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/uid_auth_db-create.sql b/utils/kamctl/mysql/uid_auth_db-create.sql
index bd4b7db..529c0df 100644
--- a/utils/kamctl/mysql/uid_auth_db-create.sql
+++ b/utils/kamctl/mysql/uid_auth_db-create.sql
@@ -9,7 +9,7 @@ CREATE TABLE uid_credentials (
     ha1 VARCHAR(32) NOT NULL,
     ha1b VARCHAR(32) DEFAULT '' NOT NULL,
     uid VARCHAR(64) NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX cred_idx ON uid_credentials (auth_username, did);
 CREATE INDEX uid ON uid_credentials (uid);
diff --git a/utils/kamctl/mysql/uid_avp_db-create.sql b/utils/kamctl/mysql/uid_avp_db-create.sql
index c4c95cf..d35f7e7 100644
--- a/utils/kamctl/mysql/uid_avp_db-create.sql
+++ b/utils/kamctl/mysql/uid_avp_db-create.sql
@@ -7,5 +7,5 @@ CREATE TABLE uid_user_attrs (
     type INT DEFAULT 0 NOT NULL,
     flags INT UNSIGNED DEFAULT 0 NOT NULL,
     CONSTRAINT userattrs_idx UNIQUE (uid, name, value)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/uid_domain-create.sql b/utils/kamctl/mysql/uid_domain-create.sql
index b0bdf79..e1d4d62 100644
--- a/utils/kamctl/mysql/uid_domain-create.sql
+++ b/utils/kamctl/mysql/uid_domain-create.sql
@@ -5,7 +5,7 @@ CREATE TABLE uid_domain (
     domain VARCHAR(64) NOT NULL,
     flags INT UNSIGNED DEFAULT 0 NOT NULL,
     CONSTRAINT domain_idx UNIQUE (domain)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX did_idx ON uid_domain (did);
 
@@ -18,7 +18,7 @@ CREATE TABLE uid_domain_attrs (
     value VARCHAR(128),
     flags INT UNSIGNED DEFAULT 0 NOT NULL,
     CONSTRAINT domain_attr_idx UNIQUE (did, name, value)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX domain_did ON uid_domain_attrs (did, flags);
 
diff --git a/utils/kamctl/mysql/uid_gflags-create.sql b/utils/kamctl/mysql/uid_gflags-create.sql
index e54858e..06e7d5f 100644
--- a/utils/kamctl/mysql/uid_gflags-create.sql
+++ b/utils/kamctl/mysql/uid_gflags-create.sql
@@ -6,5 +6,5 @@ CREATE TABLE uid_global_attrs (
     value VARCHAR(128),
     flags INT UNSIGNED DEFAULT 0 NOT NULL,
     CONSTRAINT global_attrs_idx UNIQUE (name, value)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/uid_uri_db-create.sql b/utils/kamctl/mysql/uid_uri_db-create.sql
index 8c565dc..96e7d7b 100644
--- a/utils/kamctl/mysql/uid_uri_db-create.sql
+++ b/utils/kamctl/mysql/uid_uri_db-create.sql
@@ -6,7 +6,7 @@ CREATE TABLE uid_uri (
     username VARCHAR(64) NOT NULL,
     flags INT UNSIGNED DEFAULT 0 NOT NULL,
     scheme VARCHAR(8) DEFAULT 'sip' NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX uri_idx1 ON uid_uri (username, did, scheme);
 CREATE INDEX uri_uid ON uid_uri (uid);
@@ -22,5 +22,5 @@ CREATE TABLE uid_uri_attrs (
     flags INT UNSIGNED DEFAULT 0 NOT NULL,
     scheme VARCHAR(8) DEFAULT 'sip' NOT NULL,
     CONSTRAINT uriattrs_idx UNIQUE (username, did, name, value, scheme)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/uri_db-create.sql b/utils/kamctl/mysql/uri_db-create.sql
index 429c9f8..70cc89e 100644
--- a/utils/kamctl/mysql/uri_db-create.sql
+++ b/utils/kamctl/mysql/uri_db-create.sql
@@ -6,5 +6,5 @@ CREATE TABLE uri (
     uri_user VARCHAR(64) DEFAULT '' NOT NULL,
     last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL,
     CONSTRAINT account_idx UNIQUE (username, domain, uri_user)
-) ENGINE=MyISAM;
+);
 
diff --git a/utils/kamctl/mysql/userblacklist-create.sql b/utils/kamctl/mysql/userblacklist-create.sql
index 631d5cb..12ae2c9 100644
--- a/utils/kamctl/mysql/userblacklist-create.sql
+++ b/utils/kamctl/mysql/userblacklist-create.sql
@@ -5,7 +5,7 @@ CREATE TABLE userblacklist (
     domain VARCHAR(64) DEFAULT '' NOT NULL,
     prefix VARCHAR(64) DEFAULT '' NOT NULL,
     whitelist TINYINT(1) DEFAULT 0 NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX userblacklist_idx ON userblacklist (username, domain, prefix);
 
@@ -15,7 +15,7 @@ CREATE TABLE globalblacklist (
     prefix VARCHAR(64) DEFAULT '' NOT NULL,
     whitelist TINYINT(1) DEFAULT 0 NOT NULL,
     description VARCHAR(255) DEFAULT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX globalblacklist_idx ON globalblacklist (prefix);
 
diff --git a/utils/kamctl/mysql/usrloc-create.sql b/utils/kamctl/mysql/usrloc-create.sql
index 0599ea5..b510771 100644
--- a/utils/kamctl/mysql/usrloc-create.sql
+++ b/utils/kamctl/mysql/usrloc-create.sql
@@ -20,7 +20,7 @@ CREATE TABLE location (
     instance VARCHAR(255) DEFAULT NULL,
     reg_id INT(11) DEFAULT 0 NOT NULL,
     CONSTRAINT ruid_idx UNIQUE (ruid)
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX account_contact_idx ON location (username, domain, contact);
 CREATE INDEX expires_idx ON location (expires);
@@ -35,7 +35,7 @@ CREATE TABLE location_attrs (
     atype INT(11) DEFAULT 0 NOT NULL,
     avalue VARCHAR(255) DEFAULT '' NOT NULL,
     last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL
-) ENGINE=MyISAM;
+);
 
 CREATE INDEX account_record_idx ON location_attrs (username, domain, ruid);
 CREATE INDEX last_modified_idx ON location_attrs (last_modified);
diff --git a/utils/kamctl/oracle/acc-create.sql b/utils/kamctl/oracle/acc-create.sql
index 9b81534..b15c81d 100644
--- a/utils/kamctl/oracle/acc-create.sql
+++ b/utils/kamctl/oracle/acc-create.sql
@@ -20,6 +20,24 @@ BEGIN map2users('acc'); END;
 /
 CREATE INDEX acc_callid_idx  ON acc (callid);
 
+INSERT INTO version (table_name, table_version) values ('acc_cdrs','1');
+CREATE TABLE acc_cdrs (
+    id NUMBER(10) PRIMARY KEY,
+    start_time VARCHAR2(32) DEFAULT '',
+    end_time VARCHAR2(32) DEFAULT '',
+    duration VARCHAR2(32) DEFAULT ''
+);
+
+CREATE OR REPLACE TRIGGER acc_cdrs_tr
+before insert on acc_cdrs FOR EACH ROW
+BEGIN
+  auto_id(:NEW.id);
+END acc_cdrs_tr;
+/
+BEGIN map2users('acc_cdrs'); END;
+/
+CREATE INDEX acc_cdrs_start_time_idx  ON acc_cdrs (start_time);
+
 INSERT INTO version (table_name, table_version) values ('missed_calls','3');
 CREATE TABLE missed_calls (
     id NUMBER(10) PRIMARY KEY,
diff --git a/utils/kamctl/oracle/alias_db-create.sql b/utils/kamctl/oracle/alias_db-create.sql
index 57a9ba9..03ec78a 100644
--- a/utils/kamctl/oracle/alias_db-create.sql
+++ b/utils/kamctl/oracle/alias_db-create.sql
@@ -4,8 +4,7 @@ CREATE TABLE dbaliases (
     alias_username VARCHAR2(64) DEFAULT '',
     alias_domain VARCHAR2(64) DEFAULT '',
     username VARCHAR2(64) DEFAULT '',
-    domain VARCHAR2(64) DEFAULT '',
-    CONSTRAINT dbaliases_alias_idx  UNIQUE (alias_username, alias_domain)
+    domain VARCHAR2(64) DEFAULT ''
 );
 
 CREATE OR REPLACE TRIGGER dbaliases_tr
@@ -16,5 +15,7 @@ END dbaliases_tr;
 /
 BEGIN map2users('dbaliases'); END;
 /
+CREATE INDEX dbaliases_alias_user_idx  ON dbaliases (alias_username);
+CREATE INDEX dbaliases_alias_idx  ON dbaliases (alias_username, alias_domain);
 CREATE INDEX dbaliases_target_idx  ON dbaliases (username, domain);
 
diff --git a/utils/kamctl/oracle/mohqueue-create.sql b/utils/kamctl/oracle/mohqueue-create.sql
new file mode 100644
index 0000000..1ffec50
--- /dev/null
+++ b/utils/kamctl/oracle/mohqueue-create.sql
@@ -0,0 +1,40 @@
+INSERT INTO version (table_name, table_version) values ('mohqcalls','1');
+CREATE TABLE mohqcalls (
+    id NUMBER(10) PRIMARY KEY,
+    mohq_id NUMBER(10),
+    call_id VARCHAR2(100),
+    call_status NUMBER(10),
+    call_from VARCHAR2(100),
+    call_contact VARCHAR2(100),
+    call_time DATE,
+    CONSTRAINT mohqcalls_mohqcalls_idx  UNIQUE (call_id)
+);
+
+CREATE OR REPLACE TRIGGER mohqcalls_tr
+before insert on mohqcalls FOR EACH ROW
+BEGIN
+  auto_id(:NEW.id);
+END mohqcalls_tr;
+/
+BEGIN map2users('mohqcalls'); END;
+/
+INSERT INTO version (table_name, table_version) values ('mohqueues','1');
+CREATE TABLE mohqueues (
+    id NUMBER(10) PRIMARY KEY,
+    name VARCHAR2(25),
+    uri VARCHAR2(100),
+    mohdir VARCHAR2(100),
+    mohfile VARCHAR2(100),
+    debug NUMBER(10),
+    CONSTRAINT mohqueues_mohqueue_uri_idx  UNIQUE (uri),
+    CONSTRAINT mohqueues_mohqueue_name_idx  UNIQUE (name)
+);
+
+CREATE OR REPLACE TRIGGER mohqueues_tr
+before insert on mohqueues FOR EACH ROW
+BEGIN
+  auto_id(:NEW.id);
+END mohqueues_tr;
+/
+BEGIN map2users('mohqueues'); END;
+/
diff --git a/utils/kamctl/oracle/rtpproxy-create.sql b/utils/kamctl/oracle/rtpproxy-create.sql
new file mode 100644
index 0000000..05e34e8
--- /dev/null
+++ b/utils/kamctl/oracle/rtpproxy-create.sql
@@ -0,0 +1,18 @@
+INSERT INTO version (table_name, table_version) values ('rtpproxy','1');
+CREATE TABLE rtpproxy (
+    id NUMBER(10) PRIMARY KEY,
+    setid VARCHAR2(32) DEFAULT 00 NOT NULL,
+    url VARCHAR2(64) DEFAULT '',
+    flags NUMBER(10) DEFAULT 0 NOT NULL,
+    weight NUMBER(10) DEFAULT 1 NOT NULL,
+    description VARCHAR2(64) DEFAULT ''
+);
+
+CREATE OR REPLACE TRIGGER rtpproxy_tr
+before insert on rtpproxy FOR EACH ROW
+BEGIN
+  auto_id(:NEW.id);
+END rtpproxy_tr;
+/
+BEGIN map2users('rtpproxy'); END;
+/
diff --git a/utils/kamctl/postgres/acc-create.sql b/utils/kamctl/postgres/acc-create.sql
index 4c0dda5..b278077 100644
--- a/utils/kamctl/postgres/acc-create.sql
+++ b/utils/kamctl/postgres/acc-create.sql
@@ -12,6 +12,16 @@ CREATE TABLE acc (
 
 CREATE INDEX acc_callid_idx ON acc (callid);
 
+INSERT INTO version (table_name, table_version) values ('acc_cdrs','1');
+CREATE TABLE acc_cdrs (
+    id SERIAL PRIMARY KEY NOT NULL,
+    start_time VARCHAR(32) DEFAULT '' NOT NULL,
+    end_time VARCHAR(32) DEFAULT '' NOT NULL,
+    duration VARCHAR(32) DEFAULT '' NOT NULL
+);
+
+CREATE INDEX acc_cdrs_start_time_idx ON acc_cdrs (start_time);
+
 INSERT INTO version (table_name, table_version) values ('missed_calls','3');
 CREATE TABLE missed_calls (
     id SERIAL PRIMARY KEY NOT NULL,
diff --git a/utils/kamctl/postgres/alias_db-create.sql b/utils/kamctl/postgres/alias_db-create.sql
index 1bf29ea..5947b02 100644
--- a/utils/kamctl/postgres/alias_db-create.sql
+++ b/utils/kamctl/postgres/alias_db-create.sql
@@ -4,9 +4,10 @@ CREATE TABLE dbaliases (
     alias_username VARCHAR(64) DEFAULT '' NOT NULL,
     alias_domain VARCHAR(64) DEFAULT '' NOT NULL,
     username VARCHAR(64) DEFAULT '' NOT NULL,
-    domain VARCHAR(64) DEFAULT '' NOT NULL,
-    CONSTRAINT dbaliases_alias_idx UNIQUE (alias_username, alias_domain)
+    domain VARCHAR(64) DEFAULT '' NOT NULL
 );
 
+CREATE INDEX dbaliases_alias_user_idx ON dbaliases (alias_username);
+CREATE INDEX dbaliases_alias_idx ON dbaliases (alias_username, alias_domain);
 CREATE INDEX dbaliases_target_idx ON dbaliases (username, domain);
 
diff --git a/utils/kamctl/postgres/mohqueue-create.sql b/utils/kamctl/postgres/mohqueue-create.sql
new file mode 100644
index 0000000..1dc12ff
--- /dev/null
+++ b/utils/kamctl/postgres/mohqueue-create.sql
@@ -0,0 +1,24 @@
+INSERT INTO version (table_name, table_version) values ('mohqcalls','1');
+CREATE TABLE mohqcalls (
+    id SERIAL PRIMARY KEY NOT NULL,
+    mohq_id INTEGER NOT NULL,
+    call_id VARCHAR(100) NOT NULL,
+    call_status INTEGER NOT NULL,
+    call_from VARCHAR(100) NOT NULL,
+    call_contact VARCHAR(100),
+    call_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
+    CONSTRAINT mohqcalls_mohqcalls_idx UNIQUE (call_id)
+);
+
+INSERT INTO version (table_name, table_version) values ('mohqueues','1');
+CREATE TABLE mohqueues (
+    id SERIAL PRIMARY KEY NOT NULL,
+    name VARCHAR(25) NOT NULL,
+    uri VARCHAR(100) NOT NULL,
+    mohdir VARCHAR(100),
+    mohfile VARCHAR(100) NOT NULL,
+    debug INTEGER NOT NULL,
+    CONSTRAINT mohqueues_mohqueue_uri_idx UNIQUE (uri),
+    CONSTRAINT mohqueues_mohqueue_name_idx UNIQUE (name)
+);
+
diff --git a/utils/kamctl/postgres/rtpproxy-create.sql b/utils/kamctl/postgres/rtpproxy-create.sql
new file mode 100644
index 0000000..074024b
--- /dev/null
+++ b/utils/kamctl/postgres/rtpproxy-create.sql
@@ -0,0 +1,10 @@
+INSERT INTO version (table_name, table_version) values ('rtpproxy','1');
+CREATE TABLE rtpproxy (
+    id SERIAL PRIMARY KEY NOT NULL,
+    setid VARCHAR(32) DEFAULT 00 NOT NULL,
+    url VARCHAR(64) DEFAULT '' NOT NULL,
+    flags INTEGER DEFAULT 0 NOT NULL,
+    weight INTEGER DEFAULT 1 NOT NULL,
+    description VARCHAR(64) DEFAULT '' NOT NULL
+);
+
diff --git a/utils/kamctl/xhttp_pi/acc-mod b/utils/kamctl/xhttp_pi/acc-mod
index 15a6db4..ecf891a 100644
--- a/utils/kamctl/xhttp_pi/acc-mod
+++ b/utils/kamctl/xhttp_pi/acc-mod
@@ -51,6 +51,47 @@
 			</clause_cols>
 		</cmd>
 	</mod>
+	<!-- acc_cdrs provisionning -->
+	<mod><mod_name>acc_cdrs</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>start_time</field></col>
+				<col><field>end_time</field></col>
+				<col><field>duration</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>start_time</field></col>
+				<col><field>end_time</field></col>
+				<col><field>duration</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>start_time</field></col>
+				<col><field>end_time</field></col>
+				<col><field>duration</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
 	<!-- missed_calls provisionning -->
 	<mod><mod_name>missed_calls</mod_name>
 		<cmd><cmd_name>show</cmd_name>
diff --git a/utils/kamctl/xhttp_pi/acc-table b/utils/kamctl/xhttp_pi/acc-table
index 17aa47d..f7a60e7 100644
--- a/utils/kamctl/xhttp_pi/acc-table
+++ b/utils/kamctl/xhttp_pi/acc-table
@@ -11,6 +11,15 @@
 		<column><field>sip_reason</field><type>DB1_STR</type></column>
 		<column><field>time</field><type>DB1_DATETIME</type></column>
 	</db_table>
+	<!-- Declaration of acc_cdrs table-->
+	<db_table id="acc_cdrs">
+		<table_name>acc_cdrs</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>start_time</field><type>DB1_STR</type></column>
+		<column><field>end_time</field><type>DB1_STR</type></column>
+		<column><field>duration</field><type>DB1_STR</type></column>
+	</db_table>
 	<!-- Declaration of missed_calls table-->
 	<db_table id="missed_calls">
 		<table_name>missed_calls</table_name>
diff --git a/utils/kamctl/xhttp_pi/mohqueue-mod b/utils/kamctl/xhttp_pi/mohqueue-mod
new file mode 100644
index 0000000..b60ddc2
--- /dev/null
+++ b/utils/kamctl/xhttp_pi/mohqueue-mod
@@ -0,0 +1,97 @@
+	<!-- mohqcalls provisionning -->
+	<mod><mod_name>mohqcalls</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>mohq_id</field></col>
+				<col><field>call_id</field></col>
+				<col><field>call_status</field></col>
+				<col><field>call_from</field></col>
+				<col><field>call_contact</field></col>
+				<col><field>call_time</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>mohq_id</field></col>
+				<col><field>call_id</field></col>
+				<col><field>call_status</field></col>
+				<col><field>call_from</field></col>
+				<col><field>call_contact</field></col>
+				<col><field>call_time</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>mohq_id</field></col>
+				<col><field>call_id</field></col>
+				<col><field>call_status</field></col>
+				<col><field>call_from</field></col>
+				<col><field>call_contact</field></col>
+				<col><field>call_time</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
+	<!-- mohqueues provisionning -->
+	<mod><mod_name>mohqueues</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>name</field></col>
+				<col><field>uri</field></col>
+				<col><field>mohdir</field></col>
+				<col><field>mohfile</field></col>
+				<col><field>debug</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>name</field></col>
+				<col><field>uri</field></col>
+				<col><field>mohdir</field></col>
+				<col><field>mohfile</field></col>
+				<col><field>debug</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>name</field></col>
+				<col><field>uri</field></col>
+				<col><field>mohdir</field></col>
+				<col><field>mohfile</field></col>
+				<col><field>debug</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
diff --git a/utils/kamctl/xhttp_pi/mohqueue-table b/utils/kamctl/xhttp_pi/mohqueue-table
new file mode 100644
index 0000000..784657b
--- /dev/null
+++ b/utils/kamctl/xhttp_pi/mohqueue-table
@@ -0,0 +1,23 @@
+	<!-- Declaration of mohqcalls table-->
+	<db_table id="mohqcalls">
+		<table_name>mohqcalls</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>mohq_id</field><type>DB1_INT</type></column>
+		<column><field>call_id</field><type>DB1_STR</type></column>
+		<column><field>call_status</field><type>DB1_INT</type></column>
+		<column><field>call_from</field><type>DB1_STR</type></column>
+		<column><field>call_contact</field><type>DB1_STR</type></column>
+		<column><field>call_time</field><type>DB1_DATETIME</type></column>
+	</db_table>
+	<!-- Declaration of mohqueues table-->
+	<db_table id="mohqueues">
+		<table_name>mohqueues</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>name</field><type>DB1_STR</type></column>
+		<column><field>uri</field><type>DB1_STR</type></column>
+		<column><field>mohdir</field><type>DB1_STR</type></column>
+		<column><field>mohfile</field><type>DB1_STR</type></column>
+		<column><field>debug</field><type>DB1_INT</type></column>
+	</db_table>
diff --git a/utils/kamctl/xhttp_pi/pi_framework.xml b/utils/kamctl/xhttp_pi/pi_framework.xml
index c58f47e..05240bc 100644
--- a/utils/kamctl/xhttp_pi/pi_framework.xml
+++ b/utils/kamctl/xhttp_pi/pi_framework.xml
@@ -42,6 +42,15 @@
 		<column><field>sip_reason</field><type>DB1_STR</type></column>
 		<column><field>time</field><type>DB1_DATETIME</type></column>
 	</db_table>
+	<!-- Declaration of acc_cdrs table-->
+	<db_table id="acc_cdrs">
+		<table_name>acc_cdrs</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>start_time</field><type>DB1_STR</type></column>
+		<column><field>end_time</field><type>DB1_STR</type></column>
+		<column><field>duration</field><type>DB1_STR</type></column>
+	</db_table>
 	<!-- Declaration of missed_calls table-->
 	<db_table id="missed_calls">
 		<table_name>missed_calls</table_name>
@@ -212,17 +221,6 @@
 		<column><field>attrs</field><type>DB1_STR</type></column>
 		<column><field>description</field><type>DB1_STR</type></column>
 	</db_table>
-	<!-- Declaration of domainpolicy table-->
-	<db_table id="domainpolicy">
-		<table_name>domainpolicy</table_name>
-		<db_url_id>mysql</db_url_id>
-		<column><field>id</field><type>DB1_INT</type></column>
-		<column><field>rule</field><type>DB1_STR</type></column>
-		<column><field>type</field><type>DB1_STR</type></column>
-		<column><field>att</field><type>DB1_STR</type></column>
-		<column><field>val</field><type>DB1_STR</type></column>
-		<column><field>description</field><type>DB1_STR</type></column>
-	</db_table>
 	<!-- Declaration of domain table-->
 	<db_table id="domain">
 		<table_name>domain</table_name>
@@ -243,6 +241,17 @@
 		<column><field>value</field><type>DB1_STR</type></column>
 		<column><field>last_modified</field><type>DB1_DATETIME</type></column>
 	</db_table>
+	<!-- Declaration of domainpolicy table-->
+	<db_table id="domainpolicy">
+		<table_name>domainpolicy</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>rule</field><type>DB1_STR</type></column>
+		<column><field>type</field><type>DB1_STR</type></column>
+		<column><field>att</field><type>DB1_STR</type></column>
+		<column><field>val</field><type>DB1_STR</type></column>
+		<column><field>description</field><type>DB1_STR</type></column>
+	</db_table>
 	<!-- Declaration of dr_gateways table-->
 	<db_table id="dr_gateways">
 		<table_name>dr_gateways</table_name>
@@ -384,6 +393,29 @@
 		<column><field>second</field><type>DB1_INT</type></column>
 		<column><field>res</field><type>DB1_INT</type></column>
 	</db_table>
+	<!-- Declaration of mohqcalls table-->
+	<db_table id="mohqcalls">
+		<table_name>mohqcalls</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>mohq_id</field><type>DB1_INT</type></column>
+		<column><field>call_id</field><type>DB1_STR</type></column>
+		<column><field>call_status</field><type>DB1_INT</type></column>
+		<column><field>call_from</field><type>DB1_STR</type></column>
+		<column><field>call_contact</field><type>DB1_STR</type></column>
+		<column><field>call_time</field><type>DB1_DATETIME</type></column>
+	</db_table>
+	<!-- Declaration of mohqueues table-->
+	<db_table id="mohqueues">
+		<table_name>mohqueues</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>name</field><type>DB1_STR</type></column>
+		<column><field>uri</field><type>DB1_STR</type></column>
+		<column><field>mohdir</field><type>DB1_STR</type></column>
+		<column><field>mohfile</field><type>DB1_STR</type></column>
+		<column><field>debug</field><type>DB1_INT</type></column>
+	</db_table>
 	<!-- Declaration of silo table-->
 	<db_table id="silo">
 		<table_name>silo</table_name>
@@ -630,6 +662,17 @@
 		<column><field>from_domain</field><type>DB1_STR</type></column>
 		<column><field>updated</field><type>DB1_INT</type></column>
 	</db_table>
+	<!-- Declaration of rtpproxy table-->
+	<db_table id="rtpproxy">
+		<table_name>rtpproxy</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>setid</field><type>DB1_STR</type></column>
+		<column><field>url</field><type>DB1_STR</type></column>
+		<column><field>flags</field><type>DB1_INT</type></column>
+		<column><field>weight</field><type>DB1_INT</type></column>
+		<column><field>description</field><type>DB1_STR</type></column>
+	</db_table>
 	<!-- Declaration of sca_subscriptions table-->
 	<db_table id="sca_subscriptions">
 		<table_name>sca_subscriptions</table_name>
@@ -938,6 +981,47 @@
 			</clause_cols>
 		</cmd>
 	</mod>
+	<!-- acc_cdrs provisionning -->
+	<mod><mod_name>acc_cdrs</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>start_time</field></col>
+				<col><field>end_time</field></col>
+				<col><field>duration</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>start_time</field></col>
+				<col><field>end_time</field></col>
+				<col><field>duration</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>start_time</field></col>
+				<col><field>end_time</field></col>
+				<col><field>duration</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>acc_cdrs</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
 	<!-- missed_calls provisionning -->
 	<mod><mod_name>missed_calls</mod_name>
 		<cmd><cmd_name>show</cmd_name>
@@ -2353,6 +2437,103 @@
 			</query_cols>
 		</cmd>
 	</mod>
+	<!-- mohqcalls provisionning -->
+	<mod><mod_name>mohqcalls</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>mohq_id</field></col>
+				<col><field>call_id</field></col>
+				<col><field>call_status</field></col>
+				<col><field>call_from</field></col>
+				<col><field>call_contact</field></col>
+				<col><field>call_time</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>mohq_id</field></col>
+				<col><field>call_id</field></col>
+				<col><field>call_status</field></col>
+				<col><field>call_from</field></col>
+				<col><field>call_contact</field></col>
+				<col><field>call_time</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>mohq_id</field></col>
+				<col><field>call_id</field></col>
+				<col><field>call_status</field></col>
+				<col><field>call_from</field></col>
+				<col><field>call_contact</field></col>
+				<col><field>call_time</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>mohqcalls</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
+	<!-- mohqueues provisionning -->
+	<mod><mod_name>mohqueues</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>name</field></col>
+				<col><field>uri</field></col>
+				<col><field>mohdir</field></col>
+				<col><field>mohfile</field></col>
+				<col><field>debug</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>name</field></col>
+				<col><field>uri</field></col>
+				<col><field>mohdir</field></col>
+				<col><field>mohfile</field></col>
+				<col><field>debug</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>name</field></col>
+				<col><field>uri</field></col>
+				<col><field>mohdir</field></col>
+				<col><field>mohfile</field></col>
+				<col><field>debug</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>mohqueues</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
 	<!-- silo provisionning -->
 	<mod><mod_name>silo</mod_name>
 		<cmd><cmd_name>show</cmd_name>
@@ -3315,6 +3496,53 @@
 			</clause_cols>
 		</cmd>
 	</mod>
+	<!-- rtpproxy provisionning -->
+	<mod><mod_name>rtpproxy</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>setid</field></col>
+				<col><field>url</field></col>
+				<col><field>flags</field></col>
+				<col><field>weight</field></col>
+				<col><field>description</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>setid</field></col>
+				<col><field>url</field></col>
+				<col><field>flags</field></col>
+				<col><field>weight</field></col>
+				<col><field>description</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>setid</field></col>
+				<col><field>url</field></col>
+				<col><field>flags</field></col>
+				<col><field>weight</field></col>
+				<col><field>description</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
 	<!-- sca_subscriptions provisionning -->
 	<mod><mod_name>sca_subscriptions</mod_name>
 		<cmd><cmd_name>show</cmd_name>
diff --git a/utils/kamctl/xhttp_pi/rtpproxy-mod b/utils/kamctl/xhttp_pi/rtpproxy-mod
new file mode 100644
index 0000000..558dcd1
--- /dev/null
+++ b/utils/kamctl/xhttp_pi/rtpproxy-mod
@@ -0,0 +1,47 @@
+	<!-- rtpproxy provisionning -->
+	<mod><mod_name>rtpproxy</mod_name>
+		<cmd><cmd_name>show</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_QUERY</cmd_type>
+			<query_cols>
+				<col><field>id</field></col>
+				<col><field>setid</field></col>
+				<col><field>url</field></col>
+				<col><field>flags</field></col>
+				<col><field>weight</field></col>
+				<col><field>description</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>add</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_INSERT</cmd_type>
+			<query_cols>
+				<col><field>setid</field></col>
+				<col><field>url</field></col>
+				<col><field>flags</field></col>
+				<col><field>weight</field></col>
+				<col><field>description</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>update</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_UPDATE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+			<query_cols>
+				<col><field>setid</field></col>
+				<col><field>url</field></col>
+				<col><field>flags</field></col>
+				<col><field>weight</field></col>
+				<col><field>description</field></col>
+			</query_cols>
+		</cmd>
+		<cmd><cmd_name>delete</cmd_name>
+			<db_table_id>rtpproxy</db_table_id>
+			<cmd_type>DB1_DELETE</cmd_type>
+			<clause_cols>
+				<col><field>id</field><operator>=</operator></col>
+			</clause_cols>
+		</cmd>
+	</mod>
diff --git a/utils/kamctl/xhttp_pi/rtpproxy-table b/utils/kamctl/xhttp_pi/rtpproxy-table
new file mode 100644
index 0000000..00cf317
--- /dev/null
+++ b/utils/kamctl/xhttp_pi/rtpproxy-table
@@ -0,0 +1,11 @@
+	<!-- Declaration of rtpproxy table-->
+	<db_table id="rtpproxy">
+		<table_name>rtpproxy</table_name>
+		<db_url_id>mysql</db_url_id>
+		<column><field>id</field><type>DB1_INT</type></column>
+		<column><field>setid</field><type>DB1_STR</type></column>
+		<column><field>url</field><type>DB1_STR</type></column>
+		<column><field>flags</field><type>DB1_INT</type></column>
+		<column><field>weight</field><type>DB1_INT</type></column>
+		<column><field>description</field><type>DB1_STR</type></column>
+	</db_table>
diff --git a/utils/sercmd/Makefile b/utils/sercmd/Makefile
index dacd064..86db185 100644
--- a/utils/sercmd/Makefile
+++ b/utils/sercmd/Makefile
@@ -27,7 +27,7 @@ endif #ifneq (,$(MAKECMDGOALS))
 
 # erase common DEFS (not needed)
 C_DEFS:=
-DEFS:= -DNAME='"$(NAME)"' -DSRNAME='"$(MAIN_NAME)"' -DVERSION='"$(RELEASE)"' \
+DEFS:= -DNAME='"$(NAME)"' -DSRNAME='"$(MAIN_NAME)"' -DVERSION='"$(RELEASE)"' -D__OS_$(OS) \
 		$(filter -D%HAVE -DARCH% -DOS% -D__CPU% -D__OS%, $(DEFS))
 
 # use proper libs (we can't rely on LIBS value since we might be called
diff --git a/utils/sercmd/parse_listen_id.c b/utils/sercmd/parse_listen_id.c
index 02c2f1e..5cef9cd 100644
--- a/utils/sercmd/parse_listen_id.c
+++ b/utils/sercmd/parse_listen_id.c
@@ -42,11 +42,25 @@
 #define pkg_malloc malloc
 #define pkg_free   free
 
+#ifdef EXTRA_DEBUG
+static int _debug = 1;
+#else
+static int _debug = 0;
+#endif
+
 #ifdef __SUNPRO_C
-#define DBG(...)
+#define DBG(...) \
+	do { \
+		if(_debug==1) \
+			fprintf(stderr,  __VA_ARGS__); \
+	} while(0)
 #define LOG(lev, ...) fprintf(stderr,  __VA_ARGS__)
 #else
-#define DBG(fmt, args...)
+#define DBG(fmt, args...) \
+	do { \
+		if(_debug==1) \
+			fprintf(stderr, fmt, ## args); \
+	} while(0)
 #define LOG(lev, fmt, args...) fprintf(stderr, fmt, ## args)
 #endif
 
diff --git a/ver_defs.h b/ver_defs.h
index a69a4c9..8a17ca3 100644
--- a/ver_defs.h
+++ b/ver_defs.h
@@ -39,12 +39,6 @@
 #define STATS_STR  "STATS: Off"
 #endif
 
-#ifdef USE_IPV6
-#define USE_IPV6_STR ", USE_IPV6"
-#else
-#define USE_IPV6_STR ""
-#endif
-
 #ifdef USE_TCP
 #define USE_TCP_STR ", USE_TCP"
 #else
@@ -291,12 +285,6 @@
 #define NO_SIG_DEBUG_STR ""
 #endif
 
-#ifdef USE_STUN
-#define USE_STUN_STR ", USE_STUN"
-#else
-#define USE_STUN_STR ""
-#endif
-
 #ifdef HAVE_RESOLV_RES 
 #define HAVE_RESOLV_RES_STR ", HAVE_RESOLV_RES"
 #else
@@ -334,9 +322,9 @@
 #endif
 
 #define SER_COMPILE_FLAGS \
-	STATS_STR EXTRA_DEBUG_STR USE_IPV6_STR USE_TCP_STR USE_TLS_STR \
+	STATS_STR EXTRA_DEBUG_STR USE_TCP_STR USE_TLS_STR \
 	USE_SCTP_STR CORE_TLS_STR TLS_HOOKS_STR  USE_RAW_SOCKS_STR \
-	USE_STUN_STR DISABLE_NAGLE_STR USE_MCAST_STR NO_DEBUG_STR NO_LOG_STR \
+	DISABLE_NAGLE_STR USE_MCAST_STR NO_DEBUG_STR NO_LOG_STR \
 	NO_SIG_DEBUG_STR DNS_IP_HACK_STR  SHM_MEM_STR SHM_MMAP_STR PKG_MALLOC_STR \
 	F_MALLOC_STR DL_MALLOC_STR SF_MALLOC_STR  LL_MALLOC_STR \
 	USE_SHM_MEM_STR \
diff --git a/xavp.c b/xavp.c
index 6c8566d..5f51731 100644
--- a/xavp.c
+++ b/xavp.c
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "mem/mem.h"
 #include "mem/shm_mem.h"
 #include "dprint.h"
 #include "hashes.h"
@@ -538,6 +539,85 @@ void xavp_print_list(sr_xavp_t **head)
 }
 
 /**
+ * returns a list of str with key names.
+ * Example:
+ * If we have this structure
+ * $xavp(test=>one) = 1
+ * $xavp(test[0]=>two) = "2"
+ * $xavp(test[0]=>three) = 3
+ * $xavp(test[0]=>four) = $xavp(whatever)
+ * $xavp(test[0]=>two) = "other 2"
+ *
+ * xavp_get_list_keys_names(test[0]) returns
+ * {"one", "two", "three", "four"}
+ *
+ * free the struct str_list afterwards
+ * but do *NO* free the strings inside
+ */
+struct str_list *xavp_get_list_key_names(sr_xavp_t *xavp)
+{
+	sr_xavp_t *avp = NULL;
+	struct str_list *result = NULL;
+	struct str_list *r = NULL;
+	struct str_list *f = NULL;
+	int total = 0;
+
+	if(xavp==NULL){
+		LM_ERR("xavp is NULL\n");
+		return 0;
+	}
+
+	if(xavp->val.type!=SR_XTYPE_XAVP){
+		LM_ERR("%s not xavp?\n", xavp->name.s);
+		return 0;
+	}
+
+	avp = xavp->val.v.xavp;
+
+	if (avp)
+	{
+		result = (struct str_list*)pkg_malloc(sizeof(struct str_list));
+		if (result==NULL) {
+			PKG_MEM_ERROR;
+			return 0;
+		}
+		r = result;
+		r->s.s = avp->name.s;
+		r->s.len = avp->name.len;
+		r->next = NULL;
+		avp = avp->next;
+	}
+
+	while(avp)
+	{
+		f = result;
+		while(f)
+		{
+			if((avp->name.len==f->s.len)&&
+				(strncmp(avp->name.s, f->s.s, f->s.len)==0))
+			{
+				break; /* name already on list */
+			}
+			f = f->next;
+		}
+		if (f==NULL)
+		{
+			r = append_str_list(avp->name.s, avp->name.len, &r, &total);
+			if(r==NULL){
+				while(result){
+					r = result;
+					result = result->next;
+					pkg_free(r);
+				}
+				return 0;
+			}
+		}
+		avp = avp->next;
+	}
+	return result;
+}
+
+/**
  * clone the xavp without values that are custom data
  * - only one list level is cloned, other sublists are ignored
  */
@@ -707,4 +787,53 @@ sr_xavp_t *xavp_extract(str *name, sr_xavp_t **list)
 	}
 	return NULL;
 }
+
+/**
+ * return child node of an xavp
+ * - $xavp(rname=>cname)
+ */
+sr_xavp_t* xavp_get_child(str *rname, str *cname)
+{
+	sr_xavp_t *ravp=NULL;
+
+	ravp = xavp_get(rname, NULL);
+	if(ravp==NULL || ravp->val.type!=SR_XTYPE_XAVP)
+		return NULL;
+
+	return xavp_get(cname, ravp->val.v.xavp);
+}
+
+
+/**
+ * return child node of an xavp if it has int value
+ * - $xavp(rname=>cname)
+ */
+sr_xavp_t* xavp_get_child_with_ival(str *rname, str *cname)
+{
+	sr_xavp_t *vavp=NULL;
+
+	vavp = xavp_get_child(rname, cname);
+
+	if(vavp==NULL || vavp->val.type!=SR_XTYPE_INT)
+		return NULL;
+
+	return vavp;
+}
+
+
+/**
+ * return child node of an xavp if it has string value
+ * - $xavp(rname=>cname)
+ */
+sr_xavp_t* xavp_get_child_with_sval(str *rname, str *cname)
+{
+	sr_xavp_t *vavp=NULL;
+
+	vavp = xavp_get_child(rname, cname);
+
+	if(vavp==NULL || vavp->val.type!=SR_XTYPE_STR)
+		return NULL;
+
+	return vavp;
+}
 #endif
diff --git a/xavp.h b/xavp.h
index b581c08..8332069 100644
--- a/xavp.h
+++ b/xavp.h
@@ -29,6 +29,7 @@
 
 #include <time.h>
 #include "str.h"
+#include "str_list.h"
 
 struct _sr_xavp;
 
@@ -95,6 +96,7 @@ void xavp_destroy_list(sr_xavp_t **head);
 void xavp_reset_list(void);
 sr_xavp_t **xavp_set_list(sr_xavp_t **head);
 sr_xavp_t **xavp_get_crt_list(void);
+struct str_list *xavp_get_list_key_names(sr_xavp_t *xavp);
 
 int xavp_insert(sr_xavp_t *xavp, int idx, sr_xavp_t **list);
 sr_xavp_t *xavp_extract(str *name, sr_xavp_t **list);
@@ -102,6 +104,10 @@ sr_xavp_t *xavp_extract(str *name, sr_xavp_t **list);
 void xavp_print_list(sr_xavp_t **head);
 
 sr_xavp_t *xavp_clone_level_nodata(sr_xavp_t *xold);
+
+sr_xavp_t* xavp_get_child(str *rname, str *cname);
+sr_xavp_t* xavp_get_child_with_ival(str *rname, str *cname);
+sr_xavp_t* xavp_get_child_with_sval(str *rname, str *cname);
 #endif
 
 #endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/kamailio.git



More information about the Pkg-voip-commits mailing list