Ejemplo n.º 1
0
        /// <summary>
        /// Terminates dialog.
        /// </summary>
        /// <param name="reason">Termination reason. This value may be null.</param>
        /// <param name="sendBye">If true BYE is sent to remote party.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        public virtual void Terminate(string reason, bool sendBye)
        {
            lock (m_pLock)
            {
                if (State == SIP_DialogState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (State == SIP_DialogState.Terminating || State == SIP_DialogState.Terminated)
                {
                    return;
                }

                /* RFC 3261 15.
                 *  The caller's UA MAY send a BYE for either confirmed or early dialogs, and the callee's UA MAY send a BYE on
                 *  confirmed dialogs, but MUST NOT send a BYE on early dialogs.
                 *
                 * RFC 3261 15.1.
                 *  Once the BYE is constructed, the UAC core creates a new non-INVITE client transaction, and passes it the BYE request.
                 *  The UAC MUST consider the session terminated (and therefore stop sending or listening for media) as soon as the BYE
                 *  request is passed to the client transaction. If the response for the BYE is a 481 (Call/Transaction Does Not Exist)
                 *  or a 408 (Request Timeout) or no response at all is received for the BYE (that is, a timeout is returned by the
                 *  client transaction), the UAC MUST consider the session and the dialog terminated.
                 */

                SetState(SIP_DialogState.Terminating, true);

                if (sendBye)
                {
                    // TODO: UAS early

                    if (State == SIP_DialogState.Confirmed)
                    {
                        SIP_Request bye = CreateRequest(SIP_Methods.BYE);
                        if (!string.IsNullOrEmpty(reason))
                        {
                            SIP_t_ReasonValue r = new SIP_t_ReasonValue();
                            r.Protocol = "SIP";
                            r.Text     = reason;
                            bye.Reason.Add(r.ToStringValue());
                        }

                        // Send BYE, just wait BYE to complete, we don't care about response code.
                        SIP_RequestSender sender = CreateRequestSender(bye);
                        sender.Completed += delegate { SetState(SIP_DialogState.Terminated, true); };
                        sender.Start();
                    }
                }
                else
                {
                    SetState(SIP_DialogState.Terminated, true);
                }
            }
        }
        /// <summary>
        /// This method is called when un-REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pUnregisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            SetState(SIP_UA_RegistrationState.Unregistered);
            OnUnregistered();

            if (m_AutoDispose)
            {
                Dispose();
            }

            m_pUnregisterSender = null;
        }
        /// <summary>
        /// Starts unregistering.
        /// </summary>
        /// <param name="dispose">If true, registration will be disposed after unregister.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public void BeginUnregister(bool dispose)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            m_AutoDispose = dispose;

            // Stop register timer, otherwise we may get register and unregister race condition.
            m_pTimer.Enabled = false;

            if (m_State == SIP_UA_RegistrationState.Registered)
            {
                /* RFC 3261 10.1 Constructing the REGISTER Request.
                 *  Request-URI: The Request-URI names the domain of the location service for which the registration is meant (for example,
                 *               "sip:chicago.com").  The "userinfo" and "@" components of the SIP URI MUST NOT be present.
                 */

                SIP_Request unregister = m_pStack.CreateRequest(SIP_Methods.REGISTER,
                                                                new SIP_t_NameAddress(m_pServer.Scheme + ":" +
                                                                                      m_AOR),
                                                                new SIP_t_NameAddress(m_pServer.Scheme + ":" +
                                                                                      m_AOR));
                unregister.RequestLine.Uri =
                    SIP_Uri.Parse(m_pServer.Scheme + ":" + m_AOR.Substring(m_AOR.IndexOf('@') + 1));
                unregister.Route.Add(m_pServer.ToString());
                unregister.Contact.Add("<" + Contact + ">;expires=0");

                m_pUnregisterSender = m_pStack.CreateRequestSender(unregister, m_pFlow);
                m_pUnregisterSender.ResponseReceived += m_pUnregisterSender_ResponseReceived;
                m_pUnregisterSender.Start();
            }
            else
            {
                SetState(SIP_UA_RegistrationState.Unregistered);
                OnUnregistered();

                if (m_AutoDispose)
                {
                    Dispose();
                }

                m_pUnregisterSender = null;
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates SIP request sender for the specified request.
        /// </summary>
        /// <remarks>All requests sent through this dialog SHOULD use this request sender to send out requests.</remarks>
        /// <param name="request">SIP request.</param>
        /// <returns>Returns created sender.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>request</b> is null.</exception>
        public SIP_RequestSender CreateRequestSender(SIP_Request request)
        {
            lock (m_pLock)
            {
                if (State == SIP_DialogState.Terminated)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (request == null)
                {
                    throw new ArgumentNullException("request");
                }

                SIP_RequestSender sender = m_pStack.CreateRequestSender(request, Flow);

                return(sender);
            }
        }
        /// <summary>
        /// Starts registering.
        /// </summary>
        /// <param name="autoRefresh">If true, registration takes care of refreshing itself to registrar server.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public void BeginRegister(bool autoRefresh)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            // Fix ME: Stack not running, try register on next step.
            // In ideal solution we need to start registering when stack starts.
            if (!m_pStack.IsRunning)
            {
                m_pTimer.Enabled = true;
                return;
            }

            m_AutoRefresh = autoRefresh;
            SetState(SIP_UA_RegistrationState.Registering);

            /* RFC 3261 10.1 Constructing the REGISTER Request.
             *  Request-URI: The Request-URI names the domain of the location service for which the registration is meant (for example,
             *               "sip:chicago.com").  The "userinfo" and "@" components of the SIP URI MUST NOT be present.
             */

            SIP_Request register = m_pStack.CreateRequest(SIP_Methods.REGISTER,
                                                          new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR),
                                                          new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR));

            register.RequestLine.Uri =
                SIP_Uri.Parse(m_pServer.Scheme + ":" + m_AOR.Substring(m_AOR.IndexOf('@') + 1));
            register.Route.Add(m_pServer.ToString());
            register.Contact.Add("<" + Contact + ">;expires=" + m_RefreshInterval);

            m_pRegisterSender = m_pStack.CreateRequestSender(register, m_pFlow);
            m_pRegisterSender.ResponseReceived += m_pRegisterSender_ResponseReceived;
            m_pRegisterSender.Start();
        }
        /// <summary>
        /// Starts terminating dialog.
        /// </summary>
        /// <param name="reason">Termination reason. This value may be null.</param>
        /// <param name="sendBye">If true BYE is sent to remote party.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        public override void Terminate(string reason, bool sendBye)
        {
            lock (SyncRoot)
            {
                if (State == SIP_DialogState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (State == SIP_DialogState.Terminating || State == SIP_DialogState.Terminated)
                {
                    return;
                }

                /* RFC 3261 15.
                 *  The caller's UA MAY send a BYE for either confirmed or early dialogs, and the callee's UA MAY send a BYE on
                 *  confirmed dialogs, but MUST NOT send a BYE on early dialogs.
                 *
                 * RFC 3261 15.1.
                 *  Once the BYE is constructed, the UAC core creates a new non-INVITE client transaction, and passes it the BYE request.
                 *  The UAC MUST consider the session terminated (and therefore stop sending or listening for media) as soon as the BYE
                 *  request is passed to the client transaction. If the response for the BYE is a 481 (Call/Transaction Does Not Exist)
                 *  or a 408 (Request Timeout) or no response at all is received for the BYE (that is, a timeout is returned by the
                 *  client transaction), the UAC MUST consider the session and the dialog terminated.
                 */

                if (sendBye)
                {
                    if ((State == SIP_DialogState.Early && m_pActiveInvite is SIP_ClientTransaction) ||
                        State == SIP_DialogState.Confirmed)
                    {
                        SetState(SIP_DialogState.Terminating, true);

                        SIP_Request bye = CreateRequest(SIP_Methods.BYE);
                        if (!string.IsNullOrEmpty(reason))
                        {
                            SIP_t_ReasonValue r = new SIP_t_ReasonValue();
                            r.Protocol = "SIP";
                            r.Text     = reason;
                            bye.Reason.Add(r.ToStringValue());
                        }

                        // Send BYE, just wait BYE to complete, we don't care about response code.
                        SIP_RequestSender sender = CreateRequestSender(bye);
                        sender.Completed += delegate { SetState(SIP_DialogState.Terminated, true); };
                        sender.Start();
                    }
                    else
                    {
                        /* We are "early" UAS dialog, we need todo follwoing:
                         *) If we havent sent final response, send '408 Request terminated' and we are done.
                         *) We have sen't final response, we need to wait ACK to arrive or timeout.
                         *      If will ACK arrives or timeout, send BYE.
                         */

                        if (m_pActiveInvite != null && m_pActiveInvite.FinalResponse == null)
                        {
                            Stack.CreateResponse(SIP_ResponseCodes.x408_Request_Timeout,
                                                 m_pActiveInvite.Request);

                            SetState(SIP_DialogState.Terminated, true);
                        }
                        else
                        {
                            // Wait ACK to arrive or timeout.

                            SetState(SIP_DialogState.Terminating, true);
                        }
                    }
                }
                else
                {
                    SetState(SIP_DialogState.Terminated, true);
                }
            }
        }
        /// <summary>
        /// This method is called when REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pRegisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            m_pFlow = e.ClientTransaction.Flow;

            if (e.Response.StatusCodeType == SIP_StatusCodeType.Success)
            {
                SetState(SIP_UA_RegistrationState.Registered);

                OnRegistered();

                m_pFlow.SendKeepAlives = true;
            }
            else
            {
                SetState(SIP_UA_RegistrationState.Error);

                OnError(e);
            }

            // REMOVE ME:
            if (AutoFixContact && (m_pContact is SIP_Uri))
            {
                // If Via: received or rport paramter won't match to our sent-by, use received and rport to construct new contact value.

                SIP_Uri   cContact   = ((SIP_Uri)m_pContact);
                IPAddress cContactIP = Net_Utils.IsIPAddress(cContact.Host)
                                           ? IPAddress.Parse(cContact.Host)
                                           : null;
                SIP_t_ViaParm via = e.Response.Via.GetTopMostValue();
                if (via != null && cContactIP != null)
                {
                    IPEndPoint ep = new IPEndPoint(via.Received != null ? via.Received : cContactIP,
                                                   via.RPort > 0 ? via.RPort : cContact.Port);
                    if (!cContactIP.Equals(ep.Address) || cContact.Port != via.RPort)
                    {
                        // Unregister old contact.
                        BeginUnregister(false);

                        // Fix contact.
                        cContact.Host = ep.Address.ToString();
                        cContact.Port = ep.Port;

                        m_pRegisterSender.Dispose();
                        m_pRegisterSender = null;

                        BeginRegister(m_AutoRefresh);

                        return;
                    }
                }
            }

            if (m_AutoRefresh)
            {
                // Set registration refresh timer.
                m_pTimer.Enabled = true;
            }

            m_pRegisterSender.Dispose();
            m_pRegisterSender = null;
        }
        /// <summary>
        /// This method is called when un-REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pUnregisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            SetState(SIP_UA_RegistrationState.Unregistered);
            OnUnregistered();

            if (m_AutoDispose)
            {
                Dispose();
            }

            m_pUnregisterSender = null;
        }
        /// <summary>
        /// This method is called when REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pRegisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            m_pFlow = e.ClientTransaction.Flow;

            if (e.Response.StatusCodeType == SIP_StatusCodeType.Success)
            {
                SetState(SIP_UA_RegistrationState.Registered);

                OnRegistered();

                m_pFlow.SendKeepAlives = true;
            }
            else
            {
                SetState(SIP_UA_RegistrationState.Error);

                OnError(e);
            }

            // REMOVE ME:
            if (AutoFixContact && (m_pContact is SIP_Uri))
            {
                // If Via: received or rport paramter won't match to our sent-by, use received and rport to construct new contact value.

                SIP_Uri cContact = ((SIP_Uri) m_pContact);
                IPAddress cContactIP = Net_Utils.IsIPAddress(cContact.Host)
                                           ? IPAddress.Parse(cContact.Host)
                                           : null;
                SIP_t_ViaParm via = e.Response.Via.GetTopMostValue();
                if (via != null && cContactIP != null)
                {
                    IPEndPoint ep = new IPEndPoint(via.Received != null ? via.Received : cContactIP,
                                                   via.RPort > 0 ? via.RPort : cContact.Port);
                    if (!cContactIP.Equals(ep.Address) || cContact.Port != via.RPort)
                    {
                        // Unregister old contact.
                        BeginUnregister(false);

                        // Fix contact.
                        cContact.Host = ep.Address.ToString();
                        cContact.Port = ep.Port;

                        m_pRegisterSender.Dispose();
                        m_pRegisterSender = null;

                        BeginRegister(m_AutoRefresh);

                        return;
                    }
                }
            }

            if (m_AutoRefresh)
            {
                // Set registration refresh timer.
                m_pTimer.Enabled = true;
            }

            m_pRegisterSender.Dispose();
            m_pRegisterSender = null;
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Starts unregistering.
        /// </summary>
        /// <param name="dispose">If true, registration will be disposed after unregister.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public void BeginUnregister(bool dispose)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            m_AutoDispose = dispose;

            // Stop register timer, otherwise we may get register and unregister race condition.
            m_pTimer.Enabled = false;

            if (m_State == SIP_UA_RegistrationState.Registered)
            {
                /* RFC 3261 10.1 Constructing the REGISTER Request.
                    Request-URI: The Request-URI names the domain of the location service for which the registration is meant (for example,
                                 "sip:chicago.com").  The "userinfo" and "@" components of the SIP URI MUST NOT be present.
                */

                SIP_Request unregister = m_pStack.CreateRequest(SIP_Methods.REGISTER,
                                                                new SIP_t_NameAddress(m_pServer.Scheme + ":" +
                                                                                      m_AOR),
                                                                new SIP_t_NameAddress(m_pServer.Scheme + ":" +
                                                                                      m_AOR));
                unregister.RequestLine.Uri =
                    SIP_Uri.Parse(m_pServer.Scheme + ":" + m_AOR.Substring(m_AOR.IndexOf('@') + 1));
                unregister.Route.Add(m_pServer.ToString());
                unregister.Contact.Add("<" + Contact + ">;expires=0");

                m_pUnregisterSender = m_pStack.CreateRequestSender(unregister, m_pFlow);
                m_pUnregisterSender.ResponseReceived += m_pUnregisterSender_ResponseReceived;
                m_pUnregisterSender.Start();
            }
            else
            {
                SetState(SIP_UA_RegistrationState.Unregistered);
                OnUnregistered();

                if (m_AutoDispose)
                {
                    Dispose();
                }

                m_pUnregisterSender = null;
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Starts registering.
        /// </summary>
        /// <param name="autoRefresh">If true, registration takes care of refreshing itself to registrar server.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public void BeginRegister(bool autoRefresh)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            // Fix ME: Stack not running, try register on next step.
            // In ideal solution we need to start registering when stack starts.
            if (!m_pStack.IsRunning)
            {
                m_pTimer.Enabled = true;
                return;
            }

            m_AutoRefresh = autoRefresh;
            SetState(SIP_UA_RegistrationState.Registering);

            /* RFC 3261 10.1 Constructing the REGISTER Request.
                Request-URI: The Request-URI names the domain of the location service for which the registration is meant (for example,
                             "sip:chicago.com").  The "userinfo" and "@" components of the SIP URI MUST NOT be present.
            */

            SIP_Request register = m_pStack.CreateRequest(SIP_Methods.REGISTER,
                                                          new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR),
                                                          new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR));
            register.RequestLine.Uri =
                SIP_Uri.Parse(m_pServer.Scheme + ":" + m_AOR.Substring(m_AOR.IndexOf('@') + 1));
            register.Route.Add(m_pServer.ToString());
            register.Contact.Add("<" + Contact + ">;expires=" + m_RefreshInterval);

            m_pRegisterSender = m_pStack.CreateRequestSender(register, m_pFlow);
            m_pRegisterSender.ResponseReceived += m_pRegisterSender_ResponseReceived;
            m_pRegisterSender.Start();
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Creates SIP request sender for the specified request.
        /// </summary>
        /// <param name="request">SIP request.</param>
        /// <param name="flow">Data flow.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>request</b> is null reference.</exception>
        internal SIP_RequestSender CreateRequestSender(SIP_Request request, SIP_Flow flow)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            SIP_RequestSender sender = new SIP_RequestSender(this, request, flow);
            sender.Credentials.AddRange(m_pCredentials);

            return sender;
        }