[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "telephone-events" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Wed Jul 6 11:40:47 CDT 2011


branch "telephone-events" has been updated
       via  a815ad12e32d57dc4ece7488fe72ce0e82f5e4d9 (commit)
      from  bd25df69bafa9d87b5c427a11422fc0c0c0fc5bd (commit)

Summary of changes:
 src/PJSipSessionModule.cpp |  117 ++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 108 insertions(+), 9 deletions(-)


- Log -----------------------------------------------------------------
commit a815ad12e32d57dc4ece7488fe72ce0e82f5e4d9
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Jul 6 11:34:38 2011 -0500

    Queue a DTMF INFO operation, add error checking to handleInfo.

diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index ff47c0e..066bfc9 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -912,6 +912,34 @@ void PJSipSessionModule::handleRefer(pjsip_inv_session *inv, pjsip_rx_data *rdat
     enqueueSessionWork(new HandleReferOperation(inv, tsx, tdata, replaces_param, to_tag_param, from_tag_param, target, session, mSessionRouter, mModule.id), inv);
 }
 
+class HandleInfoDTMFOperation : public SipQueueableOperation
+{
+public:
+    HandleInfoDTMFOperation(
+            pjsip_inv_session *inv,
+            pjsip_transaction *tsx,
+            pjsip_tx_data *tdata,
+            char dtmf,
+            int duration)
+        : mInv(inv), mTsx(tsx), mTdata(tdata), mDTMF(dtmf), mDuration(duration) { }
+
+    SuspendableWorkResult initial(const SuspendableWorkListenerPtr& workListener)
+    {
+        //XXX We need to send an indicated() operation to our session listeners.
+        //There's not a DTMF indication defined at the moment, so I'll withhold
+        //that until I have defined such a method.
+
+        pjsip_dlg_send_response(mInv->dlg, mTsx, mTdata);
+    }
+
+private:
+    pjsip_inv_session *mInv;
+    pjsip_transaction *mTsx;
+    pjsip_tx_data *mTdata;
+    char mDTMF;
+    int mDuration;
+};
+
 bool PJSipSessionModule::isDTMF(pjsip_rx_data *rdata)
 {
     // We should determine how to handle matters based on the "Info-Package" header,
@@ -929,9 +957,11 @@ bool PJSipSessionModule::isDTMF(pjsip_rx_data *rdata)
     pj_cstr(&dtmf, "dtmf");
     if (info_package && !pj_strcmp(&info_package->hvalue, &dtmf))
     {
+        lg(Debug) << "Info-Package header suggests DTMF";
         return true;
     }
 
+    lg(Debug) << "No Info-Package header. Checking Content-Type";
     //No biggie. I just said that not many are actually going to use Info-Package.
     //Check if the content-type is "application/dtmf-relay"
     pj_str_t application;
@@ -941,39 +971,93 @@ bool PJSipSessionModule::isDTMF(pjsip_rx_data *rdata)
     if (!pj_strcmp(&rdata->msg_info.ctype->media.type, &application) && 
             !pj_strcmp(&rdata->msg_info.ctype->media.subtype, &dtmf_relay))
     {
+        lg(Debug) << "Content-Type is application/dtmf-relay";
         return true;
     }
 
     return false;
 }
 
+class DTMFInfoException : public std::exception
+{
+public:
+    DTMFInfoException(const std::string& msg)
+        : mMsg(msg) { }
+
+    ~DTMFInfoException() throw() { }
+
+    const char *what() const throw()
+    {
+        return mMsg.c_str();
+    }
+private:
+    const std::string mMsg;
+};
+
 char PJSipSessionModule::getDTMFInfoSignal(pjsip_msg_body *body)
 {
     char *data = static_cast<char *>(body->data);
     std::string dataStr(data, body->len);
+    std::string signalStr("Signal=");
+    std::stringstream err;
 
-    size_t signalPos = dataStr.find("Signal= ");
+    size_t signalPos = dataStr.find(signalStr);
     if (signalPos == std::string::npos)
     {
-        //XXX Uh...
+        err << "Couldn't find " << signalStr << " in DTMF INFO body";
+        throw DTMFInfoException(err.str());
+    }
+
+    //The pending draft for DTMF via INFO mandates a single space after
+    //'Signal=' but pre-existing implementations do not necessarily have
+    //any spaces and may do something silly like have multiple spaces.
+    size_t signalValuePos = dataStr.find_first_not_of(' ', signalPos + signalStr.size());
+    char retSignal = dataStr.at(signalValuePos);
+
+    std::string validDTMF("1234567890#*ABCD");
+    if (!validDTMF.find(retSignal))
+    {
+        err << "Signal '" << retSignal << "' is not a valid DTMF signal";
+        throw DTMFInfoException(err.str());
     }
 
-    return dataStr.at(signalPos + sizeof("Signal= "));
+    return dataStr.at(signalValuePos);
 }
 
 int PJSipSessionModule::getDTMFInfoDuration(pjsip_msg_body *body)
 {
     char *data = static_cast<char *>(body->data);
     std::string dataStr(data, body->len);
+    std::string durationStr("Duration=");
+    std::stringstream err;
 
-    size_t durationPos = dataStr.find("Duration= ");
+    size_t durationPos = dataStr.find(durationStr);
     if (durationPos == std::string::npos)
     {
-        //XXX Uh...
+        err << "Couldn't find " << durationStr << " in DTMF INFO body";
+        throw DTMFInfoException(err.str());
     }
 
-    std::string duration(dataStr.substr(durationPos + sizeof("Duration= ")));
-    return boost::lexical_cast<int>(duration);
+    //The pending draft for DTMF via INFO mandates a single space after
+    //'Duration=' but pre-existing implementations do not necessarily have
+    //any spaces and may do something silly like have multiple spaces.
+    size_t durationValuePos = durationPos + durationStr.size();
+    size_t durationBegin = dataStr.find_first_not_of(' ', durationValuePos);
+    size_t durationEnd = dataStr.find_first_not_of(" 1234567890", durationValuePos);
+    size_t durationSize = durationEnd - durationBegin;
+    std::string duration(dataStr.substr(durationBegin, durationSize));
+
+    int retDuration;
+    try
+    {
+        retDuration = boost::lexical_cast<int>(duration);
+    }
+    catch (const boost::bad_lexical_cast& ex)
+    {
+        throw DTMFInfoException(ex.what());
+    }
+
+    return retDuration;
 }
 
 void PJSipSessionModule::handleInfo(pjsip_inv_session *inv, pjsip_rx_data *rdata)
@@ -986,10 +1070,25 @@ void PJSipSessionModule::handleInfo(pjsip_inv_session *inv, pjsip_rx_data *rdata
         return;
     }
 
+    char dtmf;
+    int duration;
     //It's DTMF! Grab the info we need! HA THAT WAS A PUN YOU JERK!
-    char dtmf = getDTMFInfoSignal(rdata->msg_info.msg->body);
-    int duration = getDTMFInfoDuration(rdata->msg_info.msg->body);
+    try
+    {
+        dtmf = getDTMFInfoSignal(rdata->msg_info.msg->body);
+        duration = getDTMFInfoDuration(rdata->msg_info.msg->body);
+    }
+    catch (const DTMFInfoException& ex)
+    {
+        lg(Error) << "Error processing DTMF INFO: " << ex.what();
+        pjsip_dlg_respond(inv->dlg, rdata, 400, NULL, NULL, NULL);
+        return;
+    }
 
+    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
+    pjsip_tx_data *tdata;
+    pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
+    enqueueSessionWork(new HandleInfoDTMFOperation(inv, tsx, tdata, dtmf, duration), inv);
     return;
 }
 

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list