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

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Mar 28 16:54:57 CDT 2011


branch "registrar" has been updated
       via  c5eff00eb9e4e64bac262fbc8f0ff7631c9b5cf8 (commit)
      from  5aa5e56f84e645b9c5238215ef4fdeb0eba28f20 (commit)

Summary of changes:
 src/PJSipRegistrarModule.cpp |  228 +++++++++++++++++++++++++++++++----------
 src/PJSipRegistrarModule.h   |   18 ++++
 2 files changed, 190 insertions(+), 56 deletions(-)


- Log -----------------------------------------------------------------
commit c5eff00eb9e4e64bac262fbc8f0ff7631c9b5cf8
Author: Mark Michelson <mmichelson at digium.com>
Date:   Mon Mar 28 16:54:30 2011 -0500

    Commit the day's progress for registrar.

diff --git a/src/PJSipRegistrarModule.cpp b/src/PJSipRegistrarModule.cpp
index ece92d6..becac42 100644
--- a/src/PJSipRegistrarModule.cpp
+++ b/src/PJSipRegistrarModule.cpp
@@ -40,7 +40,7 @@ public:
 
     ContactDict addListener(const RegistrarListenerPrx& listener)
     {
-        if (std::find(mListener.begin(), mListener.end(), listener) != mListener.end())
+        if (std::find(mListeners.begin(), mListeners.end(), listener) != mListeners.end())
         {
             mListeners.push_back(listener);
         }
@@ -58,21 +58,32 @@ public:
         return mBindings;
     }
 
-    BindingSeq getAORbindings(const std::string &aor)
+    BindingSeq getAORBindings(const std::string &aor)
     {
         BindingDict::iterator iter = mBindings.find(aor);
         if (iter != mBindings.end())
         {
-            return *iter;
+            return iter->second;
         }
         else
         {
-            //XXX Make this a static class member so that
-            //it can be returned on demand.
-            BindingSeq empty;
-            return empty;
+            return mEmpty;
         }
     }
+
+    void updateBindings(const std::string &aor, BindingSeq bindings)
+    {
+        mBindings.erase(aor);
+        if (!bindings.empty())
+        {
+            mBindings.insert(make_pair(aor, bindings));
+        }
+        //XXX We should replicate state here and update listeners here.
+    }
+
+    // Ready-made empty sequence to return when someone tries to grab
+    // bindings associated with an AOR for which we have no bindings.
+    static BindingSeq mEmpty;
     
     BindingDict mBindings;
     ContactDict mContacts;
@@ -99,87 +110,192 @@ pj_status_t PJSipRegistrarModule::unload()
     return PJ_SUCCESS;
 }
 
-BindingSeq PJSipRegistrarModule::getExistingBindings(pjsip_rx_data *rdata)
+std::string PJSipRegistrarModule::getAOR(pjsip_rx_data *rdata)
 {
     pjsip_sip_uri *toURI = (pjsip_sip_uri *) pjsip_uri_get_uri(rdata->msg_info.to->uri);
     char buf[512];
-    pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, to->uri, buf, sizeof(buf));
+    pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, toURI, buf, sizeof(buf));
     std::string aor(buf, strlen(buf));
- 
-    // Now we need to find the list of bindings that we have that are associated with
-    // this AoR. 
-    return mRegistrar->getAORBindings(aor);
+
+    // From RFC 3261, Section 10.3, step 5,
+    // The URI MUST then be converted to a canonical form.  To do that, all
+    // URI parameters MUST be removed (including the user-param), and
+    // any escaped characters MUST be converted to their unescaped
+    // form.  The result serves as an index into the list of bindings.
+    //
+    // For now, we'll strip off the parameters.
+    return aor.substr(0, aor.find_first_of(';'));
 }
 
-Ice::StringSeq PJSipRegistrarModule::extractRegisterContacts(pjsip_rx_data *rdata)
+std::vector<pjsip_contact_hdr *> PJSipRegistrarModule::extractRegisterContacts(pjsip_rx_data *rdata)
 {
-    Ice::StringSeq registerContacts;
-    pjsip_contact_hdr *contact = NULL;
-    while ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact)))
+    std::vector<pjsip_contact_hdr *> registerContacts;
+    pjsip_contact_hdr *contact = (pjsip_contact_hdr *) &rdata->msg_info.msg->hdr;
+    while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)))
     {
-        if (contact->star != 0)
+        registerContacts.push_back(contact);
+    }
+
+    return registerContacts;
+}
+
+bool verifyContacts(const std::vector<pjsip_contact_hdr *> contacts)
+{
+    bool multipleContacts = contacts.size() > 1;
+    for (<std::vector<pjsip_contact_hdr *>::iterator iter = contacts.begin();
+            iter != contacts.end(); ++iter)
+    {
+        if ((*iter)->star)
         {
+            if (multipleContacts)
+            {
 
+                // If the '*' contact is present, there must be no other
+                // contact URIs in the REGISTER request.
+                return false;
+            }
+            if ((*iter)->expires != 0)
+            {
+                // A '*' contact has to have a 0 expiration. Anything
+                // else is invalid. Unlike with other contacts, RFC 3261
+                // appears to not allow for a '*' contact to use the
+                // Expires header of the REGISTER for indicating
+                // expiration.
+                return false;
+            }
         }
-        else
+    }
+    return true;
+}
+
+BindingSeq::iterator PJSipRegistrarModule::findMatchingBinding(pjsip_contact_hdr *contact, BindingSeq& bindings)
+{
+    char buf[512];
+    pjsip_sip_uri *contactURI = (pjsip_sip_uri *)pjsip_uri_get_uri(contact->uri);
+    pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contactURI, buf, sizeof(buf));
+    std::string contactURIStr(buf, strlen(buf));
+
+    for (BindingSeq::iterator iter = bindings.begin(); iter != bindings.end(); ++iter)
+    {
+        if (contactURIStr == (*iter)->contact)
         {
-            char buf[512];
-            pjsip_sip_uri *contactURI = (pjsip_sip_uri *) pjsip_uri_get_uri(contact->uri);
-            pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contactURI, buf, sizeof(buf));
-            //XXX PICK UP HERE NEXT TIME
+            return iter;
         }
     }
+    return bindings.end();
 }
 
-pj_bool_t PJSipRegistrarModule::on_rx_request(pjsip_rx_data *rdata)
+int PJSipRegistrarModule::getExpiration(pjsip_contact_hdr *contact, pjsip_rx_data *rdata)
 {
-    // This is where we'll be handling incoming requests. What's the
-    // proper procedure?
-    
+    if (contact->expires != -1)
+    {
+        return contact->expires;
+    }
+
+    pjsip_expires_hdr *expires = (pjsip_expires_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
+
+    if (expires)
+    {
+        return expires->ivalue;
+    }
+    else
+    {
+        // RFC 3261, Section 10.3, step 7, bullet point 3, states that we must
+        // use a locally-configured default expiration if none can be determined from
+        // the REGISTER. For now, we're using a hard-coded 3600. This can be made into
+        // a file-level constant or this may be configurable later.
+        return 3600;
+    }
+}
+
+void PJSipRegistrarModule::updateBinding(BindingPtr &binding, const std::string &callID, int cSeq, int expiration)
+{
+    binding->callid = callID;
+    binding->cseq = cSeq;
+    binding->expiration = expiration;
+}
+
+BindingPtr PJSipRegistrarModule::createNewBinding(pjsip_contact_hdr *contact, const std::string &callID, int cSeq, int expiration)
+{
+    char buf[512];
+    pjsip_sip_uri *contactURI = (pjsip_sip_uri *)pjsip_uri_get_uri(contact->uri);
+    pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contactURI, buf, sizeof(buf));
+    std::string contactURIStr(buf, strlen(buf));
 
-    // 1. Make sure this is a REGISTER request. If it's not go ahead
-    // and return PJ_FALSE right away.
+    return new Binding(contactURIStr, callID, cSeq, expiration);
+}
 
+pj_bool_t PJSipRegistrarModule::on_rx_request(pjsip_rx_data *rdata)
+{
     if (rdata->msg_info.msg->line.req.method.id != PJSIP_REGISTER_METHOD)
     {
         return PJ_FALSE;
     }
 
-    // 2. We need to determine if the REGISTER should be authenticated.
+    pjsip_transaction *tsx;
+    pjsip_tsx_create_uas(&mModule, rdata, &tsx);
+    pjsip_tsx_recv_msg(tsx, rdata);
+
+    // We need to determine if the REGISTER should be authenticated.
     // This should be nearly exactly the same as the session module's
-    // procedure. For now, leave this commented out since auth work
-    // has not been merged to master.
+    // procedure. For now, leave this out since auth work has not been
+    // merged to master.
 
-    // Step 2.5 would be perhaps some sort of determination of who the
-    // REGISTER is from and determining whether they have permission
+    // We should attempt to determine at this point who the
+    // REGISTER is from and determine whether they have permission
     // to be doing this sort of thing. How this is done is still murky
     // and should perhaps be put in writing on the wiki or in some other
     // way decided upon before trying to write any code for it.
 
-    // 3. Determine the AoR to which this REGISTER pertains. This means
-    // to check out the To header.
-    
-    BindingSeq existingBindings = getExistingBindings(rdata);
-   
-    // 4. Extract each binding from the REGISTER. This means to grab
-    // all Contact headers.
+    std::string aor = getAOR(rdata);
+    BindingSeq existingBindings = mRegistrar->getAORBindings(aor);
+    std::vector<pjsip_contact_hdr *> registerContacts = extractRegisterContacts(rdata);
 
-    Ice::StringSeq registerContacts = extractRegisterContacts(rdata);
+    std::string callID(pj_strbuf(&rdata->msg_info.cid->id), pj_strlen(&rdata->msg_info.cid->id));
+    int cSeq = rdata->msg_info.cseq->cseq;
+
+    //The first thing we should do is verify that the contacts we extracted are well-formed.
+    //Specifically, we're going to make sure they haven't done something silly like including
+    //a '*' contact in a list with others or specifying a non-zero expiration for a '*' contact.
+    if (!verifyContacts(registerContacts, callID, cSeq))
+    {
+        pjsip_tx_data *tdata;
+        pjsip_endpt_create_response(tsx->endpt, rdata, 400, NULL, &tdata);
+        pjsip_tsx_send_msg(tsx, tdata);
+    }
+
+    for (std::vector<pjsip_contact_hdr *>::iterator iter = registerContacts.begin();
+            iter != registerContacts.end(); ++iter)
+    {
+        BindingSeq::iterator bindingToUpdate = findMatchingBinding(*iter, existingBindings);
+
+        int expiration = getExpiration(*iter, rdata);
+        if (bindingToUpdate != existingBindings.end())
+        {
+            if (expiration == 0)
+            {
+                existingBindings.erase(bindingToUpdate);
+            }
+            else
+            {
+                updateBinding(*existingBinding, callID, cSeq, time(NULL) + expiration);
+            }
+        }
+        else
+        {
+            BindingPtr binding = createNewBinding(*iter, callID, cSeq, time(NULL) + expiration);
+            existingBindings.push_back(binding);
+        }
+    }
+
+    // Now existingBindings should be an up-to-date list of bindings for
+    // this AoR.
+    mRegistrar->updateBindings(aor, existingBindings);
+
+    pjsip_tx_data *tdata;
+    pjsip_endpt_create_response(tsx->endpt, rdata, 200, NULL, &tdata);
+    pjsip_tsx_send_msg(tsx, tdata);
 
-    // 5. Find if we already know of each binding. This means to look
-    // up bindings in our local map.
-    //
-    // 6. Unknown contacts results in new bindings being created. This
-    // results in both state replication as well as notifying listeners.
-    //
-    // 7. Known contacts with a non-zero expiration result in an update
-    // in the bindings' expiration times. This only results in state
-    // replication.
-    //
-    // 8. Known contacts with a zero expiration result in the bindings'
-    // erasure. This results in state replication and notifying listeners.
-    //
-    // 9. We're done! Send back a 200 OK!
     return PJ_FALSE;
 }
 
diff --git a/src/PJSipRegistrarModule.h b/src/PJSipRegistrarModule.h
index 4875cd2..2f6105b 100644
--- a/src/PJSipRegistrarModule.h
+++ b/src/PJSipRegistrarModule.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <AsteriskSCF/SIP/SIPRegistrarIf.h>
+
 #include "PJSipModule.h"
 
 namespace AsteriskSCF
@@ -24,6 +26,10 @@ namespace AsteriskSCF
 namespace SipSessionManager
 {
 
+class RegistrarI;
+
+typedef IceUtil::Handle<RegistrarI> RegistrarIPtr;
+
 class PJSipRegistrarModule : public PJSipModule
 {
 public:
@@ -37,6 +43,18 @@ public:
     pj_status_t on_tx_request(pjsip_tx_data *tdata);
     pj_status_t on_tx_response(pjsip_tx_data *tdata);
     void on_tsx_state(pjsip_transaction *tsx, pjsip_event *event);
+private:
+    std::string getAOR(pjsip_rx_data *rdata);
+    std::vector<pjsip_contact_hdr *> extractRegisterContacts(pjsip_rx_data *rdata);
+    AsteriskSCF::SIP::Registration::V1::BindingSeq::iterator findMatchingBinding(pjsip_contact_hdr *contact,
+            AsteriskSCF::SIP::Registration::V1::BindingSeq& bindings);
+    int getExpiration(pjsip_contact_hdr *contact, pjsip_rx_data *rdata);
+    AsteriskSCF::SIP::Registration::V1::BindingPtr createNewBinding(pjsip_contact_hdr *contact,
+            const std::string& callID, int cSeq, int expiration);
+    void updateBinding(AsteriskSCF::SIP::Registration::V1::BindingPtr &binding,
+            const std::string &callID, int cSeq, int expiration);
+
+    RegistrarIPtr mRegistrar;
 };
 
 };

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


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list