/// <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(this.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("<" + this.Contact + ">;expires=" + m_RefreshInterval);

            m_pRegisterSender = m_pStack.CreateRequestSender(register, m_pFlow);
            m_pRegisterSender.ResponseReceived += new EventHandler <SIP_ResponseReceivedEventArgs>(m_pRegisterSender_ResponseReceived);
            m_pRegisterSender.Start();
        }
        /// <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 (this.State == SIP_DialogState.Disposed)
                {
                    throw new ObjectDisposedException(this.GetType().Name);
                }
                if (this.State == SIP_DialogState.Terminating || this.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.
                 */

                this.SetState(SIP_DialogState.Terminating, true);

                if (sendBye)
                {
                    // TODO: UAS early

                    if (this.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(object s, EventArgs a){
                            this.SetState(SIP_DialogState.Terminated, true);
                        };
                        sender.Start();
                    }
                }
                else
                {
                    this.SetState(SIP_DialogState.Terminated, true);
                }
            }
        }
        /// <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(this.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("<" + this.Contact + ">;expires=0");

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

                if (m_AutoDispose)
                {
                    Dispose();
                }

                m_pUnregisterSender = null;
            }
        }
        /// <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 void Terminate(string reason, bool sendBye)
        {
            lock (this.SyncRoot){
                if (this.State == SIP_DialogState.Disposed)
                {
                    throw new ObjectDisposedException(this.GetType().Name);
                }
                if (this.State == SIP_DialogState.Terminating || this.State == SIP_DialogState.Terminated)
                {
                    return;
                }

                m_TerminateReason = reason;

                /* 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 ((this.State == SIP_DialogState.Early && m_pActiveInvite is SIP_ClientTransaction) || this.State == SIP_DialogState.Confirmed)
                    {
                        this.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(object s, EventArgs a){
                            this.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)
                        {
                            this.Stack.CreateResponse(SIP_ResponseCodes.x408_Request_Timeout, m_pActiveInvite.Request);

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

                            this.SetState(SIP_DialogState.Terminating, true);
                        }
                    }
                }
                else
                {
                    this.SetState(SIP_DialogState.Terminated, true);
                }
            }
        }
Example #5
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(this.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("<" + this.Contact + ">;expires=0");
            
                m_pUnregisterSender = m_pStack.CreateRequestSender(unregister,m_pFlow);
                m_pUnregisterSender.ResponseReceived += new EventHandler<SIP_ResponseReceivedEventArgs>(m_pUnregisterSender_ResponseReceived);
                m_pUnregisterSender.Start();
            }
            else{
                SetState(SIP_UA_RegistrationState.Unregistered);
                OnUnregistered();

                if(m_AutoDispose){
                    Dispose();
                }

                m_pUnregisterSender = null;
            }
        }
Example #6
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(this.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.State != SIP_StackState.Started){
                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("<" + this.Contact + ">;expires=" + m_RefreshInterval);

            m_pRegisterSender = m_pStack.CreateRequestSender(register,m_pFlow);
            m_pRegisterSender.ResponseReceived += new EventHandler<SIP_ResponseReceivedEventArgs>(m_pRegisterSender_ResponseReceived);
            m_pRegisterSender.Start();
        }
Example #7
0
        /// <summary>
        /// Starts calling.
        /// </summary>
        /// <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.</exception>
        public void Start()
        {
            lock(m_pLock){
                if(m_State == SIP_UA_CallState.Disposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }
                if(m_State != SIP_UA_CallState.WaitingForStart){
                    throw new InvalidOperationException("Start method can be called only in 'SIP_UA_CallState.WaitingForStart' state.");
                }

                SetState(SIP_UA_CallState.Calling);
                        
                m_pInitialInviteSender = m_pUA.Stack.CreateRequestSender(m_pInvite);
                m_pInitialInviteSender.ResponseReceived += new EventHandler<SIP_ResponseReceivedEventArgs>(m_pInitialInviteSender_ResponseReceived);
                m_pInitialInviteSender.Start();
            }
        }