[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