Author: sayer
Date: 2010-05-25 10:37:56 +0200 (Tue, 25 May 2010)
New Revision: 1926
Added:
trunk/doc/dsm/examples/test_request_events.dsm
Modified:
trunk/apps/dsm/DSMCall.cpp
trunk/apps/dsm/DSMCall.h
trunk/apps/dsm/DSMCoreModule.cpp
trunk/apps/dsm/DSMModule.h
trunk/apps/dsm/DSMSession.h
trunk/apps/dsm/DSMStateEngine.h
trunk/apps/dsm/mods/mod_dlg/ModDlg.cpp
trunk/apps/dsm/mods/mod_dlg/ModDlg.h
trunk/apps/dsm/mods/mod_dlg/Readme.mod_dlg.txt
Log:
- event params made writable with set() and sets(); used to return value from
event processing
- raw SIP request processing from within DSM script (use
enable_request_events/enable_reply_events)
Modified: trunk/apps/dsm/DSMCall.cpp
===================================================================
--- trunk/apps/dsm/DSMCall.cpp 2010-05-19 12:30:52 UTC (rev 1925)
+++ trunk/apps/dsm/DSMCall.cpp 2010-05-25 08:37:56 UTC (rev 1926)
@@ -67,10 +67,16 @@
/** returns whether var exists && var==value*/
bool DSMCall::checkVar(const string& var_name, const string& var_val) {
map<string, string>::iterator it = var.find(var_name);
- if ((it != var.end()) && (it->second == var_val))
- return true;
+ return (it != var.end()) && (it->second == var_val);
+}
- return false;
+/** returns whether params, param exists && param==value*/
+bool checkParam(const string& par_name, const string& par_val, map<string,
string>* params) {
+ if (NULL == params)
+ return false;
+
+ map<string, string>::iterator it = params->find(par_name);
+ return (it != params->end()) && (it->second == par_val);
}
void DSMCall::onInvite(const AmSipRequest& req) {
@@ -134,7 +140,7 @@
}
}
-void DSMCall::onRinging(const AmSipReply& reply) {
+ void DSMCall::onRinging(const AmSipReply& reply) {
map<string, string> params;
params["code"] = int2str(reply.code);
params["reason"] = reply.reason;
@@ -247,7 +253,71 @@
}
}
+void DSMCall::onSipRequest(const AmSipRequest& req) {
+
+ if (checkVar(DSM_ENABLE_REQUEST_EVENTS, DSM_TRUE)) {
+ map<string, string> params;
+ params["method"] = req.method;
+ params["r_uri"] = req.r_uri;
+ params["from"] = req.from;
+ params["to"] = req.to;
+ params["hdrs"] = req.hdrs;
+
+ params["content_type"] = req.content_type;
+ params["body"] = req.body;
+
+ params["cseq"] = int2str(req.cseq);
+
+ // pass AmSipRequest for use by mod_dlg
+ DSMSipRequest* sip_req = new DSMSipRequest(&req);
+ avar[DSM_AVAR_REQUEST] = AmArg(sip_req);
+
+ engine.runEvent(this, DSMCondition::SipRequest, ¶ms);
+
+ delete sip_req;
+ avar.erase(DSM_AVAR_REQUEST);
+
+ if (checkParam(DSM_PROCESSED, DSM_TRUE, ¶ms)) {
+ DBG("DSM script processed SIP request '%s', returning\n",
+ req.method.c_str());
+ return;
+ }
+ }
+
+ AmB2BCallerSession::onSipRequest(req);
+}
+
void DSMCall::onSipReply(const AmSipReply& reply, int old_dlg_status) {
+
+ if (checkVar(DSM_ENABLE_REPLY_EVENTS, DSM_TRUE)) {
+ map<string, string> params;
+ params["code"] = int2str(reply.code);
+ params["reason"] = reply.reason;
+ params["hdrs"] = reply.hdrs;
+ params["content_type"] = reply.content_type;
+ params["body"] = reply.body;
+
+ params["cseq"] = int2str(reply.cseq);
+
+ params["dlg_status"] = int2str(dlg.getStatus());
+ params["old_dlg_status"] = int2str(old_dlg_status);
+
+ // pass AmSipReply for use by mod_dlg (? sending ACK?)
+ DSMSipReply* dsm_reply = new DSMSipReply(&reply);
+ avar[DSM_AVAR_REPLY] = AmArg(dsm_reply);
+
+ engine.runEvent(this, DSMCondition::SipReply, ¶ms);
+
+ delete dsm_reply;
+ avar.erase(DSM_AVAR_REPLY);
+
+ if (checkParam(DSM_PROCESSED, DSM_TRUE, ¶ms)) {
+ DBG("DSM script processed SIP reply '%u %s', returning\n",
+ reply.code, reply.reason.c_str());
+ return;
+ }
+ }
+
AmB2BCallerSession::onSipReply(reply,old_dlg_status);
if ((old_dlg_status < AmSipDialog::Connected) &&
Modified: trunk/apps/dsm/DSMCall.h
===================================================================
--- trunk/apps/dsm/DSMCall.h 2010-05-19 12:30:52 UTC (rev 1925)
+++ trunk/apps/dsm/DSMCall.h 2010-05-25 08:37:56 UTC (rev 1926)
@@ -82,7 +82,9 @@
void onBye(const AmSipRequest& req);
void onDtmf(int event, int duration_msec);
+ void onSipRequest(const AmSipRequest& req);
void onSipReply(const AmSipReply& reply, int old_dlg_status);
+
void process(AmEvent* event);
UACAuthCred* getCredentials();
Modified: trunk/apps/dsm/DSMCoreModule.cpp
===================================================================
--- trunk/apps/dsm/DSMCoreModule.cpp 2010-05-19 12:30:52 UTC (rev 1925)
+++ trunk/apps/dsm/DSMCoreModule.cpp 2010-05-25 08:37:56 UTC (rev 1926)
@@ -2,6 +2,7 @@
* $Id$
*
* Copyright (C) 2008 iptego GmbH
+ * Copyright (C) 2010 Stefan Sayer
*
* This file is part of SEMS, a free SIP media server.
*
@@ -169,6 +170,12 @@
if (cmd == "B2B.otherBye")
return new TestDSMCondition(params, DSMCondition::B2BOtherBye);
+ if (cmd == "sipRequest")
+ return new TestDSMCondition(params, DSMCondition::SipRequest);
+
+ if (cmd == "sipReply")
+ return new TestDSMCondition(params, DSMCondition::SipReply);
+
return NULL;
}
@@ -459,12 +466,25 @@
CONST_ACTION_2P(SCSetAction,'=', false);
EXEC_ACTION_START(SCSetAction) {
- string var_name = (par1.length() && par1[0] == '$')?
- par1.substr(1) : par1;
+ if (par1.length() && par1[0] == '#') {
+ // set param
+ if (NULL != event_params) {
+ string res = resolveVars(par2, sess, sc_sess, event_params);
+ (*event_params)[par1.substr(1)] = res;
+ DBG("set #%s='%s'\n", par1.substr(1).c_str(), res.c_str());
+ } else {
+ DBG("not setting %s (no param set)\n", par1.c_str());
+ }
+ } else {
+ // set variable
+ string var_name = (par1.length() && par1[0] == '$')?
+ par1.substr(1) : par1;
- sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params);
- DBG("set $%s='%s'\n",
- var_name.c_str(), sc_sess->var[var_name].c_str());
+ sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params);
+
+ DBG("set $%s='%s'\n",
+ var_name.c_str(), sc_sess->var[var_name].c_str());
+ }
} EXEC_ACTION_END;
string replaceParams(const string& q, AmSession* sess, DSMSession* sc_sess,
@@ -511,13 +531,25 @@
}
CONST_ACTION_2P(SCSetSAction,'=', false);
EXEC_ACTION_START(SCSetSAction) {
- string var_name = (par1.length() && par1[0] == '$')?
- par1.substr(1) : par1;
+ if (par1.length() && par1[0] == '#') {
+ // set param
+ if (NULL != event_params) {
+ string res = replaceParams(par2, sess, sc_sess, event_params);
+ (*event_params)[par1.substr(1)] = res;
+ DBG("set #%s='%s'\n", par1.substr(1).c_str(), res.c_str());
+ } else {
+ DBG("not set %s (no param set)\n", par1.c_str());
+ }
+ } else {
+ // set variable
+ string var_name = (par1.length() && par1[0] == '$')?
+ par1.substr(1) : par1;
- sc_sess->var[var_name] = replaceParams(par2, sess, sc_sess, event_params);
-
- DBG("set $%s='%s'\n",
- var_name.c_str(), sc_sess->var[var_name].c_str());
+ sc_sess->var[var_name] = replaceParams(par2, sess, sc_sess, event_params);
+
+ DBG("set $%s='%s'\n",
+ var_name.c_str(), sc_sess->var[var_name].c_str());
+ }
} EXEC_ACTION_END;
CONST_ACTION_2P(SCEvalAction,'=', false);
Modified: trunk/apps/dsm/DSMModule.h
===================================================================
--- trunk/apps/dsm/DSMModule.h 2010-05-19 12:30:52 UTC (rev 1925)
+++ trunk/apps/dsm/DSMModule.h 2010-05-25 08:37:56 UTC (rev 1926)
@@ -53,6 +53,8 @@
virtual bool onInvite(const AmSipRequest& req, DSMSession* sess) { return
true; }
};
+typedef map<string,string> EventParamT;
+
typedef void* (*SCFactoryCreate)();
#define SCSTR(x) #x
Modified: trunk/apps/dsm/DSMSession.h
===================================================================
--- trunk/apps/dsm/DSMSession.h 2010-05-19 12:30:52 UTC (rev 1925)
+++ trunk/apps/dsm/DSMSession.h 2010-05-25 08:37:56 UTC (rev 1926)
@@ -40,9 +40,12 @@
using std::map;
#include <memory>
-#define DSM_REPLY_REQUEST "reply_request" // todo: rethink these names
-#define DSM_REPLY_REQUEST_FALSE "0"
+#define DSM_TRUE "true"
+#define DSM_FALSE "false"
+#define DSM_PROCESSED "processed"
+#define DSM_CONNECT "connect"
+
#define DSM_CONNECT_SESSION "connect_session" // todo: rethink these names
#define DSM_CONNECT_SESSION_FALSE "0"
@@ -52,6 +55,13 @@
#define DSM_CONNECT_EARLY_SESSION "connect_early_session" // todo:
rethink these names
#define DSM_CONNECT_EARLY_SESSION_FALSE "0"
+#define DSM_ENABLE_REQUEST_EVENTS "enable_request_events"
+#define DSM_ENABLE_REPLY_EVENTS "enable_reply_events"
+
+
+#define DSM_AVAR_REQUEST "request"
+#define DSM_AVAR_REPLY "reply"
+
#define DSM_ERRNO_FILE "file"
#define DSM_ERRNO_UNKNOWN_ARG "arg"
#define DSM_ERRNO_SCRIPT "script"
@@ -74,6 +84,9 @@
#define CLR_STRERROR \
var["strerror"] = "";
+typedef map<string, string> VarMapT;
+typedef map<string, AmArg> AVarMapT;
+
class DSMDisposable;
class AmPlaylistItem;
@@ -127,10 +140,10 @@
virtual void releaseOwnership(DSMDisposable* d) = 0;
/* holds variables which are accessed by $varname */
- map<string, string> var;
+ VarMapT var;
- /* holds AmArg variables. todo: merge var with these */
- map<string, AmArg> avar;
+ /* holds AmArg variables. todo(?): merge var with these */
+ AVarMapT avar;
/* result of the last DI call */
AmArg di_res;
@@ -164,6 +177,27 @@
~DSMDisposableAudioFile() { }
};
+class DSMSipRequest
+: public ArgObject {
+ public:
+ const AmSipRequest* req;
+
+ DSMSipRequest(const AmSipRequest* req)
+ : req(req) { }
+ ~DSMSipRequest() { }
+};
+
+class DSMSipReply
+: public ArgObject {
+ public:
+ const AmSipReply* reply;
+
+ DSMSipReply(const AmSipReply* reply)
+ : reply(reply) { }
+ ~DSMSipReply() { }
+};
+
+
#define DSM_EVENT_ID -10
/** generic event for passing events between DSM sessions */
struct DSMEvent : public AmEvent {
Modified: trunk/apps/dsm/DSMStateEngine.h
===================================================================
--- trunk/apps/dsm/DSMStateEngine.h 2010-05-19 12:30:52 UTC (rev 1925)
+++ trunk/apps/dsm/DSMStateEngine.h 2010-05-25 08:37:56 UTC (rev 1926)
@@ -57,29 +57,33 @@
public:
enum EventType {
Any,
+
Invite,
SessionStart,
Ringing,
EarlySession,
FailedCall,
- Key,
- Timer,
+ SipRequest,
+ SipReply,
- NoAudio,
-
Hangup,
Hold,
UnHold,
- XmlrpcResponse,
- DSMEvent,
- PlaylistSeparator,
-
B2BOtherReply,
B2BOtherBye,
+ Key,
+ Timer,
+
+ NoAudio,
+ PlaylistSeparator,
+
+ DSMEvent,
DSMException,
+ XmlrpcResponse,
+
JsonRpcResponse,
JsonRpcRequest
};
Modified: trunk/apps/dsm/mods/mod_dlg/ModDlg.cpp
===================================================================
--- trunk/apps/dsm/mods/mod_dlg/ModDlg.cpp 2010-05-19 12:30:52 UTC (rev
1925)
+++ trunk/apps/dsm/mods/mod_dlg/ModDlg.cpp 2010-05-25 08:37:56 UTC (rev
1926)
@@ -43,6 +43,7 @@
MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
DEF_CMD("dlg.reply", DLGReplyAction);
+ DEF_CMD("dlg.replyRequest", DLGReplyRequestAction);
DEF_CMD("dlg.acceptInvite", DLGAcceptInviteAction);
DEF_CMD("dlg.bye", DLGByeAction);
DEF_CMD("dlg.connectCalleeRelayed", DLGConnectCalleeRelayedAction);
@@ -66,31 +67,54 @@
return false; \
}
-CONST_ACTION_2P(DLGReplyAction, ',', true);
-EXEC_ACTION_START(DLGReplyAction) {
+// todo: convert errors to exceptions
+void replyRequest(DSMSession* sc_sess, AmSession* sess,
+ EventParamT* event_params,
+ const string& par1, const string& par2,
+ const AmSipRequest& req) {
string code = resolveVars(par1, sess, sc_sess, event_params);
string reason = resolveVars(par2, sess, sc_sess, event_params);
unsigned int code_i;
if (str2i(code, code_i)) {
ERROR("decoding reply code '%s'\n", code.c_str());
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
- return false;
+ return;
}
if (!sc_sess->last_req.get()) {
ERROR("no last request to reply\n");
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("no last request to reply");
- return false;
+ return;
}
- if (sess->dlg.reply(*sc_sess->last_req.get(), code_i, reason)) {
+ if (sess->dlg.reply(req, code_i, reason)) {
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("error sending reply");
} else
sc_sess->CLR_ERRNO;
+}
+
+CONST_ACTION_2P(DLGReplyAction, ',', true);
+EXEC_ACTION_START(DLGReplyAction) {
+ replyRequest(sc_sess, sess, event_params, par1, par2,
*sc_sess->last_req.get());
} EXEC_ACTION_END;
+// todo (?) move replyRequest to core module (?)
+CONST_ACTION_2P(DLGReplyRequestAction, ',', true);
+EXEC_ACTION_START(DLGReplyRequestAction) {
+ DSMSipRequest* sip_req;
+
+ AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REQUEST);
+ if (it == sc_sess->avar.end() ||
+ !isArgAObject(it->second) ||
+ !(sip_req = dynamic_cast<DSMSipRequest*>(it->second.asObject()))) {
+ throw DSMException("dlg", "cause", "no request");
+ }
+
+ replyRequest(sc_sess, sess, event_params, par1, par2, *sip_req->req);
+} EXEC_ACTION_END;
+
CONST_ACTION_2P(DLGAcceptInviteAction, ',', true);
EXEC_ACTION_START(DLGAcceptInviteAction) {
// defaults to 200 OK
Modified: trunk/apps/dsm/mods/mod_dlg/ModDlg.h
===================================================================
--- trunk/apps/dsm/mods/mod_dlg/ModDlg.h 2010-05-19 12:30:52 UTC (rev
1925)
+++ trunk/apps/dsm/mods/mod_dlg/ModDlg.h 2010-05-25 08:37:56 UTC (rev
1926)
@@ -35,6 +35,7 @@
DECLARE_MODULE_END;
DEF_ACTION_2P(DLGReplyAction);
+DEF_ACTION_2P(DLGReplyRequestAction);
DEF_ACTION_2P(DLGAcceptInviteAction);
DEF_ACTION_2P(DLGConnectCalleeRelayedAction);
DEF_ACTION_1P(DLGByeAction);
Modified: trunk/apps/dsm/mods/mod_dlg/Readme.mod_dlg.txt
===================================================================
--- trunk/apps/dsm/mods/mod_dlg/Readme.mod_dlg.txt 2010-05-19 12:30:52 UTC
(rev 1925)
+++ trunk/apps/dsm/mods/mod_dlg/Readme.mod_dlg.txt 2010-05-25 08:37:56 UTC
(rev 1926)
@@ -1,13 +1,22 @@
-* mod_dlg saves the initial INVITE to DSMSession::last_req
+* mod_dlg saves the initial INVITE to DSMSession::last_req,
+ this can be processed with dlg.reply(...)/dlg.acceptInvite(...)
* set connect_session to 0 with set(connect_session=0)
if you want to reply with other than the standard 200 OK
to initial INVITE received.
+* for processing of other requests, use enable_request_events and replyRequest
dlg.reply(code,reason);
reply to the request in DSMSession::last_req
(usually INVITE, if not yet replied) with code and reason
* sets $errno (arg,general)
+dlg.replyRequest(code,reason);
+ request processing in script; use with set($enable_request_events="true");
+ reply to any request (in avar[DSM_AVAR_REQUEST]) with code and reason
+ * sets $errno (arg,general)
+ * throws exception if request not found (i.e. called from other event than
+ sipRequest)
+
dlg.acceptInvite([code, reason]);
e.g. dlg.acceptInvite(183, progress);
* sets $errno (arg,general)
Added: trunk/doc/dsm/examples/test_request_events.dsm
===================================================================
--- trunk/doc/dsm/examples/test_request_events.dsm 2010-05-19 12:30:52 UTC
(rev 1925)
+++ trunk/doc/dsm/examples/test_request_events.dsm 2010-05-25 08:37:56 UTC
(rev 1926)
@@ -0,0 +1,24 @@
+-- example for SIP request processing from script
+
+import(mod_dlg);
+
+initial state in_call
+ enter {
+ -- from now on, get events for SIP requests
+ set($enable_request_events="true");
+ };
+
+transition "SIP BYE request" in_call - sipRequest(#method==BYE) / {
+ dlg.replyRequest(200, "okey bye bye");
+ -- set event param "processed" - BYE will not be processed by normal app
logic
+ set(#processed=true);
+ logAll(1);
+ stop(false);
+ } -> end;
+
+transition "SIP reply" in_call - sipReply / logAll(1) -> lobby;
+
+-- this is not executed - BYE gets processed above
+transition "bye in lobby recvd" in_call - hangup / stop(false) -> end;
+
+state end;
\ No newline at end of file
_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev