From 6ead13781b1b7896173c99016f0e335831834263 Mon Sep 17 00:00:00 2001 From: Tripon Alexandru-Ionut Date: Wed, 12 Jun 2019 10:42:10 +0300 Subject: [PATCH] Moved call test configurations --- .gitignore | 1 + .../kamevapi/cgrates/etc/cgrates/cgrates.json | 2 +- .../osips/opensips/etc/opensips/opensips.cfg | 2 + .../opensips/etc/opensips/opensips.cfg | 4 +- .../asterisk_ari/asterisk/etc/asterisk/README | 15 + .../asterisk/etc/asterisk/ari.conf | 8 + .../asterisk/etc/asterisk/asterisk.conf | 12 + .../asterisk/etc/asterisk/cdr.conf | 7 + .../asterisk/etc/asterisk/cdr_custom.conf | 4 + .../asterisk/etc/asterisk/confbridge.conf | 1 + .../asterisk/etc/asterisk/extensions.conf | 8 + .../asterisk/etc/asterisk/http.conf | 4 + .../asterisk/etc/asterisk/indications.conf | 19 + .../asterisk/etc/asterisk/logger.conf | 9 + .../asterisk/etc/asterisk/manager.conf | 155 +++++++ .../asterisk/etc/asterisk/modules.conf | 136 ++++++ .../asterisk/etc/asterisk/musiconhold.conf | 5 + .../asterisk/etc/asterisk/pjsip.conf | 147 ++++++ .../asterisk/etc/asterisk/queues.conf | 19 + .../asterisk/etc/asterisk/voicemail.conf | 23 + .../asterisk_ari/asterisk/etc/init.d/asterisk | 175 +++++++ .../cgrates/etc/cgrates/cgrates.json | 145 ++++++ .../asterisk_ari/cgrates/etc/init.d/cgrates | 184 ++++++++ data/tutorials_test/fs_evsock/README.md | 17 + .../cgrates/etc/cgrates/cgrates.json | 142 ++++++ .../fs_evsock/cgrates/etc/init.d/cgrates | 184 ++++++++ .../freeswitch/etc/freeswitch_conf.tar.gz | Bin 0 -> 27632 bytes .../freeswitch/etc/init.d/freeswitch | 145 ++++++ .../kamevapi/cgrates/etc/cgrates/cgrates.json | 141 ++++++ .../kamevapi/cgrates/etc/init.d/cgrates} | 8 +- .../kamevapi/kamailio/etc/init.d/kamailio | 166 +++++++ .../etc/kamailio/kamailio-cgrates.cfg | 192 ++++++++ .../kamailio/etc/kamailio/kamailio.cfg | 439 ++++++++++++++++++ .../osips/cgrates/etc/cgrates/cgrates.json | 139 ++++++ .../osips/cgrates/etc/init.d/cgrates | 175 +++++++ .../osips/opensips/etc/default/opensips | 27 ++ .../osips/opensips/etc/init.d/opensips | 199 ++++++++ .../osips/opensips/etc/opensips/opensips.cfg | 269 +++++++++++ general_tests/tutorial_calls_test.go | 8 +- 39 files changed, 3325 insertions(+), 11 deletions(-) create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/README create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/ari.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/asterisk.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr_custom.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/confbridge.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/extensions.conf create mode 100644 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/http.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/indications.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/logger.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/manager.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/modules.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/musiconhold.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/pjsip.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/queues.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/voicemail.conf create mode 100755 data/tutorials_test/asterisk_ari/asterisk/etc/init.d/asterisk create mode 100644 data/tutorials_test/asterisk_ari/cgrates/etc/cgrates/cgrates.json create mode 100755 data/tutorials_test/asterisk_ari/cgrates/etc/init.d/cgrates create mode 100644 data/tutorials_test/fs_evsock/README.md create mode 100644 data/tutorials_test/fs_evsock/cgrates/etc/cgrates/cgrates.json create mode 100755 data/tutorials_test/fs_evsock/cgrates/etc/init.d/cgrates create mode 100644 data/tutorials_test/fs_evsock/freeswitch/etc/freeswitch_conf.tar.gz create mode 100755 data/tutorials_test/fs_evsock/freeswitch/etc/init.d/freeswitch create mode 100644 data/tutorials_test/kamevapi/cgrates/etc/cgrates/cgrates.json rename data/{tutorials/osips_native/cgrates/etc/init.d/.fuse_hidden0000001700000001 => tutorials_test/kamevapi/cgrates/etc/init.d/cgrates} (95%) create mode 100755 data/tutorials_test/kamevapi/kamailio/etc/init.d/kamailio create mode 100644 data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg create mode 100644 data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio.cfg create mode 100644 data/tutorials_test/osips/cgrates/etc/cgrates/cgrates.json create mode 100755 data/tutorials_test/osips/cgrates/etc/init.d/cgrates create mode 100755 data/tutorials_test/osips/opensips/etc/default/opensips create mode 100755 data/tutorials_test/osips/opensips/etc/init.d/opensips create mode 100644 data/tutorials_test/osips/opensips/etc/opensips/opensips.cfg diff --git a/.gitignore b/.gitignore index 6559bcf3a..9181381ee 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ dean* data/vagrant/.vagrant data/vagrant/vagrant_ansible_inventory_default data/tutorials/fs_evsock/freeswitch/etc/freeswitch/ +data/tutorials_test/fs_evsock/freeswitch/etc/freeswitch/ vendor *.test glide.lock diff --git a/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json b/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json index 7cb209405..f15bac3b7 100644 --- a/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json +++ b/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json @@ -83,7 +83,7 @@ ], "store_session_costs": true, "debit_interval": "5s", - "channel_sync_interval":"7s", // default: "5m" for test please use "7s" + "channel_sync_interval":"5m", }, diff --git a/data/tutorials/osips/opensips/etc/opensips/opensips.cfg b/data/tutorials/osips/opensips/etc/opensips/opensips.cfg index 678466d38..794255abe 100644 --- a/data/tutorials/osips/opensips/etc/opensips/opensips.cfg +++ b/data/tutorials/osips/opensips/etc/opensips/opensips.cfg @@ -203,6 +203,8 @@ route{ $cgr_opt(GetAttributes) = 1; $cgr_opt(GetSuppliers) = 1; $cgr_opt(AuthorizeResources) = 1; + $cgr_opt(AllocateResources) = 1; + $cgr_opt(ReleaseResources) = 1; $cgr_opt(ProcessThresholds) = 1; $cgr_opt(ProcessStatQueues) = 1; $cgr(RequestType) = "*prepaid"; diff --git a/data/tutorials/osips_native/opensips/etc/opensips/opensips.cfg b/data/tutorials/osips_native/opensips/etc/opensips/opensips.cfg index 01fafb284..4c439a88c 100644 --- a/data/tutorials/osips_native/opensips/etc/opensips/opensips.cfg +++ b/data/tutorials/osips_native/opensips/etc/opensips/opensips.cfg @@ -119,7 +119,7 @@ route{ if ( !loose_route() ) { # we do record-routing for all our traffic, so we should not # receive any sequential requests without Route hdr. - send_reply(404,"Not here"); + send_reply(404, "Not here"); exit; } @@ -164,7 +164,7 @@ route{ xlog("L_ERR", "Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]"); if (!is_method("ACK")) - send_reply(403,"Preload Route denied"); + send_reply(403, "Preload Route denied"); exit; } diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/README b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/README new file mode 100755 index 000000000..0f57ad6c2 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/README @@ -0,0 +1,15 @@ +The included Asterisk configuration files are intended to be an example +implementation for a fictitious company, Super Awesome Company. + +It can serve as a handy reference for understanding a simple Asterisk +configuration in an approximate real-world environment. + +If you intend to use this configuration as a template for your own, then +you will need to change many values in the various configuration files to +match your own devices, network, SIP ITSP accounts and more. + +For further documentation on this configuration see the Asterisk wiki: +https://wiki.asterisk.org/wiki/display/AST/Reference+Use+Cases+for+Asterisk. + +Please report bugs or errors in configuration on the Asterisk issue tracker: +https://wiki.asterisk.org/wiki/display/AST/Asterisk+Issue+Guidelines diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/ari.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/ari.conf new file mode 100755 index 000000000..f78a801e7 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/ari.conf @@ -0,0 +1,8 @@ +[general] +enabled = yes +allowed_origins = http://cgrates.org + +[cgrates] +type = user +read_only = no +password = CGRateS.org \ No newline at end of file diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/asterisk.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/asterisk.conf new file mode 100755 index 000000000..cb2ba8367 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/asterisk.conf @@ -0,0 +1,12 @@ +[directories] +astetcdir => /usr/share/cgrates/tutorials_test/asterisk_ari/asterisk/etc/asterisk +astspooldir => /tmp/cgr_asterisk_ari/asterisk/spool +astlogdir => /tmp/cgr_asterisk_ari/asterisk/log +astrundir => /tmp/cgr_asterisk_ari/asterisk/run +astdbdir => /tmp/cgr_asterisk_ari/asterisk/lib + +[options] +runuser = asterisk ; The user to run as. The default is root. +rungroup = asterisk ; The group to run as. The default is root + + diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr.conf new file mode 100755 index 000000000..e8749e37d --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr.conf @@ -0,0 +1,7 @@ +[general] +enable=yes + +[custom] +; We log the unique ID as it can be useful for troubleshooting any issues +; that arise. +loguniqueid=yes diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr_custom.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr_custom.conf new file mode 100755 index 000000000..12ad24fe4 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/cdr_custom.conf @@ -0,0 +1,4 @@ +[mappings] +; Our CDR log will be written to /var/log/asterisk/cdr-custom/Master.csv +; with the following schema. +Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})},${CDR(sequence)} diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/confbridge.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/confbridge.conf new file mode 100755 index 000000000..3a44e686a --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/confbridge.conf @@ -0,0 +1 @@ +; All conferences use default settings. This config must be present to load the confbridge application diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/extensions.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/extensions.conf new file mode 100755 index 000000000..7c3c8da6c --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/extensions.conf @@ -0,0 +1,8 @@ +[internal] + exten => _1XXX,1,NoOp() + same => n,Set(CGRMaxSessionTime=0); use it to disconnect automatically the call if CGRateS is not active + same => n,DumpChan() + same => n,Stasis(cgrates_auth,cgr_reqtype=*prepaid,cgr_supplier=supplier1,cgr_subsystems=*accounts*attributes*resources*stats*suppliers*thresholds) + same => n,Dial(PJSIP/${EXTEN},30,L(${CGRMaxSessionTime})) + same => n,Hangup() + diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/http.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/http.conf new file mode 100644 index 000000000..9d1f51885 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/http.conf @@ -0,0 +1,4 @@ +[general] +enabled = yes +bindaddr = 0.0.0.0 +bindport = 8088 \ No newline at end of file diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/indications.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/indications.conf new file mode 100755 index 000000000..115cddd0b --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/indications.conf @@ -0,0 +1,19 @@ +[general] +country = us ; We are in Waldo, Al, USA so the US is our default. + +[us] +description = United States / North America +ringcadence = 2000,4000 +dial = 350+440 +busy = 480+620/500,0/500 +ring = 440+480/2000,0/4000 +congestion = 480+620/250,0/250 +callwaiting = 440/300,0/10000 +dialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440 +record = 1400/500,0/15000 +info = !950/330,!1400/330,!1800/330,0 +stutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440 + +; Additional country configurations can be found in the Asterisk source +; at /configs/samples/indications.conf.sample + diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/logger.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/logger.conf new file mode 100755 index 000000000..8b0a1c19d --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/logger.conf @@ -0,0 +1,9 @@ +[general] + +[logfiles] + +console = verbose,notice,warning,error + +;messages = notice,warning,error +;full = verbose,notice,warning,error,debug +;security = security diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/manager.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/manager.conf new file mode 100755 index 000000000..bb9cc219a --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/manager.conf @@ -0,0 +1,155 @@ +; +; AMI - The Asterisk Manager Interface +; +; Third party application call management support and PBX event supervision +; +; Use the "manager show commands" at the CLI to list available manager commands +; and their authorization levels. +; +; "manager show command " will show a help text. +; +; ---------------------------- SECURITY NOTE ------------------------------- +; Note that you should not enable the AMI on a public IP address. If needed, +; block this TCP port with iptables (or another FW software) and reach it +; with IPsec, SSH, or SSL vpn tunnel. You can also make the manager +; interface available over http/https if Asterisk's http server is enabled in +; http.conf and if both "enabled" and "webenabled" are set to yes in +; this file. Both default to no. httptimeout provides the maximum +; timeout in seconds before a web based session is discarded. The +; default is 60 seconds. +; +[general] +enabled = yes +;webenabled = yes + +port = 5038 +bindaddr = 0.0.0.0 + +; Parameters that control AMI over TLS. ("enabled" must be set too). +; You can open a connection to this socket with e.g. +; +; openssl s_client -connect my_host:5039 +; +;tlsenable=no ; set to YES to enable it +;tlsbindaddr=0.0.0.0:5039 ; address and port to bind to, default to bindaddr and port 5039 +;tlscertfile=/tmp/asterisk.pem ; path to the certificate. +;tlsprivatekey=/tmp/private.pem ; path to the private key, if no private given, + ; if no tlsprivatekey is given, default is to search + ; tlscertfile for private key. +;tlscipher= ; string specifying which SSL ciphers to use or not use +; +;allowmultiplelogin = yes ; IF set to no, rejects manager logins that are already in use. +; ; The default is yes. +; +;displayconnects = yes +; +; Add a Unix epoch timestamp to events (not action responses) +; +;timestampevents = yes + +;brokeneventsaction = yes ; Restore previous behavior that caused the events + ; action to not return a response in certain + ; circumstances. Defaults to 'no'. + +; +; Display certain channel variables every time a channel-oriented +; event is emitted: +; +;channelvars = var1,var2,var3 + +; debug = on ; enable some debugging info in AMI messages (default off). + ; Also accessible through the "manager debug" CLI command. + +; authtimeout specifies the maximum number of seconds a client has to +; authenticate. If the client does not authenticate beofre this timeout +; expires, the client will be disconnected. (default: 30 seconds) + +;authtimeout = 30 + +; authlimit specifies the maximum number of unauthenticated sessions that will +; be allowed to connect at any given time. + +;authlimit = 50 + +;httptimeout = 60 +; a) httptimeout sets the Max-Age of the http cookie +; b) httptimeout is the amount of time the webserver waits +; on a action=waitevent request (actually its httptimeout-10) +; c) httptimeout is also the amount of time the webserver keeps +; a http session alive after completing a successful action + + +;[mark] +;secret = mysecret +;deny=0.0.0.0/0.0.0.0 +;permit=209.16.236.73/255.255.255.0 +;acl=named_acl_example ; use a named ACL from acl.conf +; +; +;setvar=PBXACCOUNT=edvina +; The setvar option defines channel variables that will be set when this account +; originates a call. You can define multiple setvar= commands for one manager +; user. +; +;eventfilter=Event: Newchannel +;eventfilter=Channel: (PJ)?SIP/(james|jim|john)- +;eventfilter=!Channel: DAHDI/ +; The eventfilter option is used to whitelist or blacklist events per user. +; A filter consists of an (unanchored) regular expression that is run on the +; entire event data. If the first character of the filter is an exclamation +; mark (!), the filter is appended to the blacklist instead of the whitelist. +; After first checking the read access below, the regular expression filters +; are processed as follows: +; - If no filters are configured all events are reported as normal. +; - If there are white filters only: implied black all filter processed first, +; then white filters. +; - If there are black filters only: implied white all filter processed first, +; then black filters. +; - If there are both white and black filters: implied black all filter processed +; first, then white filters, and lastly black filters. + +; +; If the device connected via this user accepts input slowly, +; the timeout for writes to it can be increased to keep it +; from being disconnected (value is in milliseconds) +; +; writetimeout = 100 +; +;displayconnects = yes ; Display on CLI user login/logoff +; +; Authorization for various classes +; +; Read authorization permits you to receive asynchronous events, in general. +; Write authorization permits you to send commands and get back responses. The +; following classes exist: +; +; all - All event classes below (including any we may have missed). +; system - General information about the system and ability to run system +; management commands, such as Shutdown, Restart, and Reload. +; call - Information about channels and ability to set information in a +; running channel. +; log - Logging information. Read-only. (Defined but not yet used.) +; verbose - Verbose information. Read-only. (Defined but not yet used.) +; agent - Information about queues and agents and ability to add queue +; members to a queue. +; user - Permission to send and receive UserEvent. +; config - Ability to read and write configuration files. +; command - Permission to run CLI commands. Write-only. +; dtmf - Receive DTMF events. Read-only. +; reporting - Ability to get information about the system. +; cdr - Output of cdr_manager, if loaded. Read-only. +; dialplan - Receive NewExten and VarSet events. Read-only. +; originate - Permission to originate new calls. Write-only. +; agi - Output AGI commands executed. Input AGI command to execute. +; cc - Call Completion events. Read-only. +; aoc - Permission to send Advice Of Charge messages and receive Advice +; - Of Charge events. +; test - Ability to read TestEvent notifications sent to the Asterisk Test +; Suite. Note that this is only enabled when the TEST_FRAMEWORK +; compiler flag is defined. +; security - Security Events. Read-only. +; message - Permissions to send out of call messages. Write-only +; +;read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan +;write = system,call,agent,user,config,command,reporting,originate,message + diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/modules.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/modules.conf new file mode 100755 index 000000000..38df4bcac --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/modules.conf @@ -0,0 +1,136 @@ +[modules] +autoload = no + +; This is a minimal module load. We are loading only the modules required for +; the Asterisk features used in the Super Awesome Company configuration. + +; Applications + +load = app_bridgewait.so +load = app_dial.so +load = app_playback.so +load = app_stack.so +load = app_verbose.so +load = app_voicemail.so +load = app_directory.so +load = app_confbridge.so +load = app_queue.so +load = app_dumpchan.so + +; Bridging + +load = bridge_builtin_features.so +load = bridge_builtin_interval_features.so +load = bridge_holding.so +load = bridge_native_rtp.so +load = bridge_simple.so +load = bridge_softmix.so + +; Call Detail Records + +load = cdr_custom.so + +; Channel Drivers + +load = chan_bridge_media.so +load = chan_pjsip.so + +; Codecs + +load = codec_gsm.so +load = codec_resample.so +load = codec_ulaw.so +load = codec_g722.so + +; Formats + +load = format_gsm.so +load = format_pcm.so +load = format_wav_gsm.so +load = format_wav.so + +; Functions + +load = func_callerid.so +load = func_cdr.so +load = func_pjsip_endpoint.so +load = func_sorcery.so +load = func_devstate.so +load = func_strings.so + +; Core/PBX + +load = pbx_config.so + +; Resources + +load = res_musiconhold.so +load = res_pjproject.so +load = res_pjsip_acl.so +load = res_pjsip_authenticator_digest.so +load = res_pjsip_caller_id.so +load = res_pjsip_dialog_info_body_generator.so +load = res_pjsip_diversion.so +load = res_pjsip_dtmf_info.so +load = res_pjsip_endpoint_identifier_anonymous.so +load = res_pjsip_endpoint_identifier_ip.so +load = res_pjsip_endpoint_identifier_user.so +load = res_pjsip_exten_state.so +load = res_pjsip_header_funcs.so +load = res_pjsip_logger.so +load = res_pjsip_messaging.so +load = res_pjsip_multihomed.so +load = res_pjsip_mwi_body_generator.so +load = res_pjsip_mwi.so +load = res_pjsip_nat.so +load = res_pjsip_notify.so +load = res_pjsip_one_touch_record_info.so +load = res_pjsip_outbound_authenticator_digest.so +load = res_pjsip_outbound_publish.so +load = res_pjsip_outbound_registration.so +load = res_pjsip_path.so +load = res_pjsip_pidf_body_generator.so +load = res_pjsip_pidf_digium_body_supplement.so +load = res_pjsip_pidf_eyebeam_body_supplement.so +load = res_pjsip_publish_asterisk.so +load = res_pjsip_pubsub.so +load = res_pjsip_refer.so +load = res_pjsip_registrar_expire.so +load = res_pjsip_registrar.so +load = res_pjsip_rfc3326.so +load = res_pjsip_sdp_rtp.so +load = res_pjsip_send_to_voicemail.so +load = res_pjsip_session.so +load = res_pjsip.so +load = res_pjsip_t38.so +load = res_pjsip_transport_websocket.so +load = res_pjsip_xpidf_body_generator.so +load = res_rtp_asterisk.so +load = res_sorcery_astdb.so +load = res_sorcery_config.so +load = res_sorcery_memory.so +load = res_sorcery_realtime.so +load = res_timing_timerfd.so + +;ARI +load => app_stasis.so +load => res_http_websocket.so +load => res_stasis.so +load => res_stasis_answer.so +load => res_stasis_device_state.so +load => res_stasis_playback.so +load => res_stasis_recording.so +load => res_stasis_snoop.so +load => res_ari.so +load => res_ari_applications.so +load => res_ari_asterisk.so +load => res_ari_bridges.so +load => res_ari_channels.so +load => res_ari_device_states.so +load => res_ari_endpoints.so +load => res_ari_events.so +load => res_ari_mailboxes.so +load => res_ari_model.so +load => res_ari_playbacks.so +load => res_ari_recordings.so +load => res_ari_sounds.so \ No newline at end of file diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/musiconhold.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/musiconhold.conf new file mode 100755 index 000000000..bc3ba2129 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/musiconhold.conf @@ -0,0 +1,5 @@ +[general] + +[default] +mode = files +directory = moh diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/pjsip.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/pjsip.conf new file mode 100755 index 000000000..a1d439b61 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/pjsip.conf @@ -0,0 +1,147 @@ +[testcalls] +type=transport +protocol=udp +bind=0.0.0.0:5080 + +[1001] +type = endpoint +transport = testcalls +context = internal +disallow = all +allow = ulaw +allow = alaw +aors = 1001 +auth = 1001 + +[1001] +type = aor +max_contacts = 5 + +[1001] +type=auth +auth_type=userpass +username=1001 +password=CGRateS.org + +[1002] +type = endpoint +transport = testcalls +context = internal +disallow = all +allow = ulaw +allow = alaw +aors = 1002 +auth = 1002 + +[1002] +type = aor +max_contacts = 5 +qualify_frequency = 0 + +[1002] +type=auth +auth_type=userpass +username=1002 +password=CGRateS.org + +[1003] +type = endpoint +transport = testcalls +context = internal +aors = 1003 +auth = 1003 +disallow = all +allow = ulaw +allow = alaw + +[1003] +type = aor +max_contacts = 5 + +[1003] +type=auth +auth_type=userpass +username=1003 +password=CGRateS.org + +[1004] +type = endpoint +transport = testcalls +context = internal +aors = 1004 +auth = 1004 +disallow = all +allow = ulaw +allow = alaw + +[1004] +type = aor +max_contacts = 5 + +[1004] +type=auth +auth_type=userpass +username=1004 +password=CGRateS.org + +[1005] +type = endpoint +transport = testcalls +context = internal +aors = 1005 +auth = 1005 +disallow = all +allow = ulaw +allow = alaw + +[1005] +type = aor +max_contacts = 5 + +[1005] +type=auth +auth_type=userpass +username=1005 +password=CGRateS.org + +[1006] +type = endpoint +transport = testcalls +context = internal +aors = 1006 +auth = 1006 +disallow = all +allow = ulaw +allow = alaw + +[1006] +type = aor +max_contacts = 5 + +[1006] +type=auth +auth_type=userpass +username=1006 +password=CGRateS.org + + +[1007] +type = endpoint +transport = testcalls +context = internal +aors = 1007 +auth = 1007 +disallow = all +allow = ulaw +allow = alaw + +[1007] +type = aor +max_contacts = 5 + +[1007] +type=auth +auth_type=userpass +username=1007 +password=CGRateS.org + diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/queues.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/queues.conf new file mode 100755 index 000000000..8aaa0b4d1 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/queues.conf @@ -0,0 +1,19 @@ +[general] +monitor-type = MixMonitor + +;========================Sales Queue == +; Calls all sales persons in a ring-all fashion +[sales] +strategy=ringall +member => PJSIP/1109 ; Terry Jules - Director of Sales +member => PJSIP/1105 ; Garnet Claude - Sales Associate +member => PJSIP/1112 ; Franny Ocean - Sales Associate + +;===================== Customer Advocate Queue == +; Calls all customer advocates in a ring-all fashion +[customer_advocate] +strategy=ringall +member => PJSIP/1101 ; Maria Berny - Director of Customer Experience +member => PJSIP/1115 ; Dusty Williams - Customer Advocate +member => PJSIP/1102 ; Tommy Briar - Customer Advocate + diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/voicemail.conf b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/voicemail.conf new file mode 100755 index 000000000..8ef72d447 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/asterisk/voicemail.conf @@ -0,0 +1,23 @@ +[general] +format = wav49|gsm|wav + +[default] + + +[example] +; Voicemail context for all internal users in the example.com domain. +1101 = 0717,Maria Berny +1102 = 7085,Tommie Briar +1103 = 1809,Penelope Bronte +1104 = 0039,Richard Casey +1105 = 6618,Garnet Claude +1106 = 9805,Aaron Courtney +1107 = 7484,Lindsey Freddie +1108 = 7788,Colby Hildred +1109 = 5750,Terry Jules +1110 = 3702,Hollis Justy +1111 = 1878,Temple Morgan +1112 = 5497,Franny Ocean +1113 = 1637,Laverne Roberts +1114 = 3717,Sal Smith +1115 = 3088,Dusty Williams diff --git a/data/tutorials_test/asterisk_ari/asterisk/etc/init.d/asterisk b/data/tutorials_test/asterisk_ari/asterisk/etc/init.d/asterisk new file mode 100755 index 000000000..611d5ca3e --- /dev/null +++ b/data/tutorials_test/asterisk_ari/asterisk/etc/init.d/asterisk @@ -0,0 +1,175 @@ +#! /bin/sh +# $Id$ +# +# Mon Jun 04 2007 IƱaki Baz Castillo +# - Eliminated SAFE_ASTERISK since it doesn't work as LSB script (it could require a independent "safe_asterisk" init script). +# - Load and use the standar "/lib/lsb/init-functions". +# - Added "--oknodo" to "start-stop-daemon" for compatibility with LSB: +# http://www.linux-foundation.org/spec/refspecs/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html +# +# Thu Nov 17 2005 Gregory Boehnlein +# - Reversed behavior of LD_ASSUME_KERNEL=2.4.1 +# - Added detailed failure messages +# +# Sun Jul 18 2004 Gregory Boehnlein +# - Added test for safe_asterisk +# - Changed "stop gracefully" to "stop now" +# - Added support for -U and -G command line options +# - Modified "reload" to call asterisk -rx 'reload' + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +NAME=asterisk +DESC="Asterisk PBX" +TUTDIR=/usr/share/cgrates/tutorials_test/asterisk_ari/asterisk +TMP_DIR=/tmp/cgr_asterisk_ari/asterisk +# Full path to asterisk binary +DAEMON=/usr/sbin/asterisk +ASTVARRUNDIR=$TMP_DIR/run +LOGDIR=$TMP_DIR/log +DBDIR=$TMP_DIR/lib +CDRDIR=$LOGDIR/cdr-custom +SPOOLDIR=$TMP_DIR/spool +ALTCONF=$TUTDIR/etc/asterisk/asterisk.conf +TRUE=/bin/true +AST_USER="asterisk" +AST_GROUP="asterisk" +VERBOSITY=1 + + +### BEGIN INIT INFO +# Provides: asterisk +# Required-Start: $network $syslog $named $local_fs $remote_fs +# Required-Stop: $network $syslog $named $local_fs $remote_fs +# Should-Start: dahdi misdn lcr wanrouter mysql postgresql +# Should-Stop: dahdi misdn lcr wanrouter mysql postgresql +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Asterisk PBX +# Description: the Asterisk Open Source PBX +### END INIT INFO + +set -e + +if ! [ -x $DAEMON ] ; then + echo "ERROR: $DAEMON not found" + exit 0 +fi + +if ! [ -d $ASTETCDIR ] ; then + echo "ERROR: $ASTETCDIR directory not found" + exit 0 +fi + +if [ ! -d $LOGDIR ]; then + mkdir -p $LOGDIR + chown -R $AST_USER:$AST_GROUP $LOGDIR +fi + + +if [ ! -d $CDRDIR ]; then + mkdir -p $CDRDIR + chown -R $AST_USER:$AST_GROUP $CDRDIR +fi + +if [ ! -d $SPOOLDIR ]; then + mkdir -p $SPOOLDIR + chown -R $AST_USER:$AST_GROUP $SPOOLDIR +fi + +if [ ! -d $DBDIR ]; then + mkdir -p $DBDIR + chown -R $AST_USER:$AST_GROUP $DBDIR +fi + +# Use the LSB standard functions for services management +. /lib/lsb/init-functions + +# Allow configuration overrides in /etc/default/asterisk +CONFIG0=`readlink $0 || :` # readlink returns 1 when something isn't a symlink +if [ "$CONFIG0" = "" ]; then + CONFIGFILE=/etc/default/`basename $0` +else + CONFIGFILE=/etc/default/`basename $CONFIG0` +fi +[ -r $CONFIGFILE ] && . $CONFIGFILE + +case "$1" in + start) + # Check if Asterisk is already running. If it is, then bug out, because + # starting up Asterisk when Asterisk is already running is very bad. + VERSION=`${DAEMON} -rx 'core show version' 2>/dev/null || ${TRUE}` + if [ "`echo $VERSION | cut -c 1-8`" = "Asterisk" ]; then + echo "Asterisk is already running. $0 will exit now." + exit 0 + fi + + log_begin_msg "Starting $DESC: $NAME" + if [ ! -d $ASTVARRUNDIR ]; then + mkdir -p $ASTVARRUNDIR + fi + if [ $AST_USER ] ; then + ASTARGS="$ASTARGS -U $AST_USER" + chown $AST_USER $ASTVARRUNDIR + fi + if [ $AST_GROUP ] ; then + ASTARGS="$ASTARGS -G $AST_GROUP" + chgrp $AST_GROUP $ASTVARRUNDIR + fi + if [ $ALTCONF ]; then + ASTARGS="$ASTARGS -C $ALTCONF" + fi + if [ "x$COREDUMP" = "xyes" ]; then + ASTARGS="$ASTARGS -g" + fi + if [ "0$MAXLOAD" -gt "0" ]; then + ASTARGS="$ASTARGS -L $MAXLOAD" + fi + if [ "0$MAXCALLS" -gt "0" ]; then + ASTARGS="$ASTARGS -M $MAXCALLS" + fi + if [ "0$VERBOSITY" -gt "0" ]; then + for i in `seq 1 $VERBOSITY`; do + ASTARGS="$ASTARGS -v" + done + # -v implies -f, so we override that implicit specification here + ASTARGS="$ASTARGS -F" + fi + if [ "x$INTERNALTIMING" = "xyes" ]; then + ASTARGS="$ASTARGS -I" + fi + if [ "x$TEMPRECORDINGLOCATION" = "xyes" -o "x$TMPRECORDINGLOCATION" = "xyes" ]; then + ASTARGS="$ASTARGS -t" + fi + if test "x$COLOR" = "xno" ; then + ASTARGS="$ASTARGS -n" + fi + # "start-stop-daemon --oknodo" returns 0 even if Asterisk was already running (as LSB expects): + echo "$DAEMON -- $ASTARGS" + start-stop-daemon --start --oknodo --exec $DAEMON -- $ASTARGS + log_end_msg $? + ;; + stop) + log_begin_msg "Stopping $DESC: $NAME" + # "start-stop-daemon --oknodo" returns 0 even if Asterisk was already stopped (as LSB expects): + start-stop-daemon --stop --oknodo --exec $DAEMON + log_end_msg $? + ;; + reload) + echo "Reloading $DESC configuration files." + $DAEMON -rx 'module reload' > /dev/null 2> /dev/null + ;; + restart|force-reload) + $0 stop + sleep 2 # It needs some time to really be stopped. + $0 start + # "restart|force-reload" starts Asterisk and returns 0 even if Asterisk was stopped (as LSB expects). + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2 + exit 1 + ;; +esac diff --git a/data/tutorials_test/asterisk_ari/cgrates/etc/cgrates/cgrates.json b/data/tutorials_test/asterisk_ari/cgrates/etc/cgrates/cgrates.json new file mode 100644 index 000000000..6878cc3a6 --- /dev/null +++ b/data/tutorials_test/asterisk_ari/cgrates/etc/cgrates/cgrates.json @@ -0,0 +1,145 @@ +{ + +// Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +// Copyright (C) ITsysCOM GmbH + +"general": { + "log_level": 7, + "node_id":"CGRAsterisk", + "reply_timeout": "5s", +}, + + +"listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080", +}, + + +"stor_db": { + "db_password": "CGRateS.org", +}, + + +"scheduler": { + "enabled": true, +}, + + +"rals": { + "enabled": true, + "thresholds_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], +}, + + +"cdrs": { + "enabled": true, + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "chargers_conns": [ + {"address": "*internal"} + ], + "sessions_cost_retries": 5, +}, + + +"chargers": { + "enabled": true, + "attributes_conns": [ + {"address": "*internal"} + ], +}, + + +"sessions": { + "enabled": true, + "rals_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "cdrs_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "resources_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "suppliers_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "attributes_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "thresholds_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "chargers_conns": [ + {"address": "*internal"} + ], + "store_session_costs": true, + "debit_interval": "5s", + "channel_sync_interval":"7s", +}, + + +"asterisk_agent": { + "enabled": true, + "asterisk_conns":[ + {"address": "127.0.0.1:8088", "user": "cgrates", + "password": "CGRateS.org", "connect_attempts": 3,"reconnects": 10} + ], + "sessions_conns": [ + {"address": "*internal"}, + ], + "create_cdr": true, +}, + + +"attributes": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"resources": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"stats": { + "enabled": true, + "string_indexed_fields": ["Account","RunID","Destination"], +}, + + +"thresholds": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"suppliers": { + "enabled": true, + "rals_conns": [ + {"address": "*internal"}, + ], + "resources_conns": [ + {"address": "*internal"}, + ], + "stats_conns": [ + {"address": "*internal"}, + ], + "string_indexed_fields": ["Account"], +}, + + +} diff --git a/data/tutorials_test/asterisk_ari/cgrates/etc/init.d/cgrates b/data/tutorials_test/asterisk_ari/cgrates/etc/init.d/cgrates new file mode 100755 index 000000000..85cc228af --- /dev/null +++ b/data/tutorials_test/asterisk_ari/cgrates/etc/init.d/cgrates @@ -0,0 +1,184 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: cgrates +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: CGRateS real-time charging system +# Description: Control CGRateS - carrier grade real-time charging system +### END INIT INFO + +# Author: DanB +# +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="CGRateS real-time online/offline Charging System" +NAME=cgrates +DAEMON=/usr/bin/cgr-engine +USER=cgrates +GROUP=cgrates +DAEMON_OPTS="" +TUTFOLDER=/usr/share/cgrates/tutorials_test/asterisk_ari/cgrates +TMP_DIR=/tmp/cgr_astevents/cgrates +SCRIPTNAME=$TUTFOLDER/etc/init.d/$NAME +RUNDIR=$TMP_DIR/run +PIDFILE=$RUNDIR/cgr-engine.pid +STACKTRACE=$RUNDIR/$NAME.strace +ENABLE=true +DAEMON_OPTS="-config_path=$TUTFOLDER/etc/cgrates" +CDREDIR=$TMP_DIR/cdre +CDRCINDIR=$TMP_DIR/cdrc/in +CDRCOUTDIR=$TMP_DIR/cdrc/out + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +if [ "$ENABLE" != "true" ]; then + echo "$DESC not yet configured. Edit $DEFAULTS first." + exit 0 +fi + +# Install the run folder +if [ ! -d $RUNDIR ]; then + mkdir -p $RUNDIR + touch $STACKTRACE + chown -R $USER:$GROUP $RUNDIR +fi +# Install the cdrc folder +if [ ! -d $CDRCINDIR ]; then + mkdir -p $CDRCINDIR + chown $USER:$GROUP $CDRCINDIR + mkdir -p $CDRCOUTDIR + chown $USER:$GROUP $CDRCOUTDIR +fi +# Install the cdre folder +if [ ! -d $CDREDIR ]; then + mkdir -p $CDREDIR + chown $USER:$GROUP $CDREDIR +fi + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + echo "\n### Started at:" `date`>>$STACKTRACE + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test\ + || return 1 + start-stop-daemon --start --quiet --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --background\ + --startas /bin/bash -- -c "exec $DAEMON $DAEMON_OPTS >> $STACKTRACE 2>&1" \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/data/tutorials_test/fs_evsock/README.md b/data/tutorials_test/fs_evsock/README.md new file mode 100644 index 000000000..15a9598f5 --- /dev/null +++ b/data/tutorials_test/fs_evsock/README.md @@ -0,0 +1,17 @@ +Tutorial FS_JSON +================ + +Scenario: +--------- + +- FreeSWITCH with minimal custom configuration. + + - Added following users (with configs in *etc/freeswitch/directory/default*): 1001-prepaid, 1002-postpaid, 1003-pseudoprepaid, 1004-rated, 1006-prepaid, 1007-prepaid. + - Have added inside default dialplan CGR own extensions just before routing towards users (*etc/freeswitch/dialplan/default.xml*). + +- **CGRateS** with following components: + + - CGR-SM started as prepaid controller, with debits taking place at 5s intervals. + - CGR-Mediator component attaching costs to the raw CDRs from FreeSWITCH_ inside CGR StorDB. + - CGR-CDRE exporting mediated CDRs from CGR StorDB (export path: */tmp*). + - CGR-CDRStats component building up stats in 5 different queues. diff --git a/data/tutorials_test/fs_evsock/cgrates/etc/cgrates/cgrates.json b/data/tutorials_test/fs_evsock/cgrates/etc/cgrates/cgrates.json new file mode 100644 index 000000000..c044b42bf --- /dev/null +++ b/data/tutorials_test/fs_evsock/cgrates/etc/cgrates/cgrates.json @@ -0,0 +1,142 @@ +{ + +// Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +// Copyright (C) ITsysCOM GmbH + +"general": { + "log_level": 7, + "node_id":"CGRFreeswitch", +}, + + +"listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080", +}, + + +"stor_db": { + "db_password": "CGRateS.org", +}, + + +"scheduler": { + "enabled": true, +}, + + +"rals": { + "enabled": true, + "thresholds_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], +}, + + +"cdrs": { + "enabled": true, + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "chargers_conns": [ + {"address": "*internal"} + ], + "sessions_cost_retries": 5, +}, + + +"chargers": { + "enabled": true, + "attributes_conns": [ + {"address": "*internal"} + ], +}, + + +"sessions": { + "enabled": true, + "rals_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "cdrs_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "resources_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "suppliers_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "attributes_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "thresholds_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "chargers_conns": [ + {"address": "*internal"} + ], + "store_session_costs": true, + "debit_interval": "5s", + "channel_sync_interval":"7s", +}, + + +"freeswitch_agent": { + "enabled": true, + "event_socket_conns":[ + {"address": "127.0.0.1:8021", "password": "ClueCon", "reconnects": -1,"alias":""} + ], + "sessions_conns": [ + {"address": "*internal"}, + ], +}, + + +"attributes": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"resources": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"stats": { + "enabled": true, + "string_indexed_fields": ["Account","RunID","Destination"], +}, + + +"thresholds": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"suppliers": { + "enabled": true, + "rals_conns": [ + {"address": "*internal"}, + ], + "resources_conns": [ + {"address": "*internal"}, + ], + "stats_conns": [ + {"address": "*internal"}, + ], + "string_indexed_fields": ["Account"], +}, + + +} diff --git a/data/tutorials_test/fs_evsock/cgrates/etc/init.d/cgrates b/data/tutorials_test/fs_evsock/cgrates/etc/init.d/cgrates new file mode 100755 index 000000000..94c7e9c36 --- /dev/null +++ b/data/tutorials_test/fs_evsock/cgrates/etc/init.d/cgrates @@ -0,0 +1,184 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: cgrates +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: CGRateS real-time charging system +# Description: Control CGRateS - carrier grade real-time charging system +### END INIT INFO + +# Author: DanB +# +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="CGRateS real-time charging system" +NAME=cgrates +DAEMON=/usr/bin/cgr-engine +USER=cgrates +GROUP=cgrates +DAEMON_OPTS="" +TUTFOLDER=/usr/share/cgrates/tutorials_test/fs_evsock/cgrates +TMP_DIR=/tmp/cgr_fsevsock/cgrates +SCRIPTNAME=$TUTFOLDER/etc/init.d/$NAME +RUNDIR=$TMP_DIR/run +PIDFILE=$RUNDIR/cgr-engine.pid +STACKTRACE=$RUNDIR/$NAME.strace +ENABLE=true +DAEMON_OPTS="-config_path=$TUTFOLDER/etc/cgrates" +CDREDIR=$TMP_DIR/cdre +CDRCINDIR=$TMP_DIR/cdrc/in +CDRCOUTDIR=$TMP_DIR/cdrc/out + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +if [ "$ENABLE" != "true" ]; then + echo "$DESC not yet configured. Edit $DEFAULTS first." + exit 0 +fi + +# Install the run folder +if [ ! -d $RUNDIR ]; then + mkdir -p $RUNDIR + touch $STACKTRACE + chown -R $USER:$GROUP $RUNDIR +fi +# Install the cdrc folder +if [ ! -d $CDRCINDIR ]; then + mkdir -p $CDRCINDIR + chown $USER:$GROUP $CDRCINDIR + mkdir -p $CDRCOUTDIR + chown $USER:$GROUP $CDRCOUTDIR +fi +# Install the cdre folder +if [ ! -d $CDREDIR ]; then + mkdir -p $CDREDIR + chown $USER:$GROUP $CDREDIR +fi + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + echo "\n### Started at:" `date`>>$STACKTRACE + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test\ + || return 1 + start-stop-daemon --start --quiet --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --background\ + --startas /bin/bash -- -c "exec $DAEMON $DAEMON_OPTS >> $STACKTRACE 2>&1" \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/data/tutorials_test/fs_evsock/freeswitch/etc/freeswitch_conf.tar.gz b/data/tutorials_test/fs_evsock/freeswitch/etc/freeswitch_conf.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..28ba3a0fb5b71c83cb300ec6632638d927bcb727 GIT binary patch literal 27632 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 g!SIjsXk^0vFE_h`QUCV_3 + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC=freeswitch +NAME=freeswitch +DAEMON=/usr/bin/freeswitch +USER=freeswitch +GROUP=freeswitch +TUTDIR=/usr/share/cgrates/tutorials_test/fs_evsock/freeswitch +SCRIPTNAME=$TUTDIR/etc/init.d/$NAME +TMP_DIR=/tmp/cgr_fsevsock/freeswitch +CONFDIR=$TUTDIR/etc/$NAME +RUNDIR=$TMP_DIR/run +LOGDIR=$TMP_DIR/log +PIDFILE=$RUNDIR/$NAME.pid +WORKDIR=$TMP_DIR/lib +DBDIR=$WORKDIR/db/ +DAEMON_ARGS="-rp -conf $CONFDIR -db $DBDIR -log $LOGDIR -u $USER -g $GROUP -nonat -nc" + + +[ -x $DAEMON ] || exit 0 +. /lib/init/vars.sh +. /lib/lsb/init-functions + +if [ ! -d $RUNDIR ]; then + mkdir -p $RUNDIR + chown -R $USER:$GROUP $RUNDIR + chmod -R ug=rwX,o= $RUNDIR +fi + +if [ ! -d $LOGDIR ]; then + mkdir -p $LOGDIR + chown -R $USER:$GROUP $LOGDIR +fi + +if [ ! -d $DBDIR ]; then + mkdir -p $DBDIR + chown -R $USER:$GROUP $DBDIR +fi + +do_start() { + if ! [ -f $CONFDIR/freeswitch.xml ]; then + echo "$NAME is not configured so not starting.">&2 + echo "Please review /usr/share/doc/$NAME/README.Debian">&2 + return 3 + fi + echo $DAEMON_ARGS + start-stop-daemon --start --quiet \ + --pidfile $PIDFILE --exec $DAEMON --name $NAME --user $USER \ + --test > /dev/null \ + || return 1 + ulimit -s 240 + start-stop-daemon --start --quiet \ + --pidfile $PIDFILE --exec $DAEMON --name $NAME --user $USER \ + --chdir $WORKDIR -- $DAEMON_ARGS $DAEMON_OPTS \ + || return 2 + return 0 +} + +stop_fs() { + start-stop-daemon --stop --quiet \ + --pidfile $PIDFILE --name $NAME --user $USER \ + --retry=TERM/30/KILL/5 +} + +stop_fs_children() { + start-stop-daemon --stop --quiet \ + --exec $DAEMON \ + --oknodo --retry=0/30/KILL/5 +} + +do_stop() { + stop_fs + RETVAL="$?" + [ "$RETVAL" -eq 2 ] && return 2 + stop_fs_children + [ "$?" -eq 2 ] && return 2 + rm -f $PIDFILE + return "$RETVAL" +} + +do_reload() { + start-stop-daemon --stop --quiet \ + --pidfile $PIDFILE --name $NAME --user $USER \ + --signal HUP +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + reload|force-reload) + log_daemon_msg "Reloading $DESC" "$NAME" + do_reload + log_end_msg $? + ;; + restart) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1|*) log_end_msg 1 ;; + esac + ;; + *) log_end_msg 1 ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +exit 0 diff --git a/data/tutorials_test/kamevapi/cgrates/etc/cgrates/cgrates.json b/data/tutorials_test/kamevapi/cgrates/etc/cgrates/cgrates.json new file mode 100644 index 000000000..a9f955719 --- /dev/null +++ b/data/tutorials_test/kamevapi/cgrates/etc/cgrates/cgrates.json @@ -0,0 +1,141 @@ +{ + +// Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +// Copyright (C) ITsysCOM GmbH + +"general": { + "log_level": 7, + "node_id":"CGRKamailio", + "reply_timeout": "5s", +}, + + +"listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080", +}, + + +"stor_db": { + "db_password": "CGRateS.org", +}, + + +"scheduler": { + "enabled": true, +}, + + +"rals": { + "enabled": true, + "thresholds_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], +}, + + +"cdrs": { + "enabled": true, + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "sessions_cost_retries": 5, +}, + + +"chargers": { + "enabled": true, + "attributes_conns": [ + {"address": "*internal"} + ], +}, + + +"sessions": { + "enabled": true, + "rals_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "cdrs_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "resources_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "suppliers_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "attributes_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "thresholds_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "chargers_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"}, + ], + "store_session_costs": true, + "debit_interval": "5s", + "channel_sync_interval":"7s", +}, + + +"kamailio_agent": { + "enabled": true, + "evapi_conns":[ + {"address": "127.0.0.1:8448", "reconnects": 5} + ], + "sessions_conns": [ + {"address": "*internal"}, + ], + "create_cdr": true, +}, + + +"attributes": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"resources": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"stats": { + "enabled": true, + "string_indexed_fields": ["Account","RunID","Destination"], +}, + + +"thresholds": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"suppliers": { + "enabled": true, + "rals_conns": [ + {"address": "*internal"}, + ], + "resources_conns": [ + {"address": "*internal"}, + ], + "stats_conns": [ + {"address": "*internal"}, + ], + "string_indexed_fields": ["Account"], +}, + + +} diff --git a/data/tutorials/osips_native/cgrates/etc/init.d/.fuse_hidden0000001700000001 b/data/tutorials_test/kamevapi/cgrates/etc/init.d/cgrates similarity index 95% rename from data/tutorials/osips_native/cgrates/etc/init.d/.fuse_hidden0000001700000001 rename to data/tutorials_test/kamevapi/cgrates/etc/init.d/cgrates index 84ccd75d8..dc8c52376 100755 --- a/data/tutorials/osips_native/cgrates/etc/init.d/.fuse_hidden0000001700000001 +++ b/data/tutorials_test/kamevapi/cgrates/etc/init.d/cgrates @@ -21,14 +21,14 @@ DAEMON=/usr/bin/cgr-engine USER=cgrates GROUP=cgrates DAEMON_OPTS="" -TUTFOLDER=/usr/share/cgrates/tutorials/fs_evsock/cgrates -TMP_DIR=/tmp/cgr_evsock/cgrates +TUTFOLDER=/usr/share/cgrates/tutorials_test/kamevapi/cgrates +TMP_DIR=/tmp/cgr_kamevapi/cgrates SCRIPTNAME=$TUTFOLDER/etc/init.d/$NAME RUNDIR=$TMP_DIR/run PIDFILE=$RUNDIR/cgr-engine.pid STACKTRACE=$RUNDIR/$NAME.strace ENABLE=true -DAEMON_OPTS="-config_path=/usr/share/cgrates/tutorials/fs_evsock/cgrates/etc/cgrates" +DAEMON_OPTS="-config_path=$TUTFOLDER/etc/cgrates" CDREDIR=$TMP_DIR/cdre # Exit if the package is not installed @@ -56,7 +56,7 @@ fi # Install the cdre folder if [ ! -d $CDREDIR ]; then mkdir -p $CDREDIR - chown $USER:$GROUP $CDREDIR + chown -R $USER:$GROUP $CDREDIR fi # diff --git a/data/tutorials_test/kamevapi/kamailio/etc/init.d/kamailio b/data/tutorials_test/kamevapi/kamailio/etc/init.d/kamailio new file mode 100755 index 000000000..e5e3bf7d4 --- /dev/null +++ b/data/tutorials_test/kamevapi/kamailio/etc/init.d/kamailio @@ -0,0 +1,166 @@ +#! /bin/sh +# +### BEGIN INIT INFO +# Provides: kamailio +# Required-Start: $syslog $network $local_fs $remote_fs $time +# Should-Start: $named slapd mysql postgresql snmpd radiusd +# Should-Stop: $named slapd mysql postgresql snmpd radiusd +# Required-Stop: $syslog $network $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the Kamailio SIP proxy server +# Description: Start the Kamailio SIP proxy server +### END INIT INFO + +. /lib/lsb/init-functions + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/kamailio +NAME=kamailio +DESC="Kamailio SIP Server" +TUTDIR=/usr/share/cgrates/tutorials_test/kamevapi/ +TMP_DIR=/tmp/cgr_kamevapi/kamailio +HOMEDIR=$TMP_DIR/run/ +PIDFILE=$HOMEDIR/$NAME.pid +CFGFILE=$TUTDIR/kamailio/etc/kamailio/kamailio.cfg +USER=kamailio +GROUP=kamailio +# Amount of shared and private memory to allocate +# for the running Kamailio server (in Mb) +SHM_MEMORY=64 +PKG_MEMORY=8 +DUMP_CORE=no + +if [ ! -d $HOMEDIR ]; then + mkdir -p $HOMEDIR + chown -R $USER:$GROUP $HOMEDIR + chmod -R ug=rwX,o= $HOMEDIR +fi + +if [ ! -d $LOGDIR ]; then + mkdir -p $LOGDIR + chown -R $USER:$GROUP $LOGDIR +fi + +# Do not start kamailio if fork=no is set in the config file +# otherwise the boot process will just stop +check_fork () +{ + if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then + log_failure_msg "Not starting $DESC: fork=no specified in config file; run /etc/init.d/kamailio debug instead" + exit 0 + fi +} + +check_kamailio_config () +{ + # Check if kamailio configuration is valid before starting the server + set +e + out=$($DAEMON -f $CFGFILE -M $PKG_MEMORY -c 2>&1 > /dev/null) + retcode=$? + set -e + if [ "$retcode" != '0' ]; then + log_failure_msg "Not starting $DESC: invalid configuration file!" + log_failure_msg + log_failure_msg "$out" + log_failure_msg + exit 1 + fi +} + +create_radius_seqfile () +{ + # Create a radius sequence file to be used by the radius client if + # radius accounting is enabled. This is needed to avoid any issue + # with the file not being writable if kamailio first starts as user + # root because DUMP_CORE is enabled and creates this file as user + # root and then later it switches back to user kamailio and cannot + # write to the file. If the file exists before kamailio starts, it + # won't change it's ownership and will be writable for both root + # and kamailio, no matter what options are chosen at install time + RADIUS_SEQ_FILE=/var/run/kamailio/kamailio_radius.seq + if [ -d /var/run/kamailio ]; then + chown ${USER}:${GROUP} /var/run/kamailio + + if [ ! -f $RADIUS_SEQ_FILE ]; then + touch $RADIUS_SEQ_FILE + fi + + chown ${USER}:${GROUP} $RADIUS_SEQ_FILE + chmod 660 $RADIUS_SEQ_FILE + fi +} + +test -f $DAEMON || exit 0 + +# Load startup options if available + + +set -e + +SHM_MEMORY=$((`echo $SHM_MEMORY | sed -e 's/[^0-9]//g'`)) +PKG_MEMORY=$((`echo $PKG_MEMORY | sed -e 's/[^0-9]//g'`)) +[ -z "$USER" ] && USER=kamailio +[ -z "$GROUP" ] && GROUP=kamailio +[ $SHM_MEMORY -le 0 ] && SHM_MEMORY=64 +[ $PKG_MEMORY -le 0 ] && PKG_MEMORY=4 + +if test "$DUMP_CORE" = "yes" ; then + # set proper ulimit + ulimit -c unlimited + + # directory for the core dump files + # COREDIR=/home/corefiles + # [ -d $COREDIR ] || mkdir $COREDIR + # chmod 777 $COREDIR + # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern +fi + +# /var/run can be a tmpfs +if [ ! -d $HOMEDIR ]; then + mkdir -p $HOMEDIR +fi + +OPTIONS="-f $CFGFILE -P $PIDFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP" + +case "$1" in + start|debug) + check_kamailio_config + create_radius_seqfile + + if [ "$1" != "debug" ]; then + check_fork + fi + + log_daemon_msg "Starting $DESC: $NAME" + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --exec $DAEMON -- $OPTIONS || log_failure_msg " already running" + log_end_msg 0 + ;; + stop) + log_daemon_msg "Stopping $DESC: $NAME" + start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON + log_end_msg 0 + ;; + restart|force-reload) + check_kamailio_config + create_radius_seqfile + + $0 stop + sleep 1 + $0 start + ;; + status) + log_daemon_msg "Status of $DESC: " + + status_of_proc -p"$PIDFILE" $NAME $NAME + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status|debug}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg b/data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg new file mode 100644 index 000000000..836d2c902 --- /dev/null +++ b/data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg @@ -0,0 +1,192 @@ +# Kamailio-CGRateS related route blocks + + +# Called on new connection over evapi, should normally be the case of CGRateS engine +event_route[evapi:connection-new] { + $sht(cgrconn=>cgr) = $evapi(srcaddr) + ":" + $evapi(srcport); # Detect presence of at least one connection +} + + +# Called when the connection with CGRateS closes +event_route[evapi:connection-closed] { + $var(connClosed) = $evapi(srcaddr) + ":" + $evapi(srcport); + if $sht(cgrconn=>cgr) == $var(connClosed) { + $sht(cgrconn=>cgr) = $null; + } +} + + +# Message received from CGRateS, dispatch it to own route +event_route[evapi:message-received] { + json_get_field("$evapi(msg)", "Event", "$var(Event)"); + route($(var(Event){s.rm,"})); # String characters are kept by json_get_field, remove them here +} + + +# Called by Kamailio on new dialog +event_route[dialog:start] { + route(CGR_CALL_START); +} + + +# Called by Kamailio on dialog end +event_route[dialog:end] { + route(CGR_CALL_END); +} + +# Parse the CGRateS attributes from encoded variable into pseudovariables +route[PARSE_CGRATES_ATTRIBUTES] { + # convert encoded attributes into individual Kamailio pseudovariables + $var(idx) = 0; + while !strempty($(var(cgrAttributes){s.select,$var(idx),,})) { + $avp($(var(cgrAttributes){s.select,$var(idx),,}{s.select,0,:})) + = $(var(cgrAttributes){s.select,$var(idx),,}{s.select,1,:}); + $var(idx) = $var(idx) + 1; + } +} + + +# CGRateS request for session disconnect +route[CGR_SESSION_DISCONNECT] { + json_get_field("$evapi(msg)", "HashEntry", "$var(HashEntry)"); + json_get_field("$evapi(msg)", "HashId", "$var(HashId)"); + json_get_field("$evapi(msg)", "Reason", "$var(Reason)"); + jsonrpc_exec('{"jsonrpc":"2.0","id":1, "method":"dlg.end_dlg","params":[$(var(HashEntry){s.rm,"}),$(var(HashId){s.rm,"})]}'); +} + +route[CGR_DLG_LIST] { + if $sht(cgrconn=>cgr) == $null { + sl_send_reply("503","Charging controller unreachable"); + exit; + } + jsonrpc_exec('{"jsonrpc":"2.0","id":1, "method":"dlg.list","params":[]}'); + evapi_relay("{\"event\":\"CGR_DLG_LIST_REPLY\", + \"jsonrpl_body\":$jsonrpl(body)}"); +} + + +# Route to mainly query account password from CGRateS +route[CGRATES_SIMPLEAUTH_REQUEST] { + if $sht(cgrconn=>cgr) == $null { + sl_send_reply("503","Charging controller unreachable"); + exit; + } + evapi_async_relay("{\"event\":\"CGR_AUTH_REQUEST\", + \"tr_index\":\"$T(id_index)\", + \"tr_label\":\"$T(id_label)\", + \"cgr_subsystems\":\"*attributes\", + \"cgr_context\":\"simpleauth\", + \"reply_route\":\"CGR_SIMPLEAUTH_REPLY\", + \"Account\":\"$fU\"}"); +} + + +# Route receiving simpleauth replies, sanitizes them and dispatch back into Kamailio inside CGRATES_SIMPLEAUTH_REPLY +route[CGR_SIMPLEAUTH_REPLY] { + + json_get_field("$evapi(msg)", "TransactionIndex", "$var(TransactionIndex)"); + $var(TransactionIndex) = $(var(TransactionIndex){s.rm,"}); + $var(id_index) = $(var(TransactionIndex){s.int}); + + json_get_field("$evapi(msg)", "TransactionLabel", "$var(TransactionLabel)"); + $var(TransactionLabel) = $(var(TransactionLabel){s.rm,"}); + $var(id_label) = $(var(TransactionLabel){s.int}); + + json_get_field("$evapi(msg)", "Attributes", "$var(cgrAttributes)"); + $var(cgrAttributes) = $(var(cgrAttributes){s.rm,"}); + + json_get_field("$evapi(msg)", "Error", "$var(cgrError)"); + $var(cgrError) = $(var(cgrError){s.rm,"}); + + t_continue("$var(id_index)", "$var(id_label)", "CGRATES_SIMPLEAUTH_REPLY"); # Unpark the transaction + +} + + +# Request session auth information from CGRateS +route[CGRATES_SESSIONAUTH_REQUEST] { + # Auth INVITEs with CGRateS + if $sht(cgrconn=>cgr) == $null { + sl_send_reply("503","Charging controller unreachable"); + exit; + } + evapi_async_relay("{\"event\":\"CGR_AUTH_REQUEST\", + \"tr_index\":\"$T(id_index)\", + \"tr_label\":\"$T(id_label)\", + \"cgr_subsystems\":\"*attributes;*accounts;*suppliers;*resources;*thresholds\", + \"reply_route\":\"CGR_SESSIONAUTH_REPLY\", + \"Account\":\"$fU\", + \"Destination\":\"$rU\", + \"SetupTime\":\"$TS\"}"); +} + + +# Process SESSIONAUTH_reply from CGRateS +route[CGR_SESSIONAUTH_REPLY] { + json_get_field("$evapi(msg)", "TransactionIndex", "$var(TransactionIndex)"); + $var(TransactionIndex) = $(var(TransactionIndex){s.rm,"}); + $var(id_index) = $(var(TransactionIndex){s.int}); + + json_get_field("$evapi(msg)", "TransactionLabel", "$var(TransactionLabel)"); + $var(TransactionLabel) = $(var(TransactionLabel){s.rm,"}); + $var(id_label) = $(var(TransactionLabel){s.int}); + + json_get_field("$evapi(msg)", "Attributes", "$var(cgrAttributes)"); + $var(cgrAttributes) = $(var(cgrAttributes){s.rm,"}); + + json_get_field("$evapi(msg)", "ResourceAllocation", "$var(cgrResourceAllocation)"); + $var($var(cgrResourceAllocation)) = $(var(cgrResourceAllocation){s.rm,"}); + + json_get_field("$evapi(msg)", "MaxUsage", "$var(MaxUsage)"); + $var(cgrMaxUsage) = $(var(MaxUsage){s.int}); + + json_get_field("$evapi(msg)", "Suppliers", "$var(cgrSuppliers)"); + $var($var(cgrSuppliers)) = $(var(cgrSuppliers){s.rm,"}); + + json_get_field("$evapi(msg)", "Error", "$var(cgrError)"); + $var(cgrError) = $(var(cgrError){s.rm,"}); + + t_continue("$var(id_index)", "$var(id_label)", "CGRATES_SESSIONAUTH_REPLY"); # Unpark the transaction +} + + +# Inform CGRateS about CALL_START (start prepaid sessions loops) +route[CGR_CALL_START] { + if $sht(cgrconn=>cgr) == $null { + xlog("Charging controller unreachable"); + exit; + } + evapi_relay("{\"event\":\"CGR_CALL_START\", + \"h_entry\":\"$dlg(h_entry)\", + \"h_id\":\"$dlg(h_id)\", + \"cgr_subsystems\":\"*attributes;*accounts;*resources;*thresholds\", + \"OriginID\":\"$dlg_var(cgrOriginID)\", + \"RequestType\":\"$dlg_var(cgrReqType)\", + \"Tenant\":\"$dlg_var(cgrTenant)\", + \"Account\":\"$dlg_var(cgrAccount)\", + \"Destination\":\"$dlg_var(cgrDestination)\", + \"SetupTime\":\"$dlg_var(SetupTime)\", + \"AnswerTime\":\"$TS\"}"); +} + + +# Inform CGRateS about CALL_END (stop debit loops, perform accounting if desired in this way) +route[CGR_CALL_END] { + if $sht(cgrconn=>cgr) == $null { + xlog("Charging controller unreachable"); + exit; + } + $var(callDur) = $TS - $dlg(start_ts); + evapi_relay("{\"event\":\"CGR_CALL_END\", + \"cgr_subsystems\":\"*accounts;*resources\", + \"OriginID\":\"$dlg_var(cgrOriginID)\", + \"RequestType\":\"$dlg_var(cgrReqType)\", + \"Tenant\":\"$dlg_var(cgrTenant)\", + \"Account\":\"$dlg_var(cgrAccount)\", + \"Destination\":\"$dlg_var(cgrDestination)\", + \"AnswerTime\":\"$dlg(start_ts)\", + \"PaypalAccount\":\"$dlg_var(paypalAccount)\", + \"SetupTime\":\"$dlg_var(SetupTime)\", + \"Usage\":\"$var(callDur)\"}"); +} + diff --git a/data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio.cfg b/data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio.cfg new file mode 100644 index 000000000..85672bced --- /dev/null +++ b/data/tutorials_test/kamevapi/kamailio/etc/kamailio/kamailio.cfg @@ -0,0 +1,439 @@ +#!KAMAILIO + +# Sample demo config for Kamailio-CGRateS communication +# tested against Kamailio 5.1 + +####### Defined Values ######### + +#!define FLT_DIALOG 4 +#!define FLT_NATS 5 +#!define FLB_NATB 6 +#!define FLB_NATSIPPING 7 + +####### Global Parameters ######### + +debug=2 +log_stderror=no + +listen=udp:enp0s3:5060 +listen=udp:127.0.0.1:5080 +listen=udp:127.0.0.1:5060 +listen=udp:enp0s3:5080 + +memdbg=5 +memlog=5 +log_facility=LOG_LOCAL0 +fork=yes +children=4 +tcp_connection_lifetime=3605 +use_dns_cache=no +dns_try_ipv6=no +dns_retr_time=1 +dns_retr_no=1 +dns_servers_no=1 +dns_use_search_list=no + +####### Modules Section ######## + +mpath="/usr/lib/x86_64-linux-gnu/kamailio/modules/" + +loadmodule "kex.so" +loadmodule "corex.so" +loadmodule "tm.so" +loadmodule "tmx.so" +loadmodule "sl.so" +loadmodule "rr.so" +loadmodule "pv.so" +loadmodule "maxfwd.so" +loadmodule "usrloc.so" +loadmodule "registrar.so" +loadmodule "textops.so" +loadmodule "siputils.so" +loadmodule "xlog.so" +loadmodule "sanity.so" +loadmodule "nathelper.so" +loadmodule "htable.so" +loadmodule "auth.so" +loadmodule "evapi.so" +loadmodule "json.so" +loadmodule "dialog.so" +loadmodule "jsonrpcs.so" + + + +# ----------------- setting module-specific parameters --------------- + +modparam("evapi", "bind_addr", "127.0.0.1:8448") + +# ----- tm params ----- +modparam("tm", "failure_reply_mode", 3) +modparam("tm", "fr_timer", 30000) +modparam("tm", "fr_inv_timer", 120000) + +# ----- rr params ----- +modparam("rr", "enable_full_lr", 0) +modparam("rr", "append_fromtag", 0) + +# ----- registrar params ----- +modparam("registrar", "method_filtering", 1) +modparam("registrar", "max_expires", 3600) + +# ----- dialog params ----- +modparam("dialog", "dlg_flag", FLT_DIALOG) +modparam("dialog", "send_bye", 1) +modparam("dialog", "timeout_noreset", 1) + +# ----- nathelper params ----- +modparam("nathelper", "natping_interval", 30) +modparam("nathelper", "ping_nated_only", 1) +modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) +modparam("nathelper", "sipping_from", "sip:pinger@kamailio.org") + +# params needed for NAT traversal in other modules +modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)") +modparam("usrloc", "nat_bflag", FLB_NATB) + +# ----- htable params ----- +modparam("htable", "htable", "cgrconn=>size=1;") + +####### Routing Logic ######## + +include_file "kamailio-cgrates.cfg" + + +# Main SIP request routing logic +request_route { + + # per request initial checks + route(REQINIT); + + # NAT detection + route(NATDETECT); + + # CANCEL processing + if (is_method("CANCEL")) { + if (t_check_trans()) { + route(RELAY); + } + exit; + } + + # handle requests within SIP dialogs + route(WITHINDLG); + + ### only initial requests (no To tag) + + # handle retransmissions + if(t_precheck_trans()) { + t_check_trans(); + exit; + } + t_check_trans(); + + # record routing for dialog forming requests (in case they are routed) + # - remove preloaded route headers + remove_hf("Route"); + if (is_method("INVITE|SUBSCRIBE")) + record_route(); + + # Not handling requests towards external domains + if uri != myself { + sl_send_reply("604", "Only local destinations accepted"); + exit; + } + + ### requests for my local domains + + # SIMPLE AUTH methods + if is_method("REGISTER|SUBSCRIBE|PUBLISH") { + route(CGRATES_SIMPLEAUTH_REQUEST); + exit; + } + + if ($rU==$null) { + # request with no Username in RURI + sl_send_reply("484","Address Incomplete"); + exit; + } + + if !is_method("INVITE") { + sl_send_reply("503", "Unsupported method"); + exit; + } + + route(CGRATES_SESSIONAUTH_REQUEST); + exit; +} + + +# Here will land requests after processing them with CGRateS. +route[CGRATES_SIMPLEAUTH_REPLY] { + if $var(cgrError) != "" { + xlog("CGR_PROFILE_ERROR: $var(cgrError)"); + sl_send_reply("503","CGR_ERROR"); + exit; + } + + # parse the CGRateS attributes + route(PARSE_CGRATES_ATTRIBUTES); + + # password based auth + route(AUTH); + + if is_method("REGISTER") { + route(REGISTRAR); + exit; + } + + # other methods going over location + route(LOCATION); + route(RELAY); +} + + +# Here will land requests after processing them with CGRateS. Call RELAY or other routes following this route +route[CGRATES_SESSIONAUTH_REPLY] { + + if $var(cgrError) != "" { + xlog("CGR_AUTH_ERROR: $var(cgrError)"); + sl_send_reply("503","CGR_ERROR"); + exit; + } + + # parse the CGRateS attributes + route(PARSE_CGRATES_ATTRIBUTES); + + # password based auth + route(AUTH); + + # track the dialog so we can set it's timeout and channel variables to store in CDRs + # cannot initialize the dialog sooner due to AUTH + dlg_manage(); + $dlg_var(SetupTime) = $TS; + $dlg_var(cgrOriginID) = $dlg(callid) + ";" + $dlg(from_tag); + $dlg_var(cgrTenant) = "cgrates.org"; + $dlg_var(cgrReqType) = $avp(RequestType); + $dlg_var(cgrAccount) = $fU; + $dlg_var(cgrDestination) = $rU; + $dlg_var(paypalAccount) = $avp(PaypalAccount); + + if $var(cgrMaxUsage) != -1 { + if $var(cgrMaxUsage) == 0 { // Not enough balance, do not allow the call to go through + sl_send_reply("403","Insufficient credit"); + exit; + } else if !dlg_set_timeout("$var(cgrMaxUsage)") { + sl_send_reply("503","CGR_MAX_USAGE_ERROR"); + exit; + } + } + + if $var(cgrSuppliers) != "" { # Enforce the supplier variable to the first one received from CGRateS, here more for demo purposes + $dlg_var(cgrSupplier) = $(var(cgrSuppliers){s.select,0,,}); + } + + # user location service + route(LOCATION); + + # send out + route(RELAY); + +} + + +# Wrapper for relaying requests +route[RELAY] { + # enable additional event routes for forwarded requests + # - serial forking, RTP relaying handling, a.s.o. + if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) { + if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH"); + } + if (is_method("INVITE|SUBSCRIBE|UPDATE")) { + if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY"); + } + if (is_method("INVITE")) { + if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE"); + } + + if (!t_relay()) { + sl_reply_error(); + } + exit; +} + +# Per SIP request initial checks +route[REQINIT] { + if (!mf_process_maxfwd_header("10")) { + sl_send_reply("483","Too Many Hops"); + exit; + } + + if(is_method("OPTIONS") && uri==myself && $rU==$null) { + sl_send_reply("200","Keepalive"); + exit; + } + + if(!sanity_check("1511", "7")) { + xlog("Malformed SIP message from $si:$sp\n"); + exit; + } +} + +# Handle requests within SIP dialogs +route[WITHINDLG] { + if (!has_totag()) return; + + # sequential request withing a dialog should + # take the path determined by record-routing + if (loose_route()) { + route(DLGURI); + if ( is_method("ACK") ) { + # ACK is forwarded statelessy + route(NATMANAGE); + } + else if ( is_method("NOTIFY") ) { + # Add Record-Route for in-dialog NOTIFY as per RFC 6665. + record_route(); + } + route(RELAY); + exit; + } + if ( is_method("ACK") ) { + if ( t_check_trans() ) { + # no loose-route, but stateful ACK; + # must be an ACK after a 487 + # or e.g. 404 from upstream server + route(RELAY); + exit; + } else { + # ACK without matching transaction ... ignore and discard + exit; + } + } + sl_send_reply("404","Not here"); + exit; +} + +# Handle SIP registrations +route[REGISTRAR] { + if(isflagset(FLT_NATS)) { + setbflag(FLB_NATB); + } + if (!save("location")) + sl_reply_error(); + exit; +} + +# User location service +route[LOCATION] { + $avp(oexten) = $rU; + if (!lookup("location")) { + $var(rc) = $rc; + t_newtran(); + switch ($var(rc)) { + case -1: + case -3: + send_reply("404", "Not Found"); + exit; + case -2: + send_reply("405", "Method Not Allowed"); + exit; + } + } +} + + +# user uthentication +route[AUTH] { + if (is_method("REGISTER")) { + if ( strempty($au) || !pv_www_authenticate("$td", "$avp(Password)", "0") ) { + www_challenge("$td", "0"); + exit; + } + } else { # All other methods here + if ( strempty($au) || !pv_proxy_authenticate("$td", "$avp(Password)", "0") ) { + proxy_challenge("$td", "0"); + exit; + } + } + consume_credentials(); + return; +} + + +# Caller NAT detection +route[NATDETECT] { + force_rport(); + if (nat_uac_test("19")) { + if (is_method("REGISTER")) { + fix_nated_register(); + } else { + if(is_first_hop()) + set_contact_alias(); + } + setflag(FLT_NATS); + } + return; +} + +# RTPProxy control and singaling updates for NAT traversal +route[NATMANAGE] { + if (is_request()) { + if(has_totag()) { + if(check_route_param("nat=yes")) { + setbflag(FLB_NATB); + } + } + } + if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))) + return; + + if (is_request()) { + if (!has_totag()) { + if(t_is_branch_route()) { + add_rr_param(";nat=yes"); + } + } + } + if (is_reply()) { + if(isbflagset(FLB_NATB)) { + if(is_first_hop()) + set_contact_alias(); + } + } + return; +} + +# URI update for dialog requests +route[DLGURI] { + if(!isdsturiset()) { + handle_ruri_alias(); + } + return; +} + + +# Manage outgoing branches +branch_route[MANAGE_BRANCH] { + route(NATMANAGE); +} + +# Manage incoming replies +onreply_route[MANAGE_REPLY] { + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); +} + +# Manage failure routing cases +failure_route[MANAGE_FAILURE] { + route(NATMANAGE); + + if (t_is_canceled()) { + exit; + } + + if (t_check_status("3[0-9][0-9]")) { + t_reply("404","Not found"); + exit; + } +} + diff --git a/data/tutorials_test/osips/cgrates/etc/cgrates/cgrates.json b/data/tutorials_test/osips/cgrates/etc/cgrates/cgrates.json new file mode 100644 index 000000000..fa3b522bb --- /dev/null +++ b/data/tutorials_test/osips/cgrates/etc/cgrates/cgrates.json @@ -0,0 +1,139 @@ +{ + +// Real-time Charging System for Telecom & ISP environments +// Copyright (C) ITsysCOM GmbH +// + + +"listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080", +}, + + +"stor_db": { + "db_password": "CGRateS.org", +}, + + +"scheduler": { + "enabled": true, +}, + + +"rals": { + "enabled": true, + "thresholds_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"} + ], + "stats_conns": [ + {"address": "127.0.0.1:2012", "transport": "*json"} + ], + "attributes_conns": [ + {"address": "*internal"} + ], +}, + + +"cdrs": { + "enabled": true, + "stats_conns": [ + {"address": "*internal"} + ], + "chargers_conns": [ + {"address": "*internal"} + ], + "sessions_cost_retries": 5, +}, + + +"chargers": { + "enabled": true, + "attributes_conns": [ + {"address": "*internal"} + ], +}, + + +"sessions": { + "enabled": true, + "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests + "chargers_conns": [ + {"address": "*internal"} + ], + "rals_conns": [ + {"address": "*internal"} + ], + "cdrs_conns": [ + {"address": "*internal"} + ], + "resources_conns": [ + {"address": "*internal"} + ], + "suppliers_conns": [ + {"address": "*internal"} + ], + "attributes_conns": [ + {"address": "*internal"} + ], + "stats_conns": [ + {"address": "*internal"} + ], + "thresholds_conns": [ + {"address": "*internal"} + ], + "debit_interval": "5s", + "channel_sync_interval":"7s", +}, + + + +"attributes": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"resources": { + "enabled": true, + "thresholds_conns": [ + {"address": "*internal"} + ], + "string_indexed_fields": ["Account"], + "prefix_indexed_fields": ["Destination"], +}, + + +"stats": { + "enabled": true, + "thresholds_conns": [ + {"address": "*internal"} + ], + "string_indexed_fields": ["Account"], +}, + + +"thresholds": { + "enabled": true, + "string_indexed_fields": ["Account"], +}, + + +"suppliers": { + "enabled": true, + "rals_conns": [ + {"address": "*internal"} + ], + "resources_conns": [ + {"address": "*internal"} + ], + "stats_conns": [ + {"address": "*internal"} + ], + "string_indexed_fields": ["Account"], + "prefix_indexed_fields": ["Destination"], +}, + + +} diff --git a/data/tutorials_test/osips/cgrates/etc/init.d/cgrates b/data/tutorials_test/osips/cgrates/etc/init.d/cgrates new file mode 100755 index 000000000..0e0833e12 --- /dev/null +++ b/data/tutorials_test/osips/cgrates/etc/init.d/cgrates @@ -0,0 +1,175 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: cgrates +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: CGRateS real-time charging system +# Description: Control CGRateS - carrier grade real-time charging system +### END INIT INFO + +# Author: DanB +# +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="CGRateS Online Charging System" +NAME=cgrates +DAEMON=/usr/bin/cgr-engine +USER=cgrates +GROUP=cgrates +DAEMON_OPTS="" +TUTFOLDER=/usr/share/cgrates/tutorials_test/osips/$NAME +TMP_DIR=/tmp/cgr_osipsnative/$NAME +SCRIPTNAME=$TUTFOLDER/etc/init.d/$NAME +RUNDIR=$TMP_DIR/run +PIDFILE=$RUNDIR/cgr-engine.pid +STACKTRACE=$RUNDIR/$NAME.strace +ENABLE=true +DAEMON_OPTS="-config_path=$TUTFOLDER/etc/cgrates" +CDREDIR=$TMP_DIR/cdre + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +if [ "$ENABLE" != "true" ]; then + echo "$DESC not yet configured. Edit $DEFAULTS first." + exit 0 +fi + +# Install the run folder +if [ ! -d $RUNDIR ]; then + mkdir -p $RUNDIR + touch $STACKTRACE + chown -R $USER:$GROUP $RUNDIR +fi +# Install the cdre folder +if [ ! -d $CDREDIR ]; then + mkdir -p $CDREDIR + chown $USER:$GROUP $CDREDIR +fi + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + echo "\n### Started at:" `date`>>$STACKTRACE + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test\ + || return 1 + start-stop-daemon --start --quiet --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --background\ + --startas /bin/bash -- -c "exec $DAEMON $DAEMON_OPTS >> $STACKTRACE 2>&1" \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/data/tutorials_test/osips/opensips/etc/default/opensips b/data/tutorials_test/osips/opensips/etc/default/opensips new file mode 100755 index 000000000..0671f96a0 --- /dev/null +++ b/data/tutorials_test/osips/opensips/etc/default/opensips @@ -0,0 +1,27 @@ +# +# OpenSIPS startup options +# + +# Set to yes to enable opensips, once configured properly. +RUN_OPENSIPS=yes + +# User to run as +USER=opensips + +# Group to run as +GROUP=opensips + +# Amount of shared memory to allocate for the running OpenSIPS server (in Mb) +S_MEMORY=64 + +# Amount of pkg memory to allocate for the running OpenSIPS server (in Mb) +P_MEMORY=4 + +# Enable the server to leave a core file when it crashes. +# Set this to 'yes' to enable OpenSIPS 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 opensips +# init file for an example configuration. +DUMP_CORE=no diff --git a/data/tutorials_test/osips/opensips/etc/init.d/opensips b/data/tutorials_test/osips/opensips/etc/init.d/opensips new file mode 100755 index 000000000..6e2ad2d1f --- /dev/null +++ b/data/tutorials_test/osips/opensips/etc/init.d/opensips @@ -0,0 +1,199 @@ +#! /bin/sh +# +### BEGIN INIT INFO +# Provides: opensips +# Required-Start: $syslog $network $local_fs $time +# Required-Stop: $syslog $network $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the OpenSIPS SIP server +# Description: Start the OpenSIPS SIP server +### END INIT INFO +# +# TODO: +# The following fields should be added (and completed): +# Should-Start: postgresql mysql radius +# Should-Stop: postgresql mysql radius + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/opensips +NAME=opensips +DESC=opensips +TUTDIR=/usr/share/cgrates/tutorials_test/osips/$NAME +SCRIPTNAME=$TUTDIR/etc/init.d/$NAME +TMP_DIR=/tmp/cgr_osipsnative/$NAME +CFGFILE=$TUTDIR/etc/$NAME/opensips.cfg +M4CFGFILE=/etc/opensips/opensips.m4 +M4ARCHIVEDIR=/etc/opensips/archive +HOMEDIR=$TMP_DIR/run/opensips +PIDFILE=$HOMEDIR/$NAME.pid +DEFAULTS=$TUTDIR/etc/default/opensips +RUN_OPENSIPS=no + +if [ ! -d $HOMEDIR ]; then + mkdir -p $HOMEDIR + chown -R $USER:$GROUP $HOMEDIR +fi + +# Do not start opensips if fork=no is set in the config file +# otherwise the boot process will just stop +check_fork () +{ + if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then + echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/opensips debug instead" + exit 1 + fi +} + +check_opensips_config () +{ + # Check if opensips configuration is valid before starting the server + set +e + out=$($DAEMON -c 2>&1 > /dev/null) + retcode=$? + set -e + if [ "$retcode" != '0' ]; then + echo "Not starting $DESC: invalid configuration file!" + echo -e "\n$out\n" + exit 1 + fi +} + +create_radius_seqfile () +{ + # Create a radius sequence file to be used by the radius client if + # radius accounting is enabled. This is needed to avoid any issue + # with the file not being writable if opensips first starts as user + # root because DUMP_CORE is enabled and creates this file as user + # root and then later it switches back to user opensips and cannot + # write to the file. If the file exists before opensips starts, it + # won't change it's ownership and will be writable for both root + # and opensips, no matter what options are chosen at install time + RADIUS_SEQ_FILE=/var/run/opensips/opensips_radius.seq + if [ -d /var/run/opensips ]; then + chown ${USER}:${GROUP} /var/run/opensips + + if [ ! -f $RADIUS_SEQ_FILE ]; then + touch $RADIUS_SEQ_FILE + fi + + chown ${USER}:${GROUP} $RADIUS_SEQ_FILE + chmod 660 $RADIUS_SEQ_FILE + fi +} + +test -f $DAEMON || exit 0 + +# Load startup options if available +if [ -f $DEFAULTS ]; then + . $DEFAULTS || true +fi + +if [ "$RUN_OPENSIPS" != "yes" ]; then + echo "OpenSIPS not yet configured. Edit /etc/default/opensips first." + exit 0 +fi + +set -e + +S_MEMORY=$((`echo $S_MEMORY | sed -e 's/[^0-9]//g'`)) +P_MEMORY=$((`echo $P_MEMORY | sed -e 's/[^0-9]//g'`)) +[ -z "$USER" ] && USER=opensips +[ -z "$GROUP" ] && GROUP=opensips +[ $S_MEMORY -le 0 ] && S_MEMORY=32 +[ $P_MEMORY -le 0 ] && P_MEMORY=32 + +if test "$DUMP_CORE" = "yes" ; then + # set proper ulimit + ulimit -c unlimited + + # directory for the core dump files + # COREDIR=/home/corefiles + # [ -d $COREDIR ] || mkdir $COREDIR + # chmod 777 $COREDIR + # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern +fi + +OPTIONS="-f $CFGFILE -P $PIDFILE -m $S_MEMORY -M $P_MEMORY -u $USER -g $GROUP -w $HOMEDIR" + +case "$1" in + start|debug) + check_opensips_config + create_radius_seqfile + + if [ "$1" != "debug" ]; then + check_fork + fi + + # dirs under /var/run can go away on reboots. + mkdir -p "$HOMEDIR" + chmod 775 "$HOMEDIR" + chown "$USER:$GROUP" "$HOMEDIR" >/dev/null 2>&1 || true + + # Generate config from M4 + if [ -f $M4CFGFILE ]; then + m4 -Q $M4CFGFILE >$CFGFILE.tmp + if [ $? != 0 ]; then + echo "Cannot process m4 macro" + rm "$CFGFILE.tmp" + exit 1 + fi + + [ -e $CFGFILE ] || touch $CFGFILE + + # compare configs + if [ `md5sum $CFGFILE|awk '{print $1}'` != `md5sum $CFGFILE.tmp|awk '{print $1}'` ]; then + mkdir -p "$M4ARCHIVEDIR" + mv "$CFGFILE" "$M4ARCHIVEDIR/$NAME.cfg-`date +%Y%m%d_%H%M%S`" + fi + + mv "$CFGFILE.tmp" "$CFGFILE" + chown $USER:$GROUP $CFGFILE + chmod 640 $CFGFILE + fi + + echo -n "Starting $DESC: $NAME" + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --exec $DAEMON -- $OPTIONS || echo -n " already running" + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON + echo "." + ;; + restart|force-reload) + check_opensips_config + create_radius_seqfile + + echo -n "Restarting $DESC: $NAME" + start-stop-daemon --oknodo --stop --quiet --pidfile \ + $PIDFILE --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + $PIDFILE --exec $DAEMON -- $OPTIONS + echo "." + ;; + status) + echo -n "Status of $DESC: " + if [ ! -r "$PIDFILE" ]; then + echo "$NAME is not running." + exit 3 + fi + if read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then + echo "$NAME is running." + exit 0 + else + echo "$NAME is not running but $PIDFILE exists." + exit 1 + fi + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|debug|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/data/tutorials_test/osips/opensips/etc/opensips/opensips.cfg b/data/tutorials_test/osips/opensips/etc/opensips/opensips.cfg new file mode 100644 index 000000000..794255abe --- /dev/null +++ b/data/tutorials_test/osips/opensips/etc/opensips/opensips.cfg @@ -0,0 +1,269 @@ +# +# OpenSIPS residential configuration script +# by OpenSIPS Solutions +# +# This script was generated via "make menuconfig", from +# the "Residential" scenario. +# You can enable / disable more features / functionalities by +# re-generating the scenario with different options.# +# +# Please refer to the Core CookBook at: +# http://www.opensips.org/Resources/DocsCookbooks +# for a explanation of possible statements, functions and parameters. +# + + +####### Global Parameters ######### + +log_level=3 +log_stderror=no +log_facility=LOG_LOCAL0 + +udp_workers=4 + +auto_aliases=no + +listen=udp:enp0s3:5060 +listen=udp:127.0.0.1:5080 +listen=udp:127.0.0.1:5060 +listen=udp:enp0s3:5080 + + + +####### Modules Section ######## + +#set module path +mpath="/usr/lib/x86_64-linux-gnu/opensips/modules/" + +#### SIGNALING module +loadmodule "signaling.so" + +#### StateLess module +loadmodule "sl.so" + +#### Transaction Module +loadmodule "tm.so" +modparam("tm", "fr_timeout", 5) +modparam("tm", "fr_inv_timeout", 30) +modparam("tm", "restart_fr_on_each_reply", 0) +modparam("tm", "onreply_avp_mode", 1) + +#### Record Route Module +loadmodule "rr.so" +/* do not append from tag to the RR (no need for this script) */ +modparam("rr", "append_fromtag", 0) + +#### MAX ForWarD module +loadmodule "maxfwd.so" + +#### SIP MSG OPerationS module +loadmodule "sipmsgops.so" + +#### FIFO Management Interface +loadmodule "mi_fifo.so" +modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo") +modparam("mi_fifo", "fifo_mode", 0666) + +#### USeR LOCation module +loadmodule "usrloc.so" +modparam("usrloc", "nat_bflag", "NAT") +modparam("usrloc", "db_mode", 0) + +#### REGISTRAR module +loadmodule "registrar.so" +modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT") + +#### ACCounting module +loadmodule "acc.so" +modparam("acc", "early_media", 0) +modparam("acc", "report_cancels", 0) +modparam("acc", "detect_direction", 0) + +loadmodule "proto_udp.so" + + +#### CGRateS module +loadmodule "dialog.so" +loadmodule "cgrates.so" +modparam("cgrates", "cgrates_engine", "127.0.0.1:2014") + + +####### Routing Logic ######## + +# main request routing logic + +route{ + + if (!mf_process_maxfwd_header(10)) { + send_reply(483,"Too Many Hops"); + exit; + } + + if (has_totag()) { + + # handle hop-by-hop ACK (no routing required) + if ( is_method("ACK") && t_check_trans() ) { + t_relay(); + exit; + } + + # sequential request within a dialog should + # take the path determined by record-routing + if ( !loose_route() ) { + # we do record-routing for all our traffic, so we should not + # receive any sequential requests without Route hdr. + send_reply(404, "Not here"); + exit; + } + + if (is_method("BYE")) { + # do accounting even if the transaction fails + do_accounting("log","failed"); + } + + # route it out to whatever destination was set by loose_route() + # in $du (destination URI). + route(relay); + exit; + } + + # CANCEL processing + if (is_method("CANCEL")) { + if (t_check_trans()) + t_relay(); + exit; + } + + # absorb retransmissions, but do not create transaction + t_check_trans(); + + if ( !(is_method("REGISTER") ) ) { + + if (is_myself("$fd")) { + + } else { + # if caller is not local, then called number must be local + + if (!is_myself("$rd")) { + send_reply(403,"Relay Forbidden"); + exit; + } + } + + } + + # preloaded route checking + if (loose_route()) { + xlog("L_ERR", + "Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]"); + if (!is_method("ACK")) + send_reply(403, "Preload Route denied"); + exit; + } + + # record routing + if (!is_method("REGISTER|MESSAGE")) + record_route(); + + if (!is_myself("$rd")) { + append_hf("P-hint: outbound\r\n"); + + route(relay); + } + + # requests for my domain + + if (is_method("PUBLISH|SUBSCRIBE")) { + send_reply(503, "Service Unavailable"); + exit; + } + + if (is_method("REGISTER")) { + + if (!save("location")) + sl_reply_error(); + + exit; + } + + if ($rU==NULL) { + # request with no Username in RURI + send_reply(484,"Address Incomplete"); + exit; + } + + # do lookup with method filtering + if (!lookup("location","m")) { + t_reply(404, "Not Found"); + exit; + } + + # check auth with CGRateS + $cgr_opt(GetMaxUsage) = 1; # also retrieve the max usage + $cgr_opt(GetAttributes) = 1; + $cgr_opt(GetSuppliers) = 1; + $cgr_opt(AuthorizeResources) = 1; + $cgr_opt(AllocateResources) = 1; + $cgr_opt(ReleaseResources) = 1; + $cgr_opt(ProcessThresholds) = 1; + $cgr_opt(ProcessStatQueues) = 1; + $cgr(RequestType) = "*prepaid"; + $cgr(OriginHost) = "127.0.0.1"; + $cgr(Source) = "OpenSIPS"; + + if (!async(cgrates_auth("$fU", "$rU"), resume_cgr_auth)) { + sl_send_reply(503, "Service Unavailable"); + exit; + } +} + +route [resume_cgr_auth] { + if ($rc != 1) { + xlog("Call not authorized: code=$cgrret!\n"); + send_reply(403, "Forbidden"); + exit; + } + $var(idx) = 0; + while ($(cgr_ret(AttributesDigest){s.select,$var(idx),,}) != NULL) { + $avp($(cgr_ret(AttributesDigest){s.select,$var(idx),,}{s.select,0,:})) + = $(cgr_ret(AttributesDigest){s.select,$var(idx),,}{s.select,1,:}); + $var(idx) = $var(idx) + 1; + } + cgrates_acc("cdr|missed", "$fU", "$rU"); + xlog("### Have authorized the call and it should go through"); + route(relay); +} + + +route[relay] { + # for INVITEs enable some additional helper routes + if (is_method("INVITE")) { + t_on_branch("per_branch_ops"); + t_on_reply("handle_nat"); + t_on_failure("missed_call"); + } + + if (!t_relay()) { + send_reply(500,"Internal Error"); + } + exit; +} + + + + +branch_route[per_branch_ops] { + xlog("new branch at $ru\n"); +} + + +onreply_route[handle_nat] { + xlog("incoming reply\n"); +} + + +failure_route[missed_call] { + if (t_was_cancelled()) { + exit; + } +} diff --git a/general_tests/tutorial_calls_test.go b/general_tests/tutorial_calls_test.go index 00480f764..edcc9b757 100755 --- a/general_tests/tutorial_calls_test.go +++ b/general_tests/tutorial_calls_test.go @@ -42,10 +42,10 @@ var tutorialCallsRpc *rpc.Client var tutorialCallsPjSuaListener *os.File var waitRater = flag.Int("wait_rater", 1000, "Number of miliseconds to wait for rater to start and cache") var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here") -var fsConfig = flag.String("fsConfig", "/usr/share/cgrates/tutorials/fs_evsock", "FreeSwitch tutorial folder") -var kamConfig = flag.String("kamConfig", "/usr/share/cgrates/tutorials/kamevapi", "Kamailio tutorial folder") -var oSipsConfig = flag.String("osConfig", "/usr/share/cgrates/tutorials/osips_native", "OpenSips tutorial folder") -var ariConf = flag.String("ariConf", "/usr/share/cgrates/tutorials/asterisk_ari", "Asterisk tutorial folder") +var fsConfig = flag.String("fsConfig", "/usr/share/cgrates/tutorials_test/fs_evsock", "FreeSwitch tutorial folder") +var kamConfig = flag.String("kamConfig", "/usr/share/cgrates/tutorials_test/kamevapi", "Kamailio tutorial folder") +var oSipsConfig = flag.String("osConfig", "/usr/share/cgrates/tutorials_test/osips", "OpenSips tutorial folder") +var ariConf = flag.String("ariConf", "/usr/share/cgrates/tutorials_test/asterisk_ari", "Asterisk tutorial folder") var optConf string var sTestsCalls = []func(t *testing.T){