<html>
<head>
<base href="https://wiki.asterisk.org/wiki">
<link rel="stylesheet" href="/wiki/s/en/2171/18/9/_/styles/combined.css?spaceKey=TOP&forWysiwyg=true" type="text/css">
</head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
<h2><a href="https://wiki.asterisk.org/wiki/display/TOP/SIP+Registrar">SIP Registrar</a></h2>
<h4>Page <b>edited</b> by <a href="https://wiki.asterisk.org/wiki/display/~mmichelson">Mark Michelson</a>
</h4>
<br/>
<h4>Changes (32)</h4>
<div id="page-diffs">
<table class="diff" cellpadding="0" cellspacing="0">
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h1. Registrar's Duties <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">Asterisk SCF provides a SIP registrar. A registrar, according to RFC 3261, is "a server that accepts REGISTER requests and places the information it receives in those requests into the location service for the domain it handles." <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">The SIP registrar's job is to maintain a mapping of addresses-of-record (AoRs) to contact URIs. The registrar is responsible for letting other SIP services within a cluster know of updates to these mappings. The registrar populates these mappings by processing and responding to SIP REGISTER requests it receives. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">h1. Slice <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h1. Endpoints <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The registrar implements some Slice interfaces, used for querying the registrar when necessary and for listening to events that occur within the registrar. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">SIP endpoints will be configured to determine which AoRs they are associated with. For instance, if a SIP endpoint named "Bob" were to be configured to be associated with the AoR "sip:bob@example.com" then this would imply the following things: <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">h3. Bindings <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;"># REGISTER requests from Bob would be permitted to add and remove bindings for the AoR sip:bob@example.com <br># SIP Requests targeted at sip:bob@example.com would be targeted for Bob. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The {{Binding}} class is defined as follows: <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">An endpoint may be associated with multiple AoRs and multiple endpoints may be associated with the same AoR. The association between endpoints and AoRs, however, is not known to the Registrar; this association exists only in the SIP components that use the Registrar's services. As a result, decisions about whether an incoming REGISTER request should be permitted to modify the mappings or not (authorization), or even whether an incoming REGISTER request must be authenticated, will fall to components outside the Registrar. The Registrar will offer Extension Points where Hooks can be attached to implement these policies as needed. <br> <br>h1. Registration data <br> <br>A binding in the Registrar is a single contact URI that is bound to an AoR. An AoR may have multiple bindings associated with it, and a single REGISTER message may create multiple bindings for a single AoR. <br> <br>The {{Binding}} object is defined in Slice since the registrar's state will need to be replicated. <br> <br></td></tr>
<tr><td class="diff-unchanged" >{code} <br>class Binding <br></td></tr>
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" > <br>dictionary<string, BindingSeq> BindingDict; <br></td></tr>
<tr><td class="diff-unchanged" >{code} <br> <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">The {{BindingDict}} object represents all the state data that needs to be replicated between registrar instances. Individual registrars will be responsible for scheduling destruction of their local {{Bindings}} based on the binding's expiration. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The {{string}} portion of a {{BindingDict}} is the address of record (AoR) to which bindings belong. Maintaining a {{BindingDict}} allows for the Registrar to maintain which bindings are associated with AoRs. It also allows for easy state replication. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">The {{BindingDict}} is the set of all bindings currently known to the Registrar; the {{string}} key is the AoR, and the {{BindingSeq}} is the list of Contact URIs currently bound to that AoR. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">h3. Interfaces <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h1. Interfaces <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The registrar also provides two interfaces, the {{RegistrarListener}} and the {{Registrar}}. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">The registrar will not have much in the way of public interfaces since the data it makes available is pushed out to the other SIP services. <br> <br></td></tr>
<tr><td class="diff-unchanged" >{code} <br>struct BindingUpdate <br></td></tr>
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" > void contactsRemoved(BindingUpdateSeq updates); <br>}; <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">{code} <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The {{RegistrarListener}} provides a method to be notified of events that occur on the registrar. The reasoning for not pushing {{Bindings}} out to {{RegistrarListeners}} is twofold: <br> <br># {{Bindings}} have information that most listeners do not care about. <br># Keeping {{RegistrarListeners}} up-to-date on all aspects of a {{Binding}} (most importantly the {{cseq}} and the {{expiration}}) would result in many more RPCs. <br> <br>If a listener is interested in all aspects of a {{Binding}} then the listener has two choices: <br> <br># Periodically query the {{Registrar}} for information regarding bindings. <br># Be a state replicator listener instead since all information is transmitted to the state replicator listener. <br> <br>{code} <br></td></tr>
<tr><td class="diff-unchanged" >interface Registrar <br>{ <br></td></tr>
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" > * Remove a listener. <br> */ <br></td></tr>
<tr><td class="diff-changed-lines" >void <span class="diff-changed-words">removeListener(RegistrarListe<span class="diff-added-chars"style="background-color: #dfd;">ne</span>r</span> *listener); <br></td></tr>
<tr><td class="diff-unchanged" > /** <br> * Get the mapping of all known AoRs and their bindings. <br></td></tr>
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" >{code} <br> <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">A {{RegistrarListener}} registers itself with the {{Registrar}} in order to receive updates about the {{Registrar}}'s bindings. Most {{RegistrarListeners}} will be other SIP services that need to use the registrar's data. A {{RegistrarListener}} is always provided with {{BindingUpdate}} objects instead of {{Binding}} objects because the {{Binding}} contains information that is not useful outside the registrar service. If a component wishes to get a full {{Binding}} object it may use a variant of {{getBindings}} to do so. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The {{Registrar}} provides two main services. First, it allows for one to add {{RegistrarListeners}} to the list of listeners to notify. Second, it allows for querying the current state of the registrar. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h1. Operation <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The following diagram provides a high-level view of how the {{Registrar}} interacts with its {{RegistrarListeners}} <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-changed-lines" ><span class="diff-changed-words">!<span class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;">R</span><span class="diff-added-chars"style="background-color: #dfd;">r</span>egistration.png!</span> <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">The diagram shows that when contacts are added or removed from the registrar, the {{RegistrarListener}} is notified. The third REGISTER transaction does not notify the listener. This is because the REGISTER was refreshing the expiration period for a previously established contact. While this results in internal changes to the registrar and its replicas, {{RegistrarListeners}} do not need to be updated. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">h1. Implementation in C++ using PJSIP <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h1. Other ideas <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">Unlike most SIP tasks, PJSIP does not provide a simplified API to use for acting as a registrar. Instead, we work directly with the transaction layer in order to respond to requests. We keep track of registrations ourself using the types defined in slice. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">* Providing a mechanism for default AoRs may be desirable. For instance, if there is an endpoint named "Bob" and his endpoint belongs to the domains "example1.com" and "example2.com" then it may be reasonable to automatically associate Bob with the AoRs "sip:bob@example1.com" and "sip:bob@example2.com." Implicit behavior is typically discouraged in Asterisk SCF, which is why default AoRs are not currently defined. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">h3. Incoming REGISTER <br> <br>On an incoming REGISTER, we go through the following steps: <br> <br># Extract the AoR from the To header of the REGISTER. <br># Get the list of bindings associated with this AoR. <br># Extract the Contact headers from the REGISTER. <br># Do a sanity check on the contacts being added. Specifically, we make sure that if a '*' contact is provided, that it is the only contact and that its expiration is set to 0. If there is an issue, we send a 400 response and do no further processing. <br># For each contact, we determine if we are going to add a new binding, renew an existing binding, or remove an existing binding. <br># Based on how each contact was categorized, do the appropriate action. <br># Notify {{RegistrarListeners}} of new bindings and removed bindings. <br># Send a 200 OK response. <br># Replicate state. <br> <br>This is all that is done. It's pretty simple. The registrar never does any sort of association between the incoming REGISTER and any SIP endpoint(s). So how, then, do bindings end up getting associated with endpoints? <br> <br>h3. Applying bindings to endpoint configuration <br> <br>The {{SipEndpointFactory}} registers a {{RegistrarListener}} at startup. This way, whenever changes are made to bindings, the endpoint factory can decide which endpoints the change applies to and update endpoint configuration directly. <br> <br>The {{SipEndpointFactory}} uses the user portion of the AoR to determine which endpoint the change applies to. So for instance, an AoR of "sip:bob@example.org" would correspond to an endpoint called "bob." From here, bob's config is updated to have his destination address set to the value of the contact. At this time, even though multiple contacts may be relayed to the {{SipEndpointFactory}}, {{SipEndpoints}} only support a single destination address, so only the first contact in the list is used. When a binding is removed, the destination address of the endpoint is blanked, meaning that there is no known address to which to send requests. <br> <br>h1. Ideas for improvement <br> <br>* Even with the use of an authentication hook, there is currently no way for the registrar to reject a well-formed but undesired REGISTER request. Since it is desirable to keep the registrar endpoint-agnostic, the use of an extension point for this would be a good way to accomplish this. <br>* The method of matching an AoR to an endpoint is suboptimal. Aor->endpoint matching falls into the realm of policy, which is something Asterisk SCF tries not to meddle in. Matching could be done either <br>** Via an extension point, e.g. the AoR is fed into the extension point and a list of endpoint names is returned. <br>** Via configuration, e.g. endpoints contain a list of AoRs to which they are associated. <br>* {{SipEndpoints}} need to be modified so that they may support multiple destination addresses. <br></td></tr>
</table>
</div> <h4>Full Content</h4>
<div class="notificationGreySide">
<p>Asterisk SCF provides a SIP registrar. A registrar, according to RFC 3261, is "a server that accepts REGISTER requests and places the information it receives in those requests into the location service for the domain it handles."</p>
<h1><a name="SIPRegistrar-Slice"></a>Slice</h1>
<p>The registrar implements some Slice interfaces, used for querying the registrar when necessary and for listening to events that occur within the registrar.</p>
<h3><a name="SIPRegistrar-Bindings"></a>Bindings</h3>
<p>The <tt>Binding</tt> class is defined as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">class Binding
{
/**
* The contact URI associated with this particular Binding.
*/
string contact;
/**
* The Call-ID from the latest successful Binding.
*/
string callid;
/**
* The CSeq from the latest successful Binding.
*/
int cseq;
/**
* A UNIX timestamp indicating when the Binding is set
* to expire
*/
int expiration;
};
sequence<Binding> BindingSeq;
dictionary<string, BindingSeq> BindingDict;</pre>
</div></div>
<p>The <tt>string</tt> portion of a <tt>BindingDict</tt> is the address of record (AoR) to which bindings belong. Maintaining a <tt>BindingDict</tt> allows for the Registrar to maintain which bindings are associated with AoRs. It also allows for easy state replication.</p>
<h3><a name="SIPRegistrar-Interfaces"></a>Interfaces</h3>
<p>The registrar also provides two interfaces, the <tt>RegistrarListener</tt> and the <tt>Registrar</tt>.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">struct BindingUpdate
{
/**
* The AoR for which bindings have been updated
*/
string aor;
/**
* The Contact URIs bound to this AoR
*/
StringSeq contacts;
}
sequence<BindingUpdate> BindingUpdateSeq;
/**
* A RegistrarListener is updated when a binding changes.
* Typical RegistrarListeners will be SIP services that
* require up-to-date information.
*/
interface RegistrarListener
{
/**
* Alerts the listener that contacts have been added
* to one or more AoRs. The AoRs may be new or they
* may have already had bindings.
*/
void contactsAdded(BindingUpdateSeq updates);
/**
* Alerts the listener that contacts have been removed.
* There is no specific call for indicating that an AoR
* no longer has contacts associated with it. After this
* operation has been invoked, listeners should take
* appropriate action if an AoR no longer has bindings.
*/
void contactsRemoved(BindingUpdateSeq updates);
};</pre>
</div></div>
<p>The <tt>RegistrarListener</tt> provides a method to be notified of events that occur on the registrar. The reasoning for not pushing <tt>Bindings</tt> out to <tt>RegistrarListeners</tt> is twofold:</p>
<ol>
        <li><tt>Bindings</tt> have information that most listeners do not care about.</li>
        <li>Keeping <tt>RegistrarListeners</tt> up-to-date on all aspects of a <tt>Binding</tt> (most importantly the <tt>cseq</tt> and the <tt>expiration</tt>) would result in many more RPCs.</li>
</ol>
<p>If a listener is interested in all aspects of a <tt>Binding</tt> then the listener has two choices:</p>
<ol>
        <li>Periodically query the <tt>Registrar</tt> for information regarding bindings.</li>
        <li>Be a state replicator listener instead since all information is transmitted to the state replicator listener.</li>
</ol>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">interface Registrar
{
/**
* Add a new listener to the registrar. The listener will
* receive all known AoRs and their bindings through
* its 'contactsAdded' operation.
*/
void addListener(RegistrarListener *listener);
/**
* Remove a listener.
*/
void removeListener(RegistrarListener *listener);
/**
* Get the mapping of all known AoRs and their bindings.
*/
BindingDict getAllBindings();
/**
* Get all bindings associated with a particular AoR.
*/
BindingSeq getAORBindings(string aor);
};</pre>
</div></div>
<p>The <tt>Registrar</tt> provides two main services. First, it allows for one to add <tt>RegistrarListeners</tt> to the list of listeners to notify. Second, it allows for querying the current state of the registrar.</p>
<p>The following diagram provides a high-level view of how the <tt>Registrar</tt> interacts with its <tt>RegistrarListeners</tt></p>
<p><span class="image-wrap" style=""><img src="/wiki/download/attachments/12550396/Registration.png?version=1&modificationDate=1299018543697" style="border: 0px solid black" /></span></p>
<h1><a name="SIPRegistrar-ImplementationinCusingPJSIP"></a>Implementation in C++ using PJSIP</h1>
<p>Unlike most SIP tasks, PJSIP does not provide a simplified API to use for acting as a registrar. Instead, we work directly with the transaction layer in order to respond to requests. We keep track of registrations ourself using the types defined in slice.</p>
<h3><a name="SIPRegistrar-IncomingREGISTER"></a>Incoming REGISTER</h3>
<p>On an incoming REGISTER, we go through the following steps:</p>
<ol>
        <li>Extract the AoR from the To header of the REGISTER.</li>
        <li>Get the list of bindings associated with this AoR.</li>
        <li>Extract the Contact headers from the REGISTER.</li>
        <li>Do a sanity check on the contacts being added. Specifically, we make sure that if a '*' contact is provided, that it is the only contact and that its expiration is set to 0. If there is an issue, we send a 400 response and do no further processing.</li>
        <li>For each contact, we determine if we are going to add a new binding, renew an existing binding, or remove an existing binding.</li>
        <li>Based on how each contact was categorized, do the appropriate action.</li>
        <li>Notify <tt>RegistrarListeners</tt> of new bindings and removed bindings.</li>
        <li>Send a 200 OK response.</li>
        <li>Replicate state.</li>
</ol>
<p>This is all that is done. It's pretty simple. The registrar never does any sort of association between the incoming REGISTER and any SIP endpoint(s). So how, then, do bindings end up getting associated with endpoints?</p>
<h3><a name="SIPRegistrar-Applyingbindingstoendpointconfiguration"></a>Applying bindings to endpoint configuration</h3>
<p>The <tt>SipEndpointFactory</tt> registers a <tt>RegistrarListener</tt> at startup. This way, whenever changes are made to bindings, the endpoint factory can decide which endpoints the change applies to and update endpoint configuration directly.</p>
<p>The <tt>SipEndpointFactory</tt> uses the user portion of the AoR to determine which endpoint the change applies to. So for instance, an AoR of "sip:bob@example.org" would correspond to an endpoint called "bob." From here, bob's config is updated to have his destination address set to the value of the contact. At this time, even though multiple contacts may be relayed to the <tt>SipEndpointFactory</tt>, <tt>SipEndpoints</tt> only support a single destination address, so only the first contact in the list is used. When a binding is removed, the destination address of the endpoint is blanked, meaning that there is no known address to which to send requests.</p>
<h1><a name="SIPRegistrar-Ideasforimprovement"></a>Ideas for improvement</h1>
<ul>
        <li>Even with the use of an authentication hook, there is currently no way for the registrar to reject a well-formed but undesired REGISTER request. Since it is desirable to keep the registrar endpoint-agnostic, the use of an extension point for this would be a good way to accomplish this.</li>
        <li>The method of matching an AoR to an endpoint is suboptimal. Aor->endpoint matching falls into the realm of policy, which is something Asterisk SCF tries not to meddle in. Matching could be done either
        <ul>
                <li>Via an extension point, e.g. the AoR is fed into the extension point and a list of endpoint names is returned.</li>
                <li>Via configuration, e.g. endpoints contain a list of AoRs to which they are associated.</li>
        </ul>
        </li>
        <li><tt>SipEndpoints</tt> need to be modified so that they may support multiple destination addresses.</li>
</ul>
</div>
<div id="commentsSection" class="wiki-content pageSection">
<div style="float: right;" class="grey">
<a href="https://wiki.asterisk.org/wiki/users/removespacenotification.action?spaceKey=TOP">Stop watching space</a>
<span style="padding: 0px 5px;">|</span>
<a href="https://wiki.asterisk.org/wiki/users/editmyemailsettings.action">Change email notification preferences</a>
</div>
<a href="https://wiki.asterisk.org/wiki/display/TOP/SIP+Registrar">View Online</a>
|
<a href="https://wiki.asterisk.org/wiki/pages/diffpagesbyversion.action?pageId=12550396&revisedVersion=16&originalVersion=15">View Changes</a>
|
<a href="https://wiki.asterisk.org/wiki/display/TOP/SIP+Registrar?showComments=true&showCommentArea=true#addcomment">Add Comment</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>