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, &params);
+
+    delete sip_req;
+    avar.erase(DSM_AVAR_REQUEST);
+
+    if (checkParam(DSM_PROCESSED, DSM_TRUE, &params)) {
+      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, &params);
+
+    delete dsm_reply;
+    avar.erase(DSM_AVAR_REPLY);
+
+    if (checkParam(DSM_PROCESSED, DSM_TRUE, &params)) {
+      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

Reply via email to