Example #1
0
 public void Refresh()
 {
     lock (this.m_pOwner.VirtualServer.Server.LockSynchronizer)
     {
         this.m_pOwner.VirtualServer.Server.TCP_Client.TcpStream.WriteLine("GetSipRegistration " + TextUtils.QuoteString(this.m_pOwner.VirtualServer.VirtualServerID) + " " + TextUtils.QuoteString(this.m_AddressOfRecord));
         string text = this.m_pOwner.VirtualServer.Server.ReadLine();
         if (!text.ToUpper().StartsWith("+OK"))
         {
             throw new Exception(text);
         }
         int num = Convert.ToInt32(text.Split(new char[]
         {
             ' '
         }, 2)[1]);
         MemoryStream memoryStream = new MemoryStream();
         this.m_pOwner.VirtualServer.Server.TCP_Client.TcpStream.ReadFixedCount(memoryStream, (long)num);
         DataSet dataSet = Utils.DecompressDataSet(memoryStream);
         if (dataSet.Tables.Contains("Contacts"))
         {
             List <SipRegistrationContact> list = new List <SipRegistrationContact>();
             foreach (DataRow dataRow in dataSet.Tables["Contacts"].Rows)
             {
                 SIP_t_ContactParam sIP_t_ContactParam = new SIP_t_ContactParam();
                 sIP_t_ContactParam.Parse(new System.NetworkToolkit.StringReader(dataRow["Value"].ToString()));
                 list.Add(new SipRegistrationContact(sIP_t_ContactParam.Address.Uri.Value, sIP_t_ContactParam.Expires, sIP_t_ContactParam.QValue));
             }
             this.m_pContacts = list.ToArray();
         }
         else
         {
             this.m_pContacts = new SipRegistrationContact[0];
         }
     }
 }
Example #2
0
        /// <summary>
        /// Sends specified request to the specified data flow.
        /// </summary>
        /// <param name="flow">SIP data flow.</param>
        /// <param name="request">SIP request to send.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        private void SendToFlow(SIP_Flow flow, SIP_Request request)
        {
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            #region Contact (RFC 3261 8.1.1.8)

            /*
             *  The Contact header field provides a SIP or SIPS URI that can be used
             *  to contact that specific instance of the UA for subsequent requests.
             *  The Contact header field MUST be present and contain exactly one SIP
             *  or SIPS URI in any request that can result in the establishment of a
             *  dialog.  For the methods defined in this specification, that includes
             *  only the INVITE request.  For these requests, the scope of the
             *  Contact is global.  That is, the Contact header field value contains
             *  the URI at which the UA would like to receive requests, and this URI
             *  MUST be valid even if used in subsequent requests outside of any
             *  dialogs.
             *
             *  If the Request-URI or top Route header field value contains a SIPS
             *  URI, the Contact header field MUST contain a SIPS URI as well.
             */

            SIP_t_ContactParam contact = request.Contact.GetTopMostValue();

            // Add contact header If request-Method can establish dialog and contact header not present.
            if (SIP_Utils.MethodCanEstablishDialog(request.RequestLine.Method) && contact == null)
            {
                SIP_Uri from = (SIP_Uri)request.From.Address.Uri;

                request.Contact.Add((flow.IsSecure ? "sips:" : "sip:") + from.User + "@" + flow.LocalPublicEP.ToString());

                // REMOVE ME: 22.10.2010
                //request.Contact.Add((flow.IsSecure ? "sips:" : "sip:" ) + from.User + "@" + m_pStack.TransportLayer.GetContactHost(flow).ToString());
            }
            // If contact SIP URI and host = auto-allocate, allocate it as needed.
            else if (contact != null && contact.Address.Uri is SIP_Uri && ((SIP_Uri)contact.Address.Uri).Host == "auto-allocate")
            {
                ((SIP_Uri)contact.Address.Uri).Host = flow.LocalPublicEP.ToString();

                // REMOVE ME: 22.10.2010
                //((SIP_Uri)contact.Address.Uri).Host =  m_pStack.TransportLayer.GetContactHost(flow).ToString();
            }

            #endregion

            m_pTransaction = m_pStack.TransactionLayer.CreateClientTransaction(flow, request, true);
            m_pTransaction.ResponseReceived += new EventHandler <SIP_ResponseReceivedEventArgs>(ClientTransaction_ResponseReceived);
            m_pTransaction.TimedOut         += new EventHandler(ClientTransaction_TimedOut);
            m_pTransaction.TransportError   += new EventHandler <ExceptionEventArgs>(ClientTransaction_TransportError);

            // Start transaction processing.
            m_pTransaction.Start();
        }
Example #3
0
        private void addVirtualServer()
        {
            Gateway gw = InfoService.Instance.CurrentGateway; //当前网关配置。

            SIP_t_ContactParam[] contacts = new SIP_t_ContactParam[1];

            SIP_t_ContactParam c  = new SIP_t_ContactParam();
            StringReader       sr = new StringReader($"<sip:{gw.SipNumber}@{_localIP}:{gw.Port}>;expires={Expires};qvalue=1.00");

            c.Parse(sr);
            contacts[0] = c;

            string aor = $"{gw.SipNumber}@{_localIP}";

            _sipProxy.Registrar.SetRegistration(aor, contacts);

            if (_regTimer == null)
            {
                _regTimer = new System.Threading.Timer(timer_Callback, null, (int)(Expires * 0.9) * 1000, Timeout.Infinite);
            }
            else
            {
                _regTimer.Change((int)(Expires * 0.9) * 1000, Timeout.Infinite);
            }
        }
        /// <summary>
        /// Converts <b>ContactUri</b> to valid Contact header value.
        /// </summary>
        /// <returns>Returns contact header value.</returns>
        public string ToContactValue()
        {
            SIP_t_ContactParam retVal = new SIP_t_ContactParam();

            retVal.Parse(new StringReader(m_ContactURI.ToString()));
            retVal.Expires = m_Expires;

            return(retVal.ToStringValue());
        }
        /// <summary>
        /// Gets server events and binds them to this.
        /// </summary>
        private void Bind()
        {
            /* GetSipRegistrations "<virtualServerID>"
             *    Responses:
             +OK <sizeOfData>
             *      <data>
             *
             *      -ERR <errorText>
             */

            lock (m_pOwner.Server.LockSynchronizer){
                m_pOwner.Server.TcpClient.TcpStream.WriteLine("GetSipRegistrations " +
                                                              TextUtils.QuoteString(m_pOwner.VirtualServerID)
                                                              );

                string response = m_pOwner.Server.ReadLine();
                if (!response.ToUpper().StartsWith("+OK"))
                {
                    throw new Exception(response);
                }

                int          sizeOfData = Convert.ToInt32(response.Split(new char[] { ' ' }, 2)[1]);
                MemoryStream ms         = new MemoryStream();
                m_pOwner.Server.TcpClient.TcpStream.ReadFixedCount(ms, sizeOfData);

                // Decompress dataset
                DataSet ds = Utils.DecompressDataSet(ms);

                if (ds.Tables.Contains("SipRegistrations"))
                {
                    foreach (DataRow dr in ds.Tables["SipRegistrations"].Rows)
                    {
                        //--- Parse contact -------------------------------------------------------------//
                        List <SipRegistrationContact> contacts = new List <SipRegistrationContact>();
                        foreach (string contact in dr["Contacts"].ToString().Split('\t'))
                        {
                            if (!string.IsNullOrEmpty(contact))
                            {
                                SIP_t_ContactParam c = new SIP_t_ContactParam();
                                c.Parse(new LumiSoft.Net.StringReader(contact));
                                contacts.Add(new SipRegistrationContact(c.Address.Uri.Value, c.Expires, c.QValue));
                            }
                        }
                        //--------------------------------------------------------------------------------//

                        m_pRegistrations.Add(new SipRegistration(
                                                 this,
                                                 dr["UserName"].ToString(),
                                                 dr["AddressOfRecord"].ToString(),
                                                 contacts.ToArray()
                                                 ));
                    }
                }
            }
        }
Example #6
0
        /// <summary>
        /// Refreshes specified registration info.
        /// </summary>
        public void Refresh()
        {
            /* GetSipRegistration "<virtualServerID>" "<addressOfRecord>"
             *    Responses:
             +OK <sizeOfData>
             *      <data>
             *
             *      -ERR <errorText>
             */

            lock (m_pOwner.VirtualServer.Server.LockSynchronizer){
                m_pOwner.VirtualServer.Server.TcpClient.TcpStream.WriteLine("GetSipRegistration " +
                                                                            TextUtils.QuoteString(m_pOwner.VirtualServer.VirtualServerID) + " " +
                                                                            TextUtils.QuoteString(m_AddressOfRecord)
                                                                            );

                string response = m_pOwner.VirtualServer.Server.ReadLine();
                if (!response.ToUpper().StartsWith("+OK"))
                {
                    throw new Exception(response);
                }

                int          sizeOfData = Convert.ToInt32(response.Split(new char[] { ' ' }, 2)[1]);
                MemoryStream ms         = new MemoryStream();
                m_pOwner.VirtualServer.Server.TcpClient.TcpStream.ReadFixedCount(ms, sizeOfData);

                // Decompress dataset
                DataSet ds = Utils.DecompressDataSet(ms);

                if (ds.Tables.Contains("Contacts"))
                {
                    List <SipRegistrationContact> contacts = new List <SipRegistrationContact>();
                    foreach (DataRow dr in ds.Tables["Contacts"].Rows)
                    {
                        SIP_t_ContactParam c = new SIP_t_ContactParam();
                        c.Parse(new LumiSoft.Net.StringReader(dr["Value"].ToString()));
                        contacts.Add(new SipRegistrationContact(c.Address.Uri.Value, c.Expires, c.QValue));
                    }
                    m_pContacts = contacts.ToArray();
                }
                else
                {
                    m_pContacts = new SipRegistrationContact[0];
                }
            }
        }
Example #7
0
 private void Bind()
 {
     lock (this.m_pOwner.Server.LockSynchronizer)
     {
         this.m_pOwner.Server.TCP_Client.TcpStream.WriteLine("GetSipRegistrations " + TextUtils.QuoteString(this.m_pOwner.VirtualServerID));
         string text = this.m_pOwner.Server.ReadLine();
         if (!text.ToUpper().StartsWith("+OK"))
         {
             throw new Exception(text);
         }
         int num = Convert.ToInt32(text.Split(new char[]
         {
             ' '
         }, 2)[1]);
         MemoryStream memoryStream = new MemoryStream();
         this.m_pOwner.Server.TCP_Client.TcpStream.ReadFixedCount(memoryStream, (long)num);
         DataSet dataSet = Utils.DecompressDataSet(memoryStream);
         if (dataSet.Tables.Contains("SipRegistrations"))
         {
             foreach (DataRow dataRow in dataSet.Tables["SipRegistrations"].Rows)
             {
                 List <SipRegistrationContact> list = new List <SipRegistrationContact>();
                 string[] array = dataRow["Contacts"].ToString().Split(new char[]
                 {
                     '\t'
                 });
                 for (int i = 0; i < array.Length; i++)
                 {
                     string text2 = array[i];
                     if (!string.IsNullOrEmpty(text2))
                     {
                         SIP_t_ContactParam sIP_t_ContactParam = new SIP_t_ContactParam();
                         sIP_t_ContactParam.Parse(new System.NetworkToolkit.StringReader(text2));
                         list.Add(new SipRegistrationContact(sIP_t_ContactParam.Address.Uri.Value, sIP_t_ContactParam.Expires, sIP_t_ContactParam.QValue));
                     }
                 }
                 this.m_pRegistrations.Add(new SipRegistration(this, dataRow["UserName"].ToString(), dataRow["AddressOfRecord"].ToString(), list.ToArray()));
             }
         }
     }
 }
Example #8
0
        private void register()
        {
            SIP_t_ContactParam[] contacts = new SIP_t_ContactParam[1];

            SIP_t_ContactParam c  = new SIP_t_ContactParam();
            StringReader       sr = new StringReader($"<sip:{_localAOR}:{_gateway.Port}>;expires={Expires};qvalue=1.00");

            c.Parse(sr);
            contacts[0] = c;

            _registrar.SetRegistration(_localAOR, contacts);

            if (_regTimer == null)
            {
                _regTimer = new Timer(timer_Callback, null, (int)(Expires * 0.9) * 1000, Timeout.Infinite);
            }
            else
            {
                _regTimer.Change((int)(Expires * 0.9) * 1000, Timeout.Infinite);
            }
        }
Example #9
0
        /// <summary>
        /// Handles REGISTER method.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        internal void Register(SIP_RequestReceivedEventArgs e)
        {
            /* RFC 3261 10.3 Processing REGISTER Requests.
             *  1. The registrar inspects the Request-URI to determine whether it
             *     has access to bindings for the domain identified in the
             *     Request-URI.  If not, and if the server also acts as a proxy
             *     server, the server SHOULD forward the request to the addressed
             *     domain, following the general behavior for proxying messages
             *     described in Section 16.
             *
             *  2. To guarantee that the registrar supports any necessary extensions,
             *     the registrar MUST process the Require header field.
             *
             *  3. A registrar SHOULD authenticate the UAC.
             *
             *  4. The registrar SHOULD determine if the authenticated user is
             *     authorized to modify registrations for this address-of-record.
             *     For example, a registrar might consult an authorization
             *     database that maps user names to a list of addresses-of-record
             *     for which that user has authorization to modify bindings.  If
             *     the authenticated user is not authorized to modify bindings,
             *     the registrar MUST return a 403 (Forbidden) and skip the
             *     remaining steps.
             *
             *  5. The registrar extracts the address-of-record from the To header
             *     field of the request.  If the address-of-record is not valid
             *     for the domain in the Request-URI, the registrar MUST send a
             *     404 (Not Found) response and skip the remaining steps.  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.
             *
             *  6. The registrar checks whether the request contains the Contact
             *     header field.  If not, it skips to the last step.  If the
             *     Contact header field is present, the registrar checks if there
             *     is one Contact field value that contains the special value "*"
             *     and an Expires field.  If the request has additional Contact
             *     fields or an expiration time other than zero, the request is
             *     invalid, and the server MUST return a 400 (Invalid Request) and
             *     skip the remaining steps.  If not, the registrar checks whether
             *     the Call-ID agrees with the value stored for each binding.  If
             *     not, it MUST remove the binding.  If it does agree, it MUST
             *     remove the binding only if the CSeq in the request is higher
             *     than the value stored for that binding.  Otherwise, the update
             *     MUST be aborted and the request fails.
             *
             *  7. The registrar now processes each contact address in the Contact
             *     header field in turn.  For each address, it determines the
             *     expiration interval as follows:
             *
             *       -  If the field value has an "expires" parameter, that value
             *          MUST be taken as the requested expiration.
             *
             *       -  If there is no such parameter, but the request has an
             *          Expires header field, that value MUST be taken as the requested expiration.
             *
             *       -  If there is neither, a locally-configured default value MUST
             *          be taken as the requested expiration.
             *
             *     The registrar MAY choose an expiration less than the requested
             *     expiration interval.  If and only if the requested expiration
             *     interval is greater than zero AND smaller than one hour AND
             *     less than a registrar-configured minimum, the registrar MAY
             *     reject the registration with a response of 423 (Interval Too
             *     Brief).  This response MUST contain a Min-Expires header field
             *     that states the minimum expiration interval the registrar is
             *     willing to honor.  It then skips the remaining steps.
             *
             *     For each address, the registrar then searches the list of
             *     current bindings using the URI comparison rules.  If the
             *     binding does not exist, it is tentatively added.  If the
             *     binding does exist, the registrar checks the Call-ID value.  If
             *     the Call-ID value in the existing binding differs from the
             *     Call-ID value in the request, the binding MUST be removed if
             *     the expiration time is zero and updated otherwise.  If they are
             *     the same, the registrar compares the CSeq value.  If the value
             *     is higher than that of the existing binding, it MUST update or
             *     remove the binding as above.  If not, the update MUST be
             *     aborted and the request fails.
             *
             *     This algorithm ensures that out-of-order requests from the same
             *     UA are ignored.
             *
             *     Each binding record records the Call-ID and CSeq values from
             *     the request.
             *
             *     The binding updates MUST be committed (that is, made visible to
             *     the proxy or redirect server) if and only if all binding
             *     updates and additions succeed.  If any one of them fails (for
             *     example, because the back-end database commit failed), the
             *     request MUST fail with a 500 (Server Error) response and all
             *     tentative binding updates MUST be removed.
             *
             *  8. The registrar returns a 200 (OK) response.  The response MUST
             *     contain Contact header field values enumerating all current
             *     bindings.  Each Contact value MUST feature an "expires"
             *     parameter indicating its expiration interval chosen by the
             *     registrar.  The response SHOULD include a Date header field.
             */

            SIP_ServerTransaction transaction = e.ServerTransaction;
            SIP_Request           request     = e.Request;
            SIP_Uri to       = null;
            string  userName = "";

            // Probably we need to do validate in SIP stack.

            #region Validate request

            if (SIP_Utils.IsSipOrSipsUri(request.To.Address.Uri.ToString()))
            {
                to = (SIP_Uri)request.To.Address.Uri;
            }
            else
            {
                transaction.SendResponse(
                    m_pStack.CreateResponse(
                        SIP_ResponseCodes.x400_Bad_Request + ": To: value must be SIP or SIPS URI.", request));
                return;
            }

            #endregion

            #region 1. Check if we are responsible for Request-URI domain

            // if(m_pProxy.OnIsLocalUri(e.Request.Uri)){
            // }
            // TODO:

            #endregion

            #region 2. Check that all required extentions supported

            #endregion

            #region 3. Authenticate request

            if (!m_pProxy.AuthenticateRequest(e, out userName))
            {
                return;
            }

            #endregion

            #region 4. Check if user user is authorized to modify registrations

            // We do this in next step(5.).

            #endregion

            #region 5. Check if address of record exists

            if (!m_pProxy.OnAddressExists(to.Address))
            {
                transaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x404_Not_Found, request));
                return;
            }
            else if (!OnCanRegister(userName, to.Address))
            {
                transaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x403_Forbidden, request));
                return;
            }

            #endregion

            #region 6. Process * Contact if exists

            // Check if we have star contact.
            SIP_t_ContactParam starContact = null;
            foreach (SIP_t_ContactParam c in request.Contact.GetAllValues())
            {
                if (c.IsStarContact)
                {
                    starContact = c;
                    break;
                }
            }

            // We have star contact.
            if (starContact != null)
            {
                if (request.Contact.GetAllValues().Length > 1)
                {
                    transaction.SendResponse(
                        m_pStack.CreateResponse(
                            SIP_ResponseCodes.x400_Bad_Request +
                            ": RFC 3261 10.3.6 -> If star(*) present, only 1 contact allowed.",
                            request));
                    return;
                }
                else if (starContact.Expires != 0)
                {
                    transaction.SendResponse(
                        m_pStack.CreateResponse(
                            SIP_ResponseCodes.x400_Bad_Request +
                            ": RFC 3261 10.3.6 -> star(*) contact parameter 'expires' value must be always '0'.",
                            request));
                    return;
                }

                // Remove bindings.
                SIP_Registration reg = m_pRegistrations[to.Address];
                if (reg != null)
                {
                    foreach (SIP_RegistrationBinding b in reg.Bindings)
                    {
                        if (request.CallID != b.CallID || request.CSeq.SequenceNumber > b.CSeqNo)
                        {
                            b.Remove();
                        }
                    }
                }
            }

            #endregion

            #region 7. Process Contact values

            if (starContact == null)
            {
                SIP_Registration reg = m_pRegistrations[to.Address];
                if (reg == null)
                {
                    reg = new SIP_Registration(userName, to.Address);
                    m_pRegistrations.Add(reg);
                }

                // We may do updates in batch only.
                // We just validate all values then do update(this ensures that update doesn't fail).

                // Check expires and CSeq.
                foreach (SIP_t_ContactParam c in request.Contact.GetAllValues())
                {
                    if (c.Expires == -1)
                    {
                        c.Expires = request.Expires;
                    }
                    if (c.Expires == -1)
                    {
                        c.Expires = m_pProxy.Stack.MinimumExpireTime;
                    }
                    // We must accept 0 values - means remove contact.
                    if (c.Expires != 0 && c.Expires < m_pProxy.Stack.MinimumExpireTime)
                    {
                        SIP_Response resp = m_pStack.CreateResponse(
                            SIP_ResponseCodes.x423_Interval_Too_Brief, request);
                        resp.MinExpires = m_pProxy.Stack.MinimumExpireTime;
                        transaction.SendResponse(resp);
                        return;
                    }

                    SIP_RegistrationBinding currentBinding = reg.GetBinding(c.Address.Uri);
                    if (currentBinding != null && currentBinding.CallID == request.CallID &&
                        request.CSeq.SequenceNumber < currentBinding.CSeqNo)
                    {
                        transaction.SendResponse(
                            m_pStack.CreateResponse(
                                SIP_ResponseCodes.x400_Bad_Request + ": CSeq value out of order.", request));
                        return;
                    }
                }

                // Do binding updates.
                reg.AddOrUpdateBindings(e.ServerTransaction.Flow,
                                        request.CallID,
                                        request.CSeq.SequenceNumber,
                                        request.Contact.GetAllValues());
            }

            #endregion

            #region 8. Create 200 OK response and return all current bindings

            SIP_Response response = m_pStack.CreateResponse(SIP_ResponseCodes.x200_Ok, request);
            response.Date = DateTime.Now;
            SIP_Registration registration = m_pRegistrations[to.Address];
            if (registration != null)
            {
                foreach (SIP_RegistrationBinding b in registration.Bindings)
                {
                    // Don't list expired bindings what wait to be disposed.
                    if (b.TTL > 1)
                    {
                        response.Header.Add("Contact:", b.ToContactValue());
                    }
                }
            }
            // Add Authentication-Info:, then client knows next nonce.
            response.AuthenticationInfo.Add("qop=\"auth\",nextnonce=\"" +
                                            m_pStack.DigestNonceManager.CreateNonce() + "\"");
            transaction.SendResponse(response);

            #endregion
        }
        /// <summary>
        /// Converts <b>ContactUri</b> to valid Contact header value.
        /// </summary>
        /// <returns>Returns contact header value.</returns>
        public string ToContactValue()
        {
            SIP_t_ContactParam retVal = new SIP_t_ContactParam();
            retVal.Parse(new StringReader(m_ContactURI.ToString()));
            retVal.Expires = m_Expires;

            return retVal.ToStringValue();
        }
Example #11
0
        /// <summary>
        /// Redirects incoming call to speified contact(s).
        /// </summary>
        /// <param name="contacts">Redirection targets.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when call is not in valid state and this method is called.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>contacts</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public void Redirect(SIP_t_ContactParam[] contacts)
        {
            lock (m_pLock)
            {
                if (State == SIP_UA_CallState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (State != SIP_UA_CallState.WaitingToAccept)
                {
                    throw new InvalidOperationException("Call is not in valid state.");
                }
                if (contacts == null)
                {
                    throw new ArgumentNullException("contacts");
                }
                if (contacts.Length == 0)
                {
                    throw new ArgumentException("Arguments 'contacts' must contain at least 1 value.");
                }

                // TODO:
                //m_pUA.Stack.CreateResponse(SIP_ResponseCodes.,m_pInitialInviteTransaction);

                throw new NotImplementedException();
            }
        }
        /// <summary>
        /// Add or updates specified SIP registration info.
        /// </summary>
        /// <param name="aor">Registration address of record.</param>
        /// <param name="contacts">Registration address of record contacts to update.</param>
        /// <param name="flow">SIP proxy local data flow what accpeted this contact registration.</param>
        public void SetRegistration(string aor, SIP_t_ContactParam[] contacts, SIP_Flow flow)
        {
            lock (m_pRegistrations)
            {
                SIP_Registration registration = m_pRegistrations[aor];
                if (registration == null)
                {
                    registration = new SIP_Registration("system", aor);
                    m_pRegistrations.Add(registration);
                    OnAorRegistered(registration);
                }

                registration.AddOrUpdateBindings(flow, "", 1, contacts);
            }
        }
 /// <summary>
 /// Add or updates specified SIP registration info.
 /// </summary>
 /// <param name="aor">Registration address of record.</param>
 /// <param name="contacts">Registration address of record contacts to update.</param>
 public void SetRegistration(string aor, SIP_t_ContactParam[] contacts)
 {
     SetRegistration(aor, contacts, null);
 }
        /// <summary>
        /// Adds or updates matching bindings.
        /// </summary>
        /// <param name="flow">SIP data flow what updates this binding. This value is null if binding was not added through network or
        /// flow has disposed.</param>
        /// <param name="callID">Call-ID header field value.</param>
        /// <param name="cseqNo">CSeq header field sequence number value.</param>
        /// <param name="contacts">Contacts to add or update.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>callID</b> or <b>contacts</b> is null reference.</exception>
        public void AddOrUpdateBindings(SIP_Flow flow,
                                        string callID,
                                        int cseqNo,
                                        SIP_t_ContactParam[] contacts)
        {
            if (callID == null)
            {
                throw new ArgumentNullException("callID");
            }
            if (cseqNo < 0)
            {
                throw new ArgumentException("Argument 'cseqNo' value must be >= 0.");
            }
            if (contacts == null)
            {
                throw new ArgumentNullException("contacts");
            }

            lock (m_pLock)
            {
                foreach (SIP_t_ContactParam contact in contacts)
                {
                    SIP_RegistrationBinding binding = GetBinding(contact.Address.Uri);
                    // Add binding.
                    if (binding == null)
                    {
                        binding = new SIP_RegistrationBinding(this, contact.Address.Uri);
                        m_pBindings.Add(binding);
                    }

                    // Update binding.
                    binding.Update(flow,
                                   contact.Expires == -1 ? 3600 : contact.Expires,
                                   contact.QValue == -1 ? 1.0 : contact.QValue,
                                   callID,
                                   cseqNo);
                }
            }
        }