| @ -0,0 +1,84 @@ | |||
| version: 2 | |||
| workflows: | |||
| version: 2 | |||
| build_branch: | |||
| jobs: | |||
| - build_centos7 | |||
| build_release: | |||
| jobs: | |||
| - build_centos7: | |||
| filters: | |||
| tags: | |||
| only: /^\d+\.\d+\.\d+$/ | |||
| branches: | |||
| ignore: /.*/ | |||
| jobs: | |||
| build_centos7: | |||
| docker: | |||
| - image: offical2600hz/metapackager:1.0-centos-7 | |||
| user: circleci | |||
| shell: /bin/bash --login | |||
| working_directory: /home/circleci/2600hz/the_app | |||
| environment: | |||
| CIRCLE_ARTIFACTS: /tmp/circleci-artifacts | |||
| CIRCLE_TEST_REPORTS: /tmp/circleci-test-results | |||
| BASH_ENV: "/home/circleci/2600hz/.bashrc" | |||
| BUILD_ROOT: "/home/circleci/2600hz/packager" | |||
| CORE_ROOT: "/home/circleci/2600hz/the_app" | |||
| BUILD_SOURCES: "/home/circleci/2600hz/packager/SOURCES" | |||
| BUILD_RPMS: "/home/circleci/2600hz/packager/RPMS" | |||
| APP_DIR: "/home/circleci/2600hz/the_app" | |||
| steps: | |||
| - checkout | |||
| - run: | |||
| name: Setting up Directories | |||
| command: | | |||
| APP=${CIRCLE_PROJECT_REPONAME#meta-} | |||
| echo -e "export APP=${APP}\n" >> $BASH_ENV | |||
| - run: | |||
| name: Generating version info | |||
| command: | | |||
| cd $BUILD_ROOT | |||
| VERSION=$(./version) | |||
| RELEASE=$(./release) | |||
| PACKAGE_NAME=$(./package_name) | |||
| echo "export PACKAGE_NAME=${PACKAGE_NAME}" >> $BASH_ENV | |||
| echo "export VERSION=${VERSION}" >> $BASH_ENV | |||
| echo "export RELEASE=${RELEASE}" >> $BASH_ENV | |||
| PACKAGE_NAME=$(./package_name) | |||
| echo "export PACKAGE_NAME=${PACKAGE_NAME}" >> $BASH_ENV | |||
| echo "build version for ${PACKAGE_NAME} version: ${VERSION} release: ${RELEASE}" | |||
| - run: | |||
| name: Generating CHANGELOG and VERSION files | |||
| command: | | |||
| cd $BUILD_ROOT | |||
| echo " - generate build version and changelog" | |||
| ./package_docs | |||
| - run: | |||
| name: Preparing source for packaging | |||
| command: | | |||
| echo " - preparing source" | |||
| cp -R ${APP_DIR}/* ${BUILD_SOURCES}/ | |||
| cd $BUILD_SOURCES | |||
| echo " - removing files that should not be packaged in the source tar" | |||
| rm -rf ${BUILD_SOURCES}/.??* | |||
| rm -rf ${BUILD_SOURCES}/doc* | |||
| rm -rf ${BUILD_SOURCES}/*.md | |||
| echo " - creating the source tar" | |||
| cd $BUILD_ROOT | |||
| ARTIFACTS_NAME=${PACKAGE_NAME}-${VERSION} | |||
| mkdir -p ${ARTIFACTS_NAME} | |||
| cp -r ${BUILD_SOURCES}/* ${ARTIFACTS_NAME}/. | |||
| tar -cf ${ARTIFACTS_NAME}.tar ${ARTIFACTS_NAME} | |||
| cp ${ARTIFACTS_NAME}.tar ${BUILD_SOURCES}/. | |||
| - run: | |||
| name: Building package | |||
| command: | | |||
| cd $BUILD_ROOT | |||
| ./build | |||
| - store_artifacts: | |||
| path: /home/circleci/2600hz/packager/RPMS | |||
| @ -0,0 +1,86 @@ | |||
| name: kazoo-configs-kamailio | |||
| base_branch: origin/4.3 | |||
| base_core: null | |||
| template: spec.tmpl | |||
| package: | |||
| centos7: | |||
| name: kazoo-configs-kamailio | |||
| group: Productivity/Telephony | |||
| license: MPL1.1 | |||
| build_arch: noarch | |||
| build_requires: | |||
| - rpm-build | |||
| summary: Kazoo specific configuration for Kamailio | |||
| description: | | |||
| The Kazoo platform uses Kamailio to provide SIP services | |||
| as well as dispatch requests to FreeSWITCH. This package | |||
| is an elaborate Kamailio configuration based on 'roles' that | |||
| configure and perform these actions. If you need help you | |||
| can contact us via the dev mailing list or on IRC at #2600hz | |||
| on FreeNode. | |||
| dist: .el7.centos | |||
| requires: | |||
| sudo: {} | |||
| source: '%{_build_tar}' | |||
| prep: '%setup -q' | |||
| install: | | |||
| mkdir -p %{buildroot}/etc/kazoo | |||
| cp -r kamailio %{buildroot}/etc/kazoo | |||
| cp CHANGELOG VERSION %{buildroot}/etc/kazoo/kamailio | |||
| chmod +x %{buildroot}/etc/kazoo/kamailio/db_scripts/*.sh | |||
| find %{buildroot}/etc/kazoo/kamailio -type f > filelist.txt | |||
| sed -i 's#%{buildroot}##g' filelist.txt | |||
| to_replace="local.cfg tls.cfg" | |||
| for NOREPLACE in ${to_replace} | |||
| do | |||
| sed -i "s!/etc/kazoo/kamailio/$NOREPLACE!%config(noreplace) /etc/kazoo/kamailio/$NOREPLACE!g" filelist.txt | |||
| done | |||
| cat filelist.txt | |||
| mkdir -p %{buildroot}/usr/sbin | |||
| cp -r system/sbin/* %{buildroot}/usr/sbin | |||
| chmod +x %{buildroot}/usr/sbin/* | |||
| mkdir -p %{buildroot}/etc/rsyslog.d | |||
| rm -rf system/rsyslog.d/1-default-config-override.conf | |||
| rm -rf system/rsyslog.d/5-rate-limits.conf | |||
| cp -r system/rsyslog.d/*.conf %{buildroot}/etc/rsyslog.d | |||
| mkdir -p %{buildroot}/etc/logrotate.d | |||
| cp -r system/logrotate.d/*.conf %{buildroot}/etc/logrotate.d | |||
| mkdir -p %{buildroot}/etc/security/limits.d | |||
| cp -r system/security/limits.d/*.conf %{buildroot}/etc/security/limits.d | |||
| mkdir -p %{buildroot}/usr/lib/systemd/system | |||
| cp system/systemd/* %{buildroot}/usr/lib/systemd/system | |||
| files: | |||
| doc: | |||
| - CHANGELOG | |||
| - VERSION | |||
| list: filelist.txt | |||
| dir: /etc/kazoo/kamailio | |||
| config: | |||
| - mode: noreplace | |||
| path: /etc/rsyslog.d/*kamailio* | |||
| - mode: noreplace | |||
| path: /etc/logrotate.d/*kamailio* | |||
| - mode: noreplace | |||
| path: /etc/security/limits.d/*kamailio* | |||
| path: | |||
| - /usr/sbin/kazoo-kamailio | |||
| - /usr/lib/systemd/system/kazoo-kamailio.service | |||
| post: systemctl -q enable kazoo-kamailio.service | |||
| preun: '%{?systemd_preun kazoo-kamailio.service}' | |||
| postun: '%{?systemd_postun kazoo-kamailio.service}' | |||
| url: 'http://www.2600hz.org' | |||
| vendor: 2600Hz | |||
| metapackage: | |||
| - | |||
| name: meta-kazoo-kamailio | |||
| package: kazoo-configs-kamailio | |||
| type: required | |||
| branch: '4.3' | |||
| @ -0,0 +1,115 @@ | |||
| ## Notes on upgrading to Kamailio 5.5 and moving to Postgres backend. | |||
| Thus removing the dependency on KazooDB which is closed source. | |||
| First completely remove the current installation | |||
| ``` | |||
| Removing existing kazoo-kamailo: | |||
| yum remove kazoo-kamailio | |||
| yum remove kamailio | |||
| yum remove kazoo-configs-kamailio | |||
| rm -rf /etc/kazoo | |||
| ``` | |||
| Next install the lastest Kamailio (currently 5.5.0) | |||
| ``` | |||
| yum -y install yum-utils | |||
| yum-config-manager --add-repo https://rpm.kamailio.org/centos/kamailio.repo | |||
| yum install git kamailio kamailio-kazoo kamailio-outbound kamailio-presence kamailio-tls kamailio-utils kamailio-uuid kamailio-websocket kamailio-xmpp kamailio-postgresql | |||
| ``` | |||
| Now install latest postgres (currently 12.7) | |||
| ``` | |||
| # Install the repository RPM: | |||
| sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-6-x86_64/pgdg-redhat-repo-latest.noarch.rpm | |||
| sudo yum install -y postgresql12-server | |||
| /usr/pgsql-12/bin/postgresql-12-setup initdb | |||
| sudo chkconfig postgresql-12 on | |||
| sudo service postgresql-12 start | |||
| ``` | |||
| Create Kamailio DB | |||
| ``` | |||
| su - postgres -c '/usr/pgsql-12/bin/createdb kamailio' | |||
| ``` | |||
| Add DB user and grant privileges | |||
| ``` | |||
| sudo su - postgres -c psql | |||
| CREATE USER kamailio WITH PASSWORD 'kamailio'; | |||
| GRANT ALL privileges on database kamailio to kamailio; | |||
| ``` | |||
| Modify default postgres authentication to allow kamailio access | |||
| ``` | |||
| vi /var/lib/pgsql/12/data/pg_hba.conf | |||
| # "local" is for Unix domain socket connections only | |||
| local all all password | |||
| # IPv4 local connections: | |||
| host all all 127.0.0.1/32 password | |||
| # IPv6 local connections: | |||
| host all all ::1/128 password | |||
| ``` | |||
| Increase the max number of connections and shared memory | |||
| ``` | |||
| vi /var/lib/pgsql/12/data/postgresql.conf | |||
| shared_buffers = 256MB | |||
| max_connections = 500 | |||
| ``` | |||
| Restart postgres and check kamailio access to DB | |||
| ``` | |||
| systemctl restart postgresql-12 | |||
| psql -U kamailio -d postgres://kamailio:kamailio@127.0.0.1/kamailio | |||
| ``` | |||
| Get the postgres kamailio configs: | |||
| ``` | |||
| git clone https://github.com/kageds/kazoo-configs-kamailio /etc/kazoo | |||
| cd /etc/kazoo/kamailio | |||
| git checkout 4.3-postgres | |||
| ``` | |||
| Initialize the kamailio database with all the required tables: | |||
| ``` | |||
| psql -U kamailio -d postgres://kamailio:kamailio@127.0.0.1/kamailio -f /etc/kazoo/kamailio/db_scripts/kamailio_initdb_postgres.sql | |||
| ``` | |||
| Notice that the backend DB in local.cfg is now postgres | |||
| ``` | |||
| #!trydef KZ_DB_MODULE postgres | |||
| #!substdef "!KAMAILIO_DBMS!postgres!g" | |||
| #!substdef "!KAZOO_DB_URL!postgres://kamailio:kamailio@127.0.0.1/kamailio!g" | |||
| ``` | |||
| Tell kamailio where the configuration files are | |||
| ``` | |||
| vi /etc/sysconfig/kamailio | |||
| # | |||
| # Kamailio startup options | |||
| # | |||
| # Amount of shared memory to allocate for the running Kamailio server (in Mb) | |||
| #SHM_MEMORY=64 | |||
| # Amount of per-process (package) memory to allocate for Kamailio (in Mb) | |||
| #PKG_MEMORY=4 | |||
| # Enable the server to leave a core file when it crashes. | |||
| # Set this to 'yes' to enable kamailio to leave a core file when it crashes | |||
| # or 'no' to disable this feature. This option is case sensitive and only | |||
| # accepts 'yes' and 'no' and only in lowercase letters. | |||
| # On some systems (e.g. Ubuntu 6.10, Debian 4.0) it is necessary to specify | |||
| # a directory for the core files to get a dump. Look into the kamailio | |||
| # init file for an example configuration. | |||
| DUMP_CORE=no | |||
| CFGFILE=/etc/kazoo/kamailio/kamailio.cfg | |||
| ``` | |||
| TEMP: Patch the kazoo module | |||
| [https://github.com/kamailio/kamailio/pull/2786] | |||
| ``` | |||
| cp /etc/kazoo/kazoo_module/kazoo.so /usr/lib64/kamailio/modules/kazoo.so | |||
| ``` | |||
| Start kamailio (NOT kazoo-kamailio) | |||
| ``` | |||
| systemctl enable kamailio | |||
| systemctl start kamailio | |||
| ``` | |||
| @ -0,0 +1,130 @@ | |||
| route[AUTH] | |||
| { | |||
| if (!is_method("INVITE|MESSAGE|REFER")) { | |||
| return; | |||
| } | |||
| #!ifdef DISPATCHER_ROLE | |||
| if (!isflagset(FLAG_INTERNALLY_SOURCED)) { | |||
| route(SETUP_AUTH_HEADERS); | |||
| } | |||
| #!endif | |||
| } | |||
| route[AUTH_HEADERS] | |||
| { | |||
| remove_hf_re("^X-"); | |||
| if (!is_method("INVITE|MESSAGE|REFER")) { | |||
| return; | |||
| } | |||
| xavp_params_implode("hf", "$var(outx)"); | |||
| $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); | |||
| $var(c) = $(var(out){param.count}); | |||
| xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); | |||
| while($var(c) > 0) { | |||
| $var(idx) = $var(c) - 1; | |||
| xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); | |||
| append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); | |||
| $var(c) = $var(c) - 1; | |||
| } | |||
| } | |||
| route[AUTH_HEADERS_JSON] | |||
| { | |||
| xavp_params_implode("hf", "$var(outx)"); | |||
| $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); | |||
| $var(c) = $(var(out){param.count}); | |||
| $var(headers_json) = ""; | |||
| $var(sep) = ""; | |||
| xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); | |||
| while($var(c) > 0) { | |||
| $var(idx) = $var(c) - 1; | |||
| xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); | |||
| append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); | |||
| $var(headers_json) = $_s($var(headers_json)$var(sep)"$(var(out){param.name,$var(idx)})" : "$(var(out){param.valueat,$var(idx)}{s.unescape.param})"); | |||
| $var(c) = $var(c) - 1; | |||
| $var(sep) = " , "; | |||
| } | |||
| $var(headers_json) = $_s({ $var(headers_json) }); | |||
| } | |||
| route[SETUP_AUTH_HEADERS] | |||
| { | |||
| $xavp(hf=>X-AUTH-IP) = $si; | |||
| $xavp(hf[0]=>X-AUTH-PORT) = $sp; | |||
| #!ifdef REGISTRAR_ROLE | |||
| $avp(is_registered) = "false"; | |||
| $xavp(regcfg=>match_received) = $su; | |||
| if (registered("location","$fu", 2, 1) != 1) return; | |||
| $avp(is_registered) = "true"; | |||
| #!ifdef WITH_AUTH_TOKEN | |||
| route(AUTH_TOKEN); | |||
| #!else | |||
| route(AUTH_CCVS); | |||
| #!endif | |||
| #!endif | |||
| } | |||
| #!ifdef REGISTRAR_ROLE | |||
| route[AUTH_TOKEN] | |||
| { | |||
| if($(xavp(ulattrs=>token){s.len}) > 0) { | |||
| $xavp(hf[0]=>X-AUTH-Token) = $xavp(ulattrs=>token); | |||
| } else { | |||
| if($(xavp(ulattrs=>Authorizing-ID){s.len}) > 0 && $(xavp(ulattrs=>Account-ID){s.len})) { | |||
| $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID})); | |||
| } | |||
| } | |||
| } | |||
| route[AUTH_CCVS] | |||
| { | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0 && $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID})); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Account-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Authorizing-Type) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Authorizing-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Username}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Username) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Username}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Account-Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Account-Name) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.escape.param}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Presence-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Owner-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}); | |||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID}{s.len}) > 0) | |||
| $xavp(hf[0]=>X-ecallmgr_Hotdesk-Current-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID}); | |||
| } | |||
| #!endif | |||
| @ -0,0 +1,23 @@ | |||
| ## to be enhanced | |||
| route[AUTHORIZATION_CHECK] | |||
| { | |||
| if (!is_method("MESSAGE|NOTIFY|SUBSCRIBE|PUBLISH")) | |||
| return; | |||
| if(has_totag()) | |||
| return; | |||
| if (isflagset(FLAG_INTERNALLY_SOURCED)) | |||
| return; | |||
| if (isflagset(FLAG_TRUSTED_SOURCE)) | |||
| return; | |||
| $xavp(regcfg=>match_received) = $su; | |||
| if(!(registered("location", "$fu", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1)) { | |||
| xlog("L_INFO", "$ci|log|not authorized $fu from $si:$sp\n"); | |||
| send_reply("503", "Not Registered"); | |||
| exit; | |||
| } | |||
| } | |||
| @ -0,0 +1,39 @@ | |||
| ######## BLOCK BY IP[PORT] ######## | |||
| #!trydef KZ_BLOCK_ENABLE 1 | |||
| #!trydef KZ_BLOCK_LOG_LEVEL 1 | |||
| #!trydef KZ_BLOCK_LOG_BUFFER 0 | |||
| #!trydef KZ_BLOCK_DRY_RUN 0 | |||
| #!ifdef KZ_BLOCK_COLD_CACHE | |||
| #!substdef "!BLOCK_S_WARM_CACHE!!g" | |||
| #!else | |||
| #!substdef "!BLOCK_S_WARM_CACHE!dbtable=block_cache;dbmode=1;!g" | |||
| #!endif | |||
| modparam("htable", "htable", "block=>size=8;BLOCK_S_WARM_CACHE") | |||
| modparam("statistics","variable", "block:blocked_requests") | |||
| kazoo.block_enable = KZ_BLOCK_ENABLE descr "enable block processing" | |||
| kazoo.block_log_level = KZ_BLOCK_LOG_LEVEL descr "block log level" | |||
| kazoo.block_log_buffer = KZ_BLOCK_LOG_BUFFER descr "log the received buffer" | |||
| kazoo.block_dry_run = KZ_BLOCK_DRY_RUN descr "log but keep processing" | |||
| ## global param to enable route | |||
| received_route_mode=1 | |||
| event_route[core:msg-received] | |||
| { | |||
| if($sel(cfg_get.kazoo.block_enable) == 1) { | |||
| if($sht(block=>$rcv(srcip)) || $sht(block=>$rcv(srcip)::$rcv(srcport))) { | |||
| if($sel(cfg_get.kazoo.block_log_buffer) == 1) { | |||
| xlog("$(sel(cfg_get.kazoo.block_log_level){s.int})", "|block|request from [$rcv(srcip):$rcv(srcport)] to [$rcv(rcvip):$rcv(rcvport)] was blocked => [$rcv(buf)]\n"); | |||
| } else { | |||
| xlog("$(sel(cfg_get.kazoo.block_log_level){s.int})", "|block|request from [$rcv(srcip):$rcv(srcport)] to [$rcv(rcvip):$rcv(rcvport)] was blocked\n"); | |||
| } | |||
| if($sel(cfg_get.kazoo.block_dry_run) == 0) { | |||
| drop; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1,14 @@ | |||
| #### db_kazoo module ### | |||
| #!trydef KZ_DB_HOOK_TRACE 1 | |||
| #!trydef KZ_DB_TRACE 0 | |||
| #!trydef KZ_DB_TRACE_LOG_LEVEL 3 | |||
| #!trydef KZ_DB_TRACE_FILTER 110 | |||
| loadmodule "db_kazoo.so" | |||
| modparam("db_kazoo", "trace_hook", KZ_DB_HOOK_TRACE) | |||
| modparam("db_kazoo", "trace_enable", KZ_DB_TRACE) | |||
| modparam("db_kazoo", "trace_log_level", KZ_DB_TRACE_LOG_LEVEL) | |||
| modparam("db_kazoo", "trace_filter", KZ_DB_TRACE_FILTER) | |||
| include_file "db_queries_kazoo.cfg" | |||
| @ -0,0 +1,4 @@ | |||
| #### db_mysql module ### | |||
| loadmodule "db_mysql.so" | |||
| include_file "db_queries_mysql.cfg" | |||
| @ -0,0 +1,4 @@ | |||
| #### db_postgres module ### | |||
| loadmodule "db_postgres.so" | |||
| include_file "db_queries_postgres.cfg" | |||
| @ -1,15 +1,33 @@ | |||
| ####### Database queries ######## | |||
| #!substdef "!KZQ_CHECK_MEDIA_SERVER_INSERT!insert into dispatcher (setid, destination) select \$var(SetId), \"\$var(MediaUrl)\" where not exists(select * from dispatcher where destination = \"\$var(MediaUrl)\")!g" | |||
| #!substdef "!KZQ_COUNT_ALL_SUBSCRIBERS!select a.event, count(distinct watcher_username || \"@\" || watcher_domain) count_unique, count(*) count from event_list a, active_watchers b where b.event = a.event group by a.event!g" | |||
| #!substdef "!KZQ_CHECK_MEDIA_SERVER_INSERT!insert into dispatcher (setid, destination, flags, attrs, description) select \$var(SetId), \"\$var(MediaUrl)\", \$var(flags), \"\$var(attrs)\", \"added by nodes role\" where not exists(select * from dispatcher where destination = \"\$var(MediaUrl)\")!g" | |||
| #!substdef "!KZQ_COUNT_ALL_SUBSCRIBERS!select a.event, count(distinct watcher_uri) count_unique, count(*) count from event_list a left outer join active_watchers b on a.event = b.event group by a.event!g" | |||
| #!substdef "!KZQ_COUNT_PRESENTITIES!select event, (select count(*) from presentity b where username = \"\$(var(payload){kz.json,From}{uri.user})\" and domain = \"\$(var(payload){kz.json,From}{uri.domain})\" and b.event = a.event) count from event_list a!g" | |||
| #!substdef "!KZQ_COUNT_SUBSCRIBERS!select event, (select count(*) from active_watchers b where presentity_uri = \"\$var(presentity)\" and b.event = a.event) count from event_list a!g" | |||
| #!substdef "!KZQ_COUNT_SUBSCRIBERS!select event, (select count(*) from active_watchers b where presentity_uri = \"\$var(presentity)\" and b.event = a.event) count from event_list a union all select \"self\", count(distinct callid) from presentities where presentity_uri = \"\$var(presentity)\" and callid <> \"\$var(callid)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||
| #!substdef "!KZQ_EVENT_PRESENCE_RESET_DELETE!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\" and username = \"\$(kzE{kz.json,Username})\"!g" | |||
| #!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE1!delete from active_watchers where callid = \"\$ci\"!g" | |||
| #!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE2!delete from active_watchers where watcher_username=\"\$fU\" and presentity_uri=\"\$var(presentity_uri)\" and to_user=\"\$tU\" and watcher_domain=\"\$fd\" and event=\"\$hdr(Event)\"!g" | |||
| #!substdef "!KZQ_RESET_ACCOUNT_DELETE!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\"!g" | |||
| #!substdef "!KZQ_RESET_ACCOUNT_UPDATE!update active_watchers set expires = \$TS where watcher_domain=\"\$(kzE{kz.json,Realm})\"!g" | |||
| #!substdef "!KZQ_RESET_PUBLISHER_UPDATE!update active_watchers set expires = \$TS where id in (select b.id from presentity a inner join active_watchers b on a.username = b.to_user and a.domain = b.to_domain and a.event = b.event where a.sender = \"\$var(MediaUrl)\")!g" | |||
| #!substdef "!KZQ_PRESENCE_SEARCH_DETAIL!select * from active_watchers_log where presentity_uri = \"\$var(presentity_uri)\"!g" | |||
| #!substdef "!KZQ_PRESENCE_SEARCH_SUMMARY!select * from active_watchers where watcher_domain = \"\$var(Domain)\"!g" | |||
| #!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE2!delete from active_watchers where presentity_uri=\"\$var(presentity_uri)\" and event=\"\$hdr(Event)\" and watcher_username=\"\$fU\" and to_user=\"\$tU\" and watcher_domain=\"\$fd\"!g" | |||
| #!substdef "!KZQ_PRESENCE_SEARCH_SUMMARY!select * from active_watchers where to_domain = \"\$var(Domain)\"!g" | |||
| #!substdef "!KZQ_PRESENCE_SEARCH_DETAIL!select a.*, b.time, b.result, b.sent_msg, b.received_msg from active_watchers a left outer join active_watchers_log b on a.presentity_uri = b.presentity_uri and a.event = b.event and a.callid = b.callid where a.presentity_uri = \"\$var(presentity_uri)\" !g" | |||
| #!substdef "!KZQ_HAS_PRESENTITY!select count(*) as count from presentity where username = \"\$subs(to_user)\" and domain = \"\$subs(to_domain)\" and event = \"\$subs(event)\"!g" | |||
| #!substdef "!KZQ_REPLACE_WATCHERS_LOG!REPLACE INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES (\"\$subs(uri)\", \"\$subs(watcher_username)\", \"\$subs(watcher_domain)\", \"\$subs(event)\",\"\$subs(callid)\",\"\$subs(to_user)\",\"\$subs(to_domain)\", '\$(subs(user_agent){s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})', \$TS, \$notify_reply(\$rs), '\$(mb{s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})', '\$(notify_reply(\$mb){s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})')!g" | |||
| # # #!substdef "!KZQ_RESET_PUBLISHER_UPDATE!update active_watchers set expires = \$TS where id in (select b.id from presentity a inner join active_watchers b on a.username = b.to_user and a.domain = b.to_domain and a.event = b.event where a.sender = \"\$var(MediaUrl)\")!g" | |||
| #!substdef "!KZQ_RESET_PUBLISHER_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where sender = \"\$var(MediaUrl)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||
| #!substdef "!KZQ_PRESENCE_RESET!delete from presentity where sender = \"\$var(MediaUrl)\"!g" | |||
| # # #!substdef "!KZQ_RESET_ACCOUNT_UPDATE!update active_watchers set expires = \$TS where watcher_domain=\"\$(kzE{kz.json,Realm})\"!g" | |||
| #!substdef "!KZQ_RESET_ACCOUNT_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where domain=\"\$(kzE{kz.json,Realm})\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||
| #!substdef "!KZQ_RESET_ACCOUNT_RESET!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\"!g" | |||
| #!substdef "!KZQ_RESET_PUBLISHER_ZONE_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join wdispatcher c on a.sender = c.destination inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where zone = \"\$var(Zone)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||
| #!substdef "!KZQ_PRESENCE_ZONE_RESET!delete from presentity where id in(select a.id from presentities a join wdispatcher c on a.sender = c.destination where zone = \"\$var(Zone)\")!g" | |||
| #!substdef "!KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_EXPIRES!DELETE FROM active_watchers WHERE expires > 0 AND datetime(expires, 'unixepoch') < datetime('now', '-90 seconds')!g" | |||
| #!substdef "!KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_PRESENTITY!DELETE FROM ACTIVE_WATCHERS WHERE PRESENTITY_URI=\"\$subs(uri)\" AND EVENT=\"\$subs(event)\" AND FROM_USER = \"\$subs(from_user)\" AND FROM_DOMAIN=\"\$subs(from_domain)\" AND CALLID <> \"\$subs(callid)\"!g" | |||
| #!substdef "!KZQ_DELETE_FROM_PRESENTITY_WHERE_EXPIRES!DELETE FROM PRESENTITY WHERE expires > 0 AND datetime(expires, 'unixepoch') < datetime('now')!g" | |||
| #!substdef "!KZQ_DELETE_FROM_PRESENTITY_WHERE_DIALOG_TERMINATED!DELETE FROM PRESENTITY WHERE ID IN(select id from presentities where event = 'dialog' and state = 'terminated' and received < datetime('now', '-5 minutes'))!g" | |||
| @ -0,0 +1,46 @@ | |||
| #!/bin/sh | |||
| TEMP_DB_LOCATION=/tmp/db | |||
| TEMP_DB=${TEMP_DB_LOCATION}/kazoo.db | |||
| rm -rf ${TEMP_DB_LOCATION} | |||
| . $(dirname $0)/kazoodb-sql.sh --source-only | |||
| file=$(sql_db_prepare) | |||
| sql_setup $file ${TEMP_DB_LOCATION} | |||
| DB_VERSION=`KazooDB -db ${TEMP_DB} "select sum(table_version) from version;"` | |||
| DB_CURRENT_DB=${DB_LOCATION:-/etc/kazoo/kamailio}/kazoo.db | |||
| DB_CURRENT_VERSION=`KazooDB -db ${DB_CURRENT_DB} "select sum(table_version) from version;"` | |||
| if [[ $DB_CURRENT_VERSION -ne $DB_VERSION ]]; then | |||
| echo "db required version is ${DB_VERSION}, existing version is ${DB_CURRENT_VERSION}, applying diff" | |||
| KazooDB-diff --schema ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB} | |||
| KazooDB-diff --primarykey --table version ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB} | |||
| KazooDB-diff --primarykey --table event_list ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB} | |||
| fi | |||
| for VIEW in `ls ${DB_SCRIPT_DIR}/vw_*.sql`; do | |||
| filename=$(basename -- "$VIEW") | |||
| filename="${filename%.*}" | |||
| viewname=${filename#*_} | |||
| v1=$(KazooDB -db ${DB_CURRENT_DB} "select sql from sqlite_master where type='view' and name='$viewname'" 2> /dev/null | tr -d ' ' | md5sum | cut -d ' ' -f1) | |||
| v2=$(cat $VIEW | tr -d ' ' | md5sum | cut -d ' ' -f1) | |||
| if [[ "$v1" != "$v2" ]]; then | |||
| echo "rebuilding view $viewname" | |||
| KazooDB -db ${DB_CURRENT_DB} "drop view if exists $viewname;" | |||
| KazooDB -db ${DB_CURRENT_DB} < $VIEW | |||
| fi | |||
| done | |||
| if [ -f ${DB_SCRIPT_DIR}/db_extra_check.sql ]; then | |||
| . ${DB_SCRIPT_DIR}/db_extra_check.sql --source-only | |||
| do_db_extra_check; | |||
| fi | |||
| for INIT in `ls ${DB_SCRIPT_DIR}/db_init_*.sql`; do | |||
| KazooDB -db ${DB_CURRENT_DB} < $INIT | |||
| done | |||
| @ -1,104 +1,9 @@ | |||
| #!/bin/sh -e | |||
| ##################################################################################### | |||
| ## | |||
| ## If you want prepare SQL file for PostgreSQL or MySQL server, then need to execute | |||
| ## DB_ENGINE=postgres ./create-kazoodb-sql.sh | |||
| ## | |||
| ##################################################################################### | |||
| KAMAILIO_SHARE_DIR=${KAMAILIO_SHARE_DIR:-/usr/share/kamailio} | |||
| DB_ENGINE=${DB_ENGINE:-db_kazoo} | |||
| RESULTED_SQL=${RESULTED_SQL:-/tmp/kamailio_initdb.sql} | |||
| . $(dirname $0)/kazoodb-sql.sh --source-only | |||
| . $(dirname $0)/$DB_ENGINE-specific --source-only | |||
| sql_filelist() { | |||
| cat << EOF | |||
| acc-create.sql | |||
| lcr-create.sql | |||
| domain-create.sql | |||
| group-create.sql | |||
| permissions-create.sql | |||
| registrar-create.sql | |||
| usrloc-create.sql | |||
| msilo-create.sql | |||
| alias_db-create.sql | |||
| uri_db-create.sql | |||
| speeddial-create.sql | |||
| avpops-create.sql | |||
| auth_db-create.sql | |||
| pdt-create.sql | |||
| dialog-create.sql | |||
| dispatcher-create.sql | |||
| dialplan-create.sql | |||
| topos-create.sql | |||
| presence-create.sql | |||
| rls-create.sql | |||
| imc-create.sql | |||
| cpl-create.sql | |||
| siptrace-create.sql | |||
| domainpolicy-create.sql | |||
| carrierroute-create.sql | |||
| userblacklist-create.sql | |||
| htable-create.sql | |||
| purple-create.sql | |||
| uac-create.sql | |||
| pipelimit-create.sql | |||
| mtree-create.sql | |||
| sca-create.sql | |||
| mohqueue-create.sql | |||
| rtpproxy-create.sql | |||
| uid_auth_db-create.sql | |||
| uid_avp_db-create.sql | |||
| uid_domain-create.sql | |||
| uid_gflags-create.sql | |||
| uid_uri_db-create.sql | |||
| EOF | |||
| } | |||
| sql_all_header() { | |||
| cat << EOF | |||
| CREATE TABLE version ( | |||
| table_name VARCHAR(32) NOT NULL, | |||
| table_version INTEGER DEFAULT 0 NOT NULL, | |||
| CONSTRAINT version_table_name_idx UNIQUE (table_name) | |||
| ); | |||
| INSERT INTO version VALUES('version',1); | |||
| EOF | |||
| } | |||
| sql_all_extra_tables() { | |||
| cat << EOF | |||
| CREATE TABLE event_list ( event varchar(25) PRIMARY KEY NOT NULL); | |||
| INSERT INTO event_list VALUES('dialog'); | |||
| INSERT INTO event_list VALUES('presence'); | |||
| INSERT INTO event_list VALUES('message-summary'); | |||
| INSERT INTO version VALUES('event_list',1); | |||
| EOF | |||
| } | |||
| sql_all_footer() { | |||
| cat << EOF | |||
| COMMIT; | |||
| EOF | |||
| } | |||
| echo "Creating kamailio database init file in '$RESULTED_SQL'" | |||
| sql_db_pre_setup > $RESULTED_SQL | |||
| sql_all_header >> $RESULTED_SQL | |||
| sql_header >> $RESULTED_SQL | |||
| for i in $(sql_filelist); do | |||
| cat $KAMAILIO_SHARE_DIR/$DB_ENGINE/$i >> $RESULTED_SQL | |||
| done | |||
| sql_all_extra_tables >> $RESULTED_SQL | |||
| sql_extra_tables >> $RESULTED_SQL | |||
| sql_footer >> $RESULTED_SQL | |||
| sql_all_footer >> $RESULTED_SQL | |||
| sql_setup $RESULTED_SQL | |||
| file=$(sql_db_prepare) | |||
| echo "setting up kazoo db from init script $file" | |||
| sql_setup $file | |||
| exit 0 | |||
| @ -0,0 +1,34 @@ | |||
| do_db_extra_check() { | |||
| # location | |||
| if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from location where socket not like 'udp:%';" | |||
| fi | |||
| ##KazooDB -db ${DB_CURRENT_DB} "delete from location where expires > 0 and datetime(expires) < datetime('now', '-30 seconds');" | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from location_attrs where not exists(select id from location where ruid = location_attrs.ruid);" | |||
| ## presence | |||
| if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers where socket_info not like 'udp:%';" | |||
| fi | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers where expires > 0 and datetime(expires, 'unixepoch') < datetime('now', '-10 seconds');" | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where expires > 0 AND datetime(expires, 'unixepoch') < datetime('now', '-10 seconds');" | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities where state in('terminated','available'));" | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers_log where id in(select id from active_watchers_log a where not exists(select callid from active_watchers b where b.callid = a.callid and b.watcher_username = a.watcher_username and b.watcher_domain = a.watcher_domain));" | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities a where not exists(select * from active_watchers where presentity_uri = a.presentity_uri));" | |||
| ## notify watchers of pending calls | |||
| ## 'create temp table as' because it will be dropped as soon as we ended the session | |||
| KazooDB -db ${DB_CURRENT_DB} "drop table if exists tmp_probe;" | |||
| KazooDB -db ${DB_CURRENT_DB} "create table tmp_probe as select distinct a.event, a.presentity_uri, cast(2 as integer) action from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where state in('early', 'confirmed', 'onthephone', 'busy');" | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities where state in('early', 'confirmed', 'onthephone', 'busy'));" | |||
| ## keepalive | |||
| if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then | |||
| KazooDB -db ${DB_CURRENT_DB} "delete from keepalive where sockinfo NOT LIKE 'udp%';" | |||
| fi | |||
| KazooDB -db ${DB_CURRENT_DB} "update keepalive set selected = 0, time_sent = datetime('now') where selected < 3;" | |||
| } | |||
| @ -0,0 +1,14 @@ | |||
| CREATE TRIGGER if not exists active_watchers_watcher_uri_insert | |||
| AFTER INSERT ON active_watchers | |||
| FOR EACH ROW | |||
| BEGIN | |||
| UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id; | |||
| END; | |||
| CREATE TRIGGER if not exists active_watchers_watcher_uri_update | |||
| AFTER UPDATE ON active_watchers | |||
| FOR EACH ROW | |||
| WHEN OLD.watcher_username <> NEW.watcher_username OR OLD.watcher_domain <> NEW.watcher_domain | |||
| BEGIN | |||
| UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id; | |||
| END; | |||
| @ -0,0 +1,56 @@ | |||
| #!/bin/sh -e | |||
| KAMAILIO_SHARE_DIR=${KAMAILIO_SHARE_DIR:-/usr/share/kamailio} | |||
| DB_ENGINE=${DB_ENGINE:-db_kazoo} | |||
| RESULTED_SQL=${RESULTED_SQL:-/tmp/kamailio_initdb.sql} | |||
| . $(dirname $0)/$DB_ENGINE-specific --source-only | |||
| sql_filelist() { | |||
| echo `ls -A1 ${KAMAILIO_SHARE_DIR}/${DB_ENGINE}/*.sql | grep -v standard | tr '\n' '\0' | xargs -0 -n 1 basename | sort` | |||
| } | |||
| sql_all_header() { | |||
| cat << EOF | |||
| CREATE TABLE version ( | |||
| table_name VARCHAR(32) NOT NULL, | |||
| table_version INTEGER DEFAULT 0 NOT NULL, | |||
| PRIMARY KEY(table_name) | |||
| ); | |||
| INSERT INTO version VALUES('version',1); | |||
| EOF | |||
| } | |||
| sql_all_extra_tables() { | |||
| cat << EOF | |||
| CREATE TABLE event_list ( event varchar(25) PRIMARY KEY NOT NULL); | |||
| INSERT INTO event_list VALUES('dialog'); | |||
| INSERT INTO event_list VALUES('presence'); | |||
| INSERT INTO event_list VALUES('message-summary'); | |||
| INSERT INTO version VALUES('event_list',1); | |||
| EOF | |||
| } | |||
| sql_all_footer() { | |||
| cat << EOF | |||
| COMMIT; | |||
| EOF | |||
| } | |||
| sql_db_prepare() { | |||
| sql_db_pre_setup > $RESULTED_SQL | |||
| sql_all_header >> $RESULTED_SQL | |||
| sql_header >> $RESULTED_SQL | |||
| for i in $(sql_filelist); do | |||
| cat $KAMAILIO_SHARE_DIR/$DB_ENGINE/$i >> $RESULTED_SQL | |||
| done | |||
| sql_all_extra_tables >> $RESULTED_SQL | |||
| sql_extra_tables >> $RESULTED_SQL | |||
| sql_footer >> $RESULTED_SQL | |||
| sql_all_footer >> $RESULTED_SQL | |||
| echo "$RESULTED_SQL" | |||
| } | |||
| @ -0,0 +1,20 @@ | |||
| CREATE VIEW presentities as | |||
| select id, cast(printf("sip:%s@%s",username,domain) as varchar(64)) presentity_uri , | |||
| username, domain, event, cast(substr(etag, instr(etag,"@")+1) as varchar(64)) callid, | |||
| datetime(received_time, 'unixepoch') as received, | |||
| datetime(expires, 'unixepoch') as expire_date, | |||
| expires, cast(sender as varchar(30)) sender, | |||
| lower(cast( case when event = "dialog" | |||
| then substr(body, instr(BODY,"<state>")+7, instr(body,"</state>") - instr(body,"<state>") - 7) | |||
| when event = "presence" | |||
| then case when instr(body,"<dm:note>") == 0 | |||
| then replace(substr(body, instr(body,"<note>")+6, instr(body,"</note>") - instr(body,"<note>") - 6), " ", "") | |||
| else replace(substr(body, instr(body,"<dm:note>")+9, instr(body,"</dm:note>") - instr(body,"<dm:note>") - 9), " ", "") | |||
| end | |||
| when event = "message-summary" | |||
| then case when instr(body,"Messages-Waiting: yes") = 0 | |||
| then "Waiting" | |||
| else "Not-Waiting" | |||
| end | |||
| end as varchar(12))) state | |||
| from presentity | |||
| @ -0,0 +1,6 @@ | |||
| CREATE VIEW w_keepalive_contact as | |||
| select id, slot, selected, failed, case when instr(contact,";") > 0 | |||
| then substr(contact, 1, instr(contact,";")-1) | |||
| else contact | |||
| end as contact | |||
| from keepalive | |||
| @ -0,0 +1,6 @@ | |||
| CREATE VIEW w_location_contact as | |||
| select id, ruid, case when instr(contact,";") > 0 | |||
| then substr(contact, 1, instr(contact,";")-1) | |||
| else contact | |||
| end as contact | |||
| from location | |||
| @ -0,0 +1,6 @@ | |||
| CREATE VIEW w_watchers_contact as | |||
| select id, case when instr(contact,";") > 0 | |||
| then substr(contact, 1, instr(contact,";")-1) | |||
| else contact | |||
| end as contact | |||
| from active_watchers | |||
| @ -0,0 +1,6 @@ | |||
| CREATE VIEW wdispatcher as | |||
| select *, | |||
| cast(substr(attrs, instr(attrs, "zone=")+5, instr(attrs, ";profile")-instr(attrs, "zone=")-5) as varchar(20)) zone, | |||
| cast(substr(attrs, instr(attrs, "duid=")+5, instr(attrs, ";node")-instr(attrs, "duid=")-5) as integer) idx, | |||
| cast(substr(attrs, instr(attrs, "node=")+5) as varchar(50)) node | |||
| from dispatcher | |||
| @ -0,0 +1,88 @@ | |||
| ## NOTE: DO NOT CHANGE THIS FILE, EDIT local.cfg ## | |||
| ####### amqp defs ######## | |||
| #!ifndef AMQP_DEFAULTS_INCLUDED | |||
| #!define AMQP_DEFAULTS_INCLUDED | |||
| #!trydef MY_AMQP_MAX_CHANNELS 25 | |||
| #!trydef MY_AMQP_CONSUMER_PROCESSES 4 | |||
| #!trydef MY_AMQP_CONSUMER_WORKERS 16 | |||
| #!trydef MY_AMQP_HEARTBEATS 5 | |||
| #!ifndef MY_AMQP_ZONE | |||
| #!substdef "!MY_AMQP_ZONE!local!g" | |||
| #!endif | |||
| #!ifdef PRESENCE_ROLE | |||
| #!trydef MY_AMQP_PUA_MODE 1 | |||
| #!else | |||
| #!trydef MY_AMQP_PUA_MODE 0 | |||
| #!endif | |||
| #!ifndef MY_AMQP_URL | |||
| #!ifdef AMQP_URL1 | |||
| #!substdef "!MY_AMQP_URL!$def(AMQP_URL1)!g" | |||
| #!else | |||
| #!substdef "!MY_AMQP_URL!amqp://guest:guest@127.0.0.1:5672!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_SECONDARY_URL | |||
| #!ifdef AMQP_URL2 | |||
| #!substdef "!MY_AMQP_SECONDARY_URL!$def(AMQP_URL2)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_TERTIARY_URL | |||
| #!ifdef AMQP_URL3 | |||
| #!substdef "!MY_AMQP_TERTIARY_URL!$def(AMQP_URL3)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_QUATERNARY_URL | |||
| #!ifdef AMQP_URL4 | |||
| #!substdef "!MY_AMQP_QUATERNARY_URL!$def(AMQP_URL4)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_QUINARY_URL | |||
| #!ifdef AMQP_URL5 | |||
| #!substdef "!MY_AMQP_QUINARY_URL!$def(AMQP_URL5)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_SENARY_URL | |||
| #!ifdef AMQP_URL6 | |||
| #!substdef "!MY_AMQP_SENARY_URL!$def(AMQP_URL6)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_SEPTENARY_URL | |||
| #!ifdef AMQP_URL7 | |||
| #!substdef "!MY_AMQP_SEPTENARY_URL!$def(AMQP_URL7)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_OCTONARY_URL | |||
| #!ifdef AMQP_URL8 | |||
| #!substdef "!MY_AMQP_OCTONARY_URL!$def(AMQP_URL8)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_NONARY_URL | |||
| #!ifdef AMQP_URL9 | |||
| #!substdef "!MY_AMQP_NONARY_URL!$def(AMQP_URL9)!g" | |||
| #!endif | |||
| #!endif | |||
| #!ifndef MY_AMQP_DENARY_URL | |||
| #!ifdef AMQP_URL10 | |||
| #!substdef "!MY_AMQP_DENARY_URL!$def(AMQP_URL10)!g" | |||
| #!endif | |||
| #!endif | |||
| #!endif | |||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||
| @ -0,0 +1,306 @@ | |||
| ### DISPATCHER ROLE #### | |||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||
| #!trydef DISPATCHER_ALG 0 | |||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||
| ####### Dispatcher module ######## | |||
| loadmodule "dispatcher.so" | |||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||
| modparam("dispatcher", "flags", 2) | |||
| modparam("dispatcher", "use_default", 0) | |||
| modparam("dispatcher", "force_dst", 1) | |||
| modparam("dispatcher", "dst_avp", "$avp(ds_dst)") | |||
| modparam("dispatcher", "attrs_avp", "$avp(ds_attrs)") | |||
| modparam("dispatcher", "grp_avp", "$avp(ds_grp)") | |||
| modparam("dispatcher", "cnt_avp", "$avp(ds_cnt)") | |||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||
| modparam("dispatcher", "ds_ping_interval", 10) | |||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||
| #!import_file "dispatcher-network-params.cfg" | |||
| ## Dispatcher Groups: | |||
| ## 1 - Primary media servers | |||
| ## 2 - Backup media servers | |||
| ## 3 - Alternate media server IPs (used only for classification) | |||
| ## 10 - Presence servers (if not locally handled) | |||
| ## 20 - Registrar servers (if not locally handled) | |||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||
| ####### Dispatcher Logic ######## | |||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||
| { | |||
| #!import_file "dispatcher-network-classify.cfg" | |||
| if (is_myself("$ou")) { | |||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||
| } else { | |||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||
| setflag(FLAG_INTERNALLY_SOURCED); | |||
| } else { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||
| } | |||
| } | |||
| } | |||
| # Take the routes from dispatcher - hash over callid | |||
| # If prefered route defined, reorder the destionations | |||
| route[DISPATCHER_FIND_ROUTES] | |||
| { | |||
| $var(ds_primary_group) = $sel(cfg_get.kazoo.dispatcher_primary_group); | |||
| $var(ds_backup_group) = $sel(cfg_get.kazoo.dispatcher_secondary_group); | |||
| #!ifndef PRESENCE_ROLE | |||
| if (is_method("SUBSCRIBE")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||
| add_path(); | |||
| } | |||
| #!endif | |||
| #!ifndef REGISTRAR_ROLE | |||
| if (is_method("REGISTER")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||
| add_path(); | |||
| } | |||
| #!endif | |||
| #!ifdef PRESENCE_ROLE | |||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||
| #!endif | |||
| #!import_file "dispatcher-network-find.cfg" | |||
| $var(ds_group) = $var(ds_primary_group); | |||
| if (!ds_select_dst("$var(ds_primary_group)", "$sel(cfg_get.kazoo.dispatcher_algorithm)") || $(avp(ds_dst)[0]) == $null) { | |||
| # we selected from primary group, try again in backup group | |||
| if (!ds_select_dst("$var(ds_backup_group)", "$sel(cfg_get.kazoo.dispatcher_algorithm)") || $(avp(ds_dst)[0]) == $null) { | |||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||
| sl_send_reply("480", "All servers busy"); | |||
| exit; | |||
| } else { | |||
| $var(ds_group) = $var(ds_backup_group); | |||
| } | |||
| } | |||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||
| if ($sht(associations=>$var(user_source)) != $null) { | |||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||
| route(DISPATCHER_PREFERRED_ROUTE); | |||
| } | |||
| $sht(associations=>$var(user_source)) = $null; | |||
| } | |||
| $avp(ds_retries) = 0; | |||
| } | |||
| route[DISPATCHER_PREFERRED_ROUTE] | |||
| { | |||
| ###### | |||
| # check if the preferred route is active | |||
| ###### | |||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $avp(ds_dst)\n"); | |||
| return -1; | |||
| } | |||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||
| ###### | |||
| # filters current list from prefered route | |||
| # * saves the current list to temp avp removing the preferred route if it exists | |||
| # * resets current list | |||
| # * copies the temp back to list | |||
| # sets the prefered at top | |||
| # sets $du (destination) to prefered | |||
| ###### | |||
| $var(i) = 0; | |||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||
| if($(avp(ds_dst)[$var(i)]) != $var(prefered_route)) { | |||
| $avp(tmp_ds_dst) = $(avp(ds_dst)[$var(i)]); | |||
| } | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| $(avp(ds_dst)[*]) = $null; | |||
| $var(i) = 0; | |||
| while($(avp(tmp_ds_dst)[$var(i)]) != $null) { | |||
| $avp(ds_dst) = $(avp(tmp_ds_dst)[$var(i)]); | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| $avp(ds_dst) = $var(prefered_route); | |||
| $du = $var(prefered_route); | |||
| $(avp(tmp_ds_dst)[*]) = $null; | |||
| return 1; | |||
| } | |||
| route[DISPATCHER_NEXT_ROUTE] | |||
| { | |||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||
| $var(remaining) = $(sel(cfg_get.kazoo.dispatcher_max_retries){s.int}) - $avp(ds_retries); | |||
| if(ds_next_dst()) { | |||
| xlog("L_INFO", "$ci|log|remaining failed retry attempts: $var(remaining)\n"); | |||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| # reset the final reply timer | |||
| $avp(final_reply_timer) = 3; | |||
| # relay the request to the new media server | |||
| route(RELAY); | |||
| exit(); | |||
| } | |||
| } | |||
| event_route[dispatcher:dst-down] | |||
| { | |||
| xlog("L_WARNING", "Destination down: $ru\n"); | |||
| } | |||
| event_route[dispatcher:dst-up] | |||
| { | |||
| xlog("L_NOTICE", "Destination up: $ru\n"); | |||
| } | |||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||
| { | |||
| $var(check_media_server_ret) = 0; | |||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||
| $var(SetId) = 1; | |||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||
| $var(SetId) = 2; | |||
| } | |||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| #!import_file "dispatcher-custom-media-check.cfg" | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||
| $var(MediaUrlBack) = $var(MediaUrl); | |||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| $var(MediaUrl) = $var(MediaUrlBack); | |||
| } | |||
| } | |||
| } | |||
| return $var(check_media_server_ret); | |||
| } | |||
| route[DISPATCHER_RELOAD] | |||
| { | |||
| if($shv(dispatcher_reload) == 1) { | |||
| xlog("L_NOTICE", "reloading dispatcher table\n"); | |||
| ds_reload(); | |||
| }; | |||
| $shv(dispatcher_reload) = 0; | |||
| } | |||
| route[DISPATCHER_STATUS] | |||
| { | |||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||
| $var(i) = 0; | |||
| $var(ds_groups_json)=""; | |||
| $var(Sep1) = ""; | |||
| while($var(i) < $var(Sets)) { | |||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||
| $var(Sep2)=""; | |||
| $var(ds_group_json)=""; | |||
| $var(c) = 0; | |||
| while($var(c) < $var(SetCount)) { | |||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||
| $var(Sep2) = ","; | |||
| $var(c) = $var(c) + 1; | |||
| } | |||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||
| $var(Sep1)=", "; | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||
| @ -0,0 +1,309 @@ | |||
| ### DISPATCHER ROLE #### | |||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||
| #!trydef DISPATCHER_ALG 0 | |||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||
| #!trydef KZ_DISPATCHER_PRINT_ROUTES 1 | |||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||
| kazoo.dispatcher_print_routes = KZ_DISPATCHER_PRINT_ROUTES descr "should we log the selected routes" | |||
| ####### Dispatcher module ######## | |||
| loadmodule "dispatcher.so" | |||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||
| modparam("dispatcher", "flags", 2) | |||
| modparam("dispatcher", "use_default", 0) | |||
| modparam("dispatcher", "force_dst", 1) | |||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||
| modparam("dispatcher", "ds_ping_interval", 10) | |||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||
| modparam("dispatcher", "xavp_dst", "ds_dst") | |||
| modparam("dispatcher", "xavp_ctx", "ds_ctx") | |||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||
| ## Dispatcher Groups: | |||
| ## 1 - Primary media servers | |||
| ## 2 - Backup media servers | |||
| ## 3 - Alternate media server IPs (used only for classification) | |||
| ## 10 - Presence servers (if not locally handled) | |||
| ## 20 - Registrar servers (if not locally handled) | |||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||
| ####### Dispatcher Logic ######## | |||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||
| { | |||
| route_if_exists("DISPATCHER_CUSTOM_NETWORK_CLASSIFY"); | |||
| if (!isflagset(FLAG_NETWORK_CLASSIFIED)) { | |||
| if (is_myself("$ou")) { | |||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||
| } else { | |||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||
| setflag(FLAG_INTERNALLY_SOURCED); | |||
| } else { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| # Take the routes from dispatcher - hash over callid | |||
| # If prefered route defined, reorder the destionations | |||
| route[DISPATCHER_FIND_ROUTES] | |||
| { | |||
| $var(ds_primary_group) = $(sel(cfg_get.kazoo.dispatcher_primary_group){s.int}); | |||
| $var(ds_backup_group) = $(sel(cfg_get.kazoo.dispatcher_secondary_group){s.int}); | |||
| #!ifndef PRESENCE_ROLE | |||
| if (is_method("SUBSCRIBE")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||
| } | |||
| #!endif | |||
| #!ifndef REGISTRAR_ROLE | |||
| if (is_method("REGISTER")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||
| } | |||
| #!endif | |||
| #!ifdef PRESENCE_ROLE | |||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||
| #!endif | |||
| route_if_exists("DISPATCHER_CUSTOM_SET_GROUPS"); | |||
| $var(ds_group) = $var(ds_primary_group); | |||
| $var(ds_alg) = $sel(cfg_get.kazoo.dispatcher_algorithm); | |||
| if(ds_list_exists("$var(ds_backup_group)")) { | |||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg);$var(ds_backup_group)=$var(ds_alg)); | |||
| } else { | |||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg)); | |||
| } | |||
| ds_select_routes("$var(ds_rule)", "2"); | |||
| if ($xavp(ds_ctx=>cnt) == 0) { | |||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||
| sl_send_reply("480", "All servers busy"); | |||
| exit; | |||
| } | |||
| route(PRINT_ROUTES); | |||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||
| + @ruri.user + "@" + @ruri.host; | |||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||
| xlog("L_INFO", "$ci|route|found redirect for $var(redirect) to $var(prefered_route)\n"); | |||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||
| route(DISPATCHER_PREFERRED_ROUTE); | |||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||
| route(DISPATCHER_PREFERRED_ROUTE); | |||
| } | |||
| $sht(associations=>$var(user_source)) = $null; | |||
| } | |||
| $avp(ds_group) = $xavp(ds_dst=>grp); | |||
| $avp(ds_retries) = 0; | |||
| ds_set_dst(); | |||
| } | |||
| route[DISPATCHER_PREFERRED_ROUTE] | |||
| { | |||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $xavp(ds_dst=>uri)\n"); | |||
| return -1; | |||
| } | |||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||
| $var(i) = $xavp(ds_ctx=>cnt) - 1; | |||
| while($var(i) >= 0) { | |||
| if($xavp(ds_dst[$var(i)]=>uri) == $var(prefered_route)) { | |||
| $xavp(ds_dst[$var(i)]) = $null; | |||
| } | |||
| $var(i) = $var(i) - 1; | |||
| } | |||
| $xavp(ds_dst=>uri) = $var(prefered_route); | |||
| $xavp(ds_dst[0]=>grp) = $var(setid); | |||
| $xavp(ds_dst[0]=>attrs) = $var(attrs); | |||
| return 1; | |||
| } | |||
| route[PRINT_ROUTES] | |||
| { | |||
| if($sel(cfg_get.kazoo.dispatcher_print_routes) == 0) return; | |||
| $var(i) = 0; | |||
| while($xavp(ds_dst[$var(i)]=>uri) != $null) { | |||
| xlog("L_INFO", "$ci|route|group $xavp(ds_dst[$var(i)]=>grp) => $xavp(ds_dst[$var(i)]=>uri) => zone $(xavp(ds_dst[$var(i)]=>attrs){param.value,zone})\n"); | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| #!import_file "dispatcher-next-route.cfg" | |||
| #!ifndef CUSTOM_DISPATCHER_NEXT_ROUTE | |||
| # Try next destinations in failure route | |||
| route[DISPATCHER_NEXT_ROUTE] | |||
| { | |||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||
| if(ds_next_dst()) { | |||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| # relay the request to the new media server | |||
| route(RELAY); | |||
| exit; | |||
| } | |||
| } | |||
| #!endif | |||
| event_route[dispatcher:dst-down] | |||
| { | |||
| xlog("L_WARNING", "Destination down: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||
| } | |||
| event_route[dispatcher:dst-up] | |||
| { | |||
| xlog("L_WARNING", "Destination up: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||
| } | |||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||
| { | |||
| $var(check_media_server_ret) = 0; | |||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||
| $var(SetId) = 1; | |||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||
| $var(SetId) = 2; | |||
| } | |||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||
| $var(MediaUrlBack) = $var(MediaUrl); | |||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| $var(MediaUrl) = $var(MediaUrlBack); | |||
| } | |||
| } | |||
| } | |||
| return $var(check_media_server_ret); | |||
| } | |||
| route[DISPATCHER_RELOAD] | |||
| { | |||
| if($shv(dispatcher_reload) == 1) { | |||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||
| ds_reload(); | |||
| }; | |||
| $shv(dispatcher_reload) = 0; | |||
| } | |||
| route[DISPATCHER_STATUS] | |||
| { | |||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||
| $var(i) = 0; | |||
| $var(ds_groups_json)=""; | |||
| $var(Sep1) = ""; | |||
| while($var(i) < $var(Sets)) { | |||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||
| $var(Sep2)=""; | |||
| $var(ds_group_json)=""; | |||
| $var(c) = 0; | |||
| while($var(c) < $var(SetCount)) { | |||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||
| $var(Sep2) = ","; | |||
| $var(c) = $var(c) + 1; | |||
| } | |||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||
| $var(Sep1)=", "; | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||
| @ -0,0 +1,309 @@ | |||
| ### DISPATCHER ROLE #### | |||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||
| #!trydef DISPATCHER_ALG 0 | |||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||
| #!trydef KZ_DISPATCHER_PRINT_ROUTES 1 | |||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||
| kazoo.dispatcher_print_routes = KZ_DISPATCHER_PRINT_ROUTES descr "should we log the selected routes" | |||
| ####### Dispatcher module ######## | |||
| loadmodule "dispatcher.so" | |||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||
| modparam("dispatcher", "flags", 2) | |||
| modparam("dispatcher", "use_default", 0) | |||
| modparam("dispatcher", "force_dst", 1) | |||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||
| modparam("dispatcher", "ds_ping_interval", 10) | |||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||
| modparam("dispatcher", "xavp_dst", "ds_dst") | |||
| modparam("dispatcher", "xavp_ctx", "ds_ctx") | |||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||
| ## Dispatcher Groups: | |||
| ## 1 - Primary media servers | |||
| ## 2 - Backup media servers | |||
| ## 3 - Alternate media server IPs (used only for classification) | |||
| ## 10 - Presence servers (if not locally handled) | |||
| ## 20 - Registrar servers (if not locally handled) | |||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||
| ####### Dispatcher Logic ######## | |||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||
| { | |||
| route_if_exists("DISPATCHER_CUSTOM_NETWORK_CLASSIFY"); | |||
| if (!isflagset(FLAG_NETWORK_CLASSIFIED)) { | |||
| if (is_myself("$ou")) { | |||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||
| } else { | |||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||
| setflag(FLAG_INTERNALLY_SOURCED); | |||
| } else { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| # Take the routes from dispatcher - hash over callid | |||
| # If prefered route defined, reorder the destionations | |||
| route[DISPATCHER_FIND_ROUTES] | |||
| { | |||
| $var(ds_primary_group) = $(sel(cfg_get.kazoo.dispatcher_primary_group){s.int}); | |||
| $var(ds_backup_group) = $(sel(cfg_get.kazoo.dispatcher_secondary_group){s.int}); | |||
| #!ifndef PRESENCE_ROLE | |||
| if (is_method("SUBSCRIBE")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||
| } | |||
| #!endif | |||
| #!ifndef REGISTRAR_ROLE | |||
| if (is_method("REGISTER")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||
| } | |||
| #!endif | |||
| #!ifdef PRESENCE_ROLE | |||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||
| #!endif | |||
| route_if_exists("DISPATCHER_CUSTOM_SET_GROUPS"); | |||
| $var(ds_group) = $var(ds_primary_group); | |||
| $var(ds_alg) = $sel(cfg_get.kazoo.dispatcher_algorithm); | |||
| if(ds_list_exists("$var(ds_backup_group)")) { | |||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg);$var(ds_backup_group)=$var(ds_alg)); | |||
| } else { | |||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg)); | |||
| } | |||
| ds_select_routes("$var(ds_rule)", "2"); | |||
| if ($xavp(ds_ctx=>cnt) == 0) { | |||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||
| sl_send_reply("480", "All servers busy"); | |||
| exit; | |||
| } | |||
| route(PRINT_ROUTES); | |||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||
| + @ruri.user + "@" + @ruri.host; | |||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||
| xlog("L_INFO", "$ci|route|found redirect for $var(redirect) to $var(prefered_route)\n"); | |||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||
| route(DISPATCHER_PREFERRED_ROUTE); | |||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||
| route(DISPATCHER_PREFERRED_ROUTE); | |||
| } | |||
| $sht(associations=>$var(user_source)) = $null; | |||
| } | |||
| $avp(ds_group) = $xavp(ds_dst=>grp); | |||
| $avp(ds_retries) = 0; | |||
| ds_set_dst(); | |||
| } | |||
| route[DISPATCHER_PREFERRED_ROUTE] | |||
| { | |||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $xavp(ds_dst=>uri)\n"); | |||
| return -1; | |||
| } | |||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||
| $var(i) = $xavp(ds_ctx=>cnt) - 1; | |||
| while($var(i) >= 0) { | |||
| if($xavp(ds_dst[$var(i)]=>uri) == $var(prefered_route)) { | |||
| $xavp(ds_dst[$var(i)]) = $null; | |||
| } | |||
| $var(i) = $var(i) - 1; | |||
| } | |||
| $xavp(ds_dst=>uri) = $var(prefered_route); | |||
| $xavp(ds_dst[0]=>grp) = $var(setid); | |||
| $xavp(ds_dst[0]=>attrs) = $var(attrs); | |||
| return 1; | |||
| } | |||
| route[PRINT_ROUTES] | |||
| { | |||
| if($sel(cfg_get.kazoo.dispatcher_print_routes) == 0) return; | |||
| $var(i) = 0; | |||
| while($xavp(ds_dst[$var(i)]=>uri) != $null) { | |||
| xlog("L_INFO", "$ci|route|group $xavp(ds_dst[$var(i)]=>grp) => $xavp(ds_dst[$var(i)]=>uri) => zone $(xavp(ds_dst[$var(i)]=>attrs){param.value,zone})\n"); | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| #!import_file "dispatcher-next-route.cfg" | |||
| #!ifndef CUSTOM_DISPATCHER_NEXT_ROUTE | |||
| # Try next destinations in failure route | |||
| route[DISPATCHER_NEXT_ROUTE] | |||
| { | |||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||
| if(ds_next_dst()) { | |||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| # relay the request to the new media server | |||
| route(RELAY); | |||
| exit; | |||
| } | |||
| } | |||
| #!endif | |||
| event_route[dispatcher:dst-down] | |||
| { | |||
| xlog("L_WARNING", "Destination down: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||
| } | |||
| event_route[dispatcher:dst-up] | |||
| { | |||
| xlog("L_WARNING", "Destination up: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||
| } | |||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||
| { | |||
| $var(check_media_server_ret) = 0; | |||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||
| $var(SetId) = 1; | |||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||
| $var(SetId) = 2; | |||
| } | |||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||
| $var(MediaUrlBack) = $var(MediaUrl); | |||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| $var(MediaUrl) = $var(MediaUrlBack); | |||
| } | |||
| } | |||
| } | |||
| return $var(check_media_server_ret); | |||
| } | |||
| route[DISPATCHER_RELOAD] | |||
| { | |||
| if($shv(dispatcher_reload) == 1) { | |||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||
| ds_reload(); | |||
| }; | |||
| $shv(dispatcher_reload) = 0; | |||
| } | |||
| route[DISPATCHER_STATUS] | |||
| { | |||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||
| $var(i) = 0; | |||
| $var(ds_groups_json)=""; | |||
| $var(Sep1) = ""; | |||
| while($var(i) < $var(Sets)) { | |||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||
| $var(Sep2)=""; | |||
| $var(ds_group_json)=""; | |||
| $var(c) = 0; | |||
| while($var(c) < $var(SetCount)) { | |||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||
| $var(Sep2) = ","; | |||
| $var(c) = $var(c) + 1; | |||
| } | |||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||
| $var(Sep1)=", "; | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||
| @ -0,0 +1,309 @@ | |||
| ### DISPATCHER ROLE #### | |||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||
| #!trydef DISPATCHER_ALG 0 | |||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||
| #!trydef KZ_DISPATCHER_PRINT_ROUTES 1 | |||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||
| kazoo.dispatcher_print_routes = KZ_DISPATCHER_PRINT_ROUTES descr "should we log the selected routes" | |||
| ####### Dispatcher module ######## | |||
| loadmodule "dispatcher.so" | |||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||
| modparam("dispatcher", "flags", 2) | |||
| modparam("dispatcher", "use_default", 0) | |||
| modparam("dispatcher", "force_dst", 1) | |||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||
| modparam("dispatcher", "ds_ping_interval", 10) | |||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||
| modparam("dispatcher", "xavp_dst", "ds_dst") | |||
| modparam("dispatcher", "xavp_ctx", "ds_ctx") | |||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||
| ## Dispatcher Groups: | |||
| ## 1 - Primary media servers | |||
| ## 2 - Backup media servers | |||
| ## 3 - Alternate media server IPs (used only for classification) | |||
| ## 10 - Presence servers (if not locally handled) | |||
| ## 20 - Registrar servers (if not locally handled) | |||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||
| ####### Dispatcher Logic ######## | |||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||
| { | |||
| route_if_exists("DISPATCHER_CUSTOM_NETWORK_CLASSIFY"); | |||
| if (!isflagset(FLAG_NETWORK_CLASSIFIED)) { | |||
| if (is_myself("$ou")) { | |||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||
| } else { | |||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||
| setflag(FLAG_INTERNALLY_SOURCED); | |||
| } else { | |||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| # Take the routes from dispatcher - hash over callid | |||
| # If prefered route defined, reorder the destionations | |||
| route[DISPATCHER_FIND_ROUTES] | |||
| { | |||
| $var(ds_primary_group) = $(sel(cfg_get.kazoo.dispatcher_primary_group){s.int}); | |||
| $var(ds_backup_group) = $(sel(cfg_get.kazoo.dispatcher_secondary_group){s.int}); | |||
| #!ifndef PRESENCE_ROLE | |||
| if (is_method("SUBSCRIBE")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||
| } | |||
| #!endif | |||
| #!ifndef REGISTRAR_ROLE | |||
| if (is_method("REGISTER")) { | |||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||
| } | |||
| #!endif | |||
| #!ifdef PRESENCE_ROLE | |||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||
| #!endif | |||
| route_if_exists("DISPATCHER_CUSTOM_SET_GROUPS"); | |||
| $var(ds_group) = $var(ds_primary_group); | |||
| $var(ds_alg) = $sel(cfg_get.kazoo.dispatcher_algorithm); | |||
| if(ds_list_exists("$var(ds_backup_group)")) { | |||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg);$var(ds_backup_group)=$var(ds_alg)); | |||
| } else { | |||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg)); | |||
| } | |||
| ds_select_routes("$var(ds_rule)", "2"); | |||
| if ($xavp(ds_ctx=>cnt) == 0) { | |||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||
| sl_send_reply("480", "All servers busy"); | |||
| exit; | |||
| } | |||
| route(PRINT_ROUTES); | |||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||
| + @ruri.user + "@" + @ruri.host; | |||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||
| xlog("L_INFO", "$ci|route|found redirect for $var(redirect) to $var(prefered_route)\n"); | |||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||
| route(DISPATCHER_PREFERRED_ROUTE); | |||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||
| route(DISPATCHER_PREFERRED_ROUTE); | |||
| } | |||
| $sht(associations=>$var(user_source)) = $null; | |||
| } | |||
| $avp(ds_group) = $xavp(ds_dst=>grp); | |||
| $avp(ds_retries) = 0; | |||
| ds_set_dst(); | |||
| } | |||
| route[DISPATCHER_PREFERRED_ROUTE] | |||
| { | |||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $xavp(ds_dst=>uri)\n"); | |||
| return -1; | |||
| } | |||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||
| $var(i) = $xavp(ds_ctx=>cnt) - 1; | |||
| while($var(i) >= 0) { | |||
| if($xavp(ds_dst[$var(i)]=>uri) == $var(prefered_route)) { | |||
| $xavp(ds_dst[$var(i)]) = $null; | |||
| } | |||
| $var(i) = $var(i) - 1; | |||
| } | |||
| $xavp(ds_dst=>uri) = $var(prefered_route); | |||
| $xavp(ds_dst[0]=>grp) = $var(setid); | |||
| $xavp(ds_dst[0]=>attrs) = $var(attrs); | |||
| return 1; | |||
| } | |||
| route[PRINT_ROUTES] | |||
| { | |||
| if($sel(cfg_get.kazoo.dispatcher_print_routes) == 0) return; | |||
| $var(i) = 0; | |||
| while($xavp(ds_dst[$var(i)]=>uri) != $null) { | |||
| xlog("L_INFO", "$ci|route|group $xavp(ds_dst[$var(i)]=>grp) => $xavp(ds_dst[$var(i)]=>uri) => zone $(xavp(ds_dst[$var(i)]=>attrs){param.value,zone})\n"); | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| #!import_file "dispatcher-next-route.cfg" | |||
| #!ifndef CUSTOM_DISPATCHER_NEXT_ROUTE | |||
| # Try next destinations in failure route | |||
| route[DISPATCHER_NEXT_ROUTE] | |||
| { | |||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||
| if(ds_next_dst()) { | |||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| # relay the request to the new media server | |||
| route(RELAY); | |||
| exit; | |||
| } | |||
| } | |||
| #!endif | |||
| event_route[dispatcher:dst-down] | |||
| { | |||
| xlog("L_WARNING", "Destination down: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||
| } | |||
| event_route[dispatcher:dst-up] | |||
| { | |||
| xlog("L_WARNING", "Destination up: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||
| } | |||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||
| { | |||
| $var(check_media_server_ret) = 0; | |||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||
| $var(SetId) = 1; | |||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||
| $var(SetId) = 2; | |||
| } | |||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||
| $var(MediaUrlBack) = $var(MediaUrl); | |||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| $shv(dispatcher_reload) = 1; | |||
| $var(check_media_server_ret) = 1; | |||
| } | |||
| $var(MediaUrl) = $var(MediaUrlBack); | |||
| } | |||
| } | |||
| } | |||
| return $var(check_media_server_ret); | |||
| } | |||
| route[DISPATCHER_RELOAD] | |||
| { | |||
| if($shv(dispatcher_reload) == 1) { | |||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||
| ds_reload(); | |||
| }; | |||
| $shv(dispatcher_reload) = 0; | |||
| } | |||
| route[DISPATCHER_STATUS] | |||
| { | |||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||
| $var(i) = 0; | |||
| $var(ds_groups_json)=""; | |||
| $var(Sep1) = ""; | |||
| while($var(i) < $var(Sets)) { | |||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||
| $var(Sep2)=""; | |||
| $var(ds_group_json)=""; | |||
| $var(c) = 0; | |||
| while($var(c) < $var(SetCount)) { | |||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||
| $var(Sep2) = ","; | |||
| $var(c) = $var(c) + 1; | |||
| } | |||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||
| $var(Sep1)=", "; | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||
| @ -1,264 +0,0 @@ | |||
| ######## Generic Hash Table container in shared memory ######## | |||
| modparam("htable", "htable", "failover=>size=16;autoexpire=120") | |||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||
| ####### Dispatcher module ######## | |||
| loadmodule "dispatcher.so" | |||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||
| modparam("dispatcher", "flags", 2) | |||
| modparam("dispatcher", "use_default", 0) | |||
| modparam("dispatcher", "force_dst", 1) | |||
| modparam("dispatcher", "dst_avp", "$avp(ds_dst)") | |||
| modparam("dispatcher", "attrs_avp", "$avp(ds_attrs)") | |||
| modparam("dispatcher", "grp_avp", "$avp(ds_grp)") | |||
| modparam("dispatcher", "cnt_avp", "$avp(ds_cnt)") | |||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||
| modparam("dispatcher", "ds_ping_interval", 10) | |||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||
| modparam("dispatcher", "ds_probing_mode", 1) | |||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||
| #!import_file "dispatcher-network-params.cfg" | |||
| ## Dispatcher Groups: | |||
| ## 1 - Primary media servers | |||
| ## 2 - Backup media servers | |||
| ## 3 - Alternate media server IPs (used only for classification) | |||
| ## 10 - Presence servers (if not locally handled) | |||
| ## 20 - Registrar servers (if not locally handled) | |||
| ####### Dispatcher Logic ######## | |||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||
| { | |||
| #!import_file "dispatcher-network-classify.cfg" | |||
| if (is_myself("$ou")) { | |||
| xlog("L_INFO", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||
| } else if ( | |||
| ds_is_from_list(1, 3) || | |||
| ds_is_from_list(2, 3) || | |||
| ds_is_from_list(3, 3) || | |||
| ds_is_from_list(10, 3) || | |||
| ds_is_from_list(20, 3) | |||
| ) { | |||
| xlog("L_INFO", "$ci|log|originated from internal sources\n"); | |||
| setflag(FLAG_INTERNALLY_SOURCED); | |||
| } else { | |||
| xlog("L_INFO", "$ci|log|originated from external sources\n"); | |||
| } | |||
| } | |||
| # Take the routes from dispatcher - hash over callid | |||
| # If prefered route defined, reorder the destionations | |||
| route[DISPATCHER_FIND_ROUTES] | |||
| { | |||
| if ($sht(failover=>$ci::current) != $null) { | |||
| $du = $sht(failover=>$ci::current); | |||
| return; | |||
| } | |||
| $var(ds_primary_group) = 1; | |||
| $var(ds_backup_group) = 2; | |||
| #!ifndef PRESENCE_ROLE | |||
| if (is_method("SUBSCRIBE")) { | |||
| $var(ds_primary_group) = 10; | |||
| $var(ds_backup_group) = 11; | |||
| } | |||
| #!endif | |||
| #!ifndef REGISTRAR_ROLE | |||
| if (is_method("REGISTER")) { | |||
| $var(ds_primary_group) = 20; | |||
| $var(ds_backup_group) = 21; | |||
| } | |||
| #!endif | |||
| #!ifdef FAST_PICKUP_ROLE | |||
| route(FAST_PICKUP_ATTEMPT); | |||
| #!endif | |||
| #!import_file "dispatcher-network-find.cfg" | |||
| $var(ds_group) = $var(ds_primary_group); | |||
| if (!ds_select_dst("$var(ds_primary_group)", "0") || $(avp(ds_dst)[0]) == $null) { | |||
| # we selected from primary group, try again in backup group | |||
| if (!ds_select_dst("$var(ds_backup_group)", "0") || $(avp(ds_dst)[0]) == $null) { | |||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||
| sl_send_reply("480", "All servers busy"); | |||
| exit; | |||
| } else { | |||
| $var(ds_group) = $var(ds_backup_group); | |||
| } | |||
| } | |||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||
| + @ruri.user + "@" + @ruri.host; | |||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||
| xlog("L_INFO", "$ci|log|found redirect for $var(redirect)\n"); | |||
| if (route(DISPATCHER_REORDER_ROUTES)) { | |||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||
| } | |||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||
| xlog("L_INFO", "$ci|log|found association for contact uri $var(user_source)\n"); | |||
| if (!route(DISPATCHER_REORDER_ROUTES)) { | |||
| $sht(associations=>$var(association)) = $null; | |||
| } | |||
| } | |||
| } | |||
| route[DISPATCHER_REORDER_ROUTES] | |||
| { | |||
| $var(i) = 0; | |||
| $var(found) = 0; | |||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||
| if($(avp(ds_dst)[$var(i)]) != $var(prefered_route)) { | |||
| $avp(tmp_ds_dst) = $(avp(ds_dst)[$var(i)]); | |||
| } else { | |||
| $var(found) = 1; | |||
| } | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| if (!$var(found) && $var(ds_group) == $var(ds_primary_group) && ds_select_dst("$var(ds_backup_group)", "0")) { | |||
| $var(i) = 0; | |||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||
| if($(avp(ds_dst)[$var(i)]) == $var(prefered_route)) { | |||
| xlog("L_INFO", "$ci|log|found associated media server in backup list\n"); | |||
| $var(found) = 1; | |||
| break; | |||
| } | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| if ($var(found)) { | |||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||
| $(avp(ds_dst)[*]) = $null; | |||
| $var(i) = 0; | |||
| while($(avp(tmp_ds_dst)[$var(i)]) != $null) { | |||
| $avp(ds_dst) = $(avp(tmp_ds_dst)[$var(i)]); | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| $avp(ds_dst) = $var(prefered_route); | |||
| $du = $var(prefered_route); | |||
| $(avp(tmp_ds_dst)[*]) = $null; | |||
| } else { | |||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $rd\n"); | |||
| return -1; | |||
| } | |||
| return 1; | |||
| } | |||
| route[DISPATCHER_NEXT_ROUTE] | |||
| { | |||
| $var(failover_count) = $sht(failover=>$ci::counts); | |||
| if ($sht(failover=>$ci::counts) == $null) { | |||
| $var(i) = 0; | |||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||
| $sht(failover=>$ci[$var(i)]) = $(avp(ds_dst)[$var(i)]); | |||
| $var(i) = $var(i) + 1; | |||
| if ($var(i) >= 3) { | |||
| break; | |||
| } | |||
| } | |||
| $sht(failover=>$ci::counts) = $var(i); | |||
| $var(failover_count) = $var(i); | |||
| } | |||
| # try to find a new media server to send the call to | |||
| if ($var(failover_count) > 1) { | |||
| $var(failover_count) = $var(failover_count) - 1; | |||
| $du = $sht(failover=>$ci[$var(failover_count)]); | |||
| $sht(failover=>$ci::counts) = $var(failover_count); | |||
| $sht(failover=>$ci::current) = $du; | |||
| xlog("L_INFO", "$ci|log|remaining failed retry attempts: $var(failover_count)\n"); | |||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| # reset the final reply timer | |||
| $avp(final_reply_timer) = 3; | |||
| t_on_reply("INTERNAL_REPLY"); | |||
| t_on_failure("INTERNAL_FAULT"); | |||
| # relay the request to the new media server | |||
| route(EXTERNAL_TO_INTERNAL_RELAY); | |||
| exit(); | |||
| } | |||
| } | |||
| event_route[dispatcher:dst-down] | |||
| { | |||
| xlog("L_ERR", "Destination down: $ru\n"); | |||
| } | |||
| event_route[dispatcher:dst-up] | |||
| { | |||
| xlog("L_WARNING", "Destination up: $ru\n"); | |||
| } | |||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||
| { | |||
| if(@cfg_get.kazoo.dispatcher_auto_add == 1) { | |||
| $var(SetId) = 1; | |||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||
| $var(SetId) = 2; | |||
| } | |||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||
| if($sqlrows(exec) > 0) { | |||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||
| ds_reload(); | |||
| } | |||
| } | |||
| } | |||
| route[DISPATCHER_STATUS] | |||
| { | |||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||
| $var(i) = 0; | |||
| $var(ds_groups_json)=""; | |||
| $var(Sep1) = ""; | |||
| while($var(i) < $var(Sets)) { | |||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||
| $var(Sep2)=""; | |||
| $var(ds_group_json)=""; | |||
| $var(c) = 0; | |||
| while($var(c) < $var(SetCount)) { | |||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||
| $var(Sep2) = ","; | |||
| $var(c) = $var(c) + 1; | |||
| } | |||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||
| $var(Sep1)=", "; | |||
| $var(i) = $var(i) + 1; | |||
| } | |||
| } | |||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||
| @ -0,0 +1,343 @@ | |||
| ######## KEEPALIVE PINGING ######## | |||
| #!trydef KEEPALIVE_ENABLED 1 | |||
| #!trydef KEEPALIVE_NAT_ONLY 0 | |||
| #!trydef KEEPALIVE_UDP_ONLY 0 | |||
| #!trydef KEEPALIVE_TIMERS 4 | |||
| #!trydef KEEPALIVE_INTERVAL 60 | |||
| #!trydef KEEPALIVE_TIMEOUT 5000 | |||
| #!trydef KEEPALIVE_FAILED_THRESHOLD 2 | |||
| #!trydef KEEPALIVE_EXPIRE_SUBSCRIPTIONS 1 | |||
| #!trydef KEEPALIVE_EXPIRE_REGISTRATIONS 1 | |||
| #!trydef KEEPALIVE_FAILED_ACTION 1 | |||
| #!trydef KEEPALIVE_FAILED_LOG_LEVEL 0 | |||
| #!trydef KEEPALIVE_EXPIRED_SUBSCRIPTION_ACTION 1 | |||
| #!trydef KEEPALIVE_EXPIRED_REGISTRATION_ACTION 1 | |||
| #!trydef KEEPALIVE_ON_SUBSCRIPTION_ACTION 1 | |||
| #!trydef KEEPALIVE_ON_REGISTRATION_ACTION 1 | |||
| #!substdef "!KEEPALIVE_S_FROM_URI!sip:keepalive@MY_HOSTNAME!g" | |||
| #!substdef "!KEEPALIVE_S_TIMERS!$def(KEEPALIVE_TIMERS)!g" | |||
| kazoo.keepalive_udp_only = KEEPALIVE_UDP_ONLY descr "should we send keepalive for udp only" | |||
| kazoo.keepalive_nat_only = KEEPALIVE_NAT_ONLY descr "should we send keepalive for nat phones only" | |||
| kazoo.keepalive_timeout = KEEPALIVE_TIMEOUT descr "timeout in ms for keepalive transaction" | |||
| kazoo.keepalive_failed_threshold = KEEPALIVE_FAILED_THRESHOLD descr "how many times can a device fail to respond to OPTIONS" | |||
| kazoo.keepalive_expire_subscriptions = KEEPALIVE_EXPIRE_SUBSCRIPTIONS descr "expires subscriptions that do not respond to OPTIONS" | |||
| kazoo.keepalive_expire_registrations = KEEPALIVE_EXPIRE_REGISTRATIONS descr "expires registrations that do not respond to OPTIONS" | |||
| kazoo.keepalive_failed_log_level = KEEPALIVE_FAILED_LOG_LEVEL descr "loglevel for keepalive failed reply" | |||
| kazoo.keepalive_failed_action = KEEPALIVE_FAILED_ACTION descr "action for devices that exceed the threshold. 1 = disable, 2 = delete" | |||
| kazoo.keepalive_interval = KEEPALIVE_INTERVAL descr "interval in seconds between attempts to send OPTIONS to device" | |||
| kazoo.keepalive_expired_registration_action = KEEPALIVE_EXPIRED_REGISTRATION_ACTION descr "action when registrar expires a registration, 1 = delete , 2 = disable, 0 = none" | |||
| kazoo.keepalive_expired_subscription_action = KEEPALIVE_EXPIRED_SUBSCRIPTION_ACTION descr "action when presence expires a subscription, 1 = delete , 2 = disable, 0 = none" | |||
| kazoo.keepalive_on_registration_action = KEEPALIVE_ON_REGISTRATION_ACTION descr "action on registration, 1 = insert in keepalive , 0 = none" | |||
| kazoo.keepalive_on_subscription_action = KEEPALIVE_ON_SUBSCRIPTION_ACTION descr "action on subscription, 1 = insert in keepalive , 0 = none" | |||
| kazoo.keepalive_enable = KEEPALIVE_ENABLED descr "enable keepalive, 1 = on , 0 = off" | |||
| modparam("rtimer", "timer", "name=keepalive_timer;interval=1;mode=KEEPALIVE_S_TIMERS;") | |||
| modparam("rtimer", "exec", "timer=keepalive_timer;route=KEEPALIVE_TIMER") | |||
| modparam("rtimer", "timer", "name=keepalive_db_timer;interval=1;mode=1;") | |||
| modparam("rtimer", "exec", "timer=keepalive_db_timer;route=KEEPALIVE_DB_TIMER") | |||
| ##modparam("rtimer", "timer", "name=keepalive_cleanup;interval=5;mode=1;") | |||
| ##modparam("rtimer", "exec", "timer=keepalive_cleanup;route=KEEPALIVE_CLEANUP") | |||
| modparam("mqueue","mqueue", "name=keepalive_db_queue") | |||
| modparam("statistics","variable", "keepalive:success") | |||
| modparam("statistics","variable", "keepalive:failure") | |||
| modparam("statistics","variable", "keepalive:db:success") | |||
| modparam("statistics","variable", "keepalive:db:failure") | |||
| modparam("statistics","variable", "keepalive:client_options") | |||
| modparam("statistics","variable", "keepalive:client_notify") | |||
| modparam("statistics","variable", "keepalive:disabled") | |||
| modparam("statistics","variable", "keepalive:removed") | |||
| modparam("statistics","variable", "keepalive:expired_registrations") | |||
| modparam("statistics","variable", "keepalive:expired_subscriptions") | |||
| modparam("statistics","variable", "keepalive:from_registration") | |||
| modparam("statistics","variable", "keepalive:from_subscription") | |||
| modparam("statistics","variable", "keepalive:removed_from_registration") | |||
| modparam("statistics","variable", "keepalive:removed_from_subscription") | |||
| modparam("statistics","variable", "keepalive:disabled_from_expired_registration") | |||
| modparam("statistics","variable", "keepalive:removed_from_expired_registration") | |||
| modparam("statistics","variable", "keepalive:disabled_from_expired_subscription") | |||
| modparam("statistics","variable", "keepalive:removed_from_expired_subscription") | |||
| modparam("htable", "htable", "keepalive=>size=32;") | |||
| route[KEEPALIVE_DB_TIMER] | |||
| { | |||
| $var(runloop) = 1; | |||
| while(mq_fetch("keepalive_db_queue") == 1 && $var(runloop) < MAX_WHILE_LOOPS) { | |||
| $var(ci) = $mqk(keepalive_db_queue); | |||
| xlog("L_DEBUG", "Query : $var(ci) => $mqv(keepalive_db_queue)\n"); | |||
| $var(sqlres) = sql_query("cb", "$mqv(keepalive_db_queue)"); | |||
| xlog("L_DEBUG", "Query result : $var(sqlres)\n"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$var(ci)|log|error running query : $mqv(keepalive_db_queue)\n"); | |||
| } else { | |||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||
| update_stat("$var(ci)", "$var(stat_update)"); | |||
| $var(nrows) = $sqlrows(cb); | |||
| xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows) => $var(stat_update)\n"); | |||
| if($var(nrows) == 0) { | |||
| xlog("L_DEBUG", "$var(ci)|log|error no rows affected when running query\n"); | |||
| } | |||
| } | |||
| $var(runloop) = $var(runloop) + 1; | |||
| } | |||
| } | |||
| route[KEEPALIVE_CLEANUP] | |||
| { | |||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||
| $var(Query) = $_s(UPDATE keepalive SET SELECTED = 9 WHERE slot = $var(slot) AND selected = 0 and failed > $sel(cfg_get.kazoo.keepalive_failed_threshold)); | |||
| # $var(Query) = $_s(UPDATE keepalive SET SELECTED = 9 where selected < 3 and failed > $sel(cfg_get.kazoo.keepalive_failed_threshold)); | |||
| sql_query("cb", "$var(Query)"); | |||
| if($sqlrows(cb) > 0) { | |||
| if($sel(cfg_get.kazoo.keepalive_expire_registrations) == 1) { | |||
| if($def(REGISTRAR_DB_MODE) == 3) { | |||
| $var(Query) = $_s(update location set expires = last_modified where id in(select b.id from w_keepalive_contact a inner join w_location_contact b on a.contact = b.contact where selected = 9)); | |||
| sql_query("cb", "$var(Query)"); | |||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||
| update_stat("keepalive:expired_registrations", "$var(stat_update)"); | |||
| } else { | |||
| $var(Query) = $_s(update location set expires = last_modified where id in(select b.id from w_keepalive_contact a inner join w_location_contact b on a.contact = b.contact where selected = 9)); | |||
| sql_query("cb", "$var(Query)"); | |||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||
| update_stat("keepalive:expired_registrations", "$var(stat_update)"); | |||
| } | |||
| } | |||
| if($sel(cfg_get.kazoo.keepalive_expire_subscriptions) == 1) { | |||
| $var(Query) = $_s(DELETE FROM active_watchers where id in(select b.id from w_keepalive_contact a inner join w_watchers_contact b on a.contact = b.contact where selected = 9)); | |||
| sql_query("cb", "$var(Query)"); | |||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||
| update_stat("keepalive:expired_subscriptions", "$var(stat_update)"); | |||
| } | |||
| if($sel(cfg_get.kazoo.keepalive_failed_action) == 2) { | |||
| ## disable | |||
| $var(Query) = $_s(UPDATE keepalive SET SELECTED = 10 where selected = 9); | |||
| $var(stat) = "keepalive:disabled"; | |||
| } else if($sel(cfg_get.kazoo.keepalive_failed_action) == 1) { | |||
| ## delete - will be recreated on registration/subscription with same contact | |||
| $var(Query) = $_s(DELETE FROM keepalive where selected = 9); | |||
| $var(stat) = "keepalive:removed"; | |||
| } | |||
| sql_query("cb", "$var(Query)"); | |||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||
| update_stat("$var(stat)", "$var(stat_update)"); | |||
| } | |||
| } | |||
| route[KEEPALIVE_TIMER] | |||
| { | |||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||
| $var(base_slot) = $rtimer_worker * $sel(cfg_get.kazoo.keepalive_interval); | |||
| $var(slot) = $var(base_slot) + $var(tick); | |||
| $var(Query) = $_s(UPDATE keepalive SET selected = 1 WHERE slot = $var(slot) AND selected = 0 AND time_sent < datetime('now', '-$sel(cfg_get.kazoo.keepalive_interval) seconds')); | |||
| ## xlog("L_NOTICE", "SQLTIMER ($var(base_slot) + $var(tick))> $var(Query)\n"); | |||
| $var(sqlres) = sql_query("cb", "$var(Query)"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$rtimer_worker|$var(tick)|log|error running query : $var(Query)\n"); | |||
| } else { | |||
| $var(nrows) = $sqlrows(cb); | |||
| xlog("L_DEBUG", "$rtimer_worker|$var(tick)|log|selected $var(nrows) endpoints to ping\n"); | |||
| } | |||
| route(KEEPALIVE_CLEANUP); | |||
| $var(Query) = $_s(SELECT id, contact, sockinfo from keepalive WHERE slot = $var(slot) AND selected = 1); | |||
| xlog("L_DEBUG", "$rtimer_worker|$var(tick)|timer|SQL => $var(Query)\n"); | |||
| $var(result) =sql_xquery("cb", "$var(Query)", "ra"); | |||
| if($var(result) == 1) { | |||
| while($xavp(ra) != $null) { | |||
| $var(loop) = 0; | |||
| while($xavp(ra) != $null && $var(loop) < MAX_WHILE_LOOPS) { | |||
| route(KEEPALIVE_SEND_PING); | |||
| pv_unset("$xavp(ra)"); | |||
| $var(loop) = $var(loop) + 1; | |||
| } | |||
| } | |||
| } | |||
| $var(Query) = $_s(UPDATE keepalive SET selected = 2 WHERE slot = $var(slot) AND selected = 1); | |||
| $var(sqlres) = sql_query("cb", "$var(Query)"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$rtimer_worker|$var(tick)|log|error running query : $var(Query)\n"); | |||
| } | |||
| $var(tick) = $var(tick) + 1; | |||
| if($var(tick) > $sel(cfg_get.kazoo.keepalive_interval)) { | |||
| $var(tick) = 0; | |||
| } | |||
| } | |||
| route[KEEPALIVE_SEND_PING] | |||
| { | |||
| $var(CallId) = $uuid(g); | |||
| xlog("L_DEBUG", "$var(CallId)|$rtimer_worker|timer|SENDING PING FROM $xavp(ra=>local_contact) TO => $xavp(ra=>contact)\n"); | |||
| $uac_req(method)="OPTIONS"; | |||
| $uac_req(hdrs) = "X-TM-Local: KEEPALIVE_PING\r\nX-TM-SockInfo: " + $xavp(ra=>sockinfo) + "\r\n"; | |||
| $uac_req(turi) = $xavp(ra=>contact); | |||
| $uac_req(ruri) = $xavp(ra=>contact); | |||
| $uac_req(furi) = $_s(KEEPALIVE_S_FROM_URI;nat_id=$xavp(ra=>id)); | |||
| $uac_req(ouri) = "sip:127.0.0.1:5090;transport=tcp"; | |||
| $uac_req(callid) = $var(CallId); | |||
| uac_req_send(); | |||
| } | |||
| onreply_route[KEEPALIVE_REPLY] | |||
| { | |||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE REPLY $(tu{nameaddr.uri})\n"); | |||
| $var(Query) = $_s(UPDATE keepalive SET selected = 0, failed = 0, time_sent = datetime('now') WHERE id = $(fu{uri.param,nat_id}) AND SELECTED = 2); | |||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE UPDATE SQL => '$var(Query)'\n"); | |||
| mq_add("keepalive_db_queue", "keepalive:db:success", "$var(Query)"); | |||
| update_stat("keepalive:success", "+1"); | |||
| resetflag(FLAG_SIP_TRACE); | |||
| } | |||
| failure_route[KEEPALIVE_FAULT] | |||
| { | |||
| xlog("$(sel(cfg_get.kazoo.keepalive_failed_log_level){s.int})", "$ci|keepalive|received error $T_reply_code $T_reply_reason from $(tu{nameaddr.uri})\n"); | |||
| $var(Query) = $_s(UPDATE keepalive SET selected = 0, failed = failed + 1, time_sent = datetime('now') WHERE id = $(fu{uri.param,nat_id}) AND SELECTED = 2); | |||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE REMOVE SQL => '$var(Query)'\n"); | |||
| mq_add("keepalive_db_queue", "keepalive:db:failure", "$var(Query)"); | |||
| update_stat("keepalive:failure", "+1"); | |||
| resetflag(FLAG_SIP_TRACE); | |||
| } | |||
| route[KEEPALIVE_PING] | |||
| { | |||
| $fs = $hdr(X-TM-SockInfo); | |||
| remove_hf_re("^X-TM-SockInfo"); | |||
| force_rport(); | |||
| handle_ruri_alias(); | |||
| record_route(); | |||
| xlog("L_DEBUG", "$ci|local|sending $proto keepalive using $fs to $ru => $du => $tu\n"); | |||
| t_on_reply("KEEPALIVE_REPLY"); | |||
| t_on_failure("KEEPALIVE_FAULT"); | |||
| t_set_fr(0, $sel(cfg_get.kazoo.keepalive_timeout)); | |||
| t_relay(); | |||
| } | |||
| route[KEEPALIVE_ON_REGISTRATION] | |||
| { | |||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||
| if($sel(cfg_get.kazoo.keepalive_on_registration_action) == 0) { | |||
| return; | |||
| } | |||
| if($proto == "ws" || $proto == "wss") { | |||
| return; | |||
| } | |||
| if($sht(keepalive=>$si~$sp~$prid) != $null) { | |||
| return; | |||
| } | |||
| if (isbflagset(FLB_NATB)) { | |||
| if(!isbflagset(FLB_NATSIPPING)) { | |||
| return; | |||
| } | |||
| } else { | |||
| if($sel(cfg_get.kazoo.keepalive_nat_only) == 1) { | |||
| return; | |||
| } | |||
| } | |||
| $var(alias) = $(avp(AVP_RECV_PARAM){uri.host}) + "~" + $(avp(AVP_RECV_PARAM){uri.port}) + "~" + $prid; | |||
| $var(contact) = $(ct{nameaddr.uri}) + ";alias=" + $var(alias); | |||
| $var(local_contact) = "sip:" + $Ri + ":" + $Rp + ";transport=" + $proto; | |||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE ON REG $var(save_result) $proto $RAut $var(contact) $var(alias) $(ct{nameaddr.uri}) $ct $avp(AVP_RECV_PARAM) $tu $xavp(ulrcd=>ruid) , $xavp(ulrcd=>contact) , $xavp(ulrcd=>expires)\n"); | |||
| if($var(save_result) == 3) { | |||
| $var(sql) = $_s(DELETE FROM keepalive WHERE contact = "$var(contact)"); | |||
| $var(stat) = "keepalive:removed_from_registration"; | |||
| } else { | |||
| $var(max_slots) = $sel(cfg_get.kazoo.keepalive_interval) * KEEPALIVE_S_TIMERS; | |||
| $var(slot) = $(var(contact){s.corehash, $var(max_slots)}); | |||
| $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, received, sockinfo, slot) values("$var(contact)", "$var(alias)", "$(RAut{uri.tosocket})", $var(slot))); | |||
| $var(stat) = "keepalive:from_registration"; | |||
| } | |||
| mq_add("keepalive_db_queue", "$var(stat)", "$var(sql)"); | |||
| return; | |||
| } | |||
| route[KEEPALIVE_ON_SUBSCRIBE] | |||
| { | |||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||
| if($sel(cfg_get.kazoo.keepalive_on_subscription_action) == 0) { | |||
| return; | |||
| } | |||
| if($sht(keepalive=>$si~$sp~$prid) != $null) { | |||
| return; | |||
| } | |||
| $var(max_slots) = $sel(cfg_get.kazoo.keepalive_interval) * KEEPALIVE_S_TIMERS; | |||
| $var(slot) = $(subs(contact){s.corehash, $var(max_slots)}); | |||
| $var(alias) = $(subs(contact){uri.param,alias}); | |||
| $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, received, sockinfo, slot) values("$subs(contact)", "$var(alias)", "$subs(sockinfo)", $var(slot))); | |||
| mq_add("keepalive_db_queue", "keepalive:from_subscription", "$var(sql)"); | |||
| } | |||
| route[KEEPALIVE_ON_EXPIRED_REGISTRATION] | |||
| { | |||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||
| if($sel(cfg_get.kazoo.keepalive_expired_registration_action) == 2) { | |||
| ## disable | |||
| $var(Query) = $_s(UPDATE keepalive SET SELECTED = 10 where selected < 3 and contact like "$ulc(exp=>addr)%"); | |||
| mq_add("keepalive_db_queue", "keepalive:disabled_from_expired_registration", "$var(Query)"); | |||
| } else if($sel(cfg_get.kazoo.keepalive_expired_registration_action) == 1) { | |||
| ## delete - will be recreated on registration with same contact | |||
| $var(Query) = $_s(DELETE FROM keepalive where selected < 3 and contact like "$ulc(exp=>addr)%"); | |||
| mq_add("keepalive_db_queue", "keepalive:removed_from_expired_registration", "$var(Query)"); | |||
| } | |||
| } | |||
| route[KEEPALIVE_ON_OPTIONS] | |||
| { | |||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||
| if($shtinc(keepalive=>$si~$sp~$prid) == 1) { | |||
| $var(Query) = $_s(UPDATE keepalive set selected = 3 where received = "$si~$sp~$prid" and selected <> 3 ); | |||
| mq_add("keepalive_db_queue", "keepalive:client_options", "$var(Query)"); | |||
| } | |||
| } | |||
| route[KEEPALIVE_ON_NOTIFY] | |||
| { | |||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||
| if($shtinc(keepalive=>$si~$sp~$prid) == 1) { | |||
| $var(Query) = $_s(UPDATE keepalive set selected = 4 where received = "$si~$sp~$prid" and selected <> 4 ); | |||
| mq_add("keepalive_db_queue", "keepalive:client_notify", "$var(Query)"); | |||
| } | |||
| } | |||
| @ -1,60 +1,101 @@ | |||
| modparam("htable", "htable", "msg=>size=32;autoexpire=60;") | |||
| event_route[kazoo:consumer-event-message-route] | |||
| route[HANDLE_MESSAGE] | |||
| { | |||
| $var(uri_username) = ""; | |||
| kazoo_json($kzE, "Endpoints[0].To-Username", "$var(uri_username)"); | |||
| $var(x) = $(kzE{kz.json,Endpoints[0].To-Username}); | |||
| xlog("L_INFO", "received message route for $(kzE{kz.json,Endpoints[0].To-DID})\n"); | |||
| if( $var(uri_username) != "" ) { | |||
| $var(from_uri) = "sip:" + $(kzE{kz.json,Caller-ID-Number}) + "@" + $(kzE{kz.json,Endpoints[0].To-Realm}); | |||
| $var(to_uri) = "sip:" + $(kzE{kz.json,Endpoints[0].To-Username}) + "@" + $(kzE{kz.json,Endpoints[0].To-Realm}); | |||
| if (!is_method("MESSAGE")) return; | |||
| if (isflagset(FLAG_INTERNALLY_SOURCED) || src_ip == myself) return; | |||
| xlog("L_INFO", "$ci|log|MESSAGE from $fu to $tu\n"); | |||
| route(AUTH); | |||
| $xavp(regcfg=>match_received) = $su; | |||
| if($avp(is_registered) != "true") { | |||
| sl_send_reply("403", "Forbidden"); | |||
| exit; | |||
| } else { | |||
| $var(from_uri) = "sip:" + $(kzE{kz.json,Caller-ID-Number}) + $(kzE{kz.json,Endpoints[0].To-Realm}); | |||
| $var(to_uri) = $(kzE{kz.json,Endpoints[0].Route}); | |||
| if($hdr(Content-Type) =~ "text/plain" || | |||
| $hdr(Content-Type) =~ "text/html") { | |||
| route(MESSAGE_INBOUND); | |||
| } else { | |||
| xlog("L_WARN", "$ci|end|dropping MESSAGE $hdr(Content-Type)\n"); | |||
| sl_send_reply("200", "OK"); | |||
| exit; | |||
| } | |||
| } | |||
| $sht(msg=>$(kzE{kz.json,Call-ID})) = $kzE; | |||
| } | |||
| route[MESSAGE_INBOUND] | |||
| { | |||
| $var(key) = "kamailio@MY_HOSTNAME"; | |||
| route(AUTH_HEADERS_JSON); | |||
| $var(Payload) = $_s({"Event-Category" : "sms", "Event-Name" : "inbound", "Call-ID" : "$ci", "Message-ID" : "$ci", "Route-Type" : "onnet", "Route-ID" : "$(var(key){kz.encode})", "From" : "$fU", "To" : "$tU", "Body" : "$rb", "Custom-SIP-Headers" : $var(headers_json), "Msg-ID" : "$uuid(g)"}); | |||
| $var(exchange) = "im"; | |||
| $var(RoutingKey) = $_s(sms.inbound.onnet.$(ci{kz.encode})); | |||
| xlog("L_INFO", "$ci|msg|sending inbound message $var(RoutingKey) => $var(Payload)\n"); | |||
| kazoo_publish($var(exchange), $var(RoutingKey), $var(Payload)); | |||
| sl_send_reply("200", "OK"); | |||
| exit; | |||
| } | |||
| event_route[kazoo:consumer-event-sms-outbound] | |||
| { | |||
| xlog("L_INFO", "$(kzE{kz.json,Message-ID})|log|received message outbound for $(kzE{kz.json,Endpoints[0].To-DID})\n"); | |||
| $var(from_uri) = $_s(sip:$(kzE{kz.json,From})@$(kzE{kz.json,Custom-Vars.Realm})); | |||
| $var(to_uri) = $_s(sip:$(kzE{kz.json,Endpoints[0].To-Username})@$(kzE{kz.json,Endpoints[0].To-Realm})); | |||
| $uac_req(method)="MESSAGE"; | |||
| $uac_req(body)= $(kzE{kz.json,Body}); | |||
| $uac_req(hdrs)="X-KAZOO-AOR: " + $var(to_uri)+ "\r\nContent-Type: text/plain\r\n"; | |||
| $uac_req(body)= $kzE; | |||
| $uac_req(hdrs)="X-TM-Local: MESSAGE_ROUTE\r\nX-KAZOO-AOR: " + $var(to_uri)+ "\r\nContent-Type: text/plain\r\n"; | |||
| $uac_req(turi) = $var(to_uri); | |||
| $uac_req(ruri) = $var(to_uri); | |||
| $uac_req(furi) = $var(from_uri); | |||
| $uac_req(ouri) = "sip:MY_IP_ADDRESS:5060"; | |||
| $uac_req(callid) = $(kzE{kz.json,Call-ID}); | |||
| xlog("L_INFO", "sending message from $var(from_uri) to $var(to_uri) \n"); | |||
| $uac_req(ouri) = "sip:127.0.0.1:5090;transport=tcp"; | |||
| $uac_req(callid) = $(kzE{kz.json,Message-ID}); | |||
| xlog("L_INFO", "$(kzE{kz.json,Message-ID})|log|sending message from $var(from_uri) to $var(to_uri) \n"); | |||
| uac_req_send(); | |||
| } | |||
| route[MESSAGE_REPLY] | |||
| route[MESSAGE_ROUTE] | |||
| { | |||
| if( $(sht(msg=>$ci)) == $null) { | |||
| exit(); | |||
| } | |||
| remove_hf_re("^X-"); | |||
| if($T_reply_code != 200 && $T_reply_code != 202) { | |||
| $var(Result) = "Failure"; | |||
| } else { | |||
| $var(Result) = "Success"; | |||
| route(ROUTE_TO_AOR); | |||
| $var(JObj) = $rb; | |||
| set_body("$(var(JObj){kz.json,Body})", "text/plain"); | |||
| $avp(message_id) = $(var(JObj){kz.json,Message-ID}); | |||
| $avp(msg_id) = $(var(JObj){kz.json,Msg-ID}); | |||
| $avp(server_id) = $(var(JObj){kz.json,Server-ID}); | |||
| t_on_reply("MESSAGE_REPLY"); | |||
| t_on_failure("MESSAGE_FAULT"); | |||
| t_relay(); | |||
| } | |||
| onreply_route[MESSAGE_REPLY] | |||
| { | |||
| if($T_reply_code < 300) { | |||
| xlog("L_INFO", "$ci|log|sending success delivery message to $avp(server_id)\n"); | |||
| $var(Payload) = $_s({"Event-Category" : "message", "Event-Name" : "delivery", "Call-ID" : "$ci", "Message-ID" : "$avp(message_id)" , "Delivery-Result-Code" : "sip:$T_reply_code", "Msg-ID" : "$avp(msg_id)" , "Status" : "delivered"}); | |||
| $var(exchange) = "targeted"; | |||
| $var(RK) = $avp(server_id); | |||
| kazoo_publish($var(exchange), $var(RK), $var(Payload)); | |||
| } | |||
| } | |||
| $var(Payload) = '{ "Event-Category" : "message", "Event-Name" : "delivery", "Call-ID" : "$(sht(msg=>$ci){kz.json,Call-ID})", "Message-ID" : "$(sht(msg=>$ci){kz.json,Message-ID})" , "Delivery-Result-Code" : "sip:$T_reply_code", "Msg-ID" : "$(sht(msg=>$ci){kz.json,Msg-ID})" , "Status" : "$var(Result)"}'; | |||
| $var(RoutingKey) = $(sht(msg=>$ci){kz.json,Server-ID}); | |||
| failure_route[MESSAGE_FAULT] | |||
| { | |||
| xlog("L_INFO", "$ci|log|sending failure delivery message to $avp(server_id)\n"); | |||
| $var(Payload) = $_s({"Event-Category" : "message", "Event-Name" : "delivery", "Call-ID" : "$ci", "Message-ID" : "$avp(message_id)" , "Delivery-Result-Code" : "sip:$T_reply_code", "Msg-ID" : "$avp(msg_id)" , "Status" : "failure"}); | |||
| $var(exchange) = "targeted"; | |||
| if($var(RoutingKey) == "") { | |||
| $var(exchange) = "sms"; | |||
| $var(RoutingKey) = "message.delivery." + $(sht(msg=>$ci){kz.json,Call-ID}{kz.encode}); | |||
| } | |||
| xlog("L_INFO", "sending delivery message for $ci\n"); | |||
| kazoo_publish($var(exchange), $var(RoutingKey), $var(Payload)); | |||
| $var(RK) = $avp(server_id); | |||
| kazoo_publish($var(exchange), $var(RK), $var(Payload)); | |||
| } | |||
| route[MESSAGE_BINDINGS] | |||
| { | |||
| $var(key) = "kamailio@MY_HOSTNAME"; | |||
| $var(payload) = "{ 'exchange' : 'sms' , 'type' : 'topic', 'queue' : 'MSG-QUEUE-MY_HOSTNAME', 'routing' : 'message.route." + $(var(key){kz.encode}) + ".*', 'no_ack' : 0 }"; | |||
| $var(payload) = $_s({"name": "sms", "exchange": "im", "type": "topic", "queue": "MSG-QUEUE-MY_HOSTNAME", "routing": "sms.outbound.$(var(key){kz.encode}).*", "no_ack": false, "federate": true }); | |||
| kazoo_subscribe("$var(payload)"); | |||
| } | |||
| @ -1,45 +1,116 @@ | |||
| ######## NAT Traversal module - signaling functions ######## | |||
| #!ifndef NATHELPER_LOADED | |||
| loadmodule "nathelper.so" | |||
| #!trydef NATHELPER_LOADED | |||
| #!endif | |||
| modparam("nathelper", "received_avp", "$avp(AVP_RECV_PARAM)") | |||
| modparam("nathelper", "sipping_from", "sip:sipcheck@MY_HOSTNAME") | |||
| modparam("nathelper", "sipping_from", "sip:registrar@MY_HOSTNAME") | |||
| #!ifdef WEBSOCKETS_ROLE | |||
| #!trydef KZ_NAT_DETECT 83 | |||
| #!else | |||
| #!trydef KZ_NAT_DETECT 19 | |||
| #!endif | |||
| #!trydef KZ_NAT_FIX_SDP_REQUEST 1 | |||
| #!trydef KZ_NAT_FIX_SDP_REPLY 1 | |||
| #!trydef KZ_NAT_SDP_TEST 8 | |||
| #!trydef KZ_NAT_SDP_FIX 10 | |||
| kazoo.nat_fix_sdp_request = KZ_NAT_FIX_SDP_REQUEST descr "performs request sdp replacement of private addresses" | |||
| kazoo.nat_fix_sdp_reply = KZ_NAT_FIX_SDP_REPLY descr "performs reply sdp replacement of private addresses" | |||
| ####### NAT Traversal Logic ######## | |||
| route[NAT_TEST_AND_CORRECT] | |||
| route[NAT_SDP] | |||
| { | |||
| if( has_body("application/sdp")) { | |||
| if( nat_uac_test(KZ_NAT_SDP_TEST)) { | |||
| xlog("L_DEBUG", "$ci|log|applying sdp nat fix\n"); | |||
| $var(ret) = fix_nated_sdp(KZ_NAT_SDP_FIX); | |||
| xlog("L_DEBUG", "$ci|log|result of applying sdp nat fix is $var(ret)\n"); | |||
| } else if( is_method("INVITE") && !isflagset(FLAG_INTERNALLY_SOURCED) && is_audio_on_hold()) { | |||
| xlog("L_DEBUG", "$ci|log|applying sdp nat fix for held channel\n"); | |||
| $var(ret) = fix_nated_sdp(KZ_NAT_SDP_FIX); | |||
| xlog("L_DEBUG", "$ci|log|result of applying sdp nat fix for held channel is $var(ret)\n"); | |||
| } | |||
| } | |||
| } | |||
| route[NAT_DETECT] | |||
| { | |||
| if($sel(cfg_get.kazoo.nat_fix_sdp_request) == 1) { | |||
| route(NAT_SDP); | |||
| } | |||
| if ($Rp == "5080") { | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| xlog("L_DEBUG", "$ci|log|skipping nat correction on PORT 5080\n"); | |||
| } else { | |||
| if (is_present_hf("Record-Route")) { | |||
| $var(i) = 0; | |||
| $var(rr_count) = $rr_count; | |||
| while($var(i) < $var(rr_count)) { | |||
| $var(rr_base) = $(hdr(Record-Route)[$var(i)]); | |||
| $var(rr_idx) = 0; | |||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||
| while($var(rr) != $null && $var(rr) != "") { | |||
| $var(i) = $var(i) + 1; | |||
| if (!is_myself("$(var(rr){nameaddr.uri})")) { | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| xlog("L_DEBUG", "$ci|log|skipping nat correction on record-route $(var(rr){nameaddr.uri})\n"); | |||
| } | |||
| $var(rr_idx) = $var(rr_idx) + 1; | |||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if (isflagset(FLAG_SKIP_NAT_CORRECTION)) { | |||
| xlog("L_DEBUG", "$ci|log|skipping nat detection\n"); | |||
| return; | |||
| } | |||
| force_rport(); | |||
| if(nat_uac_test(KZ_NAT_DETECT)) { | |||
| xlog("L_DEBUG", "$ci|log|detected nat request\n"); | |||
| setflag(FLT_NATS); | |||
| if (!is_method("REGISTER")) { | |||
| if(is_first_hop()) set_contact_alias(); | |||
| } | |||
| } | |||
| } | |||
| route[NAT_MANAGE] | |||
| { | |||
| if (is_present_hf("Record-Route")) { | |||
| $var(i) = 0; | |||
| $var(rr_count) = $rr_count; | |||
| while($var(i) < $var(rr_count)) { | |||
| $var(rr_base) = $(hdr(Record-Route)[$var(i)]); | |||
| $var(rr_idx) = 0; | |||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||
| while($var(rr) != $null && $var(rr) != "") { | |||
| $var(i) = $var(i) + 1; | |||
| if (!is_myself("$(var(rr){nameaddr.uri})")) { | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| } | |||
| $var(rr_idx) = $var(rr_idx) + 1; | |||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||
| } | |||
| } | |||
| } else if ($Rp == "5080") { | |||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||
| } | |||
| if (isflagset(FLAG_SKIP_NAT_CORRECTION)) { | |||
| return(); | |||
| } | |||
| if (nat_uac_test("NAT_UAC_TEST_LEVEL")) { | |||
| force_rport(); | |||
| fix_nated_contact(); | |||
| } | |||
| if (has_body("application/sdp") && nat_uac_test("8")) { | |||
| fix_nated_sdp("10"); | |||
| } | |||
| if( is_reply() && $sel(cfg_get.kazoo.nat_fix_sdp_reply) == 1) { | |||
| route(NAT_SDP); | |||
| } | |||
| if ( is_request() && isflagset(FLAG_INTERNALLY_SOURCED)) { | |||
| setbflag(FLB_NATB); | |||
| } | |||
| if ( is_request() && has_totag() ) { | |||
| setbflag(FLB_NATB); | |||
| } | |||
| if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))) { | |||
| return; | |||
| } | |||
| if (is_reply()) { | |||
| if(isflagset(FLT_NATS) || isbflagset(FLB_NATB)) { | |||
| if(is_first_hop()) { | |||
| set_contact_alias(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||
| @ -0,0 +1,213 @@ | |||
| #!trydef KZ_PRESENCE_REMOVE_WATCHER_ON_EXPIRED_REGISTRATION 0 | |||
| #!trydef KZ_PRESENCE_MAX_NOTIFY_ERROR 3 | |||
| #!trydef KZ_PRESENCE_NOTIFY_LOG_LEVEL 4 | |||
| kazoo.presence_notify = 1 descr "enable/disable sending notify callback to omnipresence" | |||
| kazoo.presence_notify_timeout = 5000 descr "timeout in ms waiting for notify reply" | |||
| kazoo.presence_notify_log_body = 0 descr "logs the body sent in the notification" | |||
| kazoo.presence_notify_log_resp_body = 0 descr "logs the body received from notification" | |||
| kazoo.presence_notify_log_to_table = 1 descr "logs notify/reply to active_watchers_log table" | |||
| kazoo.presence_notify_log_to_amqp = 0 descr "logs notify/reply to amqp" | |||
| kazoo.presence_notify_record_route = 1 descr "add record route header to notify msg sent" | |||
| kazoo.presence_notify_log_init_body = 0 descr "logs the body before its sent" | |||
| kazoo.presence_notify_force_send_socket = 1 descr "forces the send socket to the contact" | |||
| kazoo.presence_remove_watcher_on_expired_registration = KZ_PRESENCE_REMOVE_WATCHER_ON_EXPIRED_REGISTRATION descr "removes watcher on expired registration" | |||
| kazoo.presence_max_notify_error = KZ_PRESENCE_MAX_NOTIFY_ERROR descr "number of consecutive fails allowed before removing the subscription" | |||
| kazoo.presence_notify_log_level = KZ_PRESENCE_NOTIFY_LOG_LEVEL descr "loglevel for informational log messages" | |||
| ######## Generic Hash Table container in shared memory ######## | |||
| modparam("htable", "htable", "notify=>size=16;autoexpire=3600;updateexpire=1;initval=0") | |||
| route[PRESENCE_LOCAL_REQ_NOTIFY] | |||
| { | |||
| if($rm != "NOTIFY") { | |||
| return; | |||
| } | |||
| t_set_fr($sel(cfg_get.kazoo.presence_notify_timeout), $sel(cfg_get.kazoo.presence_notify_timeout)); | |||
| xlog("L_DEBUG", "$ci|log|init preparing $subs(event) notify to $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) : $du\n"); | |||
| if($sel(cfg_get.kazoo.presence_notify_log_init_body) == 1) { | |||
| xlog("L_INFO", "$ci|log|init|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||
| } | |||
| if($sel(cfg_get.kazoo.presence_notify_force_send_socket) == 1) { | |||
| $fs = $_s($(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port})); | |||
| xlog("L_DEBUG", "$ci|log|init|forcing socket to $fs, $(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}) , $ct\n"); | |||
| } | |||
| if($sel(cfg_get.kazoo.presence_notify_record_route) == 1) { | |||
| record_route(); | |||
| } | |||
| #!ifdef NAT_TRAVERSAL_ROLE | |||
| if(!isdsturiset()) { | |||
| handle_ruri_alias(); | |||
| } | |||
| #!endif | |||
| } | |||
| modparam("mqueue","mqueue", "name=presence_last_notity") | |||
| modparam("rtimer", "timer", "name=notifytimer;interval=1;mode=1;") | |||
| modparam("rtimer", "exec", "timer=notifytimer;route=PRESENCE_LOG_TIMER_ROUTE") | |||
| modparam("rtimer", "timer", "name=pres_cleanup;interval=10;mode=1;") | |||
| modparam("rtimer", "exec", "timer=pres_cleanup;route=PRESENCE_CLEANUP") | |||
| modparam("rtimer", "timer", "name=pres_publisher_cleanup;interval=5;mode=1;") | |||
| modparam("rtimer", "exec", "timer=pres_publisher_cleanup;route=PRESENCE_PUBLISHER_CLEANUP") | |||
| event_route[presence:notify-reply] | |||
| { | |||
| if($sel(cfg_get.kazoo.presence_notify) != 1) | |||
| return; | |||
| $xavp(pres=>delete_subscription) = 0; | |||
| if($notify_reply($rs) == 200) { | |||
| $sht(notify=>$ci) = $null; | |||
| $sht(notify=>$ci::count) = 0; | |||
| xlog("$(sel(cfg_get.kazoo.presence_notify_log_level){s.int})", "$ci|end|notified $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n"); | |||
| } else if($subs(reason) == "timeout") { | |||
| $xavp(pres=>delete_subscription) = 1; | |||
| xlog("L_DEBUG", "$ci|end|deleting subscription $subs(pres_uri) for $subs(watcher_username)@$subs(watcher_domain) due to timeout\n"); | |||
| } else if($notify_reply($rs) == 481 && $subs(reason) == "timeout") { | |||
| xlog("L_DEBUG","$ci|end|sent subscription $hdr(Subscription-State)\n"); | |||
| } else if($notify_reply($rs) == 408) { | |||
| if($rP != "UDP") { | |||
| $xavp(pres=>delete_subscription) = 1; | |||
| xlog("L_ERROR", "$ci|warning|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri) with reply $notify_reply($rs)\n"); | |||
| } else { | |||
| $var(shtinc) = $shtinc(notify=>$ci::count); | |||
| if($var(shtinc) > $sel(cfg_get.kazoo.presence_max_notify_error)) { | |||
| $xavp(pres=>delete_subscription) = 1; | |||
| xlog("L_WARNING", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri) with reply $notify_reply($rs)\n"); | |||
| } else { | |||
| $var(level) = 6 - $var(shtinc); | |||
| xlog("$var(level)", "$ci|error|received $notify_reply($rs) ($var(shtinc)/$sel(cfg_get.kazoo.presence_max_notify_error)) when notifying $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) with reply $notify_reply($rs)\n"); | |||
| } | |||
| } | |||
| } else { | |||
| $xavp(pres=>delete_subscription) = 1; | |||
| xlog("L_WARNING", "$ci|end|deleting subscription $subs(pres_uri) as $subs(watcher_username)@$subs(watcher_domain) replied with $notify_reply($rs)\n"); | |||
| } | |||
| if($sel(cfg_get.kazoo.presence_notify_log_body) == 1) | |||
| xlog("L_INFO", "$ci|log|sent|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||
| if($sel(cfg_get.kazoo.presence_notify_log_resp_body) == 1) | |||
| xlog("L_INFO", "$ci|log|resp|body $(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||
| if($sel(cfg_get.kazoo.presence_notify_log_to_amqp) == 1) { | |||
| route(PRESENCE_NOTIFY_AMQP); | |||
| } | |||
| if($sel(cfg_get.kazoo.presence_notify_log_to_table) == 1) { | |||
| if($xavp(pres=>delete_subscription) != 1 && $subs(reason) != "timeout") { | |||
| $var(Query) = $_s(KZQ_REPLACE_WATCHERS_LOG); | |||
| mq_add("presence_last_notity", "$subs(callid)", "$var(Query)"); | |||
| } | |||
| } | |||
| } | |||
| route[PRESENCE_LOG_TIMER_ROUTE] | |||
| { | |||
| $var(runloop) = 1; | |||
| while(mq_fetch("presence_last_notity") == 1 && $var(runloop) < MAX_WHILE_LOOPS) { | |||
| $var(ci) = $mqk(presence_last_notity); | |||
| xlog("L_DEBUG", "Query : $mqv(presence_last_notity)\n"); | |||
| $var(sqlres) = sql_query("cb", "$mqv(presence_last_notity)"); | |||
| xlog("L_DEBUG", "Query result : $var(sqlres)\n"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$var(ci)|log|error running query : $mqv(presence_last_notity)\n"); | |||
| } else { | |||
| $var(nrows) = $sqlrows(cb); | |||
| xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows)\n"); | |||
| if($var(nrows) == 0) { | |||
| xlog("L_DEBUG", "$var(ci)|log|error no rows affected when running query\n"); | |||
| } | |||
| } | |||
| $var(runloop) = $var(runloop) + 1; | |||
| } | |||
| } | |||
| route[PRESENCE_NOTIFY_AMQP] | |||
| { | |||
| $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "notify", "Event-Package" : "$subs(event)", "Timestamp" : $TS, "Call-ID" : "$subs(callid)", "From" : "$fu", "To" : "$subs(to_user)@$subs(to_domain)", "Sent" : "$(TS{s.ftime,%Y-%m-%d %H:%M:%S})", "Body" : "Hostname : MY_HOSTNAME\r\nTimestamp : $(TS{s.ftime,%Y-%m-%d %H:%M:%S})\r\n$(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\r\nResponse\r\n$(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})","Remote-CSeq" : $subs(remote_cseq), "Local-CSeq" : $subs(local_cseq), "Sequence" : $cs, "Version" : $subs(version), "Reply" : $notify_reply($rs) }); | |||
| $var(rk) = "notify." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode}); | |||
| kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request)); | |||
| xlog("L_INFO", "$ci|log|sent notify callback for event $subs(event) : $tu\n"); | |||
| } | |||
| route[PRESENCE_CLEANUP] | |||
| { | |||
| $var(Query) = $_s(KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_EXPIRES;); | |||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||
| $var(Query) = $_s(KZQ_DELETE_FROM_PRESENTITY_WHERE_EXPIRES;); | |||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||
| $var(Query) = $_s(KZQ_DELETE_FROM_PRESENTITY_WHERE_DIALOG_TERMINATED;); | |||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||
| $var(Query) = $_s(DELETE FROM ACTIVE_WATCHERS_LOG WHERE ID IN(select id from active_watchers_log a where not exists(select callid from active_watchers b where b.callid = a.callid and b.watcher_username = a.watcher_username and b.watcher_domain = a.watcher_domain));); | |||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||
| } | |||
| route[PRESENCE_PUBLISHER_CLEANUP] | |||
| { | |||
| xlog("L_DEBUG", "processing presence publisher cleanup\n"); | |||
| $var(sqlres) = sql_query("cb", "update tmp_probe set action = 1 where action = 0"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n"); | |||
| return; | |||
| } else { | |||
| $var(nrows) = $sqlrows(cb); | |||
| if($var(nrows) > 0) { | |||
| if (sql_xquery("cb", "select * from tmp_probe where action = 1", "cleanup_pres") == 1) | |||
| { | |||
| while($xavp(cleanup_pres) != $null) { | |||
| xlog("L_DEBUG", "processing $xavp(cleanup_pres=>event) notifies for $xavp(cleanup_pres=>presentity_uri)\n"); | |||
| pres_refresh_watchers("$xavp(cleanup_pres=>presentity_uri)", "$xavp(cleanup_pres=>event)", 1); | |||
| pv_unset("$xavp(cleanup_pres)"); | |||
| } | |||
| } | |||
| $var(sqlres) = sql_query("cb", "delete from tmp_probe where action = 1"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n"); | |||
| } else { | |||
| $var(nrows) = $sqlrows(cb); | |||
| if($var(nrows) > 0) { | |||
| xlog("L_DEBUG", "presence publisher cleanup processed $var(nrows) rows\n"); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| route[PRESENCE_DEFERRED_INIT] | |||
| { | |||
| xlog("L_INFO", "processing presence deferred init\n"); | |||
| $var(sqlres) = sql_query("cb", "update tmp_probe set action = 0 where action = 2"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n"); | |||
| return; | |||
| } else { | |||
| $var(nrows) = $sqlrows(cb); | |||
| if($var(nrows) > 0) { | |||
| xlog("L_NOTICE", "scheduled update for $var(nrows) watched presentities/event\n"); | |||
| } | |||
| } | |||
| } | |||
| route[PRESENCE_EXPIRED_REGISTRATION] | |||
| { | |||
| if($sel(cfg_get.kazoo.presence_remove_watcher_on_expired_registration) == 1) { | |||
| $var(watcher) = $_s(sip:$ulc(exp=>aor)); | |||
| $var(watcher_username) = $(var(watcher){uri.user}); | |||
| $var(watcher_domain) = $(var(watcher){uri.host}); | |||
| $var(Query) = $_s(DELETE FROM active_watchers WHERE watcher_username = "$var(watcher_username)" and watcher_domain = "$var(watcher_domain)";); | |||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||
| } | |||
| } | |||
| @ -1,117 +0,0 @@ | |||
| kazoo.presence_notify = 1 descr "enable/disable sending notify callback to omnipresence" | |||
| kazoo.presence_notify_timeout = 3000 descr "timeout in ms waiting for notify reply" | |||
| kazoo.presence_notify_log_body = 0 descr "logs the body sent in the notification" | |||
| kazoo.presence_notify_log_resp_body = 0 descr "logs the body received from notification" | |||
| kazoo.presence_notify_log_to_table = 1 descr "logs notify/reply to active_watchers_log table" | |||
| kazoo.presence_notify_log_to_amqp = 0 descr "logs notify/reply to amqp" | |||
| kazoo.presence_notify_record_route = 1 descr "add record route header to notify msg sent" | |||
| kazoo.presence_notify_log_init_body = 0 descr "logs the body before its sent" | |||
| kazoo.presence_notify_force_send_socket = 0 descr "forces the send socket to the contact" | |||
| ######## Generic Hash Table container in shared memory ######## | |||
| modparam("htable", "htable", "notify=>size=16;autoexpire=3600;updateexpire=1;initval=0") | |||
| #!trydef PRESENCE_NOTIFY_INIT | |||
| #!trydef MAX_NOTIFY_ERROR 5 | |||
| route[PRESENCE_LOCAL_NOTIFY] | |||
| { | |||
| if($rm != "NOTIFY") { | |||
| return; | |||
| } | |||
| t_set_fr(@cfg_get.kazoo.presence_notify_timeout, @cfg_get.kazoo.presence_notify_timeout); | |||
| xlog("L_INFO", "$ci|log|init preparing $subs(event) notify to $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) : $du\n"); | |||
| if(@cfg_get.kazoo.presence_notify_log_init_body == 1) { | |||
| xlog("L_INFO", "$ci|log|init|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||
| } | |||
| if(@cfg_get.kazoo.presence_notify_force_send_socket == 1) { | |||
| $fs = $_s($(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port})); | |||
| xlog("L_INFO", "$ci|log|init|forcing socket to $fs, $(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}) , $ct\n"); | |||
| } | |||
| if(@cfg_get.kazoo.presence_notify_record_route == 1) { | |||
| record_route(); | |||
| } | |||
| } | |||
| modparam("mqueue","mqueue", "name=presence_last_notity") | |||
| ####### RTIMER module ########## | |||
| #!ifndef RTIMER_LOADED | |||
| loadmodule "rtimer.so" | |||
| #!trydef RTIMER_LOADED | |||
| #!endif | |||
| modparam("rtimer", "timer", "name=notifytimer;interval=500000u;mode=2;") | |||
| modparam("rtimer", "exec", "timer=notifytimer;route=PRESENCE_LOG_TIMER_ROUTE") | |||
| event_route[presence:notify-reply] | |||
| { | |||
| if(@cfg_get.kazoo.presence_notify != 1) | |||
| return; | |||
| $xavp(pres=>delete_subscription) = 0; | |||
| if($subs(reason) == "timeout") { | |||
| $xavp(pres=>delete_subscription) = 1; | |||
| xlog("L_INFO", "$ci|end|deleting subscribtion $subs(pres_uri) for $subs(watcher_username)@$subs(watcher_domain) due to timeout\n"); | |||
| } else if($notify_reply($rs) == 200) { | |||
| $sht(notify=>$ci) = $null; | |||
| $sht(notify=>$ci::count) = 0; | |||
| xlog("L_INFO", "$ci|end|notified $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n"); | |||
| } else { | |||
| xlog("L_ERROR", "$ci|error|received $notify_reply($rs) when notifying $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n"); | |||
| if($rP != "UDP") { | |||
| $xavp(pres=>delete_subscription) = 1; | |||
| xlog("L_ERROR", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri)\n"); | |||
| } else { | |||
| $var(shtinc) = $shtinc(notify=>$ci::count); | |||
| if($var(shtinc) > MAX_NOTIFY_ERROR) { | |||
| $xavp(pres=>delete_subscription) = 1; | |||
| xlog("L_ERROR", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri)\n"); | |||
| } | |||
| } | |||
| } | |||
| if(@cfg_get.kazoo.presence_notify_log_body == 1) | |||
| xlog("L_INFO", "$ci|log|sent|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||
| if(@cfg_get.kazoo.presence_notify_log_resp_body == 1) | |||
| xlog("L_INFO", "$ci|log|resp|body $(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||
| if(@cfg_get.kazoo.presence_notify_log_to_amqp == 1) { | |||
| route(PRESENCE_NOTIFY_AMQP); | |||
| } | |||
| if(@cfg_get.kazoo.presence_notify_log_to_table == 1) { | |||
| $var(Query) = $_s(REPLACE INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES ("$subs(uri)", "$subs(watcher_username)", "$subs(watcher_domain)", "$subs(event)","$subs(callid)","$subs(to_user)","$subs(to_domain)", '$(subs(user_agent){s.escape.common}{s.replace,\',''}{s.replace,$$,})', $TS, $notify_reply($rs), '$(mb{s.escape.common}{s.replace,\',''}{s.replace,$$,})', '$(notify_reply($mb){s.escape.common}{s.replace,\',''}{s.replace,$$,})')); | |||
| mq_add("presence_last_notity", "$subs(callid)", "$var(Query)"); | |||
| } | |||
| } | |||
| route[PRESENCE_LOG_TIMER_ROUTE] | |||
| { | |||
| $var(runloop) = 1; | |||
| while(mq_fetch("presence_last_notity") == 1 && $var(runloop) < MAX_WHILE_LOOPS) { | |||
| $var(ci) = $mqk(presence_last_notity); | |||
| xlog("L_DEBUG", "Query : $mqv(presence_last_notity)\n"); | |||
| $var(sqlres) = sql_query("cb", "$mqv(presence_last_notity)"); | |||
| xlog("L_DEBUG", "Query result : $var(sqlres)\n"); | |||
| if($var(sqlres) < 0) { | |||
| xlog("L_ERROR", "$var(ci)|log|error updating active_watchers_log\n"); | |||
| } else { | |||
| $var(nrows) = $sqlrows(cb); | |||
| xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows)\n"); | |||
| if($var(nrows) == 0) { | |||
| xlog("L_ERROR", "$var(ci)|log|error no rows affected when updating active_watchers_log\n"); | |||
| } | |||
| } | |||
| $var(runloop) = $var(runloop) + 1; | |||
| } | |||
| } | |||
| route[PRESENCE_NOTIFY_AMQP] | |||
| { | |||
| $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "notify", "Event-Package" : "$subs(event)", "Timestamp" : $TS, "Call-ID" : "$subs(callid)", "From" : "$fu", "To" : "$subs(to_user)@$subs(to_domain)", "Sent" : "$(TS{s.ftime,%Y-%m-%d %H:%M:%S})", "Body" : "Hostname : MY_HOSTNAME\r\nTimestamp : $(TS{s.ftime,%Y-%m-%d %H:%M:%S})\r\n$(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\r\nResponse\r\n$(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})","Remote-CSeq" : $subs(remote_cseq), "Local-CSeq" : $subs(local_cseq), "Sequence" : $cs, "Version" : $subs(version), "Reply" : $notify_reply($rs) }); | |||
| $var(rk) = "notify." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode}); | |||
| kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request)); | |||
| xlog("L_INFO", "$ci|log|sent notify callback for event $subs(event) : $tu\n"); | |||
| } | |||
| @ -0,0 +1,67 @@ | |||
| #!trydef SANITY_CHECK_USE_PORT 1 | |||
| #!trydef SANITY_DROPS_REQUEST 1 | |||
| #!trydef SANITY_DEFAULT_CHECK 17895 | |||
| #!trydef SANITY_URI_CHECKS 7 | |||
| #!trydef SANITY_TRACE_REQUEST 1 | |||
| #!substdef "!SANITY_SUBST_CACHE_PERIOD!$def(SANITY_CACHE_PERIOD)!g" | |||
| ######## SIP message formatting sanity checks [requires sl] ######## | |||
| loadmodule "sanity.so" | |||
| modparam("sanity", "default_checks", SANITY_DEFAULT_CHECK) | |||
| modparam("sanity", "uri_checks", SANITY_URI_CHECKS) | |||
| modparam("sanity", "autodrop", 0) | |||
| modparam("sanity", "noreply", 1) | |||
| modparam("debugger", "mod_level", "sanity=-3") | |||
| kazoo.sanity_check_use_port = SANITY_CHECK_USE_PORT descr "should we keep track of ip and port for sanity failures" | |||
| kazoo.sanity_drops_request = SANITY_DROPS_REQUEST descr "should we drop the request or send error on sanity failure" | |||
| kazoo.sanity_trace_request = SANITY_TRACE_REQUEST descr "should we trace the request if sip trace role is enabled" | |||
| route[SANITY_CHECK] | |||
| { | |||
| ## CVE-2018-14767 | |||
| if($(hdr(To)[1]) != $null) { | |||
| xlog("second To header not null - dropping message"); | |||
| drop; | |||
| } | |||
| $var(sanity_key) = ""; | |||
| if($sel(cfg_get.kazoo.sanity_check_use_port) == 1) { | |||
| $var(sanity_key) = $_s("$si::$sp"); | |||
| } else { | |||
| $var(sanity_key) = $_s("$si"); | |||
| } | |||
| if (!sanity_check()) { | |||
| #!ifdef SIP_TRACE_ROLE | |||
| sip_trace(); | |||
| #!endif | |||
| if($sel(cfg_get.kazoo.sanity_drops_request) == 1) { | |||
| xlog("L_WARN", "$ci|end|dropping insane message from $si:$sp\n"); | |||
| drop; | |||
| } else { | |||
| xlog("L_WARN", "$ci|end|insane message from $si:$sp\n"); | |||
| send_reply("400", "Bad Request"); | |||
| exit; | |||
| } | |||
| } | |||
| if (!mf_process_maxfwd_header("10")) { | |||
| xlog("L_WARN", "$ci|end|too much hops, not enough barley from $si:$sp\n"); | |||
| send_reply("483", "Too Many Hops"); | |||
| exit; | |||
| } | |||
| if ($ua == "friendly-scanner" || | |||
| $ua == "sundayddr" || | |||
| $ua == "pplsip" || | |||
| $ua =~ "NiceGuy" || | |||
| $ua =~ "PortSIP" || | |||
| $ua =~ "sipcli" ) { | |||
| xlog("L_WARN", "$ci|end|dropping message with user-agent $ua from $si:$sp\n"); | |||
| drop; | |||
| } | |||
| } | |||