/// <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(); }
/// <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); } } }