Resolved conflicts:
core/AmSessionEventHandler.h
core/plug-in/uac_auth/UACAuth.cpp
b/f: missing 'old_dlg_status' param in some onReply's:
apps/auth_b2b/AuthB2B.cpp
apps/registrar_client/SIPRegistrarClient.cpp
apps/sst_b2b/SSTB2B.cpp
... | ... |
@@ -7,7 +7,9 @@ GIT = $(shell which git) |
7 | 7 |
SVNVERSION = $(shell which svnversion) |
8 | 8 |
|
9 | 9 |
ifneq ($(GIT),) |
10 |
- SCM_REV = $(shell if git --help describe |grep dirty 2>&1 >/dev/null ; then git describe --always --dirty; else git describe --always ; fi) |
|
10 |
+ SCM_REV = $(shell if git --help describe |grep dirty 2>&1 >/dev/null ; \ |
|
11 |
+ then git describe --always --dirty 2>/dev/null; \ |
|
12 |
+ else git describe --always 2>/dev/null; fi) |
|
11 | 13 |
endif |
12 | 14 |
|
13 | 15 |
ifeq ($(SCM_REV),) |
... | ... |
@@ -112,7 +112,7 @@ void AnnounceTransferDialog::onSessionStart(const AmSipRequest& req) |
112 | 112 |
status = Announcing; |
113 | 113 |
callee_uri = get_session_param(req.hdrs, "Refer-To"); |
114 | 114 |
if (!callee_uri.length()) { |
115 |
- callee_uri = getHeader(req.hdrs, "P-Refer-To"); |
|
115 |
+ callee_uri = getHeader(req.hdrs, "P-Refer-To", true); |
|
116 | 116 |
if (callee_uri.length()) { |
117 | 117 |
INFO("Use of P-Refer-To header is deprecated. " |
118 | 118 |
"Use '%s: Refer-To=<uri>' instead.\n",PARAM_HDR); |
... | ... |
@@ -140,7 +140,7 @@ void AnnounceTransferDialog::onSipRequest(const AmSipRequest& req) |
140 | 140 |
(req.method == "NOTIFY")) { |
141 | 141 |
try { |
142 | 142 |
|
143 |
- if (strip_header_params(getHeader(req.hdrs,"Event", "o")) != "refer") |
|
143 |
+ if (strip_header_params(getHeader(req.hdrs,"Event", "o", true)) != "refer") |
|
144 | 144 |
throw AmSession::Exception(481, "Subscription does not exist"); |
145 | 145 |
|
146 | 146 |
if ((strip_header_params(req.content_type) != "message/sipfrag")) |
... | ... |
@@ -142,7 +142,7 @@ void AnnRecorderFactory::getAppParams(const AmSipRequest& req, map<string, strin |
142 | 142 |
typ = DEFAULT_TYPE; |
143 | 143 |
} |
144 | 144 |
else { |
145 |
- string iptel_app_param = getHeader(req.hdrs, PARAM_HDR); |
|
145 |
+ string iptel_app_param = getHeader(req.hdrs, PARAM_HDR, true); |
|
146 | 146 |
|
147 | 147 |
if (!iptel_app_param.length()) { |
148 | 148 |
throw AmSession::Exception(500, MOD_NAME ": parameters not found"); |
... | ... |
@@ -113,7 +113,7 @@ void AuthB2BDialog::onInvite(const AmSipRequest& req) |
113 | 113 |
setInOut(NULL,NULL); |
114 | 114 |
|
115 | 115 |
if (AuthB2BFactory::user.empty()) { |
116 |
- string app_param = getHeader(req.hdrs, PARAM_HDR); |
|
116 |
+ string app_param = getHeader(req.hdrs, PARAM_HDR, true); |
|
117 | 117 |
|
118 | 118 |
if (!app_param.length()) { |
119 | 119 |
AmSession::Exception(500, "auth_b2b: parameters not found"); |
... | ... |
@@ -321,7 +321,7 @@ void AuthB2BCalleeSession::onSipReply(const AmSipReply& reply, int old_dlg_statu |
321 | 321 |
} |
322 | 322 |
|
323 | 323 |
unsigned int cseq_before = dlg.cseq; |
324 |
- if (!auth->onSipReply(reply)) { |
|
324 |
+ if (!auth->onSipReply(reply, old_dlg_status)) { |
|
325 | 325 |
AmB2BCalleeSession::onSipReply(reply,old_dlg_status); |
326 | 326 |
} else { |
327 | 327 |
if (cseq_before != dlg.cseq) { |
... | ... |
@@ -88,7 +88,7 @@ AmSession* CallTimerFactory::onInvite(const AmSipRequest& req) |
88 | 88 |
throw AmSession::Exception(500,"could not get a user timer reference"); |
89 | 89 |
} |
90 | 90 |
|
91 |
- string app_param = getHeader(req.hdrs, PARAM_HDR); |
|
91 |
+ string app_param = getHeader(req.hdrs, PARAM_HDR, true); |
|
92 | 92 |
|
93 | 93 |
unsigned int call_time = CallTimerFactory::DefaultCallTimer; |
94 | 94 |
|
... | ... |
@@ -379,22 +379,22 @@ void ConferenceDialog::onSessionStart(const AmSipRequest& req) |
379 | 379 |
int i, len; |
380 | 380 |
string lonely_user_file; |
381 | 381 |
|
382 |
- string app_param_hdr = getHeader(req.hdrs, PARAM_HDR); |
|
382 |
+ string app_param_hdr = getHeader(req.hdrs, PARAM_HDR, true); |
|
383 | 383 |
if (app_param_hdr.length()) { |
384 | 384 |
from_header = get_header_keyvalue(app_param_hdr, "Dialout-From"); |
385 | 385 |
extra_headers = get_header_keyvalue(app_param_hdr, "Dialout-Extra"); |
386 | 386 |
dialout_suffix = get_header_keyvalue(app_param_hdr, "Dialout-Suffix"); |
387 | 387 |
language = get_header_keyvalue(app_param_hdr, "Language"); |
388 | 388 |
} else { |
389 |
- from_header = getHeader(req.hdrs, "P-Dialout-From"); |
|
390 |
- extra_headers = getHeader(req.hdrs, "P-Dialout-Extra"); |
|
391 |
- dialout_suffix = getHeader(req.hdrs, "P-Dialout-Suffix"); |
|
389 |
+ from_header = getHeader(req.hdrs, "P-Dialout-From", true); |
|
390 |
+ extra_headers = getHeader(req.hdrs, "P-Dialout-Extra", true); |
|
391 |
+ dialout_suffix = getHeader(req.hdrs, "P-Dialout-Suffix", true); |
|
392 | 392 |
if (from_header.length() || extra_headers.length() |
393 | 393 |
|| dialout_suffix.length()) { |
394 | 394 |
DBG("Warning: P-Dialout- style headers are deprecated." |
395 | 395 |
" Please use P-App-Param header instead.\n"); |
396 | 396 |
} |
397 |
- language = getHeader(req.hdrs, "P-Language"); |
|
397 |
+ language = getHeader(req.hdrs, "P-Language", true); |
|
398 | 398 |
if (language.length()) { |
399 | 399 |
DBG("Warning: P-Language header is deprecated." |
400 | 400 |
" Please use P-App-Param header instead.\n"); |
... | ... |
@@ -837,14 +837,14 @@ void ConferenceDialog::onSipRequest(const AmSipRequest& req) |
837 | 837 |
dlg.remote_tag = ""; |
838 | 838 |
|
839 | 839 |
// get route set and next hop |
840 |
- string iptel_app_param = getHeader(req.hdrs, PARAM_HDR); |
|
840 |
+ string iptel_app_param = getHeader(req.hdrs, PARAM_HDR, true); |
|
841 | 841 |
if (iptel_app_param.length()) { |
842 | 842 |
dlg.route = get_header_keyvalue(iptel_app_param,"Transfer-RR"); |
843 | 843 |
} else { |
844 | 844 |
INFO("Use of P-Transfer-RR/P-Transfer-NH is deprecated. " |
845 | 845 |
"Use '%s: Transfer-RR=<rr>;Transfer-NH=<nh>' instead.\n",PARAM_HDR); |
846 | 846 |
|
847 |
- dlg.route = getHeader(req.hdrs,"P-Transfer-RR"); |
|
847 |
+ dlg.route = getHeader(req.hdrs,"P-Transfer-RR", true); |
|
848 | 848 |
} |
849 | 849 |
|
850 | 850 |
DBG("ConferenceDialog::onSipRequest: local_party = %s\n",dlg.local_party.c_str()); |
... | ... |
@@ -37,6 +37,7 @@ |
37 | 37 |
#include "DSMChartReader.h" |
38 | 38 |
#include "AmSipHeaders.h" |
39 | 39 |
#include "AmEventDispatcher.h" |
40 |
+#include "SystemDSM.h" |
|
40 | 41 |
|
41 | 42 |
#include <string> |
42 | 43 |
#include <fstream> |
... | ... |
@@ -63,6 +64,7 @@ DSMFactory* DSMFactory::instance() |
63 | 64 |
bool DSMFactory::DebugDSM; |
64 | 65 |
string DSMFactory::InboundStartDiag; |
65 | 66 |
string DSMFactory::OutboundStartDiag; |
67 |
+bool DSMFactory::CheckDSM; |
|
66 | 68 |
|
67 | 69 |
#ifdef USE_MONITORING |
68 | 70 |
bool DSMFactory::MonitoringFullCallgraph; |
... | ... |
@@ -70,8 +72,10 @@ bool DSMFactory::MonitoringFullTransitions; |
70 | 72 |
|
71 | 73 |
MonSelectType DSMFactory::MonSelectCaller; |
72 | 74 |
MonSelectType DSMFactory::MonSelectCallee; |
75 |
+vector<string> DSMFactory::MonSelectFilters; |
|
73 | 76 |
|
74 | 77 |
string DSMFactory::MonSelectFallback; |
78 |
+ |
|
75 | 79 |
#endif // USE_MONITORING |
76 | 80 |
|
77 | 81 |
DSMFactory::DSMFactory(const string& _app_name) |
... | ... |
@@ -122,6 +126,7 @@ int DSMFactory::onLoad() |
122 | 126 |
configureModule(cfg); |
123 | 127 |
|
124 | 128 |
DebugDSM = cfg.getParameter("debug_raw_dsm") == "yes"; |
129 |
+ CheckDSM = cfg.getParameter("dsm_consistency_check", "yes") == "yes"; |
|
125 | 130 |
|
126 | 131 |
if (!loadPrompts(cfg)) |
127 | 132 |
return -1; |
... | ... |
@@ -161,6 +166,17 @@ int DSMFactory::onLoad() |
161 | 166 |
|
162 | 167 |
MainScriptConfig.SetParamVariables = cfg.getParameter("set_param_variables")=="yes"; |
163 | 168 |
|
169 |
+ vector<string> system_dsms = explode(cfg.getParameter("run_system_dsms"), ","); |
|
170 |
+ for (vector<string>::iterator it=system_dsms.begin(); it != system_dsms.end(); it++) { |
|
171 |
+ string status; |
|
172 |
+ if (createSystemDSM("main", *it, false /* reload */, status)) { |
|
173 |
+ DBG("created SystemDSM '%s'\n", it->c_str()); |
|
174 |
+ } else { |
|
175 |
+ ERROR("creating system DSM '%s': '%s'\n", it->c_str(), status.c_str()); |
|
176 |
+ return -1; |
|
177 |
+ } |
|
178 |
+ } |
|
179 |
+ |
|
164 | 180 |
#ifdef USE_MONITORING |
165 | 181 |
string monitoring_full_callgraph = cfg.getParameter("monitoring_full_stategraph"); |
166 | 182 |
MonitoringFullCallgraph = monitoring_full_callgraph == "yes"; |
... | ... |
@@ -196,6 +212,20 @@ int DSMFactory::onLoad() |
196 | 212 |
cfg_usecallee.c_str()); |
197 | 213 |
} |
198 | 214 |
|
215 |
+ MonSelectFilters = explode(cfg.getParameter("monitor_select_filters"), ","); |
|
216 |
+ string filters; |
|
217 |
+ for (vector<string>::iterator it = |
|
218 |
+ MonSelectFilters.begin(); it != MonSelectFilters.end(); it++) { |
|
219 |
+ if (it != MonSelectFilters.begin()) |
|
220 |
+ filters += ", "; |
|
221 |
+ filters+=*it; |
|
222 |
+ } |
|
223 |
+ if (MonSelectFilters.size()) { |
|
224 |
+ DBG("using additional monitor app select filters: %s\n", |
|
225 |
+ filters.c_str()); |
|
226 |
+ } else { |
|
227 |
+ DBG("not using additional monitor app select filters\n"); |
|
228 |
+ } |
|
199 | 229 |
MonSelectFallback = cfg.getParameter("monitor_select_fallback"); |
200 | 230 |
#endif |
201 | 231 |
|
... | ... |
@@ -327,7 +357,7 @@ bool DSMFactory::loadDiags(AmConfigReader& cfg, DSMStateDiagramCollection* m_dia |
327 | 357 |
vector<string> diags_names = explode(LoadDiags, ","); |
328 | 358 |
for (vector<string>::iterator it= |
329 | 359 |
diags_names.begin(); it != diags_names.end(); it++) { |
330 |
- if (!m_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM)) { |
|
360 |
+ if (!m_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM, CheckDSM)) { |
|
331 | 361 |
ERROR("loading %s from %s\n", |
332 | 362 |
it->c_str(), (DiagPath+*it+".dsm").c_str()); |
333 | 363 |
return false; |
... | ... |
@@ -417,6 +447,7 @@ bool DSMFactory::loadConfig(const string& conf_file_name, const string& conf_nam |
417 | 447 |
|
418 | 448 |
ScriptConfigs_mut.lock(); |
419 | 449 |
try { |
450 |
+ Name2ScriptConfig[script_name] = script_config; |
|
420 | 451 |
// set ScriptConfig to this for all registered apps' names |
421 | 452 |
for (vector<string>::iterator reg_app_it= |
422 | 453 |
registered_apps.begin(); reg_app_it != registered_apps.end(); reg_app_it++) { |
... | ... |
@@ -439,7 +470,19 @@ bool DSMFactory::loadConfig(const string& conf_file_name, const string& conf_nam |
439 | 470 |
} |
440 | 471 |
ScriptConfigs_mut.unlock(); |
441 | 472 |
|
442 |
- return true; |
|
473 |
+ bool res = true; |
|
474 |
+ |
|
475 |
+ vector<string> system_dsms = explode(cfg.getParameter("run_system_dsms"), ","); |
|
476 |
+ for (vector<string>::iterator it=system_dsms.begin(); it != system_dsms.end(); it++) { |
|
477 |
+ string status; |
|
478 |
+ if (createSystemDSM(script_name, *it, live_reload, status)) { |
|
479 |
+ } else { |
|
480 |
+ ERROR("creating system DSM '%s': '%s'\n", it->c_str(), status.c_str()); |
|
481 |
+ res = false; |
|
482 |
+ } |
|
483 |
+ } |
|
484 |
+ |
|
485 |
+ return res; |
|
443 | 486 |
} |
444 | 487 |
|
445 | 488 |
|
... | ... |
@@ -457,7 +500,7 @@ void DSMFactory::addVariables(DSMCall* s, const string& prefix, |
457 | 500 |
void DSMFactory::addParams(DSMCall* s, const string& hdrs) { |
458 | 501 |
// TODO: use real parser with quoting and optimize |
459 | 502 |
map<string, string> params; |
460 |
- vector<string> items = explode(getHeader(hdrs, PARAM_HDR), ";"); |
|
503 |
+ vector<string> items = explode(getHeader(hdrs, PARAM_HDR, true), ";"); |
|
461 | 504 |
for (vector<string>::iterator it=items.begin(); |
462 | 505 |
it != items.end(); it++) { |
463 | 506 |
vector<string> kv = explode(*it, "="); |
... | ... |
@@ -487,12 +530,13 @@ void AmArg2DSMStrMap(const AmArg& arg, |
487 | 530 |
} |
488 | 531 |
} |
489 | 532 |
|
490 |
-void DSMFactory::runMonitorAppSelect(const AmSipRequest& req, string& start_diag, map<string, string>& vars) { |
|
533 |
+void DSMFactory::runMonitorAppSelect(const AmSipRequest& req, string& start_diag, |
|
534 |
+ map<string, string>& vars) { |
|
491 | 535 |
#define FALLBACK_OR_EXCEPTION(code, reason) \ |
492 | 536 |
if (MonSelectFallback.empty()) { \ |
493 | 537 |
throw AmSession::Exception(code, reason); \ |
494 | 538 |
} else { \ |
495 |
- INFO("falling back to '%s'\n", MonSelectFallback.c_str()); \ |
|
539 |
+ DBG("falling back to '%s'\n", MonSelectFallback.c_str()); \ |
|
496 | 540 |
start_diag = MonSelectFallback; \ |
497 | 541 |
return; \ |
498 | 542 |
} |
... | ... |
@@ -510,7 +554,7 @@ void DSMFactory::runMonitorAppSelect(const AmSipRequest& req, string& start_diag |
510 | 554 |
from_parser.uri = req.from_uri; |
511 | 555 |
else { |
512 | 556 |
size_t end; |
513 |
- string pai = getHeader(req.hdrs, SIP_HDR_P_ASSERTED_IDENTITY); |
|
557 |
+ string pai = getHeader(req.hdrs, SIP_HDR_P_ASSERTED_IDENTITY, true); |
|
514 | 558 |
if (!from_parser.parse_contact(pai, 0, end)) { |
515 | 559 |
WARN("Failed to parse " SIP_HDR_P_ASSERTED_IDENTITY " '%s'\n", |
516 | 560 |
pai.c_str()); |
... | ... |
@@ -551,13 +595,27 @@ void DSMFactory::runMonitorAppSelect(const AmSipRequest& req, string& start_diag |
551 | 595 |
} |
552 | 596 |
|
553 | 597 |
DBG(" && looking for callee=='%s'\n", req.user.c_str()); |
554 |
- di_args.push(callee_filter); |
|
598 |
+ di_args.push(callee_filter); |
|
599 |
+ } |
|
600 |
+ // apply additional filters |
|
601 |
+ if (MonSelectFilters.size()) { |
|
602 |
+ string app_params = getHeader(req.hdrs, PARAM_HDR); |
|
603 |
+ for (vector<string>::iterator it = |
|
604 |
+ MonSelectFilters.begin(); it != MonSelectFilters.end(); it++) { |
|
605 |
+ AmArg filter; |
|
606 |
+ filter.push(*it); // avp name |
|
607 |
+ string app_param_val = get_header_keyvalue(app_params, *it); |
|
608 |
+ filter.push(app_param_val); |
|
609 |
+ di_args.push(filter); |
|
610 |
+ DBG(" && looking for %s=='%s'\n", it->c_str(), app_param_val.c_str()); |
|
611 |
+ } |
|
555 | 612 |
} |
613 |
+ |
|
556 | 614 |
MONITORING_GLOBAL_INTERFACE->invoke("listByFilter",di_args,ret); |
557 | 615 |
|
558 | 616 |
if ((ret.getType()!=AmArg::Array)|| |
559 | 617 |
!ret.size()) { |
560 |
- INFO("call info not found. caller uri %s, r-uri %s\n", |
|
618 |
+ DBG("call info not found. caller uri %s, r-uri %s\n", |
|
561 | 619 |
req.from_uri.c_str(), req.r_uri.c_str()); |
562 | 620 |
FALLBACK_OR_EXCEPTION(500, "Internal Server Error"); |
563 | 621 |
} |
... | ... |
@@ -666,7 +724,7 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req, |
666 | 724 |
if (cred_obj) |
667 | 725 |
cred = dynamic_cast<UACAuthCred*>(cred_obj); |
668 | 726 |
} else if (session_params.getType() == AmArg::Array) { |
669 |
- DBG("session params is array - size %d\n", session_params.size()); |
|
727 |
+ DBG("session params is array - size %zd\n", session_params.size()); |
|
670 | 728 |
// Creds |
671 | 729 |
if (session_params.get(0).getType() == AmArg::AObject) { |
672 | 730 |
ArgObject* cred_obj = session_params.get(0).asObject(); |
... | ... |
@@ -705,7 +763,7 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req, |
705 | 763 |
addParams(s, req.hdrs); |
706 | 764 |
|
707 | 765 |
if (NULL == cred) { |
708 |
- WARN("discarding unknown session parameters.\n"); |
|
766 |
+ DBG("outgoing DSM call will not be authenticated.\n"); |
|
709 | 767 |
} else { |
710 | 768 |
AmSessionEventHandlerFactory* uac_auth_f = |
711 | 769 |
AmPlugIn::instance()->getFactory4Seh("uac_auth"); |
... | ... |
@@ -723,6 +781,39 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req, |
723 | 781 |
return s; |
724 | 782 |
} |
725 | 783 |
|
784 |
+bool DSMFactory::createSystemDSM(const string& config_name, const string& start_diag, bool reload, string& status) { |
|
785 |
+ bool res = true; |
|
786 |
+ |
|
787 |
+ DSMScriptConfig* script_config = NULL; |
|
788 |
+ ScriptConfigs_mut.lock(); |
|
789 |
+ if (config_name == "main") |
|
790 |
+ script_config = &MainScriptConfig; |
|
791 |
+ else { |
|
792 |
+ map<string, DSMScriptConfig>::iterator it = Name2ScriptConfig.find(config_name); |
|
793 |
+ if (it != Name2ScriptConfig.end()) |
|
794 |
+ script_config = &it->second; |
|
795 |
+ } |
|
796 |
+ if (script_config==NULL) { |
|
797 |
+ status = "Error: Script config '"+config_name+"' not found, in ["; |
|
798 |
+ for (map<string, DSMScriptConfig>::iterator it = |
|
799 |
+ Name2ScriptConfig.begin(); it != Name2ScriptConfig.end(); it++) { |
|
800 |
+ if (it != Name2ScriptConfig.begin()) |
|
801 |
+ status+=", "; |
|
802 |
+ status += it->first; |
|
803 |
+ } |
|
804 |
+ status += "]"; |
|
805 |
+ res = false; |
|
806 |
+ } else { |
|
807 |
+ SystemDSM* s = new SystemDSM(*script_config, start_diag, reload); |
|
808 |
+ s->start(); |
|
809 |
+ // add to garbage collector |
|
810 |
+ AmThreadWatcher::instance()->add(s); |
|
811 |
+ status = "OK"; |
|
812 |
+ } |
|
813 |
+ ScriptConfigs_mut.unlock(); |
|
814 |
+ return res; |
|
815 |
+} |
|
816 |
+ |
|
726 | 817 |
void DSMFactory::reloadDSMs(const AmArg& args, AmArg& ret) { |
727 | 818 |
DSMStateDiagramCollection* new_diags = new DSMStateDiagramCollection(); |
728 | 819 |
|
... | ... |
@@ -743,7 +834,7 @@ void DSMFactory::reloadDSMs(const AmArg& args, AmArg& ret) { |
743 | 834 |
vector<string> diags_names = explode(LoadDiags, ","); |
744 | 835 |
for (vector<string>::iterator it= |
745 | 836 |
diags_names.begin(); it != diags_names.end(); it++) { |
746 |
- if (!new_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM)) { |
|
837 |
+ if (!new_diags->loadFile(DiagPath+*it+".dsm", *it, ModPath, DebugDSM, CheckDSM)) { |
|
747 | 838 |
ERROR("loading %s from %s\n", |
748 | 839 |
it->c_str(), (DiagPath+*it+".dsm").c_str()); |
749 | 840 |
ret.push(500); |
... | ... |
@@ -949,7 +1040,7 @@ void DSMFactory::loadDSM(const AmArg& args, AmArg& ret) { |
949 | 1040 |
ret.push(400); |
950 | 1041 |
ret.push("DSM named '" + dsm_name + "' already loaded (use reloadDSMs to reload all)"); |
951 | 1042 |
} else { |
952 |
- if (!MainScriptConfig.diags->loadFile(dsm_file_name, dsm_name, ModPath, DebugDSM)) { |
|
1043 |
+ if (!MainScriptConfig.diags->loadFile(dsm_file_name, dsm_name, ModPath, DebugDSM, CheckDSM)) { |
|
953 | 1044 |
ret.push(500); |
954 | 1045 |
ret.push("error loading "+dsm_name+" from "+ dsm_file_name); |
955 | 1046 |
} else { |
... | ... |
@@ -976,7 +1067,7 @@ void DSMFactory::loadDSMWithPaths(const AmArg& args, AmArg& ret) { |
976 | 1067 |
ret.push(400); |
977 | 1068 |
ret.push("DSM named '" + dsm_name + "' already loaded (use reloadDSMs to reload all)"); |
978 | 1069 |
} else { |
979 |
- if (!MainScriptConfig.diags->loadFile(diag_path+dsm_name+".dsm", dsm_name, mod_path, DebugDSM)) { |
|
1070 |
+ if (!MainScriptConfig.diags->loadFile(diag_path+dsm_name+".dsm", dsm_name, mod_path, DebugDSM, CheckDSM)) { |
|
980 | 1071 |
ret.push(500); |
981 | 1072 |
ret.push("error loading "+dsm_name+" from "+ diag_path+dsm_name+".dsm"); |
982 | 1073 |
} else { |
... | ... |
@@ -1032,6 +1123,16 @@ void DSMFactory::invoke(const string& method, const AmArg& args, |
1032 | 1123 |
} else if (method == "loadConfig"){ |
1033 | 1124 |
args.assertArrayFmt("ss"); |
1034 | 1125 |
loadConfig(args,ret); |
1126 |
+ } else if (method == "createSystemDSM"){ |
|
1127 |
+ args.assertArrayFmt("ss"); |
|
1128 |
+ string status; |
|
1129 |
+ if (createSystemDSM(args.get(0).asCStr(), args.get(1).asCStr(), false, status)) { |
|
1130 |
+ ret.push(200); |
|
1131 |
+ ret.push(status); |
|
1132 |
+ } else { |
|
1133 |
+ ret.push(500); |
|
1134 |
+ ret.push(status); |
|
1135 |
+ } |
|
1035 | 1136 |
} else if(method == "_list"){ |
1036 | 1137 |
ret.push(AmArg("postDSMEvent")); |
1037 | 1138 |
ret.push(AmArg("reloadDSMs")); |
... | ... |
@@ -1043,6 +1144,8 @@ void DSMFactory::invoke(const string& method, const AmArg& args, |
1043 | 1144 |
ret.push(AmArg("hasDSM")); |
1044 | 1145 |
ret.push(AmArg("listDSMs")); |
1045 | 1146 |
ret.push(AmArg("registerApplication")); |
1147 |
+ ret.push(AmArg("createSystemDSM")); |
|
1046 | 1148 |
} else |
1047 | 1149 |
throw AmDynInvoke::NotImplemented(method); |
1048 | 1150 |
} |
1151 |
+ |
... | ... |
@@ -67,18 +67,23 @@ class DSMFactory |
67 | 67 |
std::set<DSMStateDiagramCollection*> old_diags; |
68 | 68 |
|
69 | 69 |
static bool DebugDSM; |
70 |
+ static bool CheckDSM; |
|
70 | 71 |
|
71 | 72 |
static string InboundStartDiag; |
72 | 73 |
static string OutboundStartDiag; |
73 | 74 |
|
74 | 75 |
DSMScriptConfig MainScriptConfig; |
76 |
+ // script name -> config |
|
75 | 77 |
map<string, DSMScriptConfig> ScriptConfigs; |
78 |
+ // config name -> config |
|
79 |
+ map<string, DSMScriptConfig> Name2ScriptConfig; |
|
76 | 80 |
AmMutex ScriptConfigs_mut; |
77 | 81 |
|
78 | 82 |
#ifdef USE_MONITORING |
79 | 83 |
static MonSelectType MonSelectCaller; |
80 | 84 |
static MonSelectType MonSelectCallee; |
81 | 85 |
static string MonSelectFallback; |
86 |
+ static vector<string> MonSelectFilters; |
|
82 | 87 |
|
83 | 88 |
#endif // USE_MONITORING |
84 | 89 |
|
... | ... |
@@ -139,6 +144,8 @@ public: |
139 | 144 |
|
140 | 145 |
void postEvent(AmEvent* e); |
141 | 146 |
|
147 |
+ bool createSystemDSM(const string& config_name, const string& start_diag, bool reload, string& status); |
|
148 |
+ |
|
142 | 149 |
}; |
143 | 150 |
|
144 | 151 |
#endif |
... | ... |
@@ -93,7 +93,7 @@ void DSMCall::onInvite(const AmSipRequest& req) { |
93 | 93 |
bool run_session_invite = engine.onInvite(req, this); |
94 | 94 |
|
95 | 95 |
if (run_invite_event) { |
96 |
- if (!engine.init(this, startDiagName, DSMCondition::Invite)) |
|
96 |
+ if (!engine.init(this, this, startDiagName, DSMCondition::Invite)) |
|
97 | 97 |
run_session_invite =false; |
98 | 98 |
|
99 | 99 |
if (checkVar(DSM_CONNECT_SESSION, DSM_CONNECT_SESSION_FALSE)) { |
... | ... |
@@ -120,7 +120,7 @@ void DSMCall::onOutgoingInvite(const string& headers) { |
120 | 120 |
bool run_session_invite = engine.onInvite(req, this); |
121 | 121 |
|
122 | 122 |
if (run_invite_event) { |
123 |
- if (!engine.init(this, startDiagName, DSMCondition::Invite)) |
|
123 |
+ if (!engine.init(this, this, startDiagName, DSMCondition::Invite)) |
|
124 | 124 |
run_session_invite =false; |
125 | 125 |
|
126 | 126 |
if (checkVar(DSM_CONNECT_SESSION, DSM_CONNECT_SESSION_FALSE)) { |
... | ... |
@@ -146,7 +146,7 @@ void DSMCall::onOutgoingInvite(const string& headers) { |
146 | 146 |
params["reason"] = reply.reason; |
147 | 147 |
params["has_body"] = reply.body.empty() ? |
148 | 148 |
"false" : "true"; |
149 |
- engine.runEvent(this, DSMCondition::Ringing, ¶ms); |
|
149 |
+ engine.runEvent(this, this, DSMCondition::Ringing, ¶ms); |
|
150 | 150 |
// todo: local ringbacktone |
151 | 151 |
} |
152 | 152 |
|
... | ... |
@@ -156,7 +156,7 @@ void DSMCall::onEarlySessionStart(const AmSipReply& reply) { |
156 | 156 |
params["reason"] = reply.reason; |
157 | 157 |
params["has_body"] = reply.body.empty() ? |
158 | 158 |
"false" : "true"; |
159 |
- engine.runEvent(this, DSMCondition::EarlySession, ¶ms); |
|
159 |
+ engine.runEvent(this, this, DSMCondition::EarlySession, ¶ms); |
|
160 | 160 |
|
161 | 161 |
if (checkVar(DSM_CONNECT_EARLY_SESSION, DSM_CONNECT_EARLY_SESSION_FALSE)) { |
162 | 162 |
DBG("call does not connect early session\n"); |
... | ... |
@@ -192,7 +192,7 @@ void DSMCall::onSessionStart(const AmSipReply& rep) |
192 | 192 |
} |
193 | 193 |
|
194 | 194 |
void DSMCall::startSession(){ |
195 |
- engine.init(this, startDiagName, DSMCondition::SessionStart); |
|
195 |
+ engine.init(this, this, startDiagName, DSMCondition::SessionStart); |
|
196 | 196 |
|
197 | 197 |
setReceiving(true); |
198 | 198 |
|
... | ... |
@@ -232,7 +232,7 @@ void DSMCall::onDtmf(int event, int duration_msec) { |
232 | 232 |
map<string, string> params; |
233 | 233 |
params["key"] = int2str(event); |
234 | 234 |
params["duration"] = int2str(duration_msec); |
235 |
- engine.runEvent(this, DSMCondition::Key, ¶ms); |
|
235 |
+ engine.runEvent(this, this, DSMCondition::Key, ¶ms); |
|
236 | 236 |
} |
237 | 237 |
|
238 | 238 |
void DSMCall::onBye(const AmSipRequest& req) |
... | ... |
@@ -241,13 +241,13 @@ void DSMCall::onBye(const AmSipRequest& req) |
241 | 241 |
map<string, string> params; |
242 | 242 |
params["headers"] = req.hdrs; |
243 | 243 |
|
244 |
- engine.runEvent(this, DSMCondition::Hangup, ¶ms); |
|
244 |
+ engine.runEvent(this, this, DSMCondition::Hangup, ¶ms); |
|
245 | 245 |
} |
246 | 246 |
|
247 | 247 |
void DSMCall::onCancel() { |
248 | 248 |
DBG("onCancel\n"); |
249 | 249 |
if (dlg.getStatus() < AmSipDialog::Connected) |
250 |
- engine.runEvent(this, DSMCondition::Hangup, NULL); |
|
250 |
+ engine.runEvent(this, this, DSMCondition::Hangup, NULL); |
|
251 | 251 |
else { |
252 | 252 |
DBG("ignoring onCancel event in established dialog\n"); |
253 | 253 |
} |
... | ... |
@@ -272,7 +272,7 @@ void DSMCall::onSipRequest(const AmSipRequest& req) { |
272 | 272 |
DSMSipRequest* sip_req = new DSMSipRequest(&req); |
273 | 273 |
avar[DSM_AVAR_REQUEST] = AmArg(sip_req); |
274 | 274 |
|
275 |
- engine.runEvent(this, DSMCondition::SipRequest, ¶ms); |
|
275 |
+ engine.runEvent(this, this, DSMCondition::SipRequest, ¶ms); |
|
276 | 276 |
|
277 | 277 |
delete sip_req; |
278 | 278 |
avar.erase(DSM_AVAR_REQUEST); |
... | ... |
@@ -306,7 +306,7 @@ void DSMCall::onSipReply(const AmSipReply& reply, int old_dlg_status) { |
306 | 306 |
DSMSipReply* dsm_reply = new DSMSipReply(&reply); |
307 | 307 |
avar[DSM_AVAR_REPLY] = AmArg(dsm_reply); |
308 | 308 |
|
309 |
- engine.runEvent(this, DSMCondition::SipReply, ¶ms); |
|
309 |
+ engine.runEvent(this, this, DSMCondition::SipReply, ¶ms); |
|
310 | 310 |
|
311 | 311 |
delete dsm_reply; |
312 | 312 |
avar.erase(DSM_AVAR_REPLY); |
... | ... |
@@ -327,7 +327,7 @@ void DSMCall::onSipReply(const AmSipReply& reply, int old_dlg_status) { |
327 | 327 |
map<string, string> params; |
328 | 328 |
params["code"] = int2str(reply.code); |
329 | 329 |
params["reason"] = reply.reason; |
330 |
- engine.runEvent(this, DSMCondition::FailedCall, ¶ms); |
|
330 |
+ engine.runEvent(this, this, DSMCondition::FailedCall, ¶ms); |
|
331 | 331 |
setStopped(); |
332 | 332 |
} |
333 | 333 |
} |
... | ... |
@@ -338,10 +338,9 @@ void DSMCall::process(AmEvent* event) |
338 | 338 |
if (event->event_id == DSM_EVENT_ID) { |
339 | 339 |
DSMEvent* dsm_event = dynamic_cast<DSMEvent*>(event); |
340 | 340 |
if (dsm_event) { |
341 |
- engine.runEvent(this, DSMCondition::DSMEvent, &dsm_event->params); |
|
341 |
+ engine.runEvent(this, this, DSMCondition::DSMEvent, &dsm_event->params); |
|
342 | 342 |
return; |
343 |
- } |
|
344 |
- |
|
343 |
+ } |
|
345 | 344 |
} |
346 | 345 |
|
347 | 346 |
AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(event); |
... | ... |
@@ -350,7 +349,7 @@ void DSMCall::process(AmEvent* event) |
350 | 349 |
(audio_event->event_id == AmAudioEvent::noAudio))){ |
351 | 350 |
map<string, string> params; |
352 | 351 |
params["type"] = audio_event->event_id == AmAudioEvent::cleared?"cleared":"noAudio"; |
353 |
- engine.runEvent(this, DSMCondition::NoAudio, ¶ms); |
|
352 |
+ engine.runEvent(this, this, DSMCondition::NoAudio, ¶ms); |
|
354 | 353 |
return; |
355 | 354 |
} |
356 | 355 |
|
... | ... |
@@ -359,14 +358,14 @@ void DSMCall::process(AmEvent* event) |
359 | 358 |
int timer_id = plugin_event->data.get(0).asInt(); |
360 | 359 |
map<string, string> params; |
361 | 360 |
params["id"] = int2str(timer_id); |
362 |
- engine.runEvent(this, DSMCondition::Timer, ¶ms); |
|
361 |
+ engine.runEvent(this, this, DSMCondition::Timer, ¶ms); |
|
363 | 362 |
} |
364 | 363 |
|
365 | 364 |
AmPlaylistSeparatorEvent* sep_ev = dynamic_cast<AmPlaylistSeparatorEvent*>(event); |
366 | 365 |
if (sep_ev) { |
367 | 366 |
map<string, string> params; |
368 | 367 |
params["id"] = int2str(sep_ev->event_id); |
369 |
- engine.runEvent(this, DSMCondition::PlaylistSeparator, ¶ms); |
|
368 |
+ engine.runEvent(this, this, DSMCondition::PlaylistSeparator, ¶ms); |
|
370 | 369 |
} |
371 | 370 |
|
372 | 371 |
// todo: give modules the possibility to define/process events |
... | ... |
@@ -386,12 +385,17 @@ void DSMCall::process(AmEvent* event) |
386 | 385 |
// decode result for easy use from script |
387 | 386 |
varPrintArg(resp_ev->response.data, params, resp_ev->response.is_error ? "error": "result"); |
388 | 387 |
|
389 |
- // save reference to full parameters |
|
390 |
- avar[DSM_AVAR_JSONRPCRESPONEDATA] = AmArg(&resp_ev->response.data); |
|
388 |
+ // decode udata for easy use from script |
|
389 |
+ varPrintArg(resp_ev->udata, params, "udata"); |
|
390 |
+ |
|
391 |
+ // save reference to full parameters as avar |
|
392 |
+ avar[DSM_AVAR_JSONRPCRESPONSEDATA] = AmArg(&resp_ev->response.data); |
|
393 |
+ avar[DSM_AVAR_JSONRPCRESPONSEUDATA] = AmArg(&resp_ev->udata); |
|
391 | 394 |
|
392 |
- engine.runEvent(this, DSMCondition::JsonRpcResponse, ¶ms); |
|
395 |
+ engine.runEvent(this, this, DSMCondition::JsonRpcResponse, ¶ms); |
|
393 | 396 |
|
394 |
- avar.erase(DSM_AVAR_JSONRPCRESPONEDATA); |
|
397 |
+ avar.erase(DSM_AVAR_JSONRPCRESPONSEUDATA); |
|
398 |
+ avar.erase(DSM_AVAR_JSONRPCRESPONSEDATA); |
|
395 | 399 |
return; |
396 | 400 |
} |
397 | 401 |
|
... | ... |
@@ -412,7 +416,7 @@ void DSMCall::process(AmEvent* event) |
412 | 416 |
// save reference to full parameters |
413 | 417 |
avar[DSM_AVAR_JSONRPCREQUESTDATA] = AmArg(&req_ev->params); |
414 | 418 |
|
415 |
- engine.runEvent(this, DSMCondition::JsonRpcRequest, ¶ms); |
|
419 |
+ engine.runEvent(this, this, DSMCondition::JsonRpcRequest, ¶ms); |
|
416 | 420 |
|
417 | 421 |
avar.erase(DSM_AVAR_JSONRPCREQUESTDATA); |
418 | 422 |
return; |
... | ... |
@@ -613,7 +617,7 @@ void DSMCall::onOtherBye(const AmSipRequest& req) { |
613 | 617 |
|
614 | 618 |
map<string, string> params; |
615 | 619 |
params["hdrs"] = req.hdrs; // todo: optimization - make this configurable |
616 |
- engine.runEvent(this, DSMCondition::B2BOtherBye, ¶ms); |
|
620 |
+ engine.runEvent(this, this, DSMCondition::B2BOtherBye, ¶ms); |
|
617 | 621 |
} |
618 | 622 |
|
619 | 623 |
bool DSMCall::onOtherReply(const AmSipReply& reply) { |
... | ... |
@@ -625,7 +629,7 @@ bool DSMCall::onOtherReply(const AmSipReply& reply) { |
625 | 629 |
params["reason"] = reply.reason; |
626 | 630 |
params["hdrs"] = reply.hdrs; // todo: optimization - make this configurable |
627 | 631 |
|
628 |
- engine.runEvent(this, DSMCondition::B2BOtherReply, ¶ms); |
|
632 |
+ engine.runEvent(this, this, DSMCondition::B2BOtherReply, ¶ms); |
|
629 | 633 |
|
630 | 634 |
return false; |
631 | 635 |
} |
... | ... |
@@ -31,6 +31,8 @@ |
31 | 31 |
#include "AmSession.h" |
32 | 32 |
#include "AmSessionContainer.h" |
33 | 33 |
#include "AmUtils.h" |
34 |
+#include "AmEventDispatcher.h" |
|
35 |
+#include "DSM.h" |
|
34 | 36 |
|
35 | 37 |
#include "jsonArg.h" |
36 | 38 |
|
... | ... |
@@ -69,6 +71,8 @@ DSMAction* DSMCoreModule::getAction(const string& from_str) { |
69 | 71 |
DEF_CMD("unmute", SCUnmuteAction); |
70 | 72 |
DEF_CMD("enableDTMFDetection", SCEnableDTMFDetection); |
71 | 73 |
DEF_CMD("disableDTMFDetection", SCDisableDTMFDetection); |
74 |
+ DEF_CMD("sendDTMF", SCSendDTMFAction); |
|
75 |
+ DEF_CMD("sendDTMFSequence", SCSendDTMFSequenceAction); |
|
72 | 76 |
|
73 | 77 |
DEF_CMD("set", SCSetAction); |
74 | 78 |
DEF_CMD("sets", SCSetSAction); |
... | ... |
@@ -80,6 +84,7 @@ DSMAction* DSMCoreModule::getAction(const string& from_str) { |
80 | 84 |
DEF_CMD("inc", SCIncAction); |
81 | 85 |
DEF_CMD("log", SCLogAction); |
82 | 86 |
DEF_CMD("clear", SCClearAction); |
87 |
+ DEF_CMD("clearArray", SCClearArrayAction); |
|
83 | 88 |
DEF_CMD("logVars", SCLogVarsAction); |
84 | 89 |
DEF_CMD("logParams", SCLogParamsAction); |
85 | 90 |
DEF_CMD("logSelects", SCLogSelectsAction); |
... | ... |
@@ -93,6 +98,10 @@ DSMAction* DSMCoreModule::getAction(const string& from_str) { |
93 | 98 |
|
94 | 99 |
DEF_CMD("postEvent", SCPostEventAction); |
95 | 100 |
|
101 |
+ DEF_CMD("registerEventQueue", SCRegisterEventQueueAction); |
|
102 |
+ DEF_CMD("unregisterEventQueue", SCUnregisterEventQueueAction); |
|
103 |
+ DEF_CMD("createSystemDSM", SCCreateSystemDSMAction); |
|
104 |
+ |
|
96 | 105 |
if (cmd == "DI") { |
97 | 106 |
SCDIAction * a = new SCDIAction(params, false); |
98 | 107 |
a->name = from_str; |
... | ... |
@@ -131,22 +140,22 @@ DSMCondition* DSMCoreModule::getCondition(const string& from_str) { |
131 | 140 |
if (cmd == "test") |
132 | 141 |
return new TestDSMCondition(params, DSMCondition::Any); |
133 | 142 |
|
134 |
- if (cmd == "keyTest") |
|
143 |
+ if ((cmd == "keyTest") || (cmd == "key")) |
|
135 | 144 |
return new TestDSMCondition(params, DSMCondition::Key); |
136 | 145 |
|
137 |
- if (cmd == "timerTest") |
|
146 |
+ if ((cmd == "timerTest") || (cmd == "timer")) |
|
138 | 147 |
return new TestDSMCondition(params, DSMCondition::Timer); |
139 | 148 |
|
140 |
- if (cmd == "noAudioTest") |
|
149 |
+ if ((cmd == "noAudioTest") || (cmd == "noAudio")) |
|
141 | 150 |
return new TestDSMCondition(params, DSMCondition::NoAudio); |
142 | 151 |
|
143 |
- if (cmd == "separatorTest") |
|
152 |
+ if ((cmd == "separatorTest") || (cmd == "separator")) |
|
144 | 153 |
return new TestDSMCondition(params, DSMCondition::PlaylistSeparator); |
145 | 154 |
|
146 | 155 |
if (cmd == "hangup") |
147 | 156 |
return new TestDSMCondition(params, DSMCondition::Hangup); |
148 | 157 |
|
149 |
- if (cmd == "eventTest") |
|
158 |
+ if ((cmd == "eventTest") || (cmd == "event")) |
|
150 | 159 |
return new TestDSMCondition(params, DSMCondition::DSMEvent); |
151 | 160 |
|
152 | 161 |
if (cmd == "invite") |
... | ... |
@@ -182,6 +191,15 @@ DSMCondition* DSMCoreModule::getCondition(const string& from_str) { |
182 | 191 |
if (cmd == "jsonRpcResponse") |
183 | 192 |
return new TestDSMCondition(params, DSMCondition::JsonRpcResponse); |
184 | 193 |
|
194 |
+ if (cmd == "startup") |
|
195 |
+ return new TestDSMCondition(params, DSMCondition::Startup); |
|
196 |
+ |
|
197 |
+ if (cmd == "reload") |
|
198 |
+ return new TestDSMCondition(params, DSMCondition::Reload); |
|
199 |
+ |
|
200 |
+ if (cmd == "system") |
|
201 |
+ return new TestDSMCondition(params, DSMCondition::System); |
|
202 |
+ |
|
185 | 203 |
return NULL; |
186 | 204 |
} |
187 | 205 |
|
... | ... |
@@ -211,8 +229,12 @@ EXEC_ACTION_START(SCPostEventAction){ |
211 | 229 |
if (!var.empty()) { |
212 | 230 |
if (var == "var") |
213 | 231 |
ev->params = sc_sess->var; |
214 |
- else |
|
215 |
- ev->params[var] = sc_sess->var[var]; |
|
232 |
+ else { |
|
233 |
+ vector<string> vars = explode(var, ";"); |
|
234 |
+ for (vector<string>::iterator it = |
|
235 |
+ vars.begin(); it != vars.end(); it++) |
|
236 |
+ ev->params[*it] = sc_sess->var[*it]; |
|
237 |
+ } |
|
216 | 238 |
} |
217 | 239 |
|
218 | 240 |
DBG("posting event to session '%s'\n", sess_id.c_str()); |
... | ... |
@@ -347,7 +369,7 @@ EXEC_ACTION_START(SCStopAction) { |
347 | 369 |
|
348 | 370 |
#define DEF_SCModActionExec(clsname) \ |
349 | 371 |
\ |
350 |
- bool clsname::execute(AmSession* sess, \ |
|
372 |
+ bool clsname::execute(AmSession* sess, DSMSession* sc_sess, \ |
|
351 | 373 |
DSMCondition::EventType event, \ |
352 | 374 |
map<string,string>* event_params) { \ |
353 | 375 |
return true; \ |
... | ... |
@@ -613,6 +635,25 @@ EXEC_ACTION_START(SCClearAction) { |
613 | 635 |
sc_sess->var.erase(var_name); |
614 | 636 |
} EXEC_ACTION_END; |
615 | 637 |
|
638 |
+EXEC_ACTION_START(SCClearArrayAction) { |
|
639 |
+ string varprefix = (arg.length() && arg[0] == '$')? |
|
640 |
+ arg.substr(1) : arg; |
|
641 |
+ DBG("clear variable array '%s.*'\n", varprefix.c_str()); |
|
642 |
+ |
|
643 |
+ varprefix+="."; |
|
644 |
+ |
|
645 |
+ map<string, string>::iterator lb = sc_sess->var.lower_bound(varprefix); |
|
646 |
+ while (lb != sc_sess->var.end()) { |
|
647 |
+ if ((lb->first.length() < varprefix.length()) || |
|
648 |
+ strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length())) |
|
649 |
+ break; |
|
650 |
+ map<string, string>::iterator lb_d = lb; |
|
651 |
+ lb++; |
|
652 |
+ sc_sess->var.erase(lb_d); |
|
653 |
+ } |
|
654 |
+ |
|
655 |
+} EXEC_ACTION_END; |
|
656 |
+ |
|
616 | 657 |
|
617 | 658 |
CONST_ACTION_2P(SCAppendAction,',', false); |
618 | 659 |
EXEC_ACTION_START(SCAppendAction) { |
... | ... |
@@ -838,7 +879,7 @@ TestDSMCondition::TestDSMCondition(const string& expr, DSMCondition::EventType e |
838 | 879 |
name = expr; |
839 | 880 |
} |
840 | 881 |
|
841 |
-bool TestDSMCondition::match(AmSession* sess, DSMCondition::EventType event, |
|
882 |
+bool TestDSMCondition::match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, |
|
842 | 883 |
map<string,string>* event_params) { |
843 | 884 |
if (ttype == None || (type != DSMCondition::Any && type != event)) |
844 | 885 |
return false; |
... | ... |
@@ -846,7 +887,6 @@ bool TestDSMCondition::match(AmSession* sess, DSMCondition::EventType event, |
846 | 887 |
if (ttype == Always) |
847 | 888 |
return true; |
848 | 889 |
|
849 |
- DSMSession* sc_sess = dynamic_cast<DSMSession*>(sess); |
|
850 | 890 |
if (!sc_sess) { |
851 | 891 |
ERROR("wrong session type\n"); |
852 | 892 |
return false; |
... | ... |
@@ -1160,3 +1200,100 @@ EXEC_ACTION_START(SCB2BClearHeadersAction) { |
1160 | 1200 |
DBG("clearing B2B headers\n"); |
1161 | 1201 |
sc_sess->B2BclearHeaders(); |
1162 | 1202 |
} EXEC_ACTION_END; |
1203 |
+ |
|
1204 |
+CONST_ACTION_2P(SCSendDTMFAction,',', true); |
|
1205 |
+EXEC_ACTION_START(SCSendDTMFAction) { |
|
1206 |
+ string event = resolveVars(par1, sess, sc_sess, event_params); |
|
1207 |
+ string duration = resolveVars(par2, sess, sc_sess, event_params); |
|
1208 |
+ |
|
1209 |
+ unsigned int event_i; |
|
1210 |
+ if (str2i(event, event_i)) { |
|
1211 |
+ ERROR("event '%s' not a valid DTMF event\n", event.c_str()); |
|
1212 |
+ throw DSMException("core", "cause", "invalid DTMF:"+ event); |
|
1213 |
+ } |
|
1214 |
+ |
|
1215 |
+ unsigned int duration_i; |
|
1216 |
+ if (duration.empty()) { |
|
1217 |
+ duration_i = 500; // default |
|
1218 |
+ } else { |
|
1219 |
+ if (str2i(duration, duration_i)) { |
|
1220 |
+ ERROR("event duration '%s' not a valid DTMF duration\n", duration.c_str()); |
|
1221 |
+ throw DSMException("core", "cause", "invalid DTMF duration:"+ duration); |
|
1222 |
+ } |
|
1223 |
+ } |
|
1224 |
+ |
|
1225 |
+ sess->sendDtmf(event_i, duration_i); |
|
1226 |
+} EXEC_ACTION_END; |
|
1227 |
+ |
|
1228 |
+CONST_ACTION_2P(SCSendDTMFSequenceAction,',', true); |
|
1229 |
+EXEC_ACTION_START(SCSendDTMFSequenceAction) { |
|
1230 |
+ string events = resolveVars(par1, sess, sc_sess, event_params); |
|
1231 |
+ string duration = resolveVars(par2, sess, sc_sess, event_params); |
|
1232 |
+ |
|
1233 |
+ unsigned int duration_i; |
|
1234 |
+ if (duration.empty()) { |
|
1235 |
+ duration_i = 500; // default |
|
1236 |
+ } else { |
|
1237 |
+ if (str2i(duration, duration_i)) { |
|
1238 |
+ ERROR("event duration '%s' not a valid DTMF duration\n", duration.c_str()); |
|
1239 |
+ throw DSMException("core", "cause", "invalid DTMF duration:"+ duration); |
|
1240 |
+ } |
|
1241 |
+ } |
|
1242 |
+ |
|
1243 |
+ for (size_t i=0;i<events.length();i++) { |
|
1244 |
+ if ((events[i]<'0' || events[i]>'9') |
|
1245 |
+ && (events[i] != '#') && (events[i] != '*') |
|
1246 |
+ && (events[i] <'A' || events[i] >'F')) { |
|
1247 |
+ DBG("skipping non-DTMF event char '%c'\n", events[i]); |
|
1248 |
+ continue; |
|
1249 |
+ } |
|
1250 |
+ int event = events[i] - '0'; |
|
1251 |
+ if (events[i] == '*') |
|
1252 |
+ event = 10; |
|
1253 |
+ else if (events[i] == '#') |
|
1254 |
+ event = 11; |
|
1255 |
+ else if (events[i] >= 'A' && events[i] <= 'F' ) |
|
1256 |
+ event = 12 + (events[i] - 'A'); |
|
1257 |
+ DBG("sending event %d duration %u\n", event, duration_i); |
|
1258 |
+ sess->sendDtmf(event, duration_i); |
|
1259 |
+ } |
|
1260 |
+} EXEC_ACTION_END; |
|
1261 |
+ |
|
1262 |
+EXEC_ACTION_START(SCRegisterEventQueueAction) { |
|
1263 |
+ string q_name = resolveVars(arg, sess, sc_sess, event_params); |
|
1264 |
+ DBG("Registering event queue '%s'\n", q_name.c_str()); |
|
1265 |
+ if (q_name.empty()) { |
|
1266 |
+ WARN("Registering empty event queue name!\n"); |
|
1267 |
+ } |
|
1268 |
+ AmEventDispatcher::instance()->addEventQueue(q_name, sess); |
|
1269 |
+} EXEC_ACTION_END; |
|
1270 |
+ |
|
1271 |
+EXEC_ACTION_START(SCUnregisterEventQueueAction) { |
|
1272 |
+ string q_name = resolveVars(arg, sess, sc_sess, event_params); |
|
1273 |
+ DBG("Unregistering event queue '%s'\n", q_name.c_str()); |
|
1274 |
+ if (q_name.empty()) { |
|
1275 |
+ WARN("Unregistering empty event queue name!\n"); |
|
1276 |
+ } |
|
1277 |
+ AmEventDispatcher::instance()->delEventQueue(q_name); |
|
1278 |
+} EXEC_ACTION_END; |
|
1279 |
+ |
|
1280 |
+CONST_ACTION_2P(SCCreateSystemDSMAction,',', false); |
|
1281 |
+EXEC_ACTION_START(SCCreateSystemDSMAction) { |
|
1282 |
+ string conf_name = resolveVars(par1, sess, sc_sess, event_params); |
|
1283 |
+ string script_name = resolveVars(par2, sess, sc_sess, event_params); |
|
1284 |
+ |
|
1285 |
+ if (conf_name.empty() || script_name.empty()) { |
|
1286 |
+ throw DSMException("core", "cause", "parameters missing - " |
|
1287 |
+ "need both conf_name and script_name for createSystemDSM"); |
|
1288 |
+ } |
|
1289 |
+ |
|
1290 |
+ DBG("creating system DSM conf_name %s, script_name %s\n", |
|
1291 |
+ conf_name.c_str(), script_name.c_str()); |
|
1292 |
+ string status; |
|
1293 |
+ if (!DSMFactory::instance()->createSystemDSM(conf_name, script_name, false, status)) { |
|
1294 |
+ ERROR("creating system DSM: %s\n", status.c_str()); |
|
1295 |
+ throw DSMException("core", "cause", status); |
|
1296 |
+ } |
|
1297 |
+ |
|
1298 |
+} EXEC_ACTION_END; |
|
1299 |
+ |
... | ... |
@@ -62,6 +62,8 @@ DEF_ACTION_1P(SCMuteAction); |
62 | 62 |
DEF_ACTION_1P(SCUnmuteAction); |
63 | 63 |
DEF_ACTION_1P(SCEnableDTMFDetection); |
64 | 64 |
DEF_ACTION_1P(SCDisableDTMFDetection); |
65 |
+DEF_ACTION_2P(SCSendDTMFAction); |
|
66 |
+DEF_ACTION_2P(SCSendDTMFSequenceAction); |
|
65 | 67 |
|
66 | 68 |
DEF_ACTION_1P(SCSetPromptsAction); |
67 | 69 |
DEF_ACTION_2P(SCAddSeparatorAction); |
... | ... |
@@ -81,6 +83,7 @@ DEF_ACTION_2P(SCAppendAction); |
81 | 83 |
DEF_ACTION_2P(SCSubStrAction); |
82 | 84 |
DEF_ACTION_1P(SCIncAction); |
83 | 85 |
DEF_ACTION_1P(SCClearAction); |
86 |
+DEF_ACTION_1P(SCClearArrayAction); |
|
84 | 87 |
DEF_ACTION_2P(SCSetTimerAction); |
85 | 88 |
DEF_ACTION_1P(SCRemoveTimerAction); |
86 | 89 |
DEF_ACTION_1P(SCRemoveTimersAction); |
... | ... |
@@ -103,13 +106,18 @@ DEF_ACTION_1P(SCB2BAddHeaderAction); |
103 | 106 |
DEF_ACTION_1P(SCB2BClearHeadersAction); |
104 | 107 |
DEF_ACTION_2P(SCB2BSetHeadersAction); |
105 | 108 |
|
109 |
+DEF_ACTION_1P(SCRegisterEventQueueAction); |
|
110 |
+DEF_ACTION_1P(SCUnregisterEventQueueAction); |
|
111 |
+ |
|
112 |
+DEF_ACTION_2P(SCCreateSystemDSMAction); |
|
113 |
+ |
|
106 | 114 |
class SCDIAction |
107 | 115 |
: public DSMAction { |
108 | 116 |
vector<string> params; |
109 | 117 |
bool get_res; |
110 | 118 |
public: |
111 | 119 |
SCDIAction(const string& arg, bool get_res); |
112 |
- bool execute(AmSession* sess, |
|
120 |
+ bool execute(AmSession* sess, DSMSession* sc_sess, |
|
113 | 121 |
DSMCondition::EventType event, |
114 | 122 |
map<string,string>* event_params); |
115 | 123 |
}; |
... | ... |
@@ -131,7 +139,7 @@ class TestDSMCondition |
131 | 139 |
|
132 | 140 |
public: |
133 | 141 |
TestDSMCondition(const string& expr, DSMCondition::EventType e); |
134 |
- bool match(AmSession* sess, DSMCondition::EventType event, |
|
142 |
+ bool match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, |
|
135 | 143 |
map<string,string>* event_params); |
136 | 144 |
}; |
137 | 145 |
|
... | ... |
@@ -105,9 +105,12 @@ string resolveVars(const string ts, AmSession* sess, |
105 | 105 |
return ""; |
106 | 106 |
} |
107 | 107 |
case '#': |
108 |
- if (event_params) |
|
109 |
- return (*event_params)[s.substr(1)]; |
|
110 |
- else |
|
108 |
+ if (event_params) { |
|
109 |
+ map<string, string>::iterator it = event_params->find(s.substr(1)); |
|
110 |
+ if (it != event_params->end()) |
|
111 |
+ return it->second; |
|
112 |
+ return ""; |
|
113 |
+ }else |
|
111 | 114 |
return string(); |
112 | 115 |
case '@': { |
113 | 116 |
string s1 = s.substr(1); |
... | ... |
@@ -96,7 +96,7 @@ class SCStrArgAction |
96 | 96 |
: public SCStrArgAction { \ |
97 | 97 |
public: \ |
98 | 98 |
CL_Name(const string& arg) : SCStrArgAction(arg) { } \ |
99 |
- bool execute(AmSession* sess, \ |
|
99 |
+ bool execute(AmSession* sess, DSMSession* sc_sess, \ |
|
100 | 100 |
DSMCondition::EventType event, \ |
101 | 101 |
map<string,string>* event_params); \ |
102 | 102 |
}; \ |
... | ... |
@@ -107,7 +107,7 @@ class SCStrArgAction |
107 | 107 |
: public SCStrArgAction { \ |
108 | 108 |
public: \ |
109 | 109 |
CL_Name(const string& arg) : SCStrArgAction(arg) { } \ |
110 |
- bool execute(AmSession* sess, \ |
|
110 |
+ bool execute(AmSession* sess, DSMSession* sc_sess, \ |
|
111 | 111 |
DSMCondition::EventType event, \ |
112 | 112 |
map<string,string>* event_params); \ |
113 | 113 |
SEAction getSEAction(std::string&); \ |
... | ... |
@@ -120,7 +120,7 @@ class SCStrArgAction |
120 | 120 |
string par2; \ |
121 | 121 |
public: \ |
122 | 122 |
CL_Name(const string& arg); \ |
123 |
- bool execute(AmSession* sess, \ |
|
123 |
+ bool execute(AmSession* sess, DSMSession* sc_sess, \ |
|
124 | 124 |
DSMCondition::EventType event, \ |
125 | 125 |
map<string,string>* event_params); \ |
126 | 126 |
}; \ |
... | ... |
@@ -195,25 +195,17 @@ class SCStrArgAction |
195 | 195 |
} \ |
196 | 196 |
|
197 | 197 |
|
198 |
-#define GET_SCSESSION() \ |
|
199 |
- DSMSession* sc_sess = dynamic_cast<DSMSession*>(sess); \ |
|
200 |
- if (!sc_sess) { \ |
|
201 |
- ERROR("wrong session type\n"); \ |
|
202 |
- return false; \ |
|
203 |
- } |
|
204 |
- |
|
205 |
- |
|
206 | 198 |
#define EXEC_ACTION_START(act_name) \ |
207 |
- bool act_name::execute(AmSession* sess, \ |
|
199 |
+ bool act_name::execute(AmSession* sess, DSMSession* sc_sess, \ |
|
208 | 200 |
DSMCondition::EventType event, \ |
209 |
- map<string,string>* event_params) { \ |
|
210 |
- GET_SCSESSION(); |
|
201 |
+ map<string,string>* event_params) { |
|
202 |
+ |
|
211 | 203 |
|
212 | 204 |
#define EXEC_ACTION_END \ |
213 | 205 |
return false; \ |
214 | 206 |
} |
215 | 207 |
|
216 |
-#define EXEC_ACTION_STOP \ |
|
208 |
+#define EXEC_ACTION_STOP \ |
|
217 | 209 |
return false; |
218 | 210 |
|
219 | 211 |
string resolveVars(const string s, AmSession* sess, |
... | ... |
@@ -241,39 +233,19 @@ void splitCmd(const string& from_str, |
241 | 233 |
\ |
242 | 234 |
public: \ |
243 | 235 |
\ |
244 |
- cond_name(const string& arg, bool inv) \ |
|
245 |
- : arg(arg), inv(inv) { } \ |
|
246 |
- bool match(AmSession* sess, DSMCondition::EventType event, \ |
|
247 |
- map<string,string>* event_params); \ |
|
248 |
- }; \ |
|
236 |
+ cond_name(const string& arg, bool inv) \ |
|
237 |
+ : arg(arg), inv(inv) { } \ |
|
238 |
+ bool match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, \ |
|
239 |
+ map<string,string>* event_params); \ |
|
240 |
+ }; |
|
249 | 241 |
|
250 | 242 |
|
251 | 243 |
#define MATCH_CONDITION_START(cond_clsname) \ |
252 |
- bool cond_clsname::match(AmSession* sess, DSMCondition::EventType event, \ |
|
253 |
- map<string,string>* event_params) { \ |
|
254 |
- GET_SCSESSION(); |
|
255 |
- |
|
256 |
-#define MATCH_CONDITION_END } |
|
257 |
- |
|
258 |
- |
|
259 |
-#define GET_SCSESSION() \ |
|
260 |
- DSMSession* sc_sess = dynamic_cast<DSMSession*>(sess); \ |
|
261 |
- if (!sc_sess) { \ |
|
262 |
- ERROR("wrong session type\n"); \ |
|
263 |
- return false; \ |
|
264 |
- } |
|
265 |
- |
|
266 |
- |
|
267 |
-#define EXEC_ACTION_START(act_name) \ |
|
268 |
- bool act_name::execute(AmSession* sess, \ |
|
269 |
- DSMCondition::EventType event, \ |
|
270 |
- map<string,string>* event_params) { \ |
|
271 |
- GET_SCSESSION(); |
|
272 |
- |
|
273 |
-#define EXEC_ACTION_END \ |
|
274 |
- return false; \ |
|
275 |
- } |
|
244 |
+ bool cond_clsname::match(AmSession* sess, DSMSession* sc_sess, \ |
|
245 |
+ DSMCondition::EventType event, \ |
|
246 |
+ map<string,string>* event_params) { |
|
276 | 247 |
|
248 |
+#define MATCH_CONDITION_END } |
|
277 | 249 |
|
278 | 250 |
#define DECLARE_MODULE(mod_cls_name) \ |
279 | 251 |
class mod_cls_name \ |
... | ... |
@@ -63,7 +63,8 @@ using std::map; |
63 | 63 |
#define DSM_AVAR_REPLY "reply" |
64 | 64 |
|
65 | 65 |
#define DSM_AVAR_JSONRPCREQUESTDATA "JsonRpcRequestParameters" |
66 |
-#define DSM_AVAR_JSONRPCRESPONEDATA "JsonRpcResponseParameters" |
|
66 |
+#define DSM_AVAR_JSONRPCRESPONSEDATA "JsonRpcResponseParameters" |
|
67 |
+#define DSM_AVAR_JSONRPCRESPONSEUDATA "JsonRpcResponseUData" |
|
67 | 68 |
|
68 | 69 |
#define DSM_ERRNO_FILE "file" |
69 | 70 |
#define DSM_ERRNO_UNKNOWN_ARG "arg" |
... | ... |
@@ -37,7 +37,7 @@ DSMStateDiagramCollection::~DSMStateDiagramCollection() { |
37 | 37 |
} |
38 | 38 |
|
39 | 39 |
bool DSMStateDiagramCollection::loadFile(const string& filename, const string& name, |
40 |
- const string& mod_path, bool debug_dsm) { |
|
40 |
+ const string& mod_path, bool debug_dsm, bool check_dsm) { |
|
41 | 41 |
DBG("loading DSM '%s' from '%s'\n", name.c_str(), filename.c_str()); |
42 | 42 |
|
43 | 43 |
DSMChartReader cr; |
... | ... |
@@ -70,6 +70,19 @@ bool DSMStateDiagramCollection::loadFile(const string& filename, const string& n |
70 | 70 |
ERROR("DonkeySM decode script error!\n"); |
71 | 71 |
return false; |
72 | 72 |
} |
73 |
+ if (check_dsm) { |
|
74 |
+ string report; |
|
75 |
+ if (!diags.back().checkConsistency(report)) { |
|
76 |
+ WARN("consistency check failed on '%s' from file '%s':\n", |
|
77 |
+ name.c_str(), filename.c_str()); |
|
78 |
+ WARN("------------------------------------------\n" |
|
79 |
+ "%s\n" |
|
80 |
+ "------------------------------------------\n", report.c_str()); |
|
81 |
+ } else { |
|
82 |
+ DBG("DSM '%s' passed consistency check\n", name.c_str()); |
|
83 |
+ } |
|
84 |
+ } |
|
85 |
+ |
|
73 | 86 |
return true; |
74 | 87 |
} |
75 | 88 |
|
... | ... |
@@ -44,7 +44,7 @@ class DSMStateDiagramCollection |
44 | 44 |
~DSMStateDiagramCollection(); |
45 | 45 |
|
46 | 46 |
bool loadFile(const string& filename, const string& name, |
47 |
- const string& mod_path, bool debug_dsm); |
|
47 |
+ const string& mod_path, bool debug_dsm, bool check_dsm); |
|
48 | 48 |
void addToEngine(DSMStateEngine* e); |
49 | 49 |
bool hasDiagram(const string& name); |
50 | 50 |
vector<string> getDiagramNames(); |
... | ... |
@@ -139,6 +139,70 @@ State* DSMStateDiagram::getInitialState() { |
139 | 139 |
} |
140 | 140 |
|
141 | 141 |
|
142 |
+bool DSMStateDiagram::checkConsistency(string& report) { |
|
143 |
+ bool res = true; |
|
144 |
+ DBG("checking consistency of '%s'\n", name.c_str()); |
|
145 |
+ res &= checkInitialState(report); |
|
146 |
+ res &= checkDestinationStates(report); |
|
147 |
+ res &= checkHangupHandled(report); |
|
148 |
+ return res; |
|
149 |
+} |
|
150 |
+ |
|
151 |
+bool DSMStateDiagram::checkInitialState(string& report) { |
|
152 |
+ DBG("checking for initial state...\n"); |
|
153 |
+ if (NULL == getInitialState()) { |
|
154 |
+ report+=name+": " "No initial state defined!\n"; |
|
155 |
+ return false; |
|
156 |
+ } |
|
157 |
+ return true; |
|
158 |
+} |
|
159 |
+bool DSMStateDiagram::checkDestinationStates(string& report) { |
|
160 |
+ DBG("checking for existence of destination states...\n"); |
|
161 |
+ bool res = true; |
|
162 |
+ for (vector<State>::iterator it= |
|
163 |
+ states.begin(); it != states.end(); it++) { |
|
164 |
+ for (vector<DSMTransition>::iterator t_it= |
|
165 |
+ it->transitions.begin(); t_it != it->transitions.end(); t_it++) { |
|
166 |
+ if (NULL == getState(t_it->to_state)) { |
|
167 |
+ report += name+": State '"+it->name+"' Transition '"+t_it->name+ |
|
168 |
+ "' : Destination state '"+ t_it->to_state +"' is not defined\n"; |
|
169 |
+ res = false; |
|
170 |
+ } |
|
171 |
+ } |
|
172 |
+ } |
|
173 |
+ return res; |
|
174 |
+} |
|
175 |
+ |
|
176 |
+bool DSMStateDiagram::checkHangupHandled(string& report) { |
|
177 |
+ DBG("checking for hangup handled in all states...\n"); |
|
178 |
+ bool res = true; |
|
179 |
+ for (vector<State>::iterator it= |
|
180 |
+ states.begin(); it != states.end(); it++) { |
|
181 |
+ bool have_hangup_trans = false; |
|
182 |
+ for (vector<DSMTransition>::iterator t_it= |
|
183 |
+ it->transitions.begin(); t_it != it->transitions.end(); t_it++) { |
|
184 |
+ for (vector<DSMCondition*>::iterator c_it= |
|
185 |
+ t_it->precond.begin(); c_it!=t_it->precond.end(); c_it++) { |
|
186 |
+ if ((*c_it)->type == DSMCondition::Hangup) { |
|
187 |
+ // todo: what if other conditions unmet? |
|
188 |
+ have_hangup_trans = true; |
|
189 |
+ break; |
|
190 |
+ } |
|
191 |
+ } |
|
192 |
+ if (have_hangup_trans) |
|
193 |
+ break; |
|
194 |
+ |
|
195 |
+ } |
|
196 |
+ if (!have_hangup_trans) { |
|
197 |
+ report += name+": State '"+it->name+"': hangup is not handled\n"; |
|
198 |
+ res = false; |
|
199 |
+ } |
|
200 |
+ } |
|
201 |
+ |
|
202 |
+ return res; |
|
203 |
+} |
|
204 |
+ |
|
205 |
+ |
|
142 | 206 |
DSMStateEngine::DSMStateEngine() |
143 | 207 |
: current(NULL) { |
144 | 208 |
} |
... | ... |
@@ -157,12 +221,12 @@ bool DSMStateEngine::onInvite(const AmSipRequest& req, DSMSession* sess) { |
157 | 221 |
|
158 | 222 |
bool DSMStateEngine::runactions(vector<DSMAction*>::iterator from, |
159 | 223 |
vector<DSMAction*>::iterator to, |
160 |
- AmSession* sess, DSMCondition::EventType event, |
|
224 |
+ AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, |
|
161 | 225 |
map<string,string>* event_params, bool& is_consumed) { |
162 | 226 |
// DBG("running %zd actions\n", to - from); |
163 | 227 |
for (vector<DSMAction*>::iterator it=from; it != to; it++) { |
164 | 228 |
DBG("executing '%s'\n", (*it)->name.c_str()); |
165 |
- if ((*it)->execute(sess, event, event_params)) { |
|
229 |
+ if ((*it)->execute(sess, sc_sess, event, event_params)) { |
|
166 | 230 |
string se_modifier; |
167 | 231 |
switch ((*it)->getSEAction(se_modifier)) { |
168 | 232 |
case DSMAction::Repost: |
... | ... |
@@ -170,17 +234,17 @@ bool DSMStateEngine::runactions(vector<DSMAction*>::iterator from, |
170 | 234 |
break; |
171 | 235 |
case DSMAction::Jump: |
172 | 236 |
DBG("jumping %s\n", se_modifier.c_str()); |
173 |
- if (jumpDiag(se_modifier, sess, event, event_params)) { |
|
237 |
+ if (jumpDiag(se_modifier, sess, sc_sess, event, event_params)) { |
|
174 | 238 |
// is_consumed = false; |
175 | 239 |
return true; |
176 | 240 |
} break; |
177 | 241 |
case DSMAction::Call: |
178 |
- if (callDiag(se_modifier, sess, event, event_params)) { |
|
242 |
+ if (callDiag(se_modifier, sess, sc_sess, event, event_params)) { |
|
179 | 243 |
// is_consumed = false; |
180 | 244 |
return true; |
181 | 245 |
} break; |
182 | 246 |
case DSMAction::Return: |
183 |
- if (returnDiag(sess)) { |
|
247 |
+ if (returnDiag(sess, sc_sess)) { |
|
184 | 248 |
//is_consumed = false; |
185 | 249 |
return true; |
186 | 250 |
} break; |
... | ... |
@@ -202,11 +266,12 @@ void DSMStateEngine::addModules(vector<DSMModule*> modules) { |
202 | 266 |
mods.push_back(*it); |
203 | 267 |
} |
204 | 268 |
|
205 |
-bool DSMStateEngine::init(AmSession* sess, const string& startDiagram, |
|
269 |
+bool DSMStateEngine::init(AmSession* sess, DSMSession* sc_sess, |
|
270 |
+ const string& startDiagram, |
|
206 | 271 |
DSMCondition::EventType init_event) { |
207 | 272 |
|
208 | 273 |
try { |
209 |
- if (!jumpDiag(startDiagram, sess, init_event, NULL)) { |
|
274 |
+ if (!jumpDiag(startDiagram, sess, sc_sess, init_event, NULL)) { |
|
210 | 275 |
ERROR("initializing with start diag '%s'\n", |
211 | 276 |
startDiagram.c_str()); |
212 | 277 |
return false; |
... | ... |
@@ -214,26 +279,26 @@ bool DSMStateEngine::init(AmSession* sess, const string& startDiagram, |
214 | 279 |
} catch (DSMException& e) { |
215 | 280 |
DBG("Exception type '%s' occured while initializing! Run init event as exception...\n", |
216 | 281 |
e.params["type"].c_str()); |
217 |
- runEvent(sess, init_event, &e.params, true); |
|
282 |
+ runEvent(sess, sc_sess, init_event, &e.params, true); |
|
218 | 283 |
return true; |
219 | 284 |
|
220 | 285 |
} |
221 | 286 |
|
222 | 287 |
DBG("run init event...\n"); |
223 |
- runEvent(sess, init_event, NULL); |
|
288 |
+ runEvent(sess, sc_sess, init_event, NULL); |
|
224 | 289 |
return true; |
225 | 290 |
} |
226 | 291 |
|
227 |
-bool DSMCondition::_match(AmSession* sess, |
|
228 |
- DSMCondition::EventType event, |
|
229 |
- map<string,string>* event_params) { |
|
292 |
+bool DSMCondition::_match(AmSession* sess, DSMSession* sc_sess, |
|
293 |
+ DSMCondition::EventType event, |
|
294 |
+ map<string,string>* event_params) { |
|
230 | 295 |
// or xor |
231 |
- return invert?(!match(sess,event,event_params)):match(sess,event,event_params); |
|
296 |
+ return invert? (!match(sess,sc_sess,event,event_params)) : match(sess, sc_sess, event, event_params); |
|
232 | 297 |
} |
233 | 298 |
|
234 |
-bool DSMCondition::match(AmSession* sess, |
|
235 |
- DSMCondition::EventType event, |
|
236 |
- map<string,string>* event_params) { |
|
299 |
+bool DSMCondition::match(AmSession* sess, DSMSession* sc_sess, |
|
300 |
+ DSMCondition::EventType event, |
|
301 |
+ map<string,string>* event_params) { |
|
237 | 302 |
|
238 | 303 |
if ((type != Any) && (event != type)) |
239 | 304 |
return false; |
... | ... |
@@ -252,7 +317,7 @@ bool DSMCondition::match(AmSession* sess, |
252 | 317 |
return true; |
253 | 318 |
} |
254 | 319 |
|
255 |
-void DSMStateEngine::runEvent(AmSession* sess, |
|
320 |
+void DSMStateEngine::runEvent(AmSession* sess, DSMSession* sc_sess, |
|
256 | 321 |
DSMCondition::EventType event, |
257 | 322 |
map<string,string>* event_params, |
258 | 323 |
bool run_exception) { |
... | ... |
@@ -278,7 +343,7 @@ void DSMStateEngine::runEvent(AmSession* sess, |
278 | 343 |
|
279 | 344 |
vector<DSMCondition*>::iterator con=tr->precond.begin(); |
280 | 345 |
while (con!=tr->precond.end()) { |
281 |
- if (!(*con)->_match(sess, active_event, active_params)) |
|
346 |
+ if (!(*con)->_match(sess, sc_sess, active_event, active_params)) |
|
282 | 347 |
break; |
283 | 348 |
con++; |
284 | 349 |
} |
... | ... |
@@ -302,7 +367,7 @@ void DSMStateEngine::runEvent(AmSession* sess, |
302 | 367 |
current->post_actions.size(), current->name.c_str()); |
303 | 368 |
if (runactions(current->post_actions.begin(), |
304 | 369 |
current->post_actions.end(), |
305 |
- sess, active_event, active_params, is_consumed)) { |
|
370 |
+ sess, sc_sess, active_event, active_params, is_consumed)) { |
|
306 | 371 |
break; |
307 | 372 |
} |
308 | 373 |
} |
... | ... |
@@ -313,7 +378,7 @@ void DSMStateEngine::runEvent(AmSession* sess, |
313 | 378 |
tr->actions.size(), tr->name.c_str()); |
314 | 379 |
if (runactions(tr->actions.begin(), |
315 | 380 |
tr->actions.end(), |
316 |
- sess, active_event, active_params, is_consumed)) { |
|
381 |
+ sess, sc_sess, active_event, active_params, is_consumed)) { |
|
317 | 382 |
break; |
318 | 383 |
} |
319 | 384 |
} |
... | ... |
@@ -348,7 +413,7 @@ void DSMStateEngine::runEvent(AmSession* sess, |
348 | 413 |
current->pre_actions.size(), current->name.c_str()); |
349 | 414 |
if (runactions(current->pre_actions.begin(), |
350 | 415 |
current->pre_actions.end(), |
351 |
- sess, active_event, active_params, is_consumed)) { |
|
416 |
+ sess, sc_sess, active_event, active_params, is_consumed)) { |
|
352 | 417 |
break; |
353 | 418 |
} |
354 | 419 |
} |
... | ... |
@@ -369,7 +434,7 @@ void DSMStateEngine::runEvent(AmSession* sess, |
369 | 434 |
} while (!is_consumed); |
370 | 435 |
} |
371 | 436 |
|
372 |
-bool DSMStateEngine::callDiag(const string& diag_name, AmSession* sess, |
|
437 |
+bool DSMStateEngine::callDiag(const string& diag_name, AmSession* sess, DSMSession* sc_sess, |
|
373 | 438 |
DSMCondition::EventType event, |
374 | 439 |
map<string,string>* event_params) { |
375 | 440 |
if (!current || !current_diag) { |
... | ... |
@@ -377,10 +442,10 @@ bool DSMStateEngine::callDiag(const string& diag_name, AmSession* sess, |
377 | 442 |
return false; |
378 | 443 |
} |
379 | 444 |
stack.push_back(std::make_pair(current_diag, current)); |
380 |
- return jumpDiag(diag_name, sess, event, event_params); |
|
445 |
+ return jumpDiag(diag_name, sess, sc_sess, event, event_params); |
|
381 | 446 |
} |
382 | 447 |
|
383 |
-bool DSMStateEngine::jumpDiag(const string& diag_name, AmSession* sess, |
|
448 |
+bool DSMStateEngine::jumpDiag(const string& diag_name, AmSession* sess, DSMSession* sc_sess, |
|
384 | 449 |
DSMCondition::EventType event, |
385 | 450 |
map<string,string>* event_params) { |
386 | 451 |
for (vector<DSMStateDiagram*>::iterator it= |
... | ... |
@@ -414,7 +479,7 @@ bool DSMStateEngine::jumpDiag(const string& diag_name, AmSession* sess, |
414 | 479 |
is_finished = true; |
415 | 480 |
runactions(current->pre_actions.begin(), |
416 | 481 |
current->pre_actions.end(), |
417 |
- sess, event, event_params, is_finished); |
|
482 |
+ sess, sc_sess, event, event_params, is_finished); |
|
418 | 483 |
|
419 | 484 |
return true; |
420 | 485 |
} |
... | ... |
@@ -423,7 +488,7 @@ bool DSMStateEngine::jumpDiag(const string& diag_name, AmSession* sess, |
423 | 488 |
return false; |
424 | 489 |
} |
425 | 490 |
|
426 |
-bool DSMStateEngine::returnDiag(AmSession* sess) { |
|
491 |
+bool DSMStateEngine::returnDiag(AmSession* sess, DSMSession* sc_sess) { |
|
427 | 492 |
if (stack.empty()) { |
428 | 493 |
ERROR("returning from empty stack\n"); |
429 | 494 |
return false; |
... | ... |
@@ -492,3 +557,4 @@ void varPrintArg(const AmArg& a, map<string, string>& dst, const string& name) { |
492 | 557 |
default: dst[name] = "<UNKONWN TYPE>"; return; |
493 | 558 |
} |
494 | 559 |
} |
560 |
+ |
... | ... |
@@ -86,7 +86,11 @@ class DSMCondition |
86 | 86 |
XmlrpcResponse, |
87 | 87 |
|
88 | 88 |
JsonRpcResponse, |
89 |
- JsonRpcRequest |
|
89 |
+ JsonRpcRequest, |
|
90 |
+ |
|
91 |
+ Startup, |
|
92 |
+ Reload, |
|
93 |
+ System |
|
90 | 94 |
}; |
91 | 95 |
|
92 | 96 |
bool invert; |
... | ... |
@@ -97,10 +101,10 @@ class DSMCondition |
97 | 101 |
EventType type; |
98 | 102 |
map<string, string> params; |
99 | 103 |
|
100 |
- bool _match(AmSession* sess, DSMCondition::EventType event, |
|
104 |
+ bool _match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, |
|
101 | 105 |
map<string,string>* event_params); |
102 | 106 |
|
103 |
- virtual bool match(AmSession* sess, DSMCondition::EventType event, |
|
107 |
+ virtual bool match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, |
|
104 | 108 |
map<string,string>* event_params); |
105 | 109 |
}; |
106 | 110 |
|
... | ... |
@@ -120,7 +124,7 @@ class DSMAction |
120 | 124 |
virtual ~DSMAction() { /* DBG("dest action\n"); */ } |
121 | 125 |
|
122 | 126 |
/** @return whether state engine is to be modified (via getSEAction) */ |
123 |
- virtual bool execute(AmSession* sess, DSMCondition::EventType event, \ |
|
127 |
+ virtual bool execute(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, \ |
|
124 | 128 |
map<string,string>* event_params) = 0; |
125 | 129 |
|
126 | 130 |
/** @return state engine modification */ |
... | ... |
@@ -161,6 +165,10 @@ class DSMStateDiagram { |
161 | 165 |
string name; |
162 | 166 |
string initial_state; |
163 | 167 |
|
168 |
+ bool checkInitialState(string& report); |
|
169 |
+ bool checkDestinationStates(string& report); |
|
170 |
+ bool checkHangupHandled(string& report); |
|
171 |
+ |
|
164 | 172 |
public: |
165 | 173 |
DSMStateDiagram(const string& name); |
166 | 174 |
~DSMStateDiagram(); |
... | ... |
@@ -171,6 +179,7 @@ class DSMStateDiagram { |
171 | 179 |
void addState(const State& state, bool is_initial = false); |
172 | 180 |
bool addTransition(const DSMTransition& trans); |
173 | 181 |
const string& getName() { return name; } |
182 |
+ bool checkConsistency(string& report); |
|
174 | 183 |
}; |
175 | 184 |
|
176 | 185 |
class DSMException { |
... | ... |
@@ -205,14 +214,16 @@ class DSMStateEngine { |
205 | 214 |
|
206 | 215 |
vector<pair<DSMStateDiagram*, State*> > stack; |
207 | 216 |
|
208 |
- bool callDiag(const string& diag_name, AmSession* sess, DSMCondition::EventType event, |
|
209 |
- map<string,string>* event_params); |
|
210 |
- bool jumpDiag(const string& diag_name, AmSession* sess, DSMCondition::EventType event, |
|
211 |
- map<string,string>* event_params); |
|
212 |
- bool returnDiag(AmSession* sess); |
|
217 |
+ bool callDiag(const string& diag_name, AmSession* sess, DSMSession* sc_sess, |
|
218 |
+ DSMCondition::EventType event, |
|