Merge branch 'ser_core_cvs' of ssh://git.sip-router.org/sip-router
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Tue, 31 Mar 2009 17:26:41 +0000 (19:26 +0200)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Tue, 31 Mar 2009 17:26:41 +0000 (19:26 +0200)
* 'ser_core_cvs' of ssh://git.sip-router.org/sip-router:
  dns: minor fixes
  Static buffer is resetted before calling the route block -- Thanks to Jan.
  Missing include is added.

Conflicts:
modules/tm/t_suspend.c : sip-router version uses
i                        run_top_route()

493 files changed:
.gitignore [new file with mode: 0644]
Makefile.rules
Makefile.sources
NEWS
action.c
action.h
cfg.lex
cfg.y
cfg_core.c
cfg_core.h
config.h
core_cmd.c
db/Makefile [deleted file]
dns_cache.c
doc/doxygen/main.dox
dprint.c
dprint.h
dset.c
dset.h
flags.c
flags.h
ip_addr.h
lib/README
lib/kmi/Makefile [new file with mode: 0644]
lib/kmi/attr.c [new file with mode: 0644]
lib/kmi/attr.h [new file with mode: 0644]
lib/kmi/fmt.c [new file with mode: 0644]
lib/kmi/fmt.h [new file with mode: 0644]
lib/kmi/mi.c [new file with mode: 0644]
lib/kmi/mi.h [new file with mode: 0644]
lib/kmi/mi_core.c [new file with mode: 0644]
lib/kmi/mi_core.h [new file with mode: 0644]
lib/kmi/tree.c [new file with mode: 0644]
lib/kmi/tree.h [new file with mode: 0644]
lib/srdb1/Makefile [new file with mode: 0644]
lib/srdb1/README [new file with mode: 0644]
lib/srdb1/db.c [new file with mode: 0644]
lib/srdb1/db.h [new file with mode: 0644]
lib/srdb1/db_cap.h [new file with mode: 0644]
lib/srdb1/db_con.h [new file with mode: 0644]
lib/srdb1/db_id.c [new file with mode: 0644]
lib/srdb1/db_id.h [new file with mode: 0644]
lib/srdb1/db_key.h [new file with mode: 0644]
lib/srdb1/db_op.h [new file with mode: 0644]
lib/srdb1/db_pool.c [new file with mode: 0644]
lib/srdb1/db_pool.h [new file with mode: 0644]
lib/srdb1/db_query.c [new file with mode: 0644]
lib/srdb1/db_query.h [new file with mode: 0644]
lib/srdb1/db_res.c [new file with mode: 0644]
lib/srdb1/db_res.h [new file with mode: 0644]
lib/srdb1/db_row.c [new file with mode: 0644]
lib/srdb1/db_row.h [new file with mode: 0644]
lib/srdb1/db_ut.c [new file with mode: 0644]
lib/srdb1/db_ut.h [new file with mode: 0644]
lib/srdb1/db_val.c [new file with mode: 0644]
lib/srdb1/db_val.h [new file with mode: 0644]
lib/srdb1/schema/Makefile [new file with mode: 0644]
lib/srdb1/schema/acc.xml [new file with mode: 0644]
lib/srdb1/schema/address.xml [new file with mode: 0644]
lib/srdb1/schema/aliases.xml [new file with mode: 0644]
lib/srdb1/schema/carrier_name.xml [new file with mode: 0644]
lib/srdb1/schema/carrierfailureroute.xml [new file with mode: 0644]
lib/srdb1/schema/carrierroute.xml [new file with mode: 0644]
lib/srdb1/schema/cpl.xml [new file with mode: 0644]
lib/srdb1/schema/dbaliases.xml [new file with mode: 0644]
lib/srdb1/schema/dialog.xml [new file with mode: 0644]
lib/srdb1/schema/dialplan.xml [new file with mode: 0644]
lib/srdb1/schema/dispatcher.xml [new file with mode: 0644]
lib/srdb1/schema/domain.xml [new file with mode: 0644]
lib/srdb1/schema/domain_name.xml [new file with mode: 0644]
lib/srdb1/schema/domainpolicy.xml [new file with mode: 0644]
lib/srdb1/schema/entities.xml [new file with mode: 0644]
lib/srdb1/schema/globalblacklist.xml [new file with mode: 0644]
lib/srdb1/schema/grp.xml [new file with mode: 0644]
lib/srdb1/schema/gw.xml [new file with mode: 0644]
lib/srdb1/schema/htable.xml [new file with mode: 0644]
lib/srdb1/schema/imc_members.xml [new file with mode: 0644]
lib/srdb1/schema/imc_rooms.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-acc.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-alias_db.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-auth_db.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-avpops.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-carrierroute.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-cpl.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-dialog.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-dialplan.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-dispatcher.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-domain.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-domainpolicy.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-extensions.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-group.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-htable.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-imc.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-lcr.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-msilo.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-pdt.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-permissions.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-presence.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-registrar.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-rls.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-siptrace.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-speeddial.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-standard.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-uri_db.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-userblacklist.xml [new file with mode: 0644]
lib/srdb1/schema/kamailio-usrloc.xml [new file with mode: 0644]
lib/srdb1/schema/lcr.xml [new file with mode: 0644]
lib/srdb1/schema/location.xml [new file with mode: 0644]
lib/srdb1/schema/missed_calls.xml [new file with mode: 0644]
lib/srdb1/schema/pdt.xml [new file with mode: 0644]
lib/srdb1/schema/pr_active_watchers.xml [new file with mode: 0644]
lib/srdb1/schema/pr_presentity.xml [new file with mode: 0644]
lib/srdb1/schema/pr_pua.xml [new file with mode: 0644]
lib/srdb1/schema/pr_watchers.xml [new file with mode: 0644]
lib/srdb1/schema/pr_xcap.xml [new file with mode: 0644]
lib/srdb1/schema/re_grp.xml [new file with mode: 0644]
lib/srdb1/schema/rls_presentity.xml [new file with mode: 0644]
lib/srdb1/schema/rls_watchers.xml [new file with mode: 0644]
lib/srdb1/schema/silo.xml [new file with mode: 0644]
lib/srdb1/schema/sip_trace.xml [new file with mode: 0644]
lib/srdb1/schema/speed_dial.xml [new file with mode: 0644]
lib/srdb1/schema/subscriber.xml [new file with mode: 0644]
lib/srdb1/schema/template.xml [new file with mode: 0644]
lib/srdb1/schema/trusted.xml [new file with mode: 0644]
lib/srdb1/schema/uri.xml [new file with mode: 0644]
lib/srdb1/schema/userblacklist.xml [new file with mode: 0644]
lib/srdb1/schema/usr_preferences.xml [new file with mode: 0644]
lib/srdb1/schema/version.xml [new file with mode: 0644]
lib/srdb2/Makefile [new file with mode: 0644]
lib/srdb2/README [moved from db/README with 100% similarity]
lib/srdb2/db.c [moved from db/db.c with 89% similarity]
lib/srdb2/db.h [moved from db/db.h with 66% similarity]
lib/srdb2/db_cmd.c [moved from db/db_cmd.c with 98% similarity]
lib/srdb2/db_cmd.h [moved from db/db_cmd.h with 100% similarity]
lib/srdb2/db_con.c [moved from db/db_con.c with 98% similarity]
lib/srdb2/db_con.h [moved from db/db_con.h with 100% similarity]
lib/srdb2/db_ctx.c [moved from db/db_ctx.c with 99% similarity]
lib/srdb2/db_ctx.h [moved from db/db_ctx.h with 98% similarity]
lib/srdb2/db_drv.c [moved from db/db_drv.c with 75% similarity]
lib/srdb2/db_drv.h [moved from db/db_drv.h with 98% similarity]
lib/srdb2/db_fld.c [moved from db/db_fld.c with 98% similarity]
lib/srdb2/db_fld.h [moved from db/db_fld.h with 99% similarity]
lib/srdb2/db_gen.c [moved from db/db_gen.c with 100% similarity]
lib/srdb2/db_gen.h [moved from db/db_gen.h with 99% similarity]
lib/srdb2/db_pool.c [moved from db/db_pool.c with 99% similarity]
lib/srdb2/db_pool.h [moved from db/db_pool.h with 99% similarity]
lib/srdb2/db_rec.c [moved from db/db_rec.c with 97% similarity]
lib/srdb2/db_rec.h [moved from db/db_rec.h with 100% similarity]
lib/srdb2/db_res.c [moved from db/db_res.c with 97% similarity]
lib/srdb2/db_res.h [moved from db/db_res.h with 100% similarity]
lib/srdb2/db_uri.c [moved from db/db_uri.c with 97% similarity]
lib/srdb2/db_uri.h [moved from db/db_uri.h with 98% similarity]
lib/srdb2/schema/Makefile [moved from db/schema/Makefile with 100% similarity]
lib/srdb2/schema/acc.xml [moved from db/schema/acc.xml with 100% similarity]
lib/srdb2/schema/aliases.xml [moved from db/schema/aliases.xml with 100% similarity]
lib/srdb2/schema/attr_types.xml [moved from db/schema/attr_types.xml with 100% similarity]
lib/srdb2/schema/contact_attrs.xml [moved from db/schema/contact_attrs.xml with 100% similarity]
lib/srdb2/schema/cpl.xml [moved from db/schema/cpl.xml with 100% similarity]
lib/srdb2/schema/credentials.xml [moved from db/schema/credentials.xml with 100% similarity]
lib/srdb2/schema/customers.xml [moved from db/schema/customers.xml with 100% similarity]
lib/srdb2/schema/domain.xml [moved from db/schema/domain.xml with 100% similarity]
lib/srdb2/schema/domain_attrs.xml [moved from db/schema/domain_attrs.xml with 100% similarity]
lib/srdb2/schema/domain_settings.xml [moved from db/schema/domain_settings.xml with 100% similarity]
lib/srdb2/schema/entities.xml [moved from db/schema/entities.xml with 100% similarity]
lib/srdb2/schema/extra_attrs.xml [moved from db/schema/extra_attrs.xml with 100% similarity]
lib/srdb2/schema/global_attrs.xml [moved from db/schema/global_attrs.xml with 100% similarity]
lib/srdb2/schema/grp.xml [moved from db/schema/grp.xml with 100% similarity]
lib/srdb2/schema/gw.xml [moved from db/schema/gw.xml with 100% similarity]
lib/srdb2/schema/gw_grp.xml [moved from db/schema/gw_grp.xml with 100% similarity]
lib/srdb2/schema/i18n-cs.xml [moved from db/schema/i18n-cs.xml with 100% similarity]
lib/srdb2/schema/i18n-en.xml [moved from db/schema/i18n-en.xml with 100% similarity]
lib/srdb2/schema/i18n.xml [moved from db/schema/i18n.xml with 100% similarity]
lib/srdb2/schema/ipmatch.xml [moved from db/schema/ipmatch.xml with 100% similarity]
lib/srdb2/schema/lcr.xml [moved from db/schema/lcr.xml with 100% similarity]
lib/srdb2/schema/location.xml [moved from db/schema/location.xml with 100% similarity]
lib/srdb2/schema/missed_calls.xml [moved from db/schema/missed_calls.xml with 100% similarity]
lib/srdb2/schema/offline_winfo.xml [moved from db/schema/offline_winfo.xml with 100% similarity]
lib/srdb2/schema/pdt.xml [moved from db/schema/pdt.xml with 100% similarity]
lib/srdb2/schema/phonebook.xml [moved from db/schema/phonebook.xml with 100% similarity]
lib/srdb2/schema/presentity.xml [moved from db/schema/presentity.xml with 100% similarity]
lib/srdb2/schema/presentity_contact.xml [moved from db/schema/presentity_contact.xml with 100% similarity]
lib/srdb2/schema/presentity_extensions.xml [moved from db/schema/presentity_extensions.xml with 100% similarity]
lib/srdb2/schema/presentity_notes.xml [moved from db/schema/presentity_notes.xml with 100% similarity]
lib/srdb2/schema/rls_subscription.xml [moved from db/schema/rls_subscription.xml with 100% similarity]
lib/srdb2/schema/rls_vs.xml [moved from db/schema/rls_vs.xml with 100% similarity]
lib/srdb2/schema/rls_vs_names.xml [moved from db/schema/rls_vs_names.xml with 100% similarity]
lib/srdb2/schema/sd_attrs.xml [moved from db/schema/sd_attrs.xml with 100% similarity]
lib/srdb2/schema/ser.xml [moved from db/schema/ser.xml with 100% similarity]
lib/srdb2/schema/silo.xml [moved from db/schema/silo.xml with 100% similarity]
lib/srdb2/schema/speed_dial.xml [moved from db/schema/speed_dial.xml with 100% similarity]
lib/srdb2/schema/trusted.xml [moved from db/schema/trusted.xml with 100% similarity]
lib/srdb2/schema/tuple_extensions.xml [moved from db/schema/tuple_extensions.xml with 100% similarity]
lib/srdb2/schema/tuple_notes.xml [moved from db/schema/tuple_notes.xml with 100% similarity]
lib/srdb2/schema/uri.xml [moved from db/schema/uri.xml with 100% similarity]
lib/srdb2/schema/uri_attrs.xml [moved from db/schema/uri_attrs.xml with 100% similarity]
lib/srdb2/schema/user_attrs.xml [moved from db/schema/user_attrs.xml with 100% similarity]
lib/srdb2/schema/watcherinfo.xml [moved from db/schema/watcherinfo.xml with 100% similarity]
lib/trie/Makefile [new file with mode: 0644]
lib/trie/dtrie.c [new file with mode: 0644]
lib/trie/dtrie.h [new file with mode: 0644]
lvalue.c [new file with mode: 0644]
lvalue.h [new file with mode: 0644]
main.c
md5utils.c
md5utils.h
mem/mem.h
mi/mi.h [new file with mode: 0644]
mod_fix.c [new file with mode: 0644]
mod_fix.h [new file with mode: 0644]
modparam.c
modules/carrierroute/Makefile [new file with mode: 0644]
modules/carrierroute/README [new file with mode: 0644]
modules/carrierroute/carrierroute.c [new file with mode: 0644]
modules/carrierroute/carrierroute.h [new file with mode: 0644]
modules/carrierroute/cr_carrier.c [new file with mode: 0644]
modules/carrierroute/cr_carrier.h [new file with mode: 0644]
modules/carrierroute/cr_config.c [new file with mode: 0644]
modules/carrierroute/cr_config.h [new file with mode: 0644]
modules/carrierroute/cr_data.c [new file with mode: 0644]
modules/carrierroute/cr_data.h [new file with mode: 0644]
modules/carrierroute/cr_db.c [new file with mode: 0644]
modules/carrierroute/cr_db.h [new file with mode: 0644]
modules/carrierroute/cr_domain.c [new file with mode: 0644]
modules/carrierroute/cr_domain.h [new file with mode: 0644]
modules/carrierroute/cr_fifo.c [new file with mode: 0644]
modules/carrierroute/cr_fifo.h [new file with mode: 0644]
modules/carrierroute/cr_fixup.c [new file with mode: 0644]
modules/carrierroute/cr_fixup.h [new file with mode: 0644]
modules/carrierroute/cr_func.c [new file with mode: 0644]
modules/carrierroute/cr_func.h [new file with mode: 0644]
modules/carrierroute/cr_map.c [new file with mode: 0644]
modules/carrierroute/cr_map.h [new file with mode: 0644]
modules/carrierroute/cr_rule.c [new file with mode: 0644]
modules/carrierroute/cr_rule.h [new file with mode: 0644]
modules/carrierroute/db_carrierroute.c [new file with mode: 0644]
modules/carrierroute/db_carrierroute.h [new file with mode: 0644]
modules/carrierroute/doc/carrierroute.xml [new file with mode: 0644]
modules/carrierroute/doc/carrierroute_admin.xml [new file with mode: 0644]
modules/carrierroute/doc/carrierroute_db.xml [new file with mode: 0644]
modules/carrierroute/prime_hash.c [new file with mode: 0644]
modules/carrierroute/prime_hash.h [new file with mode: 0644]
modules/db_berkeley/Makefile [new file with mode: 0644]
modules/db_berkeley/README [new file with mode: 0644]
modules/db_berkeley/bdb_cmd.c [new file with mode: 0644]
modules/db_berkeley/bdb_cmd.h [new file with mode: 0644]
modules/db_berkeley/bdb_con.c [new file with mode: 0644]
modules/db_berkeley/bdb_con.h [new file with mode: 0644]
modules/db_berkeley/bdb_fld.c [new file with mode: 0644]
modules/db_berkeley/bdb_fld.h [new file with mode: 0644]
modules/db_berkeley/bdb_lib.c [new file with mode: 0644]
modules/db_berkeley/bdb_lib.h [new file with mode: 0644]
modules/db_berkeley/bdb_mod.c [new file with mode: 0644]
modules/db_berkeley/bdb_mod.h [new file with mode: 0644]
modules/db_berkeley/bdb_res.c [new file with mode: 0644]
modules/db_berkeley/bdb_res.h [new file with mode: 0644]
modules/db_berkeley/bdb_uri.c [new file with mode: 0644]
modules/db_berkeley/bdb_uri.h [new file with mode: 0644]
modules/db_berkeley/doc/db_berkeley.xml [new file with mode: 0644]
modules/db_berkeley/doc/db_berkeley_admin.xml [new file with mode: 0644]
modules/db_berkeley/km_bdb_lib.c [new file with mode: 0644]
modules/db_berkeley/km_bdb_lib.h [new file with mode: 0644]
modules/db_berkeley/km_bdb_mi.c [new file with mode: 0644]
modules/db_berkeley/km_bdb_mi.h [new file with mode: 0644]
modules/db_berkeley/km_bdb_res.c [new file with mode: 0644]
modules/db_berkeley/km_bdb_res.h [new file with mode: 0644]
modules/db_berkeley/km_bdb_util.c [new file with mode: 0644]
modules/db_berkeley/km_bdb_util.h [new file with mode: 0644]
modules/db_berkeley/km_bdb_val.c [new file with mode: 0644]
modules/db_berkeley/km_bdb_val.h [new file with mode: 0644]
modules/db_berkeley/km_db_berkeley.c [new file with mode: 0644]
modules/db_berkeley/km_db_berkeley.h [new file with mode: 0644]
modules/db_berkeley/km_doc/db_berkeley.xml [new file with mode: 0644]
modules/db_berkeley/km_doc/db_berkeley_admin.xml [new file with mode: 0644]
modules/db_flatstore/Makefile [new file with mode: 0644]
modules/db_flatstore/README [new file with mode: 0644]
modules/db_flatstore/doc/Makefile [new file with mode: 0644]
modules/db_flatstore/doc/flatstore.xml [new file with mode: 0644]
modules/db_flatstore/doc/functions.xml [new file with mode: 0644]
modules/db_flatstore/doc/params.xml [new file with mode: 0644]
modules/db_flatstore/flat_cmd.c [new file with mode: 0644]
modules/db_flatstore/flat_cmd.h [new file with mode: 0644]
modules/db_flatstore/flat_con.c [new file with mode: 0644]
modules/db_flatstore/flat_con.h [new file with mode: 0644]
modules/db_flatstore/flat_rpc.c [new file with mode: 0644]
modules/db_flatstore/flat_rpc.h [new file with mode: 0644]
modules/db_flatstore/flat_uri.c [new file with mode: 0644]
modules/db_flatstore/flat_uri.h [new file with mode: 0644]
modules/db_flatstore/flatstore_mod.c [new file with mode: 0644]
modules/db_flatstore/flatstore_mod.h [new file with mode: 0644]
modules/db_flatstore/km_doc/db_flatstore.xml [new file with mode: 0644]
modules/db_flatstore/km_doc/db_flatstore_admin.xml [new file with mode: 0644]
modules/db_flatstore/km_doc/db_flatstore_devel.xml [new file with mode: 0644]
modules/db_flatstore/km_flat_con.c [new file with mode: 0644]
modules/db_flatstore/km_flat_con.h [new file with mode: 0644]
modules/db_flatstore/km_flat_id.c [new file with mode: 0644]
modules/db_flatstore/km_flat_id.h [new file with mode: 0644]
modules/db_flatstore/km_flat_mi.c [new file with mode: 0644]
modules/db_flatstore/km_flat_mi.h [new file with mode: 0644]
modules/db_flatstore/km_flat_pool.c [new file with mode: 0644]
modules/db_flatstore/km_flat_pool.h [new file with mode: 0644]
modules/db_flatstore/km_flatstore.c [new file with mode: 0644]
modules/db_flatstore/km_flatstore.h [new file with mode: 0644]
modules/db_flatstore/km_flatstore_mod.c [new file with mode: 0644]
modules/db_flatstore/km_flatstore_mod.h [new file with mode: 0644]
modules/db_flatstore/ser-flatstore.cfg [new file with mode: 0644]
modules/db_flatstore/todo.txt [new file with mode: 0644]
modules/db_mysql/Makefile [new file with mode: 0644]
modules/db_mysql/doc/mysql_parser.dia [new file with mode: 0644]
modules/db_mysql/km_README [new file with mode: 0644]
modules/db_mysql/km_db_mysql.c [new file with mode: 0644]
modules/db_mysql/km_db_mysql.h [new file with mode: 0644]
modules/db_mysql/km_dbase.c [new file with mode: 0644]
modules/db_mysql/km_dbase.h [new file with mode: 0644]
modules/db_mysql/km_doc/db_mysql.xml [new file with mode: 0644]
modules/db_mysql/km_doc/db_mysql_admin.xml [new file with mode: 0644]
modules/db_mysql/km_doc/db_mysql_parser.dia [new file with mode: 0644]
modules/db_mysql/km_my_con.c [new file with mode: 0644]
modules/db_mysql/km_my_con.h [new file with mode: 0644]
modules/db_mysql/km_res.c [new file with mode: 0644]
modules/db_mysql/km_res.h [new file with mode: 0644]
modules/db_mysql/km_row.c [new file with mode: 0644]
modules/db_mysql/km_row.h [new file with mode: 0644]
modules/db_mysql/km_val.c [new file with mode: 0644]
modules/db_mysql/km_val.h [new file with mode: 0644]
modules/db_mysql/my_cmd.c [new file with mode: 0644]
modules/db_mysql/my_cmd.h [new file with mode: 0644]
modules/db_mysql/my_con.c [new file with mode: 0644]
modules/db_mysql/my_con.h [new file with mode: 0644]
modules/db_mysql/my_fld.c [new file with mode: 0644]
modules/db_mysql/my_fld.h [new file with mode: 0644]
modules/db_mysql/my_res.c [new file with mode: 0644]
modules/db_mysql/my_res.h [new file with mode: 0644]
modules/db_mysql/my_uri.c [new file with mode: 0644]
modules/db_mysql/my_uri.h [new file with mode: 0644]
modules/db_mysql/mysql_mod.c [new file with mode: 0644]
modules/db_mysql/mysql_mod.h [new file with mode: 0644]
modules/db_postgres/Makefile [new file with mode: 0644]
modules/db_postgres/README [new file with mode: 0644]
modules/db_postgres/km_db_postgres.c [new file with mode: 0644]
modules/db_postgres/km_db_postgres.h [new file with mode: 0644]
modules/db_postgres/km_dbase.c [new file with mode: 0644]
modules/db_postgres/km_dbase.h [new file with mode: 0644]
modules/db_postgres/km_doc/db_postgres.xml [new file with mode: 0644]
modules/db_postgres/km_doc/db_postgres_admin.xml [new file with mode: 0644]
modules/db_postgres/km_pg_con.c [new file with mode: 0644]
modules/db_postgres/km_pg_con.h [new file with mode: 0644]
modules/db_postgres/km_pg_type.h [new file with mode: 0644]
modules/db_postgres/km_res.c [new file with mode: 0644]
modules/db_postgres/km_res.h [new file with mode: 0644]
modules/db_postgres/km_val.c [new file with mode: 0644]
modules/db_postgres/km_val.h [new file with mode: 0644]
modules/db_postgres/pg_cmd.c [new file with mode: 0644]
modules/db_postgres/pg_cmd.h [new file with mode: 0644]
modules/db_postgres/pg_con.c [new file with mode: 0644]
modules/db_postgres/pg_con.h [new file with mode: 0644]
modules/db_postgres/pg_fld.c [new file with mode: 0644]
modules/db_postgres/pg_fld.h [new file with mode: 0644]
modules/db_postgres/pg_mod.c [new file with mode: 0644]
modules/db_postgres/pg_mod.h [new file with mode: 0644]
modules/db_postgres/pg_oid.c [new file with mode: 0644]
modules/db_postgres/pg_oid.h [new file with mode: 0644]
modules/db_postgres/pg_res.c [new file with mode: 0644]
modules/db_postgres/pg_res.h [new file with mode: 0644]
modules/db_postgres/pg_sql.c [new file with mode: 0644]
modules/db_postgres/pg_sql.h [new file with mode: 0644]
modules/db_postgres/pg_uri.c [new file with mode: 0644]
modules/db_postgres/pg_uri.h [new file with mode: 0644]
modules/tls/Makefile [new file with mode: 0644]
modules/tls/README [new file with mode: 0644]
modules/tls/README.TLS [new file with mode: 0644]
modules/tls/doc/Makefile [new file with mode: 0644]
modules/tls/doc/certs_howto.xml [new file with mode: 0644]
modules/tls/doc/functions.xml [new file with mode: 0644]
modules/tls/doc/history.xml [new file with mode: 0644]
modules/tls/doc/params.xml [new file with mode: 0644]
modules/tls/doc/tls.xml [new file with mode: 0644]
modules/tls/fixed_c_zlib.h [new file with mode: 0644]
modules/tls/ser-tls.cfg [new file with mode: 0644]
modules/tls/ser_cert.sh [new file with mode: 0755]
modules/tls/tls.cfg [new file with mode: 0644]
modules/tls/tls_config.c [new file with mode: 0644]
modules/tls/tls_config.h [new file with mode: 0644]
modules/tls/tls_domain.c [new file with mode: 0644]
modules/tls/tls_domain.h [new file with mode: 0644]
modules/tls/tls_init.c [new file with mode: 0644]
modules/tls/tls_init.h [new file with mode: 0644]
modules/tls/tls_locking.c [new file with mode: 0644]
modules/tls/tls_locking.h [new file with mode: 0644]
modules/tls/tls_mod.c [new file with mode: 0644]
modules/tls/tls_mod.h [new file with mode: 0644]
modules/tls/tls_rpc.c [new file with mode: 0644]
modules/tls/tls_rpc.h [new file with mode: 0644]
modules/tls/tls_select.c [new file with mode: 0644]
modules/tls/tls_select.h [new file with mode: 0644]
modules/tls/tls_server.c [new file with mode: 0644]
modules/tls/tls_server.h [new file with mode: 0644]
modules/tls/tls_util.c [new file with mode: 0644]
modules/tls/tls_util.h [new file with mode: 0644]
modules/tls/tls_verify.c [new file with mode: 0644]
modules/tls/tls_verify.h [new file with mode: 0644]
modules/tls/todo.txt [new file with mode: 0644]
modules/tm/Makefile
modules/tm/config.c
modules/tm/config.h
modules/tm/dlg.c
modules/tm/dlg.h
modules/tm/doc/params.xml
modules/tm/h_table.c
modules/tm/h_table.h
modules/tm/sip_msg.c
modules/tm/t_funcs.c
modules/tm/t_fwd.c
modules/tm/t_hooks.c
modules/tm/t_hooks.h
modules/tm/t_lookup.c
modules/tm/t_msgbuilder.c
modules/tm/t_reply.c
modules/tm/t_reply.h
modules/tm/t_suspend.c
modules/tm/tm.c
modules/tm/tm_load.c
modules/tm/tm_load.h
modules/tm/uac.c
msg_translator.c
onsend.h
parser/case_path.h [new file with mode: 0644]
parser/case_priv.h [new file with mode: 0644]
parser/hf.c
parser/hf.h
parser/keys.h
parser/msg_parser.c
parser/msg_parser.h
parser/parse_allow.c
parser/parse_allow.h
parser/parse_content.c
parser/parse_content.h
parser/parse_cseq.c
parser/parse_cseq.h
parser/parse_diversion.c
parser/parse_diversion.h
parser/parse_event.c
parser/parse_event.h
parser/parse_fline.c
parser/parse_fline.h
parser/parse_from.h
parser/parse_hname2.c
parser/parse_methods.c
parser/parse_methods.h
parser/parse_param.c
parser/parse_param.h
parser/parse_to.c
parser/parse_to.h
parser/sdp/sdp.c [new file with mode: 0644]
parser/sdp/sdp.h [new file with mode: 0644]
parser/sdp/sdp_cloner.h [new file with mode: 0644]
parser/sdp/sdp_helpr_funcs.c [new file with mode: 0644]
parser/sdp/sdp_helpr_funcs.h [new file with mode: 0644]
proxy.c
proxy.h
pvapi.c [new file with mode: 0644]
pvar.h [new file with mode: 0644]
re.c
re.h
receive.c
resolve.c
resolve.h
route.c
route.h
route_struct.c
route_struct.h
rvalue.c [new file with mode: 0644]
rvalue.h [new file with mode: 0644]
scripts/kam_to_sr.sh [new file with mode: 0755]
scripts/ser_to_sr.sh [new file with mode: 0755]
select.c
select_core.c
socket_info.c
socket_info.h
sr_compat.c [new file with mode: 0644]
sr_compat.h [new file with mode: 0644]
sr_module.c
sr_module.h
statistics.h [new file with mode: 0644]
str.h
switch.c [new file with mode: 0644]
switch.h [new file with mode: 0644]
tags.h
timer_proc.c [new file with mode: 0644]
timer_proc.h [new file with mode: 0644]
usr_avp.c
usr_avp.h
ut.c
ut.h

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c3a6ef0
--- /dev/null
@@ -0,0 +1,32 @@
+# ignore autogenerated files
+cfg.tab.c
+cfg.tab.h
+lex.yy.c
+librpath.lst
+makecfg.lst
+config.mak
+modules.lst
+# ignore dependency files
+*.d
+# ignore binary files and objects
+ser
+*.so
+*.so.*
+*.o
+# archives
+*.tar.gz
+*.deb
+*.rpm
+# tags
+tags
+TAGS
+# vi swaps
+.*.swp
+# various other binaries
+test/udp_flood
+utils/gen_ha1/gen_ha1
+utils/sercmd/sercmd
+# Emacs backup files
+*~
+# Emacs file locks
+.#*
index af51b08..8767ec0 100644 (file)
 # (if not rebuild everything)
 ifeq (,$(filter $(nodep_targets),$(MAKECMDGOALS)))
 -include makecfg.lst
-ifneq ($(strip $(C_DEFS) $(DEFS)), $(strip $(CFG_DEFS)))
-#$(warning different defs: <$(strip $(C_DEFS) $(DEFS))> != )
+# if trying  to build a lib automatically and the lib is already compiled,
+# don't rebuild it if the only differences in DEFS or INCLUDES are covered
+# by LIB_NOREBUILD_DEFS/LIB_NOREBUILD_INCLUDES
+LIB_NOREBUILD_DEFS=
+
+# don't rebuild if the differences are covered by NOREBUILD_DEFS or 
+# NOREBUILD_INCLUDES
+ifneq ($(strip $(filter-out $(NOREBUILD_DEFS),\
+               $(C_DEFS) $(DEFS))),$(strip $(CFG_DEFS)))
+#$(warning different defs: <$(strip $(DEFS))> != )
 #$(warning               : <$(strip $(CFG_DEFS))>)
 $(shell rm -f makecfg.lst)
 endif
-ifneq ($(strip $(C_INCLUDES) $(INCLUDES)), $(strip $(CFG_INCLUDES)))
+ifneq ($(strip $(filter-out $(NOREBUILD_INCLUDES),\
+                       $(C_INCLUDES) $(INCLUDES))),$(strip $(CFG_INCLUDES)))
 $(shell rm -f makecfg.lst)
 endif
 endif
@@ -99,7 +108,9 @@ ALL_LIBS+=$(foreach l, $(SER_LIBS), -L$(dir $l) -l$(notdir $l))
 $(NAME): librpath.lst $(SER_LIBS_DEPS)
 
 $(SER_LIBS_DEPS): FORCE
-       $(MAKE) -wC $(dir $@)  compile_for_install=$(lib_compile_for_install)
+       @$(MAKE) -wC $(dir $@)  compile_for_install=$(lib_compile_for_install) \
+               NOREBUILD_DEFS="$(NOREBUILD_DEFS) $(LIB_NOREBUILD_DEFS)" \
+               NOREBUILD_INCLUDES="$(NOREBUILD_INCLUDES) $(LIB_NOREBUILD_INCLUDES)"
 
 .PHONY: FORCE
 FORCE:
@@ -138,10 +149,11 @@ librpath.lst: $(ALLDEP)
        @echo LIB_RPATH_LST:=$(SER_RPATH_LST) >librpath.lst
 
 makecfg.lst:
-       @echo CFG_DEFS:=\
-               $(subst ',\', $(subst ",\", $(strip $(C_DEFS) $(DEFS)))) >>$@
-       @echo CFG_INCLUDES:=\
-               $(subst ',\', $(subst ",\", $(strip $(C_INCLUDES) $(INCLUDES)))) >>$@
+       @echo CFG_DEFS:=$(subst ',\', $(subst ",\",$(strip \
+                       $(filter-out $(NOREBUILD_DEFS), $(C_DEFS) $(DEFS))))) >>$@
+       @echo CFG_INCLUDES:=$(subst ',\', $(subst ",\",$(strip \
+                       $(filter-out $(NOREBUILD_INCLUDES),\
+                               $(C_INCLUDES) $(INCLUDES))))) >>$@
 .PHONY: all
 all: $(NAME) modules
 
index d98c4a2..7178f58 100644 (file)
@@ -14,6 +14,7 @@
 sources=$(filter-out $(auto_gen), $(wildcard *.c) $(wildcard mem/*.c) \
                $(wildcard parser/*.c) $(wildcard parser/digest/*.c) \
                $(wildcard parser/contact/*.c) $(wildcard db/*.c) \
+               $(wildcard parser/sdp/*.c) \
                $(wildcard rand/*.c) $(wildcard rand/isaac/*.c) ) \
                $(wildcard cfg/*.c) $(auto_gen)
 ifeq ($(CORE_TLS), 1)
diff --git a/NEWS b/NEWS
index abe35ea..d3d6418 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,28 @@
-Release notes for SIP Express Router (ser)
+Release notes for SIP Router (sr)
 ***********************************************
 
 $Id$
 
+sip-router changes
+
+core:
+  - support for dual module interfaces: ser and kamailio
+config script changes:
+  - script mode can be switched between ser compatible, kamailio compatible
+    and max compatibility (compatible with both as much as possible), using
+      #!SER
+      #!KAMAILIO
+      #!OPENSER
+      #!ALL
+      #!MAXCOMPAT
+    where #!KAMAILIO is equivalent with #!OPENSER and #!ALL with #!MAXCOMPAT
+  - support for kamailio style pvars
+  - C-like switch()/case (integer only)
+  - while()
+  - max_while_loops - maximum iterations allowed for a while, can be changed
+    at runtime. Default 100.
+
+
 
 
 2.1.0 changes
index b35a543..b4758a5 100644 (file)
--- a/action.c
+++ b/action.c
@@ -46,6 +46,8 @@
  *              (andrei)
  *  2007-06-14  run_actions & do_action need a ctx or handle now, no more
  *               static vars (andrei)
+ *  2008-11-18  support for variable parameter module functions (andrei)
+ *  2008-12-03  use lvalues/rvalues for assignments (andrei)
  *  2008-12-17  added UDP_MTU_TRY_PROTO_T (andrei)
  */
 
@@ -63,7 +65,9 @@
 #include "parser/msg_parser.h"
 #include "parser/parse_uri.h"
 #include "ut.h"
+#include "lvalue.h"
 #include "sr_module.h"
+#include "select_buf.h"
 #include "mem/mem.h"
 #include "globals.h"
 #include "dset.h"
@@ -75,6 +79,7 @@
 #ifdef USE_SCTP
 #include "sctp_server.h"
 #endif
+#include "switch.h"
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -102,14 +107,22 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
        struct dest_info dst;
        char* tmp;
        char *new_uri, *end, *crt;
+       void* f;
        int len;
        int user;
        struct sip_uri uri, next_hop;
        struct sip_uri *u;
        unsigned short port;
-       unsigned short flags;
-       int_str name, value;
        str* dst_host;
+       int i, flags;
+       struct switch_cond_table* sct;
+       struct switch_jmp_table*  sjt;
+       struct rval_expr* rve;
+       struct match_cond_table* mct;
+       struct rvalue* rv;
+       struct rvalue* rv1;
+       struct rval_cache c1;
+       str s;
        int orig_p2t;
 
        /* reset the value of error to E_UNSPEC so avoid unknowledgable
@@ -304,7 +317,8 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                ret=E_BUG;
                                break;
                        }
-                       LOG_(a->val[0].u.number, "<script>: ", "%s", a->val[1].u.string);
+                       LOG_(DEFAULT_FACILITY, a->val[0].u.number, "<script>: ", "%s", 
+                                a->val[1].u.string);
                        ret=1;
                        break;
 
@@ -448,7 +462,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                        /*ret=((ret=run_actions(rlist[a->val[0].u.number], msg))<0)?ret:1;*/
                        ret=run_actions(h, main_rt.rlist[a->val[0].u.number], msg);
                        h->last_retcode=ret;
-                       h->run_flags&=~RETURN_R_F; /* absorb returns */
+                       h->run_flags&=~(RETURN_R_F|BREAK_R_F); /* absorb return & break */
                        break;
                case EXEC_T:
                        if (a->val[0].type!=STRING_ST){
@@ -477,6 +491,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                case SET_HOST_T:
                case SET_HOSTPORT_T:
                case SET_HOSTPORTTRANS_T:
+               case SET_HOSTALL_T:
                case SET_USER_T:
                case SET_USERPASS_T:
                case SET_PORT_T:
@@ -688,6 +703,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                /* host */
                                if ((a->type==SET_HOST_T)
                                                || (a->type==SET_HOSTPORT_T)
+                                               || (a->type==SET_HOSTALL_T)
                                                || (a->type==SET_HOSTPORTTRANS_T)
                                ) {
                                        tmp=a->val[0].u.string;
@@ -710,6 +726,8 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                        if(crt+len>end) goto error_uri;
                                        memcpy(crt,tmp,len);crt+=len;
                                }
+                               if(a->type==SET_HOSTALL_T)
+                                       goto done_seturi;
                                /* port */
                                if ((a->type==SET_HOSTPORT_T)
                                                || (a->type==SET_HOSTPORTTRANS_T))
@@ -777,6 +795,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                        *crt='?'; crt++;
                                        memcpy(crt,tmp,len);crt+=len;
                                }
+       done_seturi:
                                *crt=0; /* null terminate the thing */
                                /* copy it to the msg */
                                if (msg->new_uri.s) pkg_free(msg->new_uri.s);
@@ -804,7 +823,8 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                                ret=0;
                                                break;
                                        }
-                                       h->run_flags &= ~RETURN_R_F; /* catch returns in expr */
+                                       h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
+                                                                                                                           break in expr*/
                                        ret=1;  /*default is continue */
                                        if (v>0) {
                                                if ((a->val[1].type==ACTIONS_ST)&&a->val[1].u.data){
@@ -818,17 +838,274 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                }
                        break;
                case MODULE_T:
-                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && ((cmd_export_t*)a->val[0].u.data)->function ){
-                               ret=((cmd_export_t*)a->val[0].u.data)->function(msg,
-                                       (char*)a->val[2].u.data,
-                                       (char*)a->val[3].u.data
-                               );
+                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
+                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
+                               ret=((cmd_function)f)(msg,
+                                                                               (char*)a->val[2].u.data,
+                                                                               (char*)a->val[3].u.data
+                                                                       );
                                if (ret==0) h->run_flags|=EXIT_R_F;
                                h->last_retcode=ret;
                        } else {
                                LOG(L_CRIT,"BUG: do_action: bad module call\n");
                        }
                        break;
+               /* instead of using the parameter number, we use different names
+                * for calls to functions with 3, 4, 5, 6 or variable number of
+                * parameters due to performance reasons */
+               case MODULE3_T:
+                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
+                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
+                               ret=((cmd_function3)f)(msg,
+                                                                               (char*)a->val[2].u.data,
+                                                                               (char*)a->val[3].u.data,
+                                                                               (char*)a->val[4].u.data
+                                                                       );
+                               if (ret==0) h->run_flags|=EXIT_R_F;
+                               h->last_retcode=ret;
+                       } else {
+                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
+                       }
+                       break;
+               case MODULE4_T:
+                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
+                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
+                               ret=((cmd_function4)f)(msg,
+                                                                               (char*)a->val[2].u.data,
+                                                                               (char*)a->val[3].u.data,
+                                                                               (char*)a->val[4].u.data,
+                                                                               (char*)a->val[5].u.data
+                                                                       );
+                               if (ret==0) h->run_flags|=EXIT_R_F;
+                               h->last_retcode=ret;
+                       } else {
+                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
+                       }
+                       break;
+               case MODULE5_T:
+                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
+                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
+                               ret=((cmd_function5)f)(msg,
+                                                                               (char*)a->val[2].u.data,
+                                                                               (char*)a->val[3].u.data,
+                                                                               (char*)a->val[4].u.data,
+                                                                               (char*)a->val[5].u.data,
+                                                                               (char*)a->val[6].u.data
+                                                                       );
+                               if (ret==0) h->run_flags|=EXIT_R_F;
+                               h->last_retcode=ret;
+                       } else {
+                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
+                       }
+                       break;
+               case MODULE6_T:
+                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
+                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
+                               ret=((cmd_function6)f)(msg,
+                                                                               (char*)a->val[2].u.data,
+                                                                               (char*)a->val[3].u.data,
+                                                                               (char*)a->val[4].u.data,
+                                                                               (char*)a->val[5].u.data,
+                                                                               (char*)a->val[6].u.data,
+                                                                               (char*)a->val[7].u.data
+                                                                       );
+                               if (ret==0) h->run_flags|=EXIT_R_F;
+                               h->last_retcode=ret;
+                       } else {
+                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
+                       }
+                       break;
+               case MODULEX_T:
+                       if ( a->val[0].type==MODEXP_ST && a->val[0].u.data && 
+                                       (f=((union cmd_export_u*)a->val[0].u.data)->c.function)){
+                               ret=((cmd_function_var)f)(msg,
+                                                                                       a->val[1].u.number,
+                                                                                       &a->val[2]
+                                                                               );
+                               if (ret==0) h->run_flags|=EXIT_R_F;
+                               h->last_retcode=ret;
+                       } else {
+                               LOG(L_CRIT,"BUG: do_action: bad module call\n");
+                       }
+                       break;
+               case EVAL_T:
+                       /* only eval the expression to account for possible
+                          side-effect */
+                       rval_expr_eval_int(h, msg, &v,
+                                       (struct rval_expr*)a->val[0].u.data);
+                       if (h->run_flags & EXIT_R_F){
+                               ret=0;
+                               break;
+                       }
+                       h->run_flags &= ~RETURN_R_F|BREAK_R_F; /* catch return & break in
+                                                                                                         expr */
+                       ret=1; /* default is continue */
+                       break;
+               case SWITCH_COND_T:
+                       sct=(struct switch_cond_table*)a->val[1].u.data;
+                       if (unlikely( rval_expr_eval_int(h, msg, &v,
+                                                                       (struct rval_expr*)a->val[0].u.data) <0)){
+                               /* handle error in expression => use default */
+                               ret=-1;
+                               goto sw_cond_def;
+                       }
+                       if (h->run_flags & EXIT_R_F){
+                               ret=0;
+                               break;
+                       }
+                       h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
+                                                                                                           in expr */
+                       ret=1; /* default is continue */
+                       for(i=0; i<sct->n; i++)
+                               if (sct->cond[i]==v){
+                                       if (likely(sct->jump[i])){
+                                               ret=run_actions(h, sct->jump[i], msg);
+                                               h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                                          returns passthrough */
+                                       }
+                                       goto skip;
+                               }
+sw_cond_def:
+                       if (sct->def){
+                               ret=run_actions(h, sct->def, msg);
+                               h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                          returns passthrough */
+                       }
+                       break;
+               case SWITCH_JT_T:
+                       sjt=(struct switch_jmp_table*)a->val[1].u.data;
+                       if (unlikely( rval_expr_eval_int(h, msg, &v,
+                                                                       (struct rval_expr*)a->val[0].u.data) <0)){
+                               /* handle error in expression => use default */
+                               ret=-1;
+                               goto sw_jt_def;
+                       }
+                       if (h->run_flags & EXIT_R_F){
+                               ret=0;
+                               break;
+                       }
+                       h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
+                                                                                                           in expr */
+                       ret=1; /* default is continue */
+                       if (likely(v >= sjt->first && v <= sjt->last)){
+                               if (likely(sjt->tbl[v - sjt->first])){
+                                       ret=run_actions(h, sjt->tbl[v - sjt->first], msg);
+                                       h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                                  returns passthrough */
+                               }
+                               break; 
+                       }else{
+                               for(i=0; i<sjt->rest.n; i++)
+                                       if (sjt->rest.cond[i]==v){
+                                               if (likely(sjt->rest.jump[i])){
+                                                       ret=run_actions(h, sjt->rest.jump[i], msg);
+                                                       h->run_flags &= ~BREAK_R_F; /* catch breaks, but 
+                                                                                                                  let returns pass */
+                                               }
+                                               goto skip;
+                                       }
+                       }
+                       /* not found => try default */
+sw_jt_def:
+                       if (sjt->rest.def){
+                               ret=run_actions(h, sjt->rest.def, msg);
+                               h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                          returns passthrough */
+                       }
+                       break;
+               case BLOCK_T:
+                       if (likely(a->val[0].u.data)){
+                               ret=run_actions(h, (struct action*)a->val[0].u.data, msg);
+                               h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                          returns passthrough */
+                       }
+                       break;
+               case MATCH_COND_T:
+                       mct=(struct match_cond_table*)a->val[1].u.data;
+                       rval_cache_init(&c1);
+                       rv=0;
+                       rv1=0;
+                       ret=rval_expr_eval_rvint(h, msg, &rv, &v, 
+                                                                       (struct rval_expr*)a->val[0].u.data, &c1);
+                                                                       
+                       if (unlikely( ret<0)){
+                               /* handle error in expression => use default */
+                               ret=-1;
+                               goto match_cond_def;
+                       }
+                       if (h->run_flags & EXIT_R_F){
+                               ret=0;
+                               break;
+                       }
+                       h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
+                                                                                                           in expr */
+                       if (likely(rv)){
+                               rv1=rval_convert(h, msg, RV_STR, rv, &c1);
+                               if (unlikely(rv1==0)){
+                                       ret=-1;
+                                       goto match_cond_def;
+                               }
+                               s=rv1->v.s;
+                       }else{
+                               /* int result in v */
+                               rval_cache_clean(&c1);
+                               s.s=sint2str(v, &s.len);
+                       }
+                       ret=1; /* default is continue */
+                       for(i=0; i<mct->n; i++)
+                               if (( mct->match[i].type==MATCH_STR &&
+                                               mct->match[i].l.s.len==s.len &&
+                                               memcmp(mct->match[i].l.s.s, s.s, s.len) == 0 ) ||
+                                        ( mct->match[i].type==MATCH_RE &&
+                                         regexec(mct->match[i].l.regex, s.s, 0, 0, 0) == 0)
+                                       ){
+                                       if (likely(mct->jump[i])){
+                                               ret=run_actions(h, mct->jump[i], msg);
+                                               h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                                          returns passthrough */
+                                       }
+                                       goto match_cleanup;
+                               }
+match_cond_def:
+                       if (mct->def){
+                               ret=run_actions(h, mct->def, msg);
+                               h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                          returns passthrough */
+                       }
+match_cleanup:
+                       if (rv1){
+                               rval_destroy(rv1);
+                               rval_destroy(rv);
+                               rval_cache_clean(&c1);
+                       }else if (rv){
+                               rval_destroy(rv);
+                               rval_cache_clean(&c1);
+                       }
+                       break;
+               case WHILE_T:
+                       i=0;
+                       flags=0;
+                       rve=(struct rval_expr*)a->val[0].u.data;
+                       ret=1;
+                       while(!(flags & BREAK_R_F) && 
+                                       (rval_expr_eval_int(h, msg, &v, rve) == 0) && v){
+                               i++;
+                               if (unlikely(i > cfg_get(core, core_cfg, max_while_loops))){
+                                       LOG(L_ERR, "ERROR: runaway while (%d, %d): more then"
+                                                               " %d loops\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               cfg_get(core, core_cfg, max_while_loops));
+                                       ret=-1;
+                                       break;
+                               }
+                               if (likely(a->val[1].u.data)){
+                                       ret=run_actions(h, (struct action*)a->val[1].u.data, msg);
+                                       flags|=h->run_flags;
+                                       h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
+                                                                                                  returns passthrough */
+                               }
+                       }
+                       break;
                case FORCE_RPORT_T:
                        msg->msg_flags|=FL_FORCE_RPORT;
                        ret=1; /* continue processing */
@@ -897,125 +1174,20 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 
                case ADD_T:
                case ASSIGN_T:
-
-                       /* If the left attr was specified without indexing brackets delete
-                        * existing AVPs before adding new ones
-                        */
-                       if ((a->val[0].u.attr->type & AVP_INDEX_ALL) != AVP_INDEX_ALL) delete_avp(a->val[0].u.attr->type, a->val[0].u.attr->name);
-
-                       if (a->val[1].type == STRING_ST) {
-                               value.s = a->val[1].u.str;
-                               flags = a->val[0].u.attr->type | AVP_VAL_STR;
-                               name = a->val[0].u.attr->name;
-                               ret = 1;
-                       } else if (a->val[1].type == NUMBER_ST) {
-                               value.n = a->val[1].u.number;
-                               flags = a->val[0].u.attr->type;
-                               name = a->val[0].u.attr->name;
+                       v=lval_assign(h, msg, (struct lvalue*)a->val[0].u.data,
+                                                                 (struct rval_expr*)a->val[1].u.data);
+                       if (likely(v>=0))
                                ret = 1;
-                       } else if (a->val[1].type == ACTION_ST) {
-                               flags = a->val[0].u.attr->type;
-                               name = a->val[0].u.attr->name;
-                               if (a->val[1].u.data) {
-                                       value.n = run_actions(h, (struct action*)a->val[1].u.data,
-                                                                                       msg);
-                               } else {
-                                       value.n = -1;
-                               }
-                               ret = value.n;
-                       } else if(a->val[1].type == EXPR_ST && a->val[1].u.data) {
-                               v = eval_expr(h, (struct expr*)a->val[1].u.data, msg);
-                               if (v < 0) {
-                                       if (v == EXPR_DROP){ /* hack to quit on DROP*/
-                                               ret = 0;
-                                               break;
-                                       } else {
-                                               LOG(L_WARN,"WARNING: do_action: error in expression\n");
-                                               v = 0; /* error is treated as false (Miklos) */
-                                       }
-                               }
-
-                               flags = a->val[0].u.attr->type;
-                               name = a->val[0].u.attr->name;
-                               value.n = v;
-                       } else if (a->val[1].type == AVP_ST) {
-                               struct search_state st;
-                               avp_t* avp;
-                               avp_t* avp_mark;
-
-                               avp_mark = NULL;
-                               if ((a->val[1].u.attr->type & AVP_INDEX_ALL) == AVP_INDEX_ALL) {
-                                       avp = search_first_avp(a->val[1].u.attr->type, a->val[1].u.attr->name, &value, &st);
-                                       while(avp) {
-                                                    /* We take only the type of value and name from the source avp
-                                                     * and reset class and track flags
-                                                     */
-                                               flags = (a->val[0].u.attr->type & ~AVP_INDEX_ALL) | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
-
-                                               if (add_avp_before(avp_mark, flags, a->val[0].u.attr->name, value) < 0) {
-                                                       LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
-                                                       ret=E_UNSPEC;
-                                                       break;
-                                               }
-
-                                               /* move the mark, so the next found AVP will come before the one currently added
-                                                * so they will have the same order as in the source list
-                                                */
-                                               if (avp_mark) {
-                                                       avp_mark=avp_mark->next;
-                                               } else {
-                                                       avp_mark=search_first_avp(flags, a->val[0].u.attr->name, NULL, NULL);
-                                               }
-
-                                               avp = search_next_avp(&st, &value);
-                                       }
-                                       ret = 1;
-                                       break;
-                               } else {
-                                       avp = search_avp_by_index(a->val[1].u.attr->type, a->val[1].u.attr->name, &value, a->val[1].u.attr->index);
-                                       if (avp) {
-                                               flags = a->val[0].u.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
-                                               name = a->val[0].u.attr->name;
-                                               ret = 1;
-                                       } else {
-                                               ret = E_UNSPEC;
-                                               break;
-                                       }
-                               }
-                       } else if (a->val[1].type == SELECT_ST) {
-                               int r;
-                               r = run_select(&value.s, a->val[1].u.select, msg);
-                               if (r < 0) {
-                                       ret=E_UNSPEC;
-                                       break;
-                               } else if (r > 0) {
-                                       value.s.s = "";
-                                       value.s.len = 0;
-                               }
-
-                               flags = a->val[0].u.attr->type | AVP_VAL_STR;
-                               name = a->val[0].u.attr->name;
-                               ret = 1;
-                       } else {
-                               LOG(L_CRIT, "BUG: do_action: Bad right side of avp assignment\n");
-                               ret=E_BUG;
-                               break;
-                       }
-
-                       /* If the action is assign then remove the old avp value
-                        * before adding new ones */
-/*                     if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name); */
-                       if (add_avp(flags & ~AVP_INDEX_ALL, name, value) < 0) {
-                               LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
-                               ret=E_UNSPEC;
-                               break;
-                       }
+                       else if (unlikely (v == EXPR_DROP)) /* hack to quit on DROP*/
+                               ret=0;
+                       else
+                               ret=v;
                        break;
 
                default:
                        LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
        }
-/*skip:*/
+skip:
        return ret;
 
 error_uri:
@@ -1065,7 +1237,9 @@ int run_actions(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
 
        for (t=a; t!=0; t=t->next){
                ret=do_action(h, t, msg);
-               if (h->run_flags & (RETURN_R_F|EXIT_R_F)){
+               /* break, return or drop/exit stop execution of the current
+                  block */
+               if (h->run_flags & (BREAK_R_F|RETURN_R_F|EXIT_R_F)){
                        if (h->run_flags & EXIT_R_F){
 #ifdef USE_LONGJMP
                                h->last_retcode=ret;
@@ -1082,9 +1256,11 @@ end:
        /* process module onbreak handlers if present */
        if (h->rec_lev==0 && ret==0)
                for (mod=modules;mod;mod=mod->next)
-                       if (mod->exports && mod->exports->onbreak_f) {
-                               mod->exports->onbreak_f( msg );
-                               DBG("DEBUG: %s onbreak handler called\n", mod->exports->name);
+                       if ((mod->mod_interface_ver==0) && mod->exports && 
+                                       mod->exports->v0.onbreak_f) {
+                               mod->exports->v0.onbreak_f( msg );
+                               DBG("DEBUG: %s onbreak handler called\n",
+                                               mod->exports->c.name);
                        }
        return ret;
 
@@ -1093,3 +1269,13 @@ error:
        h->rec_lev--;
        return ret;
 }
+
+
+int run_top_route(struct action* a, sip_msg_t* msg)
+{
+       struct run_act_ctx ctx;
+       setsflagsval(0);
+       reset_static_buffer();
+       init_run_actions_ctx(&ctx);
+       return run_actions(&ctx, a, msg);
+}
index 9739d34..05b68cf 100644 (file)
--- a/action.h
+++ b/action.h
@@ -59,8 +59,6 @@ struct run_act_ctx{
 int do_action(struct run_act_ctx* c, struct action* a, struct sip_msg* msg);
 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);
 
 #endif
diff --git a/cfg.lex b/cfg.lex
index 73c23ef..9f42697 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -75,6 +75,8 @@
  *  2007-11-28  added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
  *              LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
  *  2008-01-24  added CFG_DESCRIPTION used by cfg_var (Miklos)
+ *  2008-11-28  added support for kamailio pvars and avp/pvar guessing (andrei)
+ *  2008-12-11  added support for "string1" "string2" (andrei)
  *  2009-03-10  added SET_USERPHONE action (Miklos)
 */
 
        #include "usr_avp.h"
        #include "select.h"
        #include "cfg.tab.h"
+       #include "sr_compat.h"
 
        /* states */
        #define INITIAL_S               0
        #define COMMENT_S               1
        #define COMMENT_LN_S            2
        #define STRING_S                3
-       #define ATTR_S                  4
-        #define SELECT_S                5
+       #define ATTR_S                  4  /* avp/attr */
+       #define SELECT_S                5
+       #define AVP_PVAR_S              6  /* avp or pvar */
+       #define PVAR_P_S                7  /* pvar: $(...)  or $foo(...)*/
+       #define PVARID_S                8  /* $foo.bar...*/
+       #define STR_BETWEEN_S           9
 
        #define STR_BUF_ALLOC_UNIT      128
        struct str_buf{
 
 
        static int comment_nest=0;
+       static int p_nest=0;
        static int state=0, old_state=0, old_initial=0;
        static struct str_buf s_buf;
        int line=1;
        int column=1;
        int startcolumn=1;
+       int startline=1;
+       static int ign_lines=0;
+       static int ign_columns=0;
 
        static char* addchar(struct str_buf *, char);
        static char* addstr(struct str_buf *, char*, int);
        static void count();
+       static void count_more();
+       static void count_ignore();
 
 
 %}
 
 /* start conditions */
-%x STRING1 STRING2 COMMENT COMMENT_LN ATTR SELECT
+%x STRING1 STRING2 STR_BETWEEN COMMENT COMMENT_LN ATTR SELECT AVP_PVAR PVAR_P 
+%x PVARID
+
+/* config script types : #!SER  or #!KAMAILIO or #!MAX_COMPAT */
+SER_CFG                        SER
+KAMAILIO_CFG   KAMAILIO|OPENSER
+MAXCOMPAT_CFG  MAXCOMPAT|ALL
 
 /* action keywords */
 FORWARD        forward
@@ -172,6 +191,10 @@ ELSE                       "else"
 SET_ADV_ADDRESS        "set_advertised_address"
 SET_ADV_PORT   "set_advertised_port"
 FORCE_SEND_SOCKET      "force_send_socket"
+SWITCH                 "switch"
+CASE                   "case"
+DEFAULT                        "default"
+WHILE                  "while"
 
 /*ACTION LVALUES*/
 URIHOST                        "uri:host"
@@ -223,7 +246,8 @@ PLUS        "+"
 MINUS  "-"
 
 /* Attribute specification */
-ATTR_MARK   "$"|"%"
+ATTR_MARK   "%"
+VAR_MARK    "$"
 SELECT_MARK  "@"
 ATTR_FROM         "f"
 ATTR_TO           "t"
@@ -235,6 +259,9 @@ ATTR_FROMDOMAIN   "fd"
 ATTR_TODOMAIN     "td"
 ATTR_GLOBAL       "g"
 
+/* avp prefix */
+AVP_PREF       (([ft][rud]?)|g)\.
+
 /* config vars. */
 DEBUG  debug
 FORK   fork
@@ -356,6 +383,7 @@ MCAST_TTL           "mcast_ttl"
 TOS                    "tos"
 PMTU_DISCOVERY "pmtu_discovery"
 KILL_TIMEOUT   "exit_timeout"|"ser_kill_timeout"
+MAX_WLOOPS             "max_while_loops"
 
 /* stun config variables */
 STUN_REFRESH_INTERVAL "stun_refresh_interval"
@@ -391,7 +419,7 @@ ID                  {LETTER}{ALPHANUM}*
 HEX                    [0-9a-fA-F]
 HEXNUMBER      0x{HEX}+
 OCTNUMBER      0[0-7]+
-DECNUMBER       0|-?([1-9]{DIGIT}*)
+DECNUMBER       0|([1-9]{DIGIT}*)
 BINNUMBER       [0-1]+b
 HEX4           {HEX}{1,4}
 IPV6ADDR       ({HEX4}":"){7}{HEX4}|({HEX4}":"){1,7}(":"{HEX4}){1,7}|":"(":"{HEX4}){1,7}|({HEX4}":"){1,7}":"|"::"
@@ -484,6 +512,10 @@ EAT_ABLE   [\ \t\b\r]
                                                                                return SET_ADV_PORT; }
 <INITIAL>{FORCE_SEND_SOCKET}   {       count(); yylval.strval=yytext;
                                                                        return FORCE_SEND_SOCKET; }
+<INITIAL>{SWITCH}      { count(); yylval.strval=yytext; return SWITCH; }
+<INITIAL>{CASE}        { count(); yylval.strval=yytext; return CASE; }
+<INITIAL>{DEFAULT}     { count(); yylval.strval=yytext; return DEFAULT; }
+<INITIAL>{WHILE}       { count(); yylval.strval=yytext; return WHILE; }
 
 <INITIAL>{URIHOST}     { count(); yylval.strval=yytext; return URIHOST; }
 <INITIAL>{URIPORT}     { count(); yylval.strval=yytext; return URIPORT; }
@@ -705,6 +737,8 @@ EAT_ABLE    [\ \t\b\r]
                                                                        return PMTU_DISCOVERY; }
 <INITIAL>{KILL_TIMEOUT}                        {       count(); yylval.strval=yytext;
                                                                        return KILL_TIMEOUT; }
+<INITIAL>{MAX_WLOOPS}                  {       count(); yylval.strval=yytext;
+                                                                       return MAX_WLOOPS; }
 <INITIAL>{SERVER_ID}  { count(); yylval.strval=yytext; return SERVER_ID;}
 <INITIAL>{CFG_DESCRIPTION}     { count(); yylval.strval=yytext; return CFG_DESCRIPTION; }
 <INITIAL>{LOADMODULE}  { count(); yylval.strval=yytext; return LOADMODULE; }
@@ -747,7 +781,8 @@ EAT_ABLE    [\ \t\b\r]
 <SELECT>{BINNUMBER}     { count(); yylval.intval=(int)strtol(yytext, 0, 2); return NUMBER; }
 
 
-<INITIAL>{ATTR_MARK}    { count(); state = ATTR_S; BEGIN(ATTR); return ATTR_MARK; }
+<INITIAL>{ATTR_MARK}    { count(); state = ATTR_S; BEGIN(ATTR);
+                                                       return ATTR_MARK; }
 <ATTR>{ATTR_FROM}       { count(); return ATTR_FROM; }
 <ATTR>{ATTR_TO}         { count(); return ATTR_TO; }
 <ATTR>{ATTR_FROMURI}    { count(); return ATTR_FROMURI; }
@@ -760,15 +795,88 @@ EAT_ABLE  [\ \t\b\r]
 <ATTR>{DOT}             { count(); return DOT; }
 <ATTR>{LBRACK}          { count(); return LBRACK; }
 <ATTR>{RBRACK}          { count(); return RBRACK; }
-<ATTR>{STAR}           { count(); return STAR; }
-<ATTR>{DECNUMBER}      { count(); yylval.intval=atoi(yytext);return NUMBER; }
-<ATTR>{ID}             { count(); addstr(&s_buf, yytext, yyleng);
-                           yylval.strval=s_buf.s;
-                          memset(&s_buf, 0, sizeof(s_buf));
-                           state = INITIAL_S;
-                           BEGIN(INITIAL);
-                          return ID;
-                        }
+<ATTR>{STAR}                   { count(); return STAR; }
+<ATTR>{DECNUMBER}              { count(); yylval.intval=atoi(yytext);return NUMBER; }
+<ATTR>{ID}                             { count(); addstr(&s_buf, yytext, yyleng);
+                                                       yylval.strval=s_buf.s;
+                                                       memset(&s_buf, 0, sizeof(s_buf));
+                                                       state = INITIAL_S;
+                                                       BEGIN(INITIAL);
+                                                       return ID;
+                                               }
+
+<INITIAL>{VAR_MARK}{LPAREN}    {
+                                                               switch(sr_cfg_compat){
+                                                                       case SR_COMPAT_SER:
+                                                                               state=ATTR_S; BEGIN(ATTR);
+                                                                               yyless(1);
+                                                                               count();
+                                                                               return ATTR_MARK;
+                                                                               break;
+                                                                       case SR_COMPAT_KAMAILIO:
+                                                                       case SR_COMPAT_MAX:
+                                                                       default:
+                                                                               state = PVAR_P_S; BEGIN(PVAR_P);
+                                                                               p_nest=1; yymore();
+                                                                               break;
+                                                               }
+                                                       }
+       /* eat everything between 2 () and return PVAR token and a string
+          containing everything (including $ and ()) */
+<PVAR_P>{RPAREN}                       {       p_nest--;
+                                                               if (p_nest==0){
+                                                                       count();
+                                                                       addstr(&s_buf, yytext, yyleng);
+                                                                       yylval.strval=s_buf.s;
+                                                                       memset(&s_buf, 0, sizeof(s_buf));
+                                                                       state=INITIAL_S;
+                                                                       BEGIN(INITIAL);
+                                                                       return PVAR;
+                                                               }
+                                                               yymore();
+                                                       }
+<PVAR_P>{LPAREN}                       { p_nest++; yymore(); }
+<PVAR_P>.                                      { yymore(); }
+
+<PVARID>{ID}|'.'                       {yymore(); }
+<PVARID>{LPAREN}                       {       state = PVAR_P_S; BEGIN(PVAR_P);
+                                                               p_nest=1; yymore(); }
+<PVARID>.                                      { yyless(0); state=INITIAL_S; BEGIN(INITIAL);
+                                                               return PVAR;
+                                                       }
+
+
+<INITIAL>{VAR_MARK}                    {
+                                                               switch(sr_cfg_compat){
+                                                                       case SR_COMPAT_SER:
+                                                                               count();
+                                                                               state=ATTR_S; BEGIN(ATTR);
+                                                                               return ATTR_MARK;
+                                                                               break;
+                                                                       case SR_COMPAT_KAMAILIO:
+                                                                               state=PVARID_S; BEGIN(PVARID);
+                                                                               yymore();
+                                                                               break;
+                                                                       case SR_COMPAT_MAX:
+                                                                       default: 
+                                                                               state=AVP_PVAR_S; BEGIN(AVP_PVAR);
+                                                                               yymore();
+                                                                               break;
+                                                               }
+                                                       }
+       /* avp prefix detected -> go to avp mode */
+<AVP_PVAR>{AVP_PREF}           |
+<AVP_PVAR>{ID}{LBRACK}         { state = ATTR_S; BEGIN(ATTR); yyless(1); count();
+                                                         return ATTR_MARK; }
+<AVP_PVAR>{ID}{LPAREN}         { state = PVAR_P_S; p_nest=1; BEGIN(PVAR_P);
+                                                               yymore(); }
+<AVP_PVAR>{ID}                         {       count(); addstr(&s_buf, yytext, yyleng);
+                                                               yylval.strval=s_buf.s;
+                                                               memset(&s_buf, 0, sizeof(s_buf));
+                                                               state = INITIAL_S;
+                                                               BEGIN(INITIAL);
+                                                               return AVP_OR_PVAR;
+                                                       }
 
 <INITIAL>{IPV6ADDR}            { count(); yylval.strval=yytext; return IPV6ADDR; }
 <INITIAL>{DECNUMBER}           { count(); yylval.intval=atoi(yytext);return NUMBER; }
@@ -799,7 +907,7 @@ EAT_ABLE    [\ \t\b\r]
 <INITIAL>{COMMA}               { count(); return COMMA; }
 <INITIAL>{SEMICOLON}   { count(); return SEMICOLON; }
 <INITIAL>{COLON}       { count(); return COLON; }
-<INITIAL>{STAR}        { count(); return STAR; }
+<INITIAL>{STAR}                { count(); return STAR; }
 <INITIAL>{RPAREN}      { count(); return RPAREN; }
 <INITIAL>{LPAREN}      { count(); return LPAREN; }
 <INITIAL>{LBRACE}      { count(); return LBRACE; }
@@ -812,18 +920,19 @@ EAT_ABLE  [\ \t\b\r]
 <INITIAL>{CR}          { count();/* return CR;*/ }
 
 
-<INITIAL,SELECT>{QUOTES} { count(); old_initial = YY_START; old_state = state; state=STRING_S; BEGIN(STRING1); }
-<INITIAL>{TICK} { count(); old_initial = YY_START; old_state = state; state=STRING_S; BEGIN(STRING2); }
+<INITIAL,SELECT>{QUOTES} { count(); old_initial = YY_START; 
+                                                       old_state = state; state=STRING_S;
+                                                       BEGIN(STRING1); }
+<INITIAL>{TICK} { count(); old_initial = YY_START; old_state = state;
+                                       state=STRING_S; BEGIN(STRING2); }
 
 
-<STRING1>{QUOTES} { count(); state=old_state; BEGIN(old_initial);
+<STRING1>{QUOTES} { count_more(); 
                                                yytext[yyleng-1]=0; yyleng--;
                                                addstr(&s_buf, yytext, yyleng);
-                                               yylval.strval=s_buf.s;
-                                               memset(&s_buf, 0, sizeof(s_buf));
-                                               return STRING;
+                                               BEGIN(STR_BETWEEN);
                                        }
-<STRING2>{TICK}  { count(); state=old_state; BEGIN(old_initial);
+<STRING2>{TICK}  { count_more(); state=old_state; BEGIN(old_initial);
                                                yytext[yyleng-1]=0; yyleng--;
                                                addstr(&s_buf, yytext, yyleng);
                                                yylval.strval=s_buf.s;
@@ -832,21 +941,33 @@ EAT_ABLE  [\ \t\b\r]
                                        }
 <STRING2>.|{EAT_ABLE}|{CR}     { yymore(); }
 
-<STRING1>\\n           { count(); addchar(&s_buf, '\n'); }
-<STRING1>\\r           { count(); addchar(&s_buf, '\r'); }
-<STRING1>\\a           { count(); addchar(&s_buf, '\a'); }
-<STRING1>\\t           { count(); addchar(&s_buf, '\t'); }
-<STRING1>\\{QUOTES}    { count(); addchar(&s_buf, '"');  }
-<STRING1>\\\\          { count(); addchar(&s_buf, '\\'); }
-<STRING1>\\x{HEX}{1,2} { count(); addchar(&s_buf,
+<STRING1>\\n           { count_more(); addchar(&s_buf, '\n'); }
+<STRING1>\\r           { count_more(); addchar(&s_buf, '\r'); }
+<STRING1>\\a           { count_more(); addchar(&s_buf, '\a'); }
+<STRING1>\\t           { count_more(); addchar(&s_buf, '\t'); }
+<STRING1>\\{QUOTES}    { count_more(); addchar(&s_buf, '"');  }
+<STRING1>\\\\          { count_more(); addchar(&s_buf, '\\'); }
+<STRING1>\\x{HEX}{1,2} { count_more(); addchar(&s_buf,
                                                                                        (char)strtol(yytext+2, 0, 16)); }
  /* don't allow \[0-7]{1}, it will eat the backreferences from
     subst_uri if allowed (although everybody should use '' in subt_uri) */
-<STRING1>\\[0-7]{2,3}  { count(); addchar(&s_buf,
+<STRING1>\\[0-7]{2,3}  { count_more(); addchar(&s_buf,
                                                                                        (char)strtol(yytext+1, 0, 8));  }
-<STRING1>\\{CR}                { count(); } /* eat escaped CRs */
-<STRING1>.|{EAT_ABLE}|{CR}     { addchar(&s_buf, *yytext); }
-
+<STRING1>\\{CR}                { count_more(); } /* eat escaped CRs */
+<STRING1>.|{EAT_ABLE}|{CR}     { count_more(); addchar(&s_buf, *yytext); }
+
+<STR_BETWEEN>{EAT_ABLE}|{CR}   { count_ignore(); }
+<STR_BETWEEN>{QUOTES}                  { count_more(); state=STRING_S;
+                                                                 BEGIN(STRING1);}
+<STR_BETWEEN>.                                 {       
+                                                                       yyless(0); /* reparse it */
+                                                                       /* ignore the whitespace now that is
+                                                                         counted, return saved string value */
+                                                                       state=old_state; BEGIN(old_initial);
+                                                                       yylval.strval=s_buf.s;
+                                                                       memset(&s_buf, 0, sizeof(s_buf));
+                                                                       return STRING;
+                                                               }
 
 <INITIAL,COMMENT>{COM_START}   { count(); comment_nest++; state=COMMENT_S;
                                                                                BEGIN(COMMENT); }
@@ -858,6 +979,12 @@ EAT_ABLE   [\ \t\b\r]
                                                                }
 <COMMENT>.|{EAT_ABLE}|{CR}                             { count(); };
 
+<INITIAL>{COM_LINE}!{SER_CFG}{CR}              { count();
+                                                                                       sr_cfg_compat=SR_COMPAT_SER;}
+<INITIAL>{COM_LINE}!{KAMAILIO_CFG}{CR} { count(); 
+                                                                                       sr_cfg_compat=SR_COMPAT_KAMAILIO;}
+<INITIAL>{COM_LINE}!{MAXCOMPAT_CFG}{CR}        { count(); 
+                                                                                               sr_cfg_compat=SR_COMPAT_MAX;}
 <INITIAL>{COM_LINE}.*{CR}      { count(); }
 
 <INITIAL>{ID}                  { count(); addstr(&s_buf, yytext, yyleng);
@@ -870,6 +997,12 @@ EAT_ABLE   [\ \t\b\r]
 
 <<EOF>>                                                        {
                                                                        switch(state){
+                                                                               case STR_BETWEEN_S:
+                                                                                       state=old_state;
+                                                                                       BEGIN(old_initial);
+                                                                                       yylval.strval=s_buf.s;
+                                                                                       memset(&s_buf, 0, sizeof(s_buf));
+                                                                                       return STRING;
                                                                                case STRING_S:
                                                                                        LOG(L_CRIT, "ERROR: cfg. parser: unexpected EOF in"
                                                                                                                " unclosed string\n");
@@ -887,6 +1020,23 @@ EAT_ABLE  [\ \t\b\r]
                                                                                        LOG(L_CRIT, "ERROR: unexpected EOF:"
                                                                                                                "comment line open\n");
                                                                                        break;
+                                                                               case  ATTR_S:
+                                                                                       LOG(L_CRIT, "ERROR: unexpected EOF"
+                                                                                                       " while parsing"
+                                                                                                       " avp name\n");
+                                                                                       break;
+                                                                               case PVARID_S:
+                                                                                       p_nest=0;
+                                                                               case PVAR_P_S: 
+                                                                                       LOG(L_CRIT, "ERROR: unexpected EOF"
+                                                                                                       " while parsing pvar name"
+                                                                                                       " (%d paranthesis open)\n",
+                                                                                                       p_nest);
+                                                                                       break;
+                                                                               case AVP_PVAR_S:
+                                                                                       LOG(L_CRIT, "ERROR: unexpected EOF"
+                                                                                                       " while parsing"
+                                                                                                       " avp or pvar name\n");
                                                                        }
                                                                        return 0;
                                                                }
@@ -935,26 +1085,66 @@ error:
 
 
 
-static void count()
+/** helper function for count_*(). */
+static void count_lc(int* l, int* c)
 {
        int i;
-
-       startcolumn=column;
        for (i=0; i<yyleng;i++){
                if (yytext[i]=='\n'){
-                       line++;
-                       column=startcolumn=1;
+                       (*l)++;
+                       (*c)=1;
                }else if (yytext[i]=='\t'){
-                       column++;
-                       /*column+=8 -(column%8);*/
+                       (*c)++;
+                       /*(*c)+=8 -((*c)%8);*/
                }else{
-                       column++;
+                       (*c)++;
                }
        }
 }
 
 
 
+/* helper function */
+static void count_restore_ignored()
+{
+       if (ign_lines) /* ignored line(s) => column has changed */
+               column=ign_columns;
+       else
+               column+=ign_columns;
+       line+=ign_lines;
+       ign_lines=ign_columns=0;
+}
+
+
+
+/** count/record position for stuff added to the current token. */
+static void count_more()
+{
+       count_restore_ignored();
+       count_lc(&line, &column);
+}
+
+
+
+/** count/record position for a new token. */
+static void count()
+{
+       count_restore_ignored();
+       startline=line;
+       startcolumn=column;
+       count_more();
+}
+
+
+
+/** record discarded stuff (not contained in the token) so that
+    the next token position can be adjusted properly*/
+static void count_ignore()
+{
+       count_lc(&ign_lines, &ign_columns);
+}
+
+
 /* replacement yywrap, removes libfl dependency */
 int yywrap()
 {
diff --git a/cfg.y b/cfg.y
index bcd42f0..f2383a2 100644 (file)
--- a/cfg.y
+++ b/cfg.y
  * 2007-11-28  added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
  *              LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
  * 2008-01-24  added cfg_var definition (Miklos)
+ * 2008-11-18  support for variable parameter module functions (andrei)
+ * 2007-12-03  support for generalised lvalues and rvalues:
+ *               lval=rval_expr, where lval=avp|pvar  (andrei)
+ * 2007-12-06  expression are now evaluated in terms of rvalues;
+ *             NUMBER is now always positive; cleanup (andrei)
+ * 2009-01-26  case/switch() support (andrei)
  * 2009-03-10  added SET_USERPHONE action (Miklos)
 */
 
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include "route_struct.h"
 #include "globals.h"
 #include "route.h"
+#include "switch.h"
 #include "dprint.h"
 #include "sr_module.h"
 #include "modparam.h"
 #include "tcp_init.h"
 #include "tcp_options.h"
 #include "sctp_options.h"
+#include "pvar.h"
+#include "lvalue.h"
+#include "rvalue.h"
+#include "sr_compat.h"
 #include "msg_translator.h"
 
 #include "config.h"
 
 
 extern int yylex();
-static void yyerror(char* s);
+static void yyerror(char* s, ...);
+static void yyerror_at(struct cfg_pos* pos, char* s, ...);
 static char* tmp;
 static int i_tmp;
+static unsigned u_tmp;
 static struct socket_id* lst_tmp;
 static struct name_lst*  nl_tmp;
 static int rt;  /* Type of route block for find_export */
@@ -186,15 +200,30 @@ static struct ip_addr* ip_tmp;
 static struct avp_spec* s_attr;
 static select_t sel;
 static select_t* sel_ptr;
+static pv_spec_t* pv_spec;
 static struct action *mod_func_action;
-
-static void warn(char* s);
+static struct lvalue* lval_tmp;
+static struct rvalue* rval_tmp;
+
+static void warn(char* s, ...);
+static void warn_at(struct cfg_pos* pos, char* s, ...);
+static void get_cpos(struct cfg_pos* pos);
+static struct rval_expr* mk_rve_rval(enum rval_type, void* v);
+static struct rval_expr* mk_rve1(enum rval_expr_op op, struct rval_expr* rve1);
+static struct rval_expr* mk_rve2(enum rval_expr_op op, struct rval_expr* rve1,
+                                                                       struct rval_expr* rve2);
 static struct socket_id* mk_listen_id(char*, int, int);
 static struct name_lst* mk_name_lst(char* name, int flags);
 static struct socket_id* mk_listen_id2(struct name_lst*, int, int);
 static void free_name_lst(struct name_lst* lst);
 static void free_socket_id_lst(struct socket_id* i);
 
+static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re, 
+                                                                       struct action* a, int* err);
+static int case_check_type(struct case_stms* stms);
+static int case_check_default(struct case_stms* stms);
+
+
 %}
 
 %union {
@@ -203,11 +232,16 @@ static void free_socket_id_lst(struct socket_id* i);
        char* strval;
        struct expr* expr;
        struct action* action;
+       struct case_stms* case_stms;
        struct net* ipnet;
        struct ip_addr* ipaddr;
        struct socket_id* sockid;
        struct name_lst* name_l;
        struct avp_spec* attr;
+       struct _pv_spec* pvar;
+       struct lvalue* lval;
+       struct rvalue* rval;
+       struct rval_expr* rv_expr;
        select_t* select;
 }
 
@@ -255,6 +289,10 @@ static void free_socket_id_lst(struct socket_id* i);
 %token SET_ADV_ADDRESS
 %token SET_ADV_PORT
 %token FORCE_SEND_SOCKET
+%token SWITCH
+%token CASE
+%token DEFAULT
+%token WHILE
 %token URIHOST
 %token URIPORT
 %token MAX_LEN
@@ -414,6 +452,7 @@ static void free_socket_id_lst(struct socket_id* i);
 %token TOS
 %token PMTU_DISCOVERY
 %token KILL_TIMEOUT
+%token MAX_WLOOPS
 %token CFG_DESCRIPTION
 %token SERVER_ID
 
@@ -433,32 +472,33 @@ static void free_socket_id_lst(struct socket_id* i);
 %token ATTR_GLOBAL
 %token ADDEQ
 
+
 %token STUN_REFRESH_INTERVAL
 %token STUN_ALLOW_STUN
 %token STUN_ALLOW_FP
 
 
-/* operators */
-%nonassoc EQUAL
-%nonassoc EQUAL_T
-%nonassoc GT
-%nonassoc LT
-%nonassoc GTE
-%nonassoc LTE
-%nonassoc DIFF
-%nonassoc MATCH
+/* operators, C like precedence */
+%right EQUAL
 %left LOG_OR
 %left LOG_AND
 %left BIN_OR
 %left BIN_AND
+%left EQUAL_T DIFF MATCH
+%left GT LT GTE LTE
 %left PLUS MINUS
+%left STAR SLASH
 %right NOT
+%left DOT
 
 /* values */
 %token <intval> NUMBER
 %token <strval> ID
 %token <strval> STRING
 %token <strval> IPV6ADDR
+%token <strval> PVAR
+/* not clear yet if this is an avp or pvar */
+%token <strval> AVP_OR_PVAR
 
 /* other */
 %token COMMA
@@ -469,16 +509,17 @@ static void free_socket_id_lst(struct socket_id* i);
 %token RBRACE
 %token LBRACK
 %token RBRACK
-%token SLASH
-%token DOT
 %token CR
 %token COLON
-%token STAR
 
 
 /*non-terminals */
-%type <expr> exp exp_elem /*, condition*/
-%type <action> action actions cmd fcmd if_cmd stm exp_stm assign_action
+%type <expr> exp exp_elem
+%type <intval> intno eint_op eint_op_onsend
+%type <intval> eip_op eip_op_onsend
+%type <action> action actions cmd fcmd if_cmd stm /*exp_stm*/ assign_action
+%type <action> switch_cmd while_cmd
+%type <case_stms> single_case case_stms
 %type <ipaddr> ipv4 ipv6 ipv6addr ip
 %type <ipnet> ipnet
 %type <strval> host
@@ -489,22 +530,27 @@ static void free_socket_id_lst(struct socket_id* i);
 %type <sockid>  phostport
 %type <sockid>  listen_phostport
 %type <intval> proto port
-%type <intval> equalop strop intop binop
-%type <strval> host_sep
+%type <intval> equalop strop cmpop rve_cmpop rve_equalop
 %type <intval> uri_type
 %type <attr> attr_id
 %type <attr> attr_id_num_idx
 %type <attr> attr_id_no_idx
 %type <attr> attr_id_ass
-%type <attr> attr_id_val
+/*%type <attr> attr_id_val*/
 %type <attr> attr_id_any
 %type <attr> attr_id_any_str
+%type <pvar> pvar
+%type <lval> lval
+%type <rv_expr> rval rval_expr ct_rval
+%type <lval> avp_pvar
 /* %type <intval> class_id */
 %type <intval> assign_op
 %type <select> select_id
 %type <strval> flag_name;
 %type <strval> route_name;
 %type <intval> avpflag_oper
+%type <intval> rve_un_op
+/* %type <intval> rve_op */
 
 /*%type <route_el> rules;
   %type <route_el> rule;
@@ -616,6 +662,10 @@ id_lst:
        | listen_phostport id_lst       { $$=$1; $$->next=$2; }
        ;
 
+intno: NUMBER
+       |  MINUS %prec NOT NUMBER { $$=-$2; }
+       ;
+
 flags_decl:            FLAGS_DECL      flag_list
                        |       FLAGS_DECL error { yyerror("flag list expected\n"); }
 ;
@@ -651,7 +701,7 @@ avpflag_spec:
        }
        ;
 assign_stm:
-       DEBUG_V EQUAL NUMBER { default_core_cfg.debug=$3; }
+       DEBUG_V EQUAL intno { default_core_cfg.debug=$3; }
        | DEBUG_V EQUAL error  { yyerror("number  expected"); }
        | FORK  EQUAL NUMBER { dont_fork= ! $3; }
        | FORK  EQUAL error  { yyerror("boolean value expected"); }
@@ -674,13 +724,13 @@ assign_stm:
        | DNS_TRY_NAPTR error { yyerror("boolean value expected"); }
        | DNS_SRV_LB EQUAL NUMBER   { IF_DNS_FAILOVER(default_core_cfg.dns_srv_lb=$3); }
        | DNS_SRV_LB error { yyerror("boolean value expected"); }
-       | DNS_UDP_PREF EQUAL NUMBER { IF_NAPTR(default_core_cfg.dns_udp_pref=$3);}
+       | DNS_UDP_PREF EQUAL intno { IF_NAPTR(default_core_cfg.dns_udp_pref=$3);}
        | DNS_UDP_PREF error { yyerror("number expected"); }
-       | DNS_TCP_PREF EQUAL NUMBER { IF_NAPTR(default_core_cfg.dns_tcp_pref=$3);}
+       | DNS_TCP_PREF EQUAL intno { IF_NAPTR(default_core_cfg.dns_tcp_pref=$3);}
        | DNS_TCP_PREF error { yyerror("number expected"); }
-       | DNS_TLS_PREF EQUAL NUMBER { IF_NAPTR(default_core_cfg.dns_tls_pref=$3);}
+       | DNS_TLS_PREF EQUAL intno { IF_NAPTR(default_core_cfg.dns_tls_pref=$3);}
        | DNS_TLS_PREF error { yyerror("number expected"); }
-       | DNS_SCTP_PREF EQUAL NUMBER { 
+       | DNS_SCTP_PREF EQUAL intno { 
                                                                IF_NAPTR(default_core_cfg.dns_sctp_pref=$3); }
        | DNS_SCTP_PREF error { yyerror("number expected"); }
        | DNS_RETR_TIME EQUAL NUMBER   { default_core_cfg.dns_retr_time=$3; }
@@ -740,9 +790,9 @@ assign_stm:
        | PHONE2TEL EQUAL error { yyerror("boolean value expected"); }
        | SYN_BRANCH EQUAL NUMBER { syn_branch=$3; }
        | SYN_BRANCH EQUAL error { yyerror("boolean value expected"); }
-       | MEMLOG EQUAL NUMBER { memlog=$3; }
+       | MEMLOG EQUAL intno { memlog=$3; }
        | MEMLOG EQUAL error { yyerror("int value expected"); }
-       | MEMDBG EQUAL NUMBER { memdbg=$3; }
+       | MEMDBG EQUAL intno { memdbg=$3; }
        | MEMDBG EQUAL error { yyerror("int value expected"); }
        | SIP_WARNING EQUAL NUMBER { sip_warning=$3; }
        | SIP_WARNING EQUAL error { yyerror("boolean value expected"); }
@@ -784,7 +834,7 @@ assign_stm:
                #endif
        }
        | TCP_CHILDREN EQUAL error { yyerror("number expected"); }
-       | TCP_CONNECT_TIMEOUT EQUAL NUMBER {
+       | TCP_CONNECT_TIMEOUT EQUAL intno {
                #ifdef USE_TCP
                        tcp_default_cfg.connect_timeout_s=$3;
                #else
@@ -792,7 +842,7 @@ assign_stm:
                #endif
        }
        | TCP_CONNECT_TIMEOUT EQUAL error { yyerror("number expected"); }
-       | TCP_SEND_TIMEOUT EQUAL NUMBER {
+       | TCP_SEND_TIMEOUT EQUAL intno {
                #ifdef USE_TCP
                        tcp_default_cfg.send_timeout=S_TO_TICKS($3);
                #else
@@ -800,7 +850,7 @@ assign_stm:
                #endif
        }
        | TCP_SEND_TIMEOUT EQUAL error { yyerror("number expected"); }
-       | TCP_CON_LIFETIME EQUAL NUMBER {
+       | TCP_CON_LIFETIME EQUAL intno {
                #ifdef USE_TCP
                        if ($3<0)
                                tcp_default_cfg.con_lifetime=-1;
@@ -1277,6 +1327,8 @@ assign_stm:
        | PMTU_DISCOVERY error { yyerror("number expected"); }
        | KILL_TIMEOUT EQUAL NUMBER { ser_kill_timeout=$3; }
        | KILL_TIMEOUT EQUAL error { yyerror("number expected"); }
+       | MAX_WLOOPS EQUAL NUMBER { default_core_cfg.max_while_loops=$3; }
+       | MAX_WLOOPS EQUAL error { yyerror("number 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); }
@@ -1505,281 +1557,183 @@ send_route_stm: ROUTE_SEND LBRACE actions RBRACE {
        }
        | ROUTE_SEND error { yyerror("invalid onsend_route statement"); }
        ;
-/*
-rules:
-       rules rule { push($2, &$1); $$=$1; }
-       | rule {$$=$1; }
-       | rules error { $$=0; yyerror("invalid rule"); }
-       ;
-rule:
-       condition actions CR {
-               $$=0;
-               if (add_rule($1, $2, &$$)<0) {
-                       yyerror("error calling add_rule");
-                       YYABORT;
+
+exp:   rval_expr
+               {
+                       if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
+                               yyerror("invalid expression");
+                               $$=0;
+                       }else if (i_tmp!=RV_INT && i_tmp!=RV_NONE){
+                               yyerror("invalid expression type, int expected\n");
+                               $$=0;
+                       }else
+                               $$=mk_elem(NO_OP, RVEXP_O, $1, 0, 0);
                }
-       }
-       | CR    { $$=0;}
-       | condition error { $$=0; yyerror("bad actions in rule"); }
-       ;
-condition:
-       exp {$$=$1;}
-*/
-exp:   exp LOG_AND exp         { $$=mk_exp(LOGAND_OP, $1, $3); }
-       | exp LOG_OR exp        { $$=mk_exp(LOGOR_OP, $1, $3);  }
-       | NOT exp               { $$=mk_exp(NOT_OP, $2, 0);  }
-       | LPAREN exp RPAREN     { $$=$2; }
-       | exp_elem              { $$=$1; }
        ;
+
+/* exp elem operators */
 equalop:
        EQUAL_T {$$=EQUAL_OP; }
        | DIFF  {$$=DIFF_OP; }
        ;
-intop: equalop {$$=$1; }
-       | GT    {$$=GT_OP; }
+cmpop:
+         GT    {$$=GT_OP; }
        | LT    {$$=LT_OP; }
        | GTE   {$$=GTE_OP; }
        | LTE   {$$=LTE_OP; }
        ;
-binop :
-       BIN_OR { $$= BINOR_OP; }
-       | BIN_AND { $$ = BINAND_OP; }
-       ;
 strop:
        equalop {$$=$1; }
        | MATCH {$$=MATCH_OP; }
        ;
+
+
+/* rve expr. operators */
+rve_equalop:
+       EQUAL_T {$$=RVE_EQ_OP; }
+       | DIFF  {$$=RVE_DIFF_OP; }
+       ;
+rve_cmpop:
+         GT    {$$=RVE_GT_OP; }
+       | LT    {$$=RVE_LT_OP; }
+       | GTE   {$$=RVE_GTE_OP; }
+       | LTE   {$$=RVE_LTE_OP; }
+       ;
+
+
+
+/* boolean expression uri operands */
 uri_type:
        URI             {$$=URI_O;}
        | FROM_URI      {$$=FROM_URI_O;}
        | TO_URI        {$$=TO_URI_O;}
        ;
 
+
+/* boolean expression integer operands, available only in the
+  onsend route */
+eint_op_onsend:
+                       SNDPORT         { $$=SNDPORT_O; }
+               |       TOPORT          { $$=TOPORT_O; }
+               |       SNDPROTO        { $$=SNDPROTO_O; }
+               |       SNDAF           { $$=SNDAF_O; }
+               ;
+
+/* boolean expression integer operands */
+eint_op:       SRCPORT         { $$=SRCPORT_O; }
+               |       DSTPORT         { $$=DSTPORT_O; }
+               |       PROTO           { $$=PROTO_O; }
+               |       AF                      { $$=AF_O; }
+               |       MSGLEN          { $$=MSGLEN_O; }
+               |       RETCODE         { $$=RETCODE_O; }
+               | eint_op_onsend
+       ;
+
+/* boolean expression ip/ipnet operands */
+eip_op_onsend:
+                       SNDIP           { onsend_check("snd_ip"); $$=SNDIP_O; }
+               |       TOIP            { onsend_check("to_ip");  $$=TOIP_O; }
+               ;
+
+eip_op:                SRCIP           { $$=SRCIP_O; }
+               |       DSTIP           { $$=DSTIP_O; }
+               | eip_op_onsend
+               ;
+
+
+
 exp_elem:
-       METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
-       | METHOD strop attr_id_val  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
-       | METHOD strop select_id {$$ = mk_elem($2, METHOD_O, 0, SELECT_ST, $3); }
-       | METHOD strop  ID      {$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
+       METHOD strop %prec EQUAL_T rval_expr
+               {$$= mk_elem($2, METHOD_O, 0, RVE_ST, $3);}
+       | METHOD strop %prec EQUAL_T ID
+               {$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
        | METHOD strop error { $$=0; yyerror("string expected"); }
-       | METHOD error  { $$=0; yyerror("invalid operator,== , !=, or =~ expected"); }
-       | uri_type strop STRING {$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
-       | uri_type strop host   {$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
-       | uri_type strop attr_id_val {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
-       | uri_type strop select_id {$$ = mk_elem($2, $1, 0, SELECT_ST, $3); }
-       | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
-       | uri_type strop error { $$=0; yyerror("string or MYSELF expected"); }
-       | uri_type error        { $$=0; yyerror("invalid operator, == , != or =~ expected"); }
-
-       | SRCPORT intop NUMBER { $$=mk_elem($2, SRCPORT_O, 0, NUMBER_ST, (void*)$3 ); }
-       | SRCPORT intop attr_id_val { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
-       | SRCPORT intop error { $$=0; yyerror("number expected"); }
-       | SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
-
-       | DSTPORT intop NUMBER  { $$=mk_elem($2, DSTPORT_O, 0, NUMBER_ST, (void*)$3 ); }
-       | DSTPORT intop attr_id_val     { $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); }
-       | DSTPORT intop error { $$=0; yyerror("number expected"); }
-       | DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
-
-       | SNDPORT intop NUMBER {
-               onsend_check("snd_port");
-               $$=mk_elem($2, SNDPORT_O, 0, NUMBER_ST, (void*)$3 );
-       }
-       | SNDPORT intop attr_id_val {
-               onsend_check("snd_port");
-               $$=mk_elem($2, SNDPORT_O, 0, AVP_ST, (void*)$3 );
-       }
-       | SNDPORT intop error { $$=0; yyerror("number expected"); }
-       | SNDPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
-
-       | TOPORT intop NUMBER {
-               onsend_check("to_port");
-               $$=mk_elem($2, TOPORT_O, 0, NUMBER_ST, (void*)$3 );
-       }
-       | TOPORT intop attr_id_val {
-               onsend_check("to_port");
-               $$=mk_elem($2, TOPORT_O, 0, AVP_ST, (void*)$3 );
-       }
-       | TOPORT intop error { $$=0; yyerror("number expected"); }
-       | TOPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
-
-       | PROTO intop proto     { $$=mk_elem($2, PROTO_O, 0, NUMBER_ST, (void*)$3 ); }
-       | PROTO intop attr_id_val       { $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
-       | PROTO intop error { $$=0; yyerror("protocol expected (udp, tcp or tls)"); }
-
-       | PROTO error { $$=0; yyerror("equal/!= operator expected"); }
-
-       | SNDPROTO intop proto  {
-               onsend_check("snd_proto");
-               $$=mk_elem($2, SNDPROTO_O, 0, NUMBER_ST, (void*)$3 );
-       }
-       | SNDPROTO intop attr_id_val {
-               onsend_check("snd_proto");
-               $$=mk_elem($2, SNDPROTO_O, 0, AVP_ST, (void*)$3 );
-       }
-       | SNDPROTO intop error { $$=0; yyerror("protocol expected (udp, tcp or tls)"); }
-       | SNDPROTO error { $$=0; yyerror("equal/!= operator expected"); }
-
-       | AF intop NUMBER       { $$=mk_elem($2, AF_O, 0, NUMBER_ST,(void *) $3 ); }
-       | AF intop attr_id_val  { $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
-       | AF intop error { $$=0; yyerror("number expected"); }
-       | AF error { $$=0; yyerror("equal/!= operator expected"); }
-
-       | SNDAF intop NUMBER {
-               onsend_check("snd_af");
-               $$=mk_elem($2, SNDAF_O, 0, NUMBER_ST, (void *) $3 ); }
-       | SNDAF intop attr_id_val {
-               onsend_check("snd_af");
-               $$=mk_elem($2, SNDAF_O, 0, AVP_ST, (void *) $3 );
-       }
-       | SNDAF intop error { $$=0; yyerror("number expected"); }
-       | SNDAF error { $$=0; yyerror("equal/!= operator expected"); }
-
-       | MSGLEN intop NUMBER           { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) $3 ); }
-       | MSGLEN intop attr_id_val      { $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); }
-       | MSGLEN intop MAX_LEN          { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) BUF_SIZE); }
-       | MSGLEN intop error { $$=0; yyerror("number expected"); }
-       | MSGLEN error { $$=0; yyerror("equal/!= operator expected"); }
-
-       | RETCODE intop NUMBER  { $$=mk_elem($2, RETCODE_O, 0, NUMBER_ST, (void *) $3 ); }
-       | RETCODE intop attr_id_val     { $$=mk_elem($2, RETCODE_O, 0, AVP_ST, (void *) $3 ); }
-       | RETCODE intop error { $$=0; yyerror("number expected"); }
-       | RETCODE error { $$=0; yyerror("equal/!= operator expected"); }
-
-       | SRCIP equalop ipnet   { $$=mk_elem($2, SRCIP_O, 0, NET_ST, $3); }
-       | SRCIP strop STRING {
-               s_tmp.s=$3;
-               s_tmp.len=strlen($3);
-               ip_tmp=str2ip(&s_tmp);
-       #ifdef USE_IPV6
-               if (ip_tmp==0)
-                       ip_tmp=str2ip6(&s_tmp);
-       #endif
-               if (ip_tmp) {
-                       $$=mk_elem($2, SRCIP_O, 0, NET_ST, mk_net_bitlen(ip_tmp, ip_tmp->len*8) );
-               } else {
-                       $$=mk_elem($2, SRCIP_O, 0, STRING_ST, $3);
-               }
-       }
-       | SRCIP strop host      { $$=mk_elem($2, SRCIP_O, 0, STRING_ST, $3); }
-       | SRCIP equalop MYSELF  { $$=mk_elem($2, SRCIP_O, 0, MYSELF_ST, 0);
-                                                       }
-       | SRCIP strop error { $$=0; yyerror( "ip address or hostname expected" ); }
-       | SRCIP error  { $$=0; yyerror("invalid operator, ==, != or =~ expected");}
-       | DSTIP equalop ipnet   { $$=mk_elem(   $2, DSTIP_O, 0, NET_ST, (void*)$3); }
-       | DSTIP strop STRING    {
-               s_tmp.s=$3;
-               s_tmp.len=strlen($3);
-               ip_tmp=str2ip(&s_tmp);
-       #ifdef USE_IPV6
-               if (ip_tmp==0)
-                       ip_tmp=str2ip6(&s_tmp);
-       #endif /* USE_IPV6 */
-               if (ip_tmp) {
-                       $$=mk_elem($2, DSTIP_O, 0, NET_ST, mk_net_bitlen(ip_tmp, ip_tmp->len*8) );
-               } else {
-                       $$=mk_elem($2, DSTIP_O, 0, STRING_ST, $3);
-               }
-       }
-       | DSTIP strop host      { $$=mk_elem(   $2, DSTIP_O, 0, STRING_ST, $3); }
-       | DSTIP equalop MYSELF  { $$=mk_elem(   $2, DSTIP_O, 0, MYSELF_ST, 0); }
-       | DSTIP strop error { $$=0; yyerror( "ip address or hostname expected" ); }
-       | DSTIP error { $$=0; yyerror("invalid operator, ==, != or =~ expected"); }
-       | SNDIP equalop ipnet {
-               onsend_check("snd_ip");
-               $$=mk_elem($2, SNDIP_O, 0, NET_ST, $3);
-       }
-       | SNDIP strop STRING    {
-               onsend_check("snd_ip");
-               s_tmp.s=$3;
-               s_tmp.len=strlen($3);
-               ip_tmp=str2ip(&s_tmp);
-       #ifdef USE_IPV6
-               if (ip_tmp==0)
-                       ip_tmp=str2ip6(&s_tmp);
-       #endif /* USE_IPV6 */
-               if (ip_tmp) {
-                       $$=mk_elem($2, SNDIP_O, 0, NET_ST, mk_net_bitlen(ip_tmp, ip_tmp->len*8) );
-               } else {
-                       $$=mk_elem($2, SNDIP_O, 0, STRING_ST, $3);
-               }
-       }
-       | SNDIP strop host      {
-               onsend_check("snd_ip");
-               $$=mk_elem($2, SNDIP_O, 0, STRING_ST, $3);
-       }
-       | SNDIP equalop attr_id_val     {
-               onsend_check("snd_ip");
-           $$=mk_elem($2, SNDIP_O, 0, AVP_ST, (void*)$3 ); 
-       }
-       | SNDIP equalop MYSELF  {
-               onsend_check("snd_ip");
-               $$=mk_elem($2, SNDIP_O, 0, MYSELF_ST, 0);
-       }
-       | SNDIP strop error { $$=0; yyerror( "ip address or hostname expected" ); }
-       | SNDIP error  { $$=0; yyerror("invalid operator, ==, != or =~ expected"); }
-       | TOIP equalop ipnet    {
-               onsend_check("to_ip");
-               $$=mk_elem($2, TOIP_O, 0, NET_ST, $3);
-       }
-       | TOIP strop STRING     {
-               onsend_check("to_ip");
-               s_tmp.s=$3;
-               s_tmp.len=strlen($3);
-               ip_tmp=str2ip(&s_tmp);
-       #ifdef USE_IPV6
-               if (ip_tmp==0)
-                       ip_tmp=str2ip6(&s_tmp);
-       #endif /* USE_IPV6 */
-               if (ip_tmp) {
-                       $$=mk_elem($2, TOIP_O, 0, NET_ST, mk_net_bitlen(ip_tmp, ip_tmp->len*8) );
-               } else {
-                       $$=mk_elem($2, TOIP_O, 0, STRING_ST, $3);
+       | METHOD error  
+               { $$=0; yyerror("invalid operator,== , !=, or =~ expected"); }
+       | uri_type strop %prec EQUAL_T rval_expr
+               {$$ = mk_elem($2, $1, 0, RVE_ST, $3); }
+       | uri_type strop %prec EQUAL_T MYSELF
+               {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
+       | uri_type strop %prec EQUAL_T error
+               { $$=0; yyerror("string or MYSELF expected"); }
+       | uri_type error
+               { $$=0; yyerror("invalid operator, == , != or =~ expected"); }
+       | eint_op cmpop %prec GT rval_expr { $$=mk_elem($2, $1, 0, RVE_ST, $3 ); }
+       | eint_op equalop %prec EQUAL_T rval_expr 
+               { $$=mk_elem($2, $1, 0, RVE_ST, $3 ); }
+       | eint_op cmpop error   { $$=0; yyerror("number expected"); }
+       | eint_op equalop error { $$=0; yyerror("number expected"); }
+       | eint_op error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
+       | eip_op strop %prec EQUAL_T ipnet { $$=mk_elem($2, $1, 0, NET_ST, $3); }
+       | eip_op strop %prec EQUAL_T rval_expr {
+                       s_tmp.s=0;
+                       $$=0;
+                       if (rve_is_constant($3)){
+                               i_tmp=rve_guess_type($3);
+                               if (i_tmp==RV_INT)
+                                       yyerror("string expected");
+                               else if (i_tmp==RV_STR){
+                                       if (((rval_tmp=rval_expr_eval(0, 0, $3))==0) ||
+                                                               (rval_get_str(0, 0, &s_tmp, rval_tmp, 0)<0)){
+                                               rval_destroy(rval_tmp);
+                                               yyerror("bad rvalue expression");
+                                       }else{
+                                               rval_destroy(rval_tmp);
+                                       }
+                               }else{
+                                       yyerror("BUG: unexpected dynamic type");
+                               }
+                       }else{
+                                       warn("non constant rvalue in ip comparison");
+                       }
+                       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, 
+                                                               mk_net_bitlen(ip_tmp, ip_tmp->len*8) );
+                               } else {
+                                       $$=mk_elem($2, $1, 0, RVE_ST, $3);
+                               }
+                       }else{
+                               $$=mk_elem($2, $1, 0, RVE_ST, $3);
+                       }
                }
-       }
-       | TOIP strop host       {
-               onsend_check("to_ip");
-               $$=mk_elem($2, TOIP_O, 0, STRING_ST, $3);
-       }
-       | TOIP equalop attr_id_val      {
-               onsend_check("to_ip");
-           $$=mk_elem($2, TOIP_O, 0, AVP_ST, (void*)$3 ); 
-       }
-       | TOIP equalop MYSELF  {
-               onsend_check("to_ip");
-               $$=mk_elem($2, TOIP_O, 0, MYSELF_ST, 0);
-       }
-       | TOIP strop error { $$=0; yyerror( "ip address or hostname expected" ); }
-       | TOIP error  { $$=0; yyerror("invalid operator, ==, != or =~ expected"); }
-
-       | MYSELF equalop uri_type       { $$=mk_elem($2, $3, 0, MYSELF_ST, 0); }
-       | MYSELF equalop SRCIP  { $$=mk_elem($2, SRCIP_O, 0, MYSELF_ST, 0); }
-       | MYSELF equalop DSTIP  { $$=mk_elem($2, DSTIP_O, 0, MYSELF_ST, 0); }
-       | MYSELF equalop SNDIP  {
-               onsend_check("snd_ip");
-               $$=mk_elem($2, SNDIP_O, 0, MYSELF_ST, 0);
-       }
-       | MYSELF equalop TOIP  {
-               onsend_check("to_ip");
-               $$=mk_elem($2, TOIP_O, 0, MYSELF_ST, 0);
-       }
-       | MYSELF equalop error { $$=0; yyerror(" URI, SRCIP or DSTIP expected"); }
+       | eip_op strop %prec EQUAL_T host
+               { $$=mk_elem($2, $1, 0, STRING_ST, $3); }
+       | eip_op strop %prec EQUAL_T MYSELF
+               { $$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
+       | eip_op strop %prec EQUAL_T error
+               { $$=0; yyerror( "ip address or hostname expected" ); }
+       | eip_op error
+               { $$=0; yyerror("invalid operator, ==, != or =~ expected");}
+       
+       | MYSELF equalop %prec EQUAL_T uri_type
+               { $$=mk_elem($2, $3, 0, MYSELF_ST, 0); }
+       | MYSELF equalop %prec EQUAL_T eip_op
+               { $$=mk_elem($2, $3, 0, MYSELF_ST, 0); }
+       | MYSELF equalop %prec EQUAL_T error
+               { $$=0; yyerror(" URI, SRCIP or DSTIP expected"); }
        | MYSELF error  { $$=0; yyerror ("invalid operator, == or != expected"); }
-       | exp_stm       { $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1);  }
-       | NUMBER        { $$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$1 ); }
-
-       | attr_id_any                           {$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
-       | attr_id_val strop STRING      {$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
-       | attr_id_val strop select_id   {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); }
-       | attr_id_val intop NUMBER      {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
-       | attr_id_val binop NUMBER      {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
-       | attr_id_val strop attr_id_val {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
-       | attr_id_val intop attr_id_val {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
-
-       | select_id                 { $$=mk_elem( NO_OP, SELECT_O, $1, 0, 0); }
-       | select_id strop STRING    { $$=mk_elem( $2, SELECT_O, $1, STRING_ST, $3); }
-       | select_id strop attr_id_val   { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); }
-       | select_id strop select_id { $$=mk_elem( $2, SELECT_O, $1, SELECT_ST, $3); }
+       ;
+/*
+exp_elem2:
+       rval_expr cmpop %prec GT rval_expr
+               { $$=mk_elem( $2, RVE_ST, $1, RVE_ST, $3);}
+       |
+       rval_expr equalop %prec EQUAL_T rval_expr
+               { $$=mk_elem( $2, RVE_ST, $1, RVE_ST, $3);}
+       | rval_expr LOG_AND rval_expr
+               { $$=mk_exp_rve(LOGAND_OP, $1, $3);}
+       | rval_expr LOG_OR rval_expr
+               { $$=mk_exp_rve(LOGOR_OP, $1, $3);}
 ;
+*/
+
 ipnet:
        ip SLASH ip     { $$=mk_net($1, $3); }
        | ip SLASH NUMBER {
@@ -1796,20 +1750,29 @@ ipnet:
        | ip    { $$=mk_net_bitlen($1, $1->len*8); }
        | ip SLASH error { $$=0; yyerror("netmask (eg:255.0.0.0 or 8) expected"); }
        ;
-host_sep:
-       DOT {$$=".";}
-       | MINUS {$$="-"; }
-       ;
 
 host:
        ID { $$=$1; }
-       | host host_sep ID {
+       | host DOT ID {
                $$=(char*)pkg_malloc(strlen($1)+1+strlen($3)+1);
                if ($$==0) {
                        LOG(L_CRIT, "ERROR: cfg. parser: memory allocation failure while parsing host\n");
                } else {
                        memcpy($$, $1, strlen($1));
-                       $$[strlen($1)]=*$2;
+                       $$[strlen($1)]='.';
+                       memcpy($$+strlen($1)+1, $3, strlen($3));
+                       $$[strlen($1)+1+strlen($3)]=0;
+               }
+               pkg_free($1);
+               pkg_free($3);
+       }
+       | host MINUS ID {
+               $$=(char*)pkg_malloc(strlen($1)+1+strlen($3)+1);
+               if ($$==0) {
+                       LOG(L_CRIT, "ERROR: cfg. parser: memory allocation failure while parsing host\n");
+               } else {
+                       memcpy($$, $1, strlen($1));
+                       $$[strlen($1)]='-';
                        memcpy($$+strlen($1)+1, $3, strlen($3));
                        $$[strlen($1)+1+strlen($3)]=0;
                }
@@ -1844,12 +1807,14 @@ fcmd:
                }
        }
        ;
+/*
 exp_stm:
        fcmd    { $$=$1; }
        | if_cmd        { $$=$1; }
        | assign_action { $$ = $1; }
        | LBRACE actions RBRACE { $$=$2; }
        ;
+*/
 stm:
        action  { $$=$1; }
        | LBRACE actions RBRACE { $$=$2; }
@@ -1862,6 +1827,8 @@ actions:
 action:
        fcmd SEMICOLON {$$=$1;}
        | if_cmd {$$=$1;}
+       | switch_cmd {$$=$1;}
+       | while_cmd { $$=$1; }
        | assign_action SEMICOLON {$$=$1;}
        | SEMICOLON /* null action */ {$$=0;}
        | fcmd error { $$=0; yyerror("bad command: missing ';'?"); }
@@ -1870,6 +1837,127 @@ if_cmd:
        IF exp stm              { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, NOSUBTYPE, 0); }
        | IF exp stm ELSE stm   { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, ACTIONS_ST, $5); }
        ;
+
+ct_rval: rval_expr {
+                       $$=0;
+                       if (!rve_is_constant($1)){
+                               yyerror("constant expected");
+                       /*
+                       } else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
+                               yyerror("invalid expression (bad type)");
+                       }else if (i_tmp!=RV_INT){
+                               yyerror("invalid expression type, int expected\n");
+                       */
+                       }else
+                               $$=$1;
+               }
+;
+single_case:
+       CASE ct_rval COLON actions {
+               $$=0;
+               if ($2==0) yyerror ("bad case label");
+               else if ((($$=mk_case_stm($2, 0, $4, &i_tmp))==0) && (i_tmp==-10)){
+                               YYABORT;
+               }
+       }
+| CASE SLASH ct_rval COLON actions {
+               $$=0;
+               if ($3==0) yyerror ("bad case label");
+               else if ((($$=mk_case_stm($3, 1, $5, &i_tmp))==0) && (i_tmp==-10)){
+                               YYABORT;
+               }
+       }
+       | CASE ct_rval COLON {
+               $$=0;
+               if ($2==0) yyerror ("bad case label");
+               else if ((($$=mk_case_stm($2, 0, 0, &i_tmp))==0) && (i_tmp==-10)){
+                               YYABORT;
+               }
+       }
+       | CASE SLASH ct_rval COLON {
+               $$=0;
+               if ($3==0) yyerror ("bad case label");
+               else if ((($$=mk_case_stm($3, 1, 0, &i_tmp))==0) && (i_tmp==-10)){
+                               YYABORT;
+               }
+       }
+       | DEFAULT COLON actions {
+               if ((($$=mk_case_stm(0, 0, $3, &i_tmp))==0) && (i_tmp=-10)){
+                               YYABORT;
+               }
+       }
+       | DEFAULT COLON {
+               if ((($$=mk_case_stm(0, 0, 0, &i_tmp))==0) && (i_tmp==-10)){
+                               YYABORT;
+               }
+       }
+       | CASE error { $$=0; yyerror("bad case label"); }
+       | CASE ct_rval COLON error { $$=0; yyerror ("bad case body"); }
+;
+case_stms:
+       case_stms single_case {
+               $$=$1;
+               if ($2==0) yyerror ("bad case");
+               if ($$){
+                       *($$->append)=$2;
+                       if (*($$->append)!=0)
+                               $$->append=&((*($$->append))->next);
+               }
+       }
+       | single_case {
+               $$=$1;
+               if ($1==0) yyerror ("bad case");
+               else $$->append=&($$->next);
+       }
+;
+switch_cmd:
+         SWITCH rval_expr LBRACE case_stms RBRACE { 
+               $$=0;
+               if ($2==0) yyerror("bad expression in switch(...)");
+               else if ($4==0) yyerror ("bad switch body");
+               else if (case_check_default($4)!=0)
+                       yyerror_at(&$2->fpos, "bad switch(): too many "
+                                                       "\"default:\" labels\n");
+               else if (case_check_type($4)!=0)
+                       yyerror_at(&$2->fpos, "bad switch(): mixed integer and"
+                                                       " string/RE cases not allowed\n");
+               else{
+                       $$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4);
+                       if ($$==0) {
+                               yyerror("internal error");
+                               YYABORT;
+                       }
+               }
+       }
+       | SWITCH rval_expr LBRACE RBRACE {
+               $$=0;
+               warn("empty switch()");
+               if ($2==0) yyerror("bad expression in switch(...)");
+               else{
+                       /* it might have sideffects, so leave it for the optimizer */
+                       $$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, 0);
+                       if ($$==0) {
+                               yyerror("internal error");
+                               YYABORT;
+                       }
+               }
+       }
+       | SWITCH error { $$=0; yyerror ("bad expression in switch(...)"); }
+       | SWITCH rval_expr LBRACE error RBRACE 
+               {$$=0; yyerror ("bad switch body"); }
+;
+
+while_cmd:
+       WHILE rval_expr stm {
+               if ($2){
+                       if (rve_is_constant($2))
+                               warn_at(&$2->fpos, "constant value in while(...)");
+               }else
+                       yyerror_at(&$2->fpos, "bad while(...) expression");
+               $$=mk_action( WHILE_T, 2, RVE_ST, $2, ACTIONS_ST, $3);
+       }
+;
+
 /* class_id:
        LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; }
        | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; }
@@ -1955,7 +2043,7 @@ attr_id:
        attr_mark attr_spec { $$ = s_attr; }
        ;
 attr_id_num_idx:
-       attr_mark attr_spec LBRACK NUMBER RBRACK {
+       attr_mark attr_spec LBRACK intno RBRACK {
                s_attr->type|= (AVP_NAME_STR | ($4<0?AVP_INDEX_BACKWARD:AVP_INDEX_FORWARD));
                s_attr->index = ($4<0?-$4:$4);
                $$ = s_attr;
@@ -1971,10 +2059,12 @@ attr_id_ass:
        attr_id
        | attr_id_no_idx
        ;
+/*
 attr_id_val:
        attr_id
        | attr_id_num_idx
        ;
+*/
 attr_id_any:
        attr_id
        | attr_id_no_idx
@@ -1997,7 +2087,7 @@ attr_id_any_str:
                s.len = strlen(s.s);
                if (parse_avp_name(&s, &type, &avp_spec->name, &idx)) {
                        yyerror("error when parsing AVP");
-                       pkg_free(avp_spec);
+                       pkg_free(avp_spec);
                        YYABORT;
                }
                avp_spec->type = type;
@@ -2005,6 +2095,49 @@ attr_id_any_str:
                $$ = avp_spec;
        }
        ;
+
+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");
+                               pkg_free(pv_spec);
+                               pv_spec=0;
+                               YYABORT;
+                       }
+                       $$=pv_spec;
+               }
+       ;
+
+avp_pvar:      AVP_OR_PVAR {
+                               lval_tmp=pkg_malloc(sizeof(*lval_tmp));
+                               if (!lval_tmp) {
+                                       yyerror("Not enough memory");
+                                       YYABORT;
+                               }
+                               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->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;
+                                       lval_tmp->type=LV_AVP;
+                               }else{
+                                       lval_tmp->type=LV_PVAR;
+                               }
+                               $$ = lval_tmp;
+                               DBG("parsed ambigous avp/pvar \"%.*s\" to %d\n",
+                                                       s_tmp.len, s_tmp.s, lval_tmp->type);
+                       }
+       ;
+
+
 /*
 assign_op:
        ADDEQ { $$ = ADD_T; }
@@ -2014,6 +2147,127 @@ assign_op:
 assign_op:
        EQUAL { $$ = ASSIGN_T; }
        ;
+
+
+lval: attr_id_ass {
+                                       lval_tmp=pkg_malloc(sizeof(*lval_tmp));
+                                       if (!lval_tmp) {
+                                               yyerror("Not enough memory");
+                                               YYABORT;
+                                       }
+                                       lval_tmp->type=LV_AVP; lval_tmp->lv.avps=*$1;
+                                       pkg_free($1); /* free the avp spec we just copied */
+                                       $$=lval_tmp;
+                               }
+       | pvar        {
+                                       if (!pv_is_w($1))
+                                               yyerror("read only pvar in assignment left side");
+                                       if ($1->trans!=0)
+                                               yyerror("pvar with transformations in assignment"
+                                                               " left side");
+                                       lval_tmp=pkg_malloc(sizeof(*lval_tmp));
+                                       if (!lval_tmp) {
+                                               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;
+                               }
+       | avp_pvar    {
+                                       if (($1)->type==LV_PVAR){
+                                               if (!pv_is_w(&($1)->lv.pvs))
+                                                       yyerror("read only pvar in assignment left side");
+                                               if ($1->lv.pvs.trans!=0)
+                                                       yyerror("pvar with transformations in assignment"
+                                                                       " left side");
+                                       }
+                                       $$=$1;
+                               }
+       ;
+
+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); }
+       | 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);
+                                                                       break;
+                                                               default:
+                                                                       yyerror("BUG: invalid lvalue type ");
+                                                                       YYABORT;
+                                                       }
+                                                       pkg_free($1); /* not needed anymore */
+                                               }
+       | select_id                     {$$=mk_rve_rval(RV_SEL, $1); pkg_free($1); }
+       | fcmd                          {$$=mk_rve_rval(RV_ACTION_ST, $1); }
+       | exp_elem { $$=mk_rve_rval(RV_BEXPR, $1); }
+       | LBRACE actions RBRACE {$$=mk_rve_rval(RV_ACTION_ST, $2); }
+       | LBRACE error RBRACE   { yyerror("bad command block"); }
+       | LPAREN assign_action RPAREN   {$$=mk_rve_rval(RV_ACTION_ST, $2); }
+       | LPAREN error RPAREN   { yyerror("bad expression"); }
+       ;
+
+
+rve_un_op: NOT { $$=RVE_LNOT_OP; }
+               |  MINUS %prec NOT      { $$=RVE_UMINUS_OP; } 
+               /* TODO: RVE_BOOL_OP, RVE_NOT_OP? */
+       ;
+
+/*
+rve_op:                PLUS            { $$=RVE_PLUS_OP; }
+               |       MINUS           { $$=RVE_MINUS_OP; }
+               |       STAR            { $$=RVE_MUL_OP; }
+               |       SLASH           { $$=RVE_DIV_OP; }
+       ;
+*/
+
+rval_expr: rval                                                { $$=$1;
+                                                                                       if ($$==0){
+                                                                                               yyerror("out of memory\n");
+                                                                                               YYABORT;
+                                                                                       }
+                                                                       }
+               | rve_un_op %prec NOT rval_expr {$$=mk_rve1($1, $2); }
+               | rval_expr PLUS rval_expr              {$$=mk_rve2(RVE_PLUS_OP, $1, $3); }
+               | rval_expr MINUS rval_expr             {$$=mk_rve2(RVE_MINUS_OP, $1, $3); }
+               | rval_expr STAR rval_expr              {$$=mk_rve2(RVE_MUL_OP, $1, $3); }
+               | rval_expr SLASH rval_expr             {$$=mk_rve2(RVE_DIV_OP, $1, $3); }
+               | rval_expr BIN_OR rval_expr    {$$=mk_rve2(RVE_BOR_OP, $1,  $3); }
+               | rval_expr BIN_AND rval_expr   {$$=mk_rve2(RVE_BAND_OP, $1,  $3);}
+               | rval_expr rve_cmpop %prec GT rval_expr { $$=mk_rve2( $2, $1, $3);}
+               | rval_expr rve_equalop %prec EQUAL_T rval_expr
+                       { $$=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;}
+               | rve_un_op %prec NOT error             { yyerror("bad expression"); }
+               | rval_expr PLUS error                  { yyerror("bad expression"); }
+               | rval_expr MINUS error                 { yyerror("bad expression"); }
+               | rval_expr STAR error                  { yyerror("bad expression"); }
+               | rval_expr SLASH error                 { yyerror("bad expression"); }
+               | rval_expr BIN_OR error                { yyerror("bad expression"); }
+               | rval_expr BIN_AND error               { yyerror("bad expression"); }
+               | rval_expr rve_cmpop %prec GT error
+                       { yyerror("bad expression"); }
+               | rval_expr rve_equalop %prec EQUAL_T error
+                       { yyerror("bad expression"); }
+               | rval_expr LOG_AND error               { yyerror("bad expression"); }
+               | rval_expr LOG_OR error                { yyerror("bad expression"); }
+               ;
+
+assign_action: lval assign_op  rval_expr       { $$=mk_action($2, 2, LVAL_ST, $1, 
+                                                                                                                         RVE_ST, $3);
+                                                                               }
+       ;
+
+/*
 assign_action:
        attr_id_ass assign_op STRING  { $$=mk_action($2, 2, AVP_ST, $1, STRING_ST, $3); }
        | attr_id_ass assign_op NUMBER  { $$=mk_action($2, 2, AVP_ST, $1, NUMBER_ST, (void*)$3); }
@@ -2022,6 +2276,8 @@ assign_action:
        | attr_id_ass assign_op select_id { $$=mk_action($2, 2, AVP_ST, (void*)$1, SELECT_ST, (void*)$3); }
        | attr_id_ass assign_op LPAREN exp RPAREN { $$ = mk_action($2, 2, AVP_ST, $1, EXPR_ST, $4); }
        ;
+*/
+
 avpflag_oper:
        SETAVPFLAG { $$ = 1; }
        | RESETAVPFLAG { $$ = 0; }
@@ -2239,7 +2495,7 @@ cmd:
        | RETURN                        {$$=mk_action(DROP_T, 2, NUMBER_ST, (void*)1, NUMBER_ST, (void*)RETURN_R_F); }
        | RETURN NUMBER                 {$$=mk_action(DROP_T, 2, NUMBER_ST, (void*)$2, NUMBER_ST, (void*)RETURN_R_F);}
        | RETURN RETCODE                {$$=mk_action(DROP_T, 2, RETCODE_ST, 0, NUMBER_ST, (void*)RETURN_R_F);}
-       | BREAK                         {$$=mk_action(DROP_T, 2, NUMBER_ST, 0, NUMBER_ST, (void*)RETURN_R_F); }
+       | BREAK                         {$$=mk_action(DROP_T, 2, NUMBER_ST, 0, NUMBER_ST, (void*)BREAK_R_F); }
        | LOG_TOK LPAREN STRING RPAREN  {$$=mk_action(LOG_T, 2, NUMBER_ST,
                                                                                (void*)(L_DBG+1), STRING_ST, $3); }
        | LOG_TOK LPAREN NUMBER COMMA STRING RPAREN     {$$=mk_action(LOG_T, 2, NUMBER_ST, (void*)$3, STRING_ST, $5); }
@@ -2410,31 +2666,65 @@ cmd:
                $$=0; yyerror("bad argument, [proto:]host[:port] expected");
        }
        | FORCE_SEND_SOCKET error {$$=0; yyerror("missing '(' or ')' ?"); }
-       | ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST, 0); } LPAREN func_params RPAREN      {
-               mod_func_action->val[0].u.data = find_export_record($1, mod_func_action->val[1].u.number, rt);
+       | ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST,
+                       0); } LPAREN func_params RPAREN {
+               mod_func_action->val[0].u.data = 
+                       find_export_record($1, mod_func_action->val[1].u.number, rt,
+                                                               &u_tmp);
                if (mod_func_action->val[0].u.data == 0) {
-                       if (find_export_record($1, mod_func_action->val[1].u.number, 0) ) {
+                       if (find_export_record($1, mod_func_action->val[1].u.number, 0,
+                                                                       &u_tmp) ) {
                                        yyerror("Command cannot be used in the block\n");
                        } else {
                                yyerror("unknown command, missing loadmodule?\n");
                        }
                        pkg_free(mod_func_action);
                        mod_func_action=0;
+               }else{
+                       switch( ((union cmd_export_u*)
+                                               mod_func_action->val[0].u.data)->c.param_no){
+                               case 0:
+                               case 1:
+                               case 2:
+                                       /* MODULE_T used for 0-2 params */
+                                       break;
+                               case 3:
+                                       mod_func_action->type=MODULE3_T;
+                                       break;
+                               case 4:
+                                       mod_func_action->type=MODULE4_T;
+                                       break;
+                               case 5:
+                                       mod_func_action->type=MODULE5_T;
+                                       break;
+                               case 6:
+                                       mod_func_action->type=MODULE6_T;
+                                       break;
+                               case VAR_PARAM_NO:
+                                       mod_func_action->type=MODULEX_T;
+                                       break;
+                               default:
+                                       yyerror("too many parameters for function\n");
+                                       break;
+                       }
                }
                $$ = mod_func_action;
        }
+       | ID error                                      { yyerror("'('')' expected (function call)");}
        ;
 func_params:
        /* empty */
        | func_params COMMA func_param { }
        | func_param {}
-       | func_params error { yyerror("call params error\n"); YYABORT; }
+       | func_params error { yyerror("call params error\n"); }
        ;
 func_param:
         NUMBER {
                if (mod_func_action->val[1].u.number < MAX_ACTIONS-2) {
-                       mod_func_action->val[mod_func_action->val[1].u.number+2].type = NUMBER_ST;
-                       mod_func_action->val[mod_func_action->val[1].u.number+2].u.number = $1;
+                       mod_func_action->val[mod_func_action->val[1].u.number+2].type =
+                               NUMBER_ST;
+                       mod_func_action->val[mod_func_action->val[1].u.number+2].u.number =
+                               $1;
                        mod_func_action->val[1].u.number++;
                } else {
                        yyerror("Too many arguments\n");
@@ -2455,21 +2745,160 @@ func_param:
 extern int line;
 extern int column;
 extern int startcolumn;
-static void warn(char* s)
+extern int startline;
+
+
+static void get_cpos(struct cfg_pos* pos)
 {
-       LOG(L_WARN, "cfg. warning: (%d,%d-%d): %s\n", line, startcolumn,
-                       column, s);
+       pos->s_line=startline;
+       pos->e_line=line;
+       pos->s_col=startcolumn;
+       pos->e_col=column-1;
+}
+
+
+static void warn_at(struct cfg_pos* p, char* format, ...)
+{
+       va_list ap;
+       char s[256];
+       
+       va_start(ap, format);
+       vsnprintf(s, sizeof(s), format, ap);
+       va_end(ap);
+       if (p->e_line!=p->s_line)
+               LOG(L_WARN, "cfg. warning: (%d,%d-%d,%d): %s\n",
+                                       p->s_line, p->s_col, p->e_line, p->e_col, s);
+       else if (p->s_col!=p->e_col)
+               LOG(L_WARN, "cfg. warning: (%d,%d-%d): %s\n",
+                                       p->s_line, p->s_col, p->e_col, s);
+       else
+               LOG(L_WARN, "cfg. warning: (%d,%d): %s\n",
+                               p->s_line, p->s_col, s);
        cfg_warnings++;
 }
 
-static void yyerror(char* s)
+
+
+static void yyerror_at(struct cfg_pos* p, char* format, ...)
 {
-       LOG(L_CRIT, "*** PARSE ERROR *** (%d,%d-%d): %s\n", line, startcolumn,
-                       column, s);
+       va_list ap;
+       char s[256];
+       
+       va_start(ap, format);
+       vsnprintf(s, sizeof(s), format, ap);
+       va_end(ap);
+       if (p->e_line!=p->s_line)
+               LOG(L_CRIT, "*** PARSE ERROR *** (%d,%d-%d,%d): %s\n", 
+                                       p->s_line, p->s_col, p->e_line, p->e_col, s);
+       else if (p->s_col!=p->e_col)
+               LOG(L_CRIT, "*** PARSE ERROR *** (%d,%d-%d): %s\n", 
+                                       p->s_line, p->s_col, p->e_col, s);
+       else
+               LOG(L_CRIT, "*** PARSE ERROR *** (%d,%d): %s\n", 
+                                       p->s_line, p->s_col, s);
        cfg_errors++;
 }
 
 
+
+static void warn(char* format, ...)
+{
+       va_list ap;
+       char s[256];
+       struct cfg_pos pos;
+       
+       get_cpos(&pos);
+       va_start(ap, format);
+       vsnprintf(s, sizeof(s), format, ap);
+       va_end(ap);
+       warn_at(&pos, s);
+}
+
+
+
+static void yyerror(char* format, ...)
+{
+       va_list ap;
+       char s[256];
+       struct cfg_pos pos;
+       
+       get_cpos(&pos);
+       va_start(ap, format);
+       vsnprintf(s, sizeof(s), format, ap);
+       va_end(ap);
+       yyerror_at(&pos, s);
+}
+
+
+
+/** mk_rval_expr_v wrapper.
+ *  checks mk_rval_expr_v return value and sets the cfg. pos
+ *  (line and column numbers)
+ *  @return rval_expr* on success, 0 on error (@see mk_rval_expr_v)
+ */
+static struct rval_expr* mk_rve_rval(enum rval_type type, void* v)
+{
+       struct rval_expr* ret;
+       struct cfg_pos pos;
+
+       get_cpos(&pos);
+       ret=mk_rval_expr_v(type, v, &pos);
+       if (ret==0){
+               yyerror("internal error: failed to create rval expr");
+               /* YYABORT; */
+       }
+       return ret;
+}
+
+
+/** mk_rval_expr1 wrapper.
+ *  checks mk_rval_expr1 return value (!=0 and type checking)
+ *  @return rval_expr* on success, 0 on error (@see mk_rval_expr1)
+ */
+static struct rval_expr* mk_rve1(enum rval_expr_op op, struct rval_expr* rve1)
+{
+       struct rval_expr* ret;
+       struct rval_expr* bad_rve;
+       enum rval_type type, bad_t, exp_t;
+       
+       if (rve1==0)
+               return 0;
+       ret=mk_rval_expr1(op, rve1, &rve1->fpos);
+       if (ret && (rve_check_type(&type, ret, &bad_rve, &bad_t, &exp_t)!=1)){
+               yyerror_at(&rve1->fpos, "bad expression: type mismatch"
+                                       " (%s instead of %s)", rval_type_name(bad_t),
+                                       rval_type_name(exp_t));
+       }
+       return ret;
+}
+
+
+/** mk_rval_expr2 wrapper.
+ *  checks mk_rval_expr2 return value (!=0 and type checking)
+ *  @return rval_expr* on success, 0 on error (@see mk_rval_expr2)
+ */
+static struct rval_expr* mk_rve2(enum rval_expr_op op, struct rval_expr* rve1,
+                                                                       struct rval_expr* rve2)
+{
+       struct rval_expr* ret;
+       struct rval_expr* bad_rve;
+       enum rval_type type, bad_t, exp_t;
+       struct cfg_pos pos;
+       
+       if ((rve1==0) || (rve2==0))
+               return 0;
+       cfg_pos_join(&pos, &rve1->fpos, &rve2->fpos);
+       ret=mk_rval_expr2(op, rve1, rve2, &pos);
+       if (ret && (rve_check_type(&type, ret, &bad_rve, &bad_t, &exp_t)!=1)){
+               yyerror_at(&pos, "bad expression: type mismatch:"
+                                               " %s instead of %s at (%d,%d)",
+                                               rval_type_name(bad_t), rval_type_name(exp_t),
+                                               bad_rve->fpos.s_line, bad_rve->fpos.s_col);
+       }
+       return ret;
+}
+
+
 static struct name_lst* mk_name_lst(char* host, int flags)
 {
        struct name_lst* l;
@@ -2554,6 +2983,101 @@ static void free_socket_id_lst(struct socket_id* lst)
        }
 }
 
+
+/** create a temporary case statmenet structure.
+ *  *err will be filled in case of error (return == 0):
+ *   -1 - non constant expression
+ *   -2 - expression error (bad type)
+ *   -10 - memory allocation error
+ */
+static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re,
+                                                                                       struct action* a, int* err)
+{
+       struct case_stms* s;
+       struct rval_expr* bad_rve;
+       enum rval_type type, bad_t, exp_t;
+       enum match_str_type t;
+       
+       t=MATCH_UNKNOWN;
+       if (ct){
+               /* if ct!=0 => case, else if ct==0 is a default */
+               if (!rve_is_constant(ct)){
+                       yyerror_at(&ct->fpos, "non constant expression in case");
+                       *err=-1;
+                       return 0;
+               }
+               if (rve_check_type(&type, ct, &bad_rve, &bad_t, &exp_t)!=1){
+                       yyerror_at(&ct->fpos, "bad expression: type mismatch:"
+                                                       " %s instead of %s at (%d,%d)",
+                                                       rval_type_name(bad_t), rval_type_name(exp_t),
+                                                       bad_rve->fpos.s_line, bad_rve->fpos.s_col);
+                       *err=-2;
+                       return 0;
+               }
+               if (is_re)
+                       t=MATCH_RE;
+               else if (type==RV_STR)
+                       t=MATCH_STR;
+               else
+                       t=MATCH_INT;
+       }
+
+       s=pkg_malloc(sizeof(*s));
+       if (s==0) {
+               yyerror("internal error: memory allocation failure");
+               *err=-10;
+       } else {
+               memset(s, 0, sizeof(*s));
+               s->ct_rve=ct;
+               s->type=t;
+               s->actions=a;
+               s->next=0;
+               s->append=0;
+       }
+       return s;
+}
+
+
+/*
+ * @return 0 on success, -1 on error.
+ */
+static int case_check_type(struct case_stms* stms)
+{
+       struct case_stms* c;
+       struct case_stms* s;
+       
+       for(c=stms; c ; c=c->next){
+               if (!c->ct_rve) continue;
+               for (s=c->next; s; s=s->next){
+                       if (!s->ct_rve) continue;
+                       if ((s->type!=c->type) &&
+                               !(      (c->type==MATCH_STR || c->type==MATCH_RE) &&
+                                       (s->type==MATCH_STR || s->type==MATCH_RE) ) ){
+                                       yyerror_at(&s->ct_rve->fpos, "type mismatch in case");
+                                       return -1;
+                       }
+               }
+       }
+       return 0;
+}
+
+
+/*
+ * @return 0 on success, -1 on error.
+ */
+static int case_check_default(struct case_stms* stms)
+{
+       struct case_stms* c;
+       int default_no;
+       
+       default_no=0;
+       for(c=stms; c ; c=c->next)
+               if (c->ct_rve==0) default_no++;
+       return (default_no<=1)?0:-1;
+}
+
+
+
 /*
 int main(int argc, char ** argv)
 {
index b25eb25..778a4dd 100644 (file)
@@ -89,6 +89,7 @@ struct cfg_group_core default_core_cfg = {
 #ifdef SHM_MEM
        0, /* mem_dump_shm */
 #endif
+       DEFAULT_MAX_WHILE_LOOPS, /* max_while_loops */
        0, /* udp_mtu (disabled by default) */
        0, /* udp_mtu_try_proto -> default disabled */
        0  /* force_rport */ 
@@ -181,6 +182,8 @@ cfg_def_t core_cfg_def[] = {
        {"mem_dump_shm",        CFG_VAR_INT,    0, 0, mem_dump_shm_fixup, 0,
                "dump shared memory status"},
 #endif
+       {"max_while_loops",     CFG_VAR_INT|CFG_ATOMIC, 0, 0, 0, 0,
+               "maximum iterations allowed for a while loop" },
        {"udp_mtu",     CFG_VAR_INT|CFG_ATOMIC, 0, 65535, 0, 0,
                "fallback to a congestion controlled protocol if send size"
                        " exceeds udp_mtu"},
index 8621cf1..4f493ef 100644 (file)
@@ -85,6 +85,7 @@ struct cfg_group_core {
 #ifdef SHM_MEM
        int mem_dump_shm;
 #endif
+       int max_while_loops;
        int udp_mtu; /**< maximum send size for udp, if > try another protocol*/
        int udp_mtu_try_proto; /**< if packet> udp_mtu, try proto (e.g. TCP) */
        int force_rport; /**< if set rport will always be forced*/
index b9cc4c3..317ff1c 100644 (file)
--- a/config.h
+++ b/config.h
@@ -70,6 +70,8 @@
 
 #define MAX_URI_SIZE 1024      /* used when rewriting URIs */
 
+#define MAX_PATH_SIZE 256 /* Maximum length of path header buffer */
+
 #define MY_VIA "Via: SIP/2.0/UDP "
 #define MY_VIA_LEN (sizeof(MY_VIA) - 1)
 
 
 #define DEFAULT_DID "_default"
 
+/*  maximum allowed iterations for a while (to catch runaways) */
+#define DEFAULT_MAX_WHILE_LOOPS 100
+
 #endif
index a4762c7..7b1253d 100644 (file)
@@ -49,6 +49,7 @@ void dns_cache_debug(rpc_t* rpc, void* ctx);
 void dns_cache_debug_all(rpc_t* rpc, void* ctx);
 void dns_cache_mem_info(rpc_t* rpc, void* ctx);
 void dns_cache_view(rpc_t* rpc, void* ctx);
+void dns_cache_rpc_lookup(rpc_t* rpc, void* ctx);
 void dns_cache_delete_all(rpc_t* rpc, void* ctx);
 void dns_cache_add_a(rpc_t* rpc, void* ctx);
 void dns_cache_add_aaaa(rpc_t* rpc, void* ctx);
@@ -56,6 +57,9 @@ void dns_cache_add_srv(rpc_t* rpc, void* ctx);
 void dns_cache_delete_a(rpc_t* rpc, void* ctx);
 void dns_cache_delete_aaaa(rpc_t* rpc, void* ctx);
 void dns_cache_delete_srv(rpc_t* rpc, void* ctx);
+void dns_cache_delete_naptr(rpc_t* rpc, void* ctx);
+void dns_cache_delete_cname(rpc_t* rpc, void* ctx);
+void dns_cache_delete_txt(rpc_t* rpc, void* ctx);
 
 
 static const char* dns_cache_mem_info_doc[] = {
@@ -77,6 +81,11 @@ static const char* dns_cache_view_doc[] = {
        0
 };
 
+static const char* dns_cache_rpc_lookup_doc[] = {
+       "perform a dns lookup",
+       0
+};
+
 static const char* dns_cache_delete_all_doc[] = {
        "deletes all the entries from the DNS cache",
        0
@@ -111,6 +120,22 @@ static const char* dns_cache_delete_srv_doc[] = {
        0
 };
 
+static const char* dns_cache_delete_naptr_doc[] = {
+       "deletes a NAPTR record from the DNS cache",
+       0
+};
+
+static const char* dns_cache_delete_cname_doc[] = {
+       "deletes a CNAME record from the DNS cache",
+       0
+};
+
+static const char* dns_cache_delete_txt_doc[] = {
+       "deletes a TXT record from the DNS cache",
+       0
+};
+
+
 #ifdef USE_DNS_CACHE_STATS
 void dns_cache_stats_get(rpc_t* rpc, void* ctx);
 
@@ -199,7 +224,8 @@ static void system_listMethods(rpc_t* rpc, void* c)
        }
 
        for(t = modules; t; t = t->next) {
-               for(ptr = t->exports->rpc_methods; ptr && ptr->name; ptr++) {
+               if (t->mod_interface_ver!=0) continue;
+               for(ptr = t->exports->v0.rpc_methods; ptr && ptr->name; ptr++) {
                        if (rpc->add(c, "s", ptr->name) < 0) return;
                }
        }
@@ -233,7 +259,8 @@ static void system_methodHelp(rpc_t* rpc, void* c)
        }
 
        for(t = modules; t; t = t->next) {
-               for(ptr = t->exports->rpc_methods; ptr && ptr->name; ptr++) {
+               if (t->mod_interface_ver!=0) continue;
+               for(ptr = t->exports->v0.rpc_methods; ptr && ptr->name; ptr++) {
                        if (strcmp(name, ptr->name) == 0) {
                                if (ptr->doc_str && ptr->doc_str[0]) {
                                        rpc->add(c, "s", ptr->doc_str[0]);
@@ -682,33 +709,60 @@ rpc_export_t core_rpc_methods[] = {
                0},
        {"core.sctp_info",         core_sctpinfo,          core_sctpinfo_doc,   0},
 #ifdef USE_DNS_CACHE
-       {"dns.mem_info",          dns_cache_mem_info,     dns_cache_mem_info_doc,     0 },
-       {"dns.debug",          dns_cache_debug,           dns_cache_debug_doc,        0 },
-       {"dns.debug_all",      dns_cache_debug_all,       dns_cache_debug_all_doc,        0     },
-       {"dns.view",               dns_cache_view,        dns_cache_view_doc,        0  },
-       {"dns.delete_all",         dns_cache_delete_all,  dns_cache_delete_all_doc,  0  },
-       {"dns.add_a",              dns_cache_add_a,       dns_cache_add_a_doc,       0  },
-       {"dns.add_aaaa",           dns_cache_add_aaaa,    dns_cache_add_aaaa_doc,    0  },
-       {"dns.add_srv",            dns_cache_add_srv,     dns_cache_add_srv_doc,     0  },
-       {"dns.delete_a",           dns_cache_delete_a,    dns_cache_delete_a_doc,    0  },
-       {"dns.delete_aaaa",        dns_cache_delete_aaaa, dns_cache_delete_aaaa_doc, 0  },
-       {"dns.delete_srv",         dns_cache_delete_srv,  dns_cache_delete_srv_doc,  0  },
+       {"dns.mem_info",          dns_cache_mem_info,     dns_cache_mem_info_doc,
+               0       },
+       {"dns.debug",          dns_cache_debug,           dns_cache_debug_doc,
+               0       },
+       {"dns.debug_all",      dns_cache_debug_all,       dns_cache_debug_all_doc,
+               0       },
+       {"dns.view",               dns_cache_view,        dns_cache_view_doc,
+               0       },
+       {"dns.lookup",             dns_cache_rpc_lookup,  dns_cache_rpc_lookup_doc,
+               0       },
+       {"dns.delete_all",         dns_cache_delete_all,  dns_cache_delete_all_doc,
+               0       },
+       {"dns.add_a",              dns_cache_add_a,       dns_cache_add_a_doc,
+               0       },
+       {"dns.add_aaaa",           dns_cache_add_aaaa,    dns_cache_add_aaaa_doc,
+               0       },
+       {"dns.add_srv",            dns_cache_add_srv,     dns_cache_add_srv_doc,
+               0       },
+       {"dns.delete_a",           dns_cache_delete_a,    dns_cache_delete_a_doc,
+               0       },
+       {"dns.delete_aaaa",        dns_cache_delete_aaaa,
+               dns_cache_delete_aaaa_doc, 0    },
+       {"dns.delete_srv",         dns_cache_delete_srv,
+               dns_cache_delete_srv_doc,  0    },
+       {"dns.delete_naptr",         dns_cache_delete_naptr,
+               dns_cache_delete_naptr_doc,  0  },
+       {"dns.delete_cname",         dns_cache_delete_cname,
+               dns_cache_delete_cname_doc,  0  },
+       {"dns.delete_txt",         dns_cache_delete_txt,
+               dns_cache_delete_txt_doc,  0    },
 #ifdef USE_DNS_CACHE_STATS
-       {"dns.stats_get",    dns_cache_stats_get,   dns_cache_stats_get_doc,        0   },
+       {"dns.stats_get",    dns_cache_stats_get,   dns_cache_stats_get_doc,
+               0       },
 #endif /* USE_DNS_CACHE_STATS */
 #ifdef DNS_WATCHDOG_SUPPORT
-       {"dns.set_server_state",   dns_set_server_state_rpc, dns_set_server_state_doc, 0 },
-       {"dns.get_server_state",   dns_get_server_state_rpc, dns_get_server_state_doc, 0 },
+       {"dns.set_server_state",   dns_set_server_state_rpc,
+               dns_set_server_state_doc, 0 },
+       {"dns.get_server_state",   dns_get_server_state_rpc,
+               dns_get_server_state_doc, 0 },
 #endif
 #endif
 #ifdef USE_DST_BLACKLIST
-       {"dst_blacklist.mem_info",  dst_blst_mem_info,     dst_blst_mem_info_doc,     0 },
-       {"dst_blacklist.debug",    dst_blst_debug,         dst_blst_debug_doc,        0 },
-       {"dst_blacklist.view",     dst_blst_view,         dst_blst_view_doc,         0  },
-       {"dst_blacklist.delete_all", dst_blst_delete_all, dst_blst_delete_all_doc,   0  },
-       {"dst_blacklist.add",      dst_blst_add,          dst_blst_add_doc,          0  },
+       {"dst_blacklist.mem_info",  dst_blst_mem_info,     dst_blst_mem_info_doc,
+               0       },
+       {"dst_blacklist.debug",    dst_blst_debug,         dst_blst_debug_doc,
+               0       },
+       {"dst_blacklist.view",     dst_blst_view,         dst_blst_view_doc,
+               0       },
+       {"dst_blacklist.delete_all", dst_blst_delete_all, dst_blst_delete_all_doc,
+               0       },
+       {"dst_blacklist.add",      dst_blst_add,          dst_blst_add_doc,
+               0       },
 #ifdef USE_DST_BLACKLIST_STATS
-       {"dst_blacklist.stats_get", dst_blst_stats_get, dst_blst_stats_get_doc, 0 },
+       {"dst_blacklist.stats_get", dst_blst_stats_get, dst_blst_stats_get_doc, 0},
 #endif /* USE_DST_BLACKLIST_STATS */
 #endif
        {0, 0, 0, 0}
diff --git a/db/Makefile b/db/Makefile
deleted file mode 100644 (file)
index e2426c8..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# This is a convenience make which just runs the makefile
-# in parent directory
-#
-
-all clean distclean:
-       $(MAKE) -C .. $(MAKECMDGOALS)
-
index b0e7a4d..997e232 100644 (file)
@@ -44,6 +44,7 @@
  *  2008-02-11  dns_cache_init cfg parameter is introduced (Miklos)
  *  2008-10-17  fixed srv continue with 0 hostname (when falling back to
                   aaaa) (andrei)
+ *  2009-03-30  TXT record support, more rpcs (andrei)
  */
 
 #ifdef USE_DNS_CACHE
@@ -51,6 +52,7 @@
 #ifdef DNS_SRV_LB
 #include <stdlib.h> /* FIXME: rand() */
 #endif
+#include <string.h>
 
 #include "globals.h"
 #include "cfg_core.h"
@@ -1006,6 +1008,7 @@ inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type,
        ticks_t now;
        unsigned int max_ttl;
        unsigned int ttl;
+       int i;
 
 #define rec_matches(rec, t, n) /*(struct rdata* record, int type, str* name)*/\
        (       ((rec)->name_len==(n)->len) && ((rec)->type==(t)) && \
@@ -1143,6 +1146,25 @@ inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type,
                                 * just been elimintated */
                        }
                        break;
+               case T_TXT:
+                       for(; *p;){
+                               if (!rec_matches((*p), type, name)){
+                                       /* skip this record */
+                                       p=&(*p)->next; /* advance */
+                                       continue;
+                               }
+                               /* padding to char* (because of txt[]->cstr*/
+                               size+=ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
+                                               TXT_RDATA_SIZE(*(struct txt_rdata*)(*p)->rdata));
+                               /* add it to our tmp. lst */
+                               *tail=*p;
+                               tail=&(*p)->next;
+                               /* detach it from the rd list */
+                               *p=(*p)->next;
+                               /* don't advance p, because the crt. elem. has
+                                * just been elimintated */
+                       }
+                       break;
                default:
                        LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: type %d not "
                                                        "supported\n", type);
@@ -1269,6 +1291,28 @@ inline static struct dns_hash_entry* dns_cache_mk_rd_entry(str* name, int type,
                                rr=rr->next;
                        }
                        break;
+               case T_TXT:
+                       for(l=tmp_lst; l; l=l->next){
+                               ttl=FIX_TTL(l->ttl);
+                               rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
+                               max_ttl=MAX(max_ttl, ttl);
+                               rr->rdata=(void*)((char*)rr+
+                                                       ROUND_POINTER(sizeof(struct dns_rr)));
+                               memcpy(rr->rdata, l->rdata,
+                                                       TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata));
+                               /* adjust the string pointers */
+                               for (i=0; i<((struct txt_rdata*)l->rdata)->cstr_no; i++){
+                                       ((struct txt_rdata*)rr->rdata)->txt[i].cstr=
+                                               translate_pointer((char*)rr->rdata, (char*)l->rdata,
+                                                               ((struct txt_rdata*)l->rdata)->txt[i].cstr);
+                               }
+                               rr->next=(void*)((char*)rr+
+                                               ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
+                                                       TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata)));
+                               tail_rr=&(rr->next);
+                               rr=rr->next;
+                       }
+                       break;
                default:
                        /* do nothing */
                        LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: create: type %d not "
@@ -1304,7 +1348,7 @@ inline static struct dns_hash_entry* dns_cache_mk_rd_entry2(struct rdata* rd)
        ticks_t now;
        struct tmp_rec rec[MAX_DNS_RECORDS];
        int rec_idx[MAX_DNS_RECORDS];
-       int r, i;
+       int r, i, j;
        int no_records; /* number of different records */
        unsigned int ttl;
 
@@ -1382,6 +1426,12 @@ found:
                                rec[r].size+=ROUND_POINTER(sizeof(struct dns_rr)+
                                                        CNAME_RDATA_SIZE(*(struct cname_rdata*)l->rdata));
                                break;
+                       case T_TXT:
+                                       /* padding to char* (because of txt[]->cstr*/
+                               rec[r].size+=ROUND_POINTER(ROUND_POINTER(
+                                                                                               sizeof(struct dns_rr))+
+                                                       TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata));
+                               break;
                        default:
                                LOG(L_CRIT, "BUG: dns_cache_mk_rd_entry: type %d not "
                                                        "supported\n", l->type);
@@ -1501,6 +1551,26 @@ found:
                                rec[r].tail_rr=&(rec[r].rr->next);
                                rec[r].rr=rec[r].rr->next;
                                break;
+                       case T_TXT:
+                               rec[r].rr->expire=now+S_TO_TICKS(ttl); /* maximum expire */
+                               rec[r].max_ttl=MAX(rec[r].max_ttl, ttl);
+                               rec[r].rr->rdata=(void*)((char*)rec[r].rr+
+                                                                       ROUND_POINTER(sizeof(struct dns_rr)));
+                               memcpy(rec[r].rr->rdata, l->rdata,
+                                                       TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata));
+                               /* adjust the string pointers */
+                               for (j=0; j<((struct txt_rdata*)l->rdata)->cstr_no; j++){
+                                       ((struct txt_rdata*)rec[r].rr->rdata)->txt[j].cstr=
+                                               translate_pointer((char*)rec[r].rr->rdata,
+                                                               (char*)l->rdata,
+                                                               ((struct txt_rdata*)l->rdata)->txt[j].cstr);
+                               }
+                               rec[r].rr->next=(void*)((char*)rec[r].rr+
+                                               ROUND_POINTER(ROUND_POINTER(sizeof(struct dns_rr))+
+                                                       TXT_RDATA_SIZE(*(struct txt_rdata*)l->rdata)));
+                               rec[r].tail_rr=&(rec[r].rr->next);
+                               rec[r].rr=rec[r].rr->next;
+                               break;
                        default:
                                /* do nothing */
                                ;
@@ -3445,6 +3515,12 @@ void dns_cache_debug_all(rpc_t* rpc, void* ctx)
                                                        rpc->add(ctx, "ss", "cname",
                                                                        ((struct cname_rdata*)(rr->rdata))->name);
                                                        break;
+                                               case T_TXT:
+                                                       rpc->add(ctx, "ss", "txt",
+                                                               ((struct txt_rdata*)(rr->rdata))->cstr_no?
+                                                               ((struct txt_rdata*)(rr->rdata))->txt[0].cstr:
+                                                               "");
+                                                       break;
                                                default:
                                                        rpc->add(ctx, "ss", "unknown", "?");
                                        }
@@ -3472,103 +3548,167 @@ static char *print_type(unsigned short type)
                        return "NAPTR";
                case T_CNAME:
                        return "CNAME";
+               case T_TXT:
+                       return "TXT";
                default:
                        return "unkown";
        }
 }
 
-/* dumps the content of the cache in a human-readable format */
-void dns_cache_view(rpc_t* rpc, void* ctx)
+
+/** convert string type to dns integer T_*.
+ * used for rpc type translation.
+ * @return T_* on success, -1 on error.
+ */
+static int dns_get_type(str* s)
+{
+       char *t;
+       int len;
+       
+       t=s->s;
+       len=s->len;
+       /* skip over a T_ or t_ prefix */
+       if ((len>2) && (t[0]=='T' || t[0]=='t') && (t[1]=='_')){
+               t+=2;
+               len-=2;
+       }
+       switch(len){
+               case 1:
+                       if (t[0]=='A' || t[0]=='a')
+                               return T_A;
+                       break;
+               case 4:
+                       if (strncasecmp(t, "AAAA", len)==0)
+                               return T_AAAA;
+                       break;
+               case 3:
+                       if (strncasecmp(t, "SRV", len)==0)
+                               return T_SRV;
+                       else if (strncasecmp(t, "TXT", len)==0)
+                               return T_TXT;
+                       break;
+               case 5:
+                       if (strncasecmp(t, "NAPTR", len)==0)
+                               return T_NAPTR;
+                       else if (strncasecmp(t, "CNAME", len)==0)
+                               return T_CNAME;
+                       break;
+       }
+       return -1;
+}
+
+
+/** rpc-prints a dns cache entry.
+  */
+void dns_cache_print_entry(rpc_t* rpc, void* ctx, struct dns_hash_entry* e)
 {
-       int h;
        int expires;
-       struct dns_hash_entry* e;
        struct dns_rr* rr;
        struct ip_addr ip;
        ticks_t now;
        str s;
+       int i;
+
+       now=get_ticks_raw();
+       expires = (s_ticks_t)(e->expire-now)<0?-1: TICKS_TO_S(e->expire-now);
+       if (expires < 0) {
+               return;
+       }
+       rpc->printf(ctx, "%sname: %s", SPACE_FORMAT, e->name);
+       rpc->printf(ctx, "%stype: %s", SPACE_FORMAT, print_type(e->type));
+       rpc->printf(ctx, "%ssize (bytes): %d", SPACE_FORMAT,
+                                               e->total_size);
+       rpc->printf(ctx, "%sreference counter: %d", SPACE_FORMAT,
+                                               e->refcnt.val);
+       rpc->printf(ctx, "%sexpires in (s): %d", SPACE_FORMAT, expires);
+       rpc->printf(ctx, "%slast used (s): %d", SPACE_FORMAT,
+                                               TICKS_TO_S(now-e->last_used));
+       rpc->printf(ctx, "%serror flags: %d", SPACE_FORMAT, e->err_flags);
+       
+       for (rr=e->rr_lst; rr; rr=rr->next) {
+               switch(e->type) {
+                       case T_A:
+                       case T_AAAA:
+                               if (dns_rr2ip(e->type, rr, &ip)==0){
+                                 rpc->printf(ctx, "%srr ip: %s", SPACE_FORMAT,
+                                                                       ip_addr2a(&ip) );
+                               }else{
+                                 rpc->printf(ctx, "%srr ip: <error: bad rr>", 
+                                                                       SPACE_FORMAT);
+                               }
+                               break;
+                       case T_SRV:
+                               rpc->printf(ctx, "%srr name: %s", SPACE_FORMAT,
+                                                       ((struct srv_rdata*)(rr->rdata))->name);
+                               rpc->printf(ctx, "%srr port: %d", SPACE_FORMAT,
+                                                       ((struct srv_rdata*)(rr->rdata))->port);
+                               rpc->printf(ctx, "%srr priority: %d", SPACE_FORMAT,
+                                               ((struct srv_rdata*)(rr->rdata))->priority);
+                               rpc->printf(ctx, "%srr weight: %d", SPACE_FORMAT,
+                                                       ((struct srv_rdata*)(rr->rdata))->weight);
+                               break;
+                       case T_NAPTR:
+                               rpc->printf(ctx, "%srr order: %d", SPACE_FORMAT,
+                                                       ((struct naptr_rdata*)(rr->rdata))->order);
+                               rpc->printf(ctx, "%srr preference: %d", SPACE_FORMAT,
+                                                       ((struct naptr_rdata*)(rr->rdata))->pref);
+                               s.s = ((struct naptr_rdata*)(rr->rdata))->flags;
+                               s.len = ((struct naptr_rdata*)(rr->rdata))->flags_len;
+                               rpc->printf(ctx, "%srr flags: %.*s", SPACE_FORMAT,
+                                                                       s.len, s.s);
+                               s.s=((struct naptr_rdata*)(rr->rdata))->services;
+                               s.len=((struct naptr_rdata*)(rr->rdata))->services_len;
+                               rpc->printf(ctx, "%srr service: %.*s", SPACE_FORMAT,
+                                                                       s.len, s.s);
+                               s.s = ((struct naptr_rdata*)(rr->rdata))->regexp;
+                               s.len = ((struct naptr_rdata*)(rr->rdata))->regexp_len;
+                               rpc->printf(ctx, "%srr regexp: %.*s", SPACE_FORMAT,
+                                                                       s.len, s.s);
+                               s.s = ((struct naptr_rdata*)(rr->rdata))->repl;
+                               s.len = ((struct naptr_rdata*)(rr->rdata))->repl_len;
+                               rpc->printf(ctx, "%srr replacement: %.*s", 
+                                                                       SPACE_FORMAT, s.len, s.s);
+                               break;
+                       case T_CNAME:
+                               rpc->printf(ctx, "%srr name: %s", SPACE_FORMAT,
+                                                       ((struct cname_rdata*)(rr->rdata))->name);
+                               break;
+                       case T_TXT:
+                               for (i=0; i<((struct txt_rdata*)(rr->rdata))->cstr_no;
+                                               i++){
+                                       rpc->printf(ctx, "%stxt[%d]: %s", SPACE_FORMAT, i,
+                                               ((struct txt_rdata*)(rr->rdata))->txt[i].cstr);
+                               }
+                               break;
+                       default:
+                               rpc->printf(ctx, "%sresource record: unknown",
+                                                                       SPACE_FORMAT);
+               }
+               rpc->printf(ctx, "%srr expires in (s): %d", SPACE_FORMAT,
+                                               (s_ticks_t)(rr->expire-now)<0?-1 : 
+                                               TICKS_TO_S(rr->expire-now));
+               rpc->printf(ctx, "%srr error flags: %d", SPACE_FORMAT, 
+                                               rr->err_flags);
+       }
+}
+
+
+
+/* dumps the content of the cache in a human-readable format */
+void dns_cache_view(rpc_t* rpc, void* ctx)
+{
+       int h;
+       struct dns_hash_entry* e;
 
        if (!cfg_get(core, core_cfg, use_dns_cache)){
                rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
                return;
        }
-       now=get_ticks_raw();
        LOCK_DNS_HASH();
        for (h=0; h<DNS_HASH_SIZE; h++){
                clist_foreach(&dns_hash[h], e, next){
-                       expires = (s_ticks_t)(e->expire-now)<0?-1: TICKS_TO_S(e->expire-now);
-                       if (expires < 0) {
-                               continue;
-                       }
-                       rpc->printf(ctx, "{\n%sname: %s", SPACE_FORMAT, e->name);
-                       rpc->printf(ctx, "%stype: %s", SPACE_FORMAT, print_type(e->type));
-                       rpc->printf(ctx, "%ssize (bytes): %d", SPACE_FORMAT,
-                                                               e->total_size);
-                       rpc->printf(ctx, "%sreference counter: %d", SPACE_FORMAT,
-                                                               e->refcnt.val);
-                       rpc->printf(ctx, "%sexpires in (s): %d", SPACE_FORMAT, expires);
-                       rpc->printf(ctx, "%slast used (s): %d", SPACE_FORMAT,
-                                                               TICKS_TO_S(now-e->last_used));
-                       rpc->printf(ctx, "%serror flags: %d", SPACE_FORMAT, e->err_flags);
-                       
-                       for (rr=e->rr_lst; rr; rr=rr->next) {
-                               switch(e->type) {
-                                       case T_A:
-                                       case T_AAAA:
-                                               if (dns_rr2ip(e->type, rr, &ip)==0){
-                                                 rpc->printf(ctx, "%srr ip: %s", SPACE_FORMAT,
-                                                                                       ip_addr2a(&ip) );
-                                               }else{
-                                                 rpc->printf(ctx, "%srr ip: <error: bad rr>", 
-                                                                                       SPACE_FORMAT);
-                                               }
-                                               break;
-                                       case T_SRV:
-                                               rpc->printf(ctx, "%srr name: %s", SPACE_FORMAT,
-                                                                       ((struct srv_rdata*)(rr->rdata))->name);
-                                               rpc->printf(ctx, "%srr port: %d", SPACE_FORMAT,
-                                                                       ((struct srv_rdata*)(rr->rdata))->port);
-                                               rpc->printf(ctx, "%srr priority: %d", SPACE_FORMAT,
-                                                               ((struct srv_rdata*)(rr->rdata))->priority);
-                                               rpc->printf(ctx, "%srr weight: %d", SPACE_FORMAT,
-                                                                       ((struct srv_rdata*)(rr->rdata))->weight);
-                                               break;
-                                       case T_NAPTR:
-                                               rpc->printf(ctx, "%srr order: %d", SPACE_FORMAT,
-                                                                       ((struct naptr_rdata*)(rr->rdata))->order);
-                                               rpc->printf(ctx, "%srr preference: %d", SPACE_FORMAT,
-                                                                       ((struct naptr_rdata*)(rr->rdata))->pref);
-                                               s.s = ((struct naptr_rdata*)(rr->rdata))->flags;
-                                               s.len = ((struct naptr_rdata*)(rr->rdata))->flags_len;
-                                               rpc->printf(ctx, "%srr flags: %.*s", SPACE_FORMAT,
-                                                                                       s.len, s.s);
-                                               s.s=((struct naptr_rdata*)(rr->rdata))->services;
-                                               s.len=((struct naptr_rdata*)(rr->rdata))->services_len;
-                                               rpc->printf(ctx, "%srr service: %.*s", SPACE_FORMAT,
-                                                                                       s.len, s.s);
-                                               s.s = ((struct naptr_rdata*)(rr->rdata))->regexp;
-                                               s.len = ((struct naptr_rdata*)(rr->rdata))->regexp_len;
-                                               rpc->printf(ctx, "%srr regexp: %.*s", SPACE_FORMAT,
-                                                                                       s.len, s.s);
-                                               s.s = ((struct naptr_rdata*)(rr->rdata))->repl;
-                                               s.len = ((struct naptr_rdata*)(rr->rdata))->repl_len;
-                                               rpc->printf(ctx, "%srr replacement: %.*s", 
-                                                                                       SPACE_FORMAT, s.len, s.s);
-                                               break;
-                                       case T_CNAME:
-                                               rpc->printf(ctx, "%srr name: %s", SPACE_FORMAT,
-                                                                       ((struct cname_rdata*)(rr->rdata))->name);
-                                               break;
-                                       default:
-                                               rpc->printf(ctx, "%sresource record: unknown",
-                                                                                       SPACE_FORMAT);
-                               }
-                               rpc->printf(ctx, "%srr expires in (s): %d", SPACE_FORMAT,
-                                                               (s_ticks_t)(rr->expire-now)<0?-1 : 
-                                                               TICKS_TO_S(rr->expire-now));
-                               rpc->printf(ctx, "%srr error flags: %d", SPACE_FORMAT, 
-                                                               rr->err_flags);
-                       }
+                       rpc->printf(ctx, "{\n");
+                       dns_cache_print_entry(rpc, ctx, e);
                        rpc->printf(ctx, "}");
                }
        }
@@ -3616,6 +3756,7 @@ static struct dns_hash_entry *dns_cache_clone_entry(struct dns_hash_entry *e,
        struct dns_rr *rr, *last_rr, *new_rr;
        int size, rounded_size, rr_size;
        ticks_t now;
+       int i;
 
        now=get_ticks_raw();
        size = e->total_size;
@@ -3635,6 +3776,9 @@ static struct dns_hash_entry *dns_cache_clone_entry(struct dns_hash_entry *e,
                        case T_NAPTR:
                                rr_size = ROUND_POINTER(sizeof(struct dns_rr));
                                break;
+                       case T_TXT:
+                               rr_size = ROUND_POINTER(sizeof(struct dns_rr));
+                               break;
                        default:
                                LOG(L_ERR, "ERROR: dns_cache_clone_entry: type %d not "
                                                        "supported\n", e->type);
@@ -3692,6 +3836,13 @@ static struct dns_hash_entry *dns_cache_clone_entry(struct dns_hash_entry *e,
                        ((struct naptr_rdata*)rr->rdata)->repl =
                                translate_pointer((char*)new, (char*)e,
                                        ((struct naptr_rdata*)rr->rdata)->repl);
+               }else if (e->type == T_TXT){
+                       /* there are pointers inside the TXT structure */
+                       for (i=0; i<((struct txt_rdata*)rr->rdata)->cstr_no; i++){
+                               ((struct txt_rdata*)rr->rdata)->txt[i].cstr=
+                                       translate_pointer((char*) new, (char*) e,
+                                               ((struct txt_rdata*)rr->rdata)->txt[i].cstr);
+                       }
                }
        }
 
@@ -3763,6 +3914,7 @@ static void dns_cache_add_record(rpc_t* rpc, void* ctx, unsigned short type)
                break;
        case T_CNAME:
        case T_NAPTR:
+       case T_TXT:
                rpc->fault(ctx, 400, "not implemented");
                return;
        default:
@@ -3980,6 +4132,37 @@ static void dns_cache_delete_record(rpc_t* rpc, void* ctx, unsigned short type)
 }
 
 
+/* performs  a dns lookup over rpc */
+void dns_cache_rpc_lookup(rpc_t* rpc, void* ctx)
+{
+       struct dns_hash_entry *e;
+       str name;
+       str type;
+       int t;
+
+       if (!cfg_get(core, core_cfg, use_dns_cache)){
+               rpc->fault(ctx, 500, "dns cache support disabled (see use_dns_cache)");
+               return;
+       }
+       
+       if (rpc->scan(ctx, "SS", &type, &name) < 1)
+               return;
+       t=dns_get_type(&type);
+       if (t<0){
+               rpc->fault(ctx, 400, "Invalid type");
+               return;
+       }
+       e=dns_get_entry(&name, t);
+       if (e==0){
+               rpc->fault(ctx, 400, "Not found");
+               return;
+       }
+       dns_cache_print_entry(rpc, ctx, e);
+       dns_hash_put(e);
+}
+
+
+
 /* wrapper functions for adding and deleting records */
 void dns_cache_add_a(rpc_t* rpc, void* ctx)
 {
@@ -4017,6 +4200,24 @@ void dns_cache_delete_srv(rpc_t* rpc, void* ctx)
 }
 
 
+void dns_cache_delete_naptr(rpc_t* rpc, void* ctx)
+{
+       dns_cache_delete_record(rpc, ctx, T_NAPTR);
+}
+
+
+void dns_cache_delete_cname(rpc_t* rpc, void* ctx)
+{
+       dns_cache_delete_record(rpc, ctx, T_CNAME);
+}
+
+
+void dns_cache_delete_txt(rpc_t* rpc, void* ctx)
+{
+       dns_cache_delete_record(rpc, ctx, T_TXT);
+}
+
+
 
 #ifdef DNS_WATCHDOG_SUPPORT
 /* sets the DNS server states */
index d4135bb..924323d 100644 (file)
@@ -1,14 +1,14 @@
 /**
- * \mainpage SER Development Documentation
+ * \mainpage The SIP Router Development Documentation
  *
- * The development documentation for SER consists of annotated and documented
+ * This development documentation contains annotated and documented
  * source files. For the sake of clarity the documentation is split into the
  * following groups:
  *
  * \section db_layer Database Abstraction Layer
  *
  * \ref db_api Database Abstraction Layer is a group of data structures and functions that
- * are used by all SER modules that need to access a database.
+ * are used by all SIP Router modules that need to access a database.
  *
- * \section ser_modules SER Modules
+ * \section sr_modules SIP Router Modules
  */
index ace2d78..b5bfdb8 100644 (file)
--- a/