/// <summary> /// Processes specified request through this dialog. /// </summary> /// <param name="e">Method arguments.</param> /// <returns>Returns true if this dialog processed specified request, otherwise false.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>e</b> is null reference.</exception> protected internal override bool ProcessRequest(SIP_RequestReceivedEventArgs e) { if (e == null) { throw new ArgumentNullException("e"); } if (base.ProcessRequest(e)) { return true; } // We must support: INVITE(re-invite),UPDATE,ACK, [BYE will be handled by base class] #region INVITE if (e.Request.RequestLine.Method == SIP_Methods.INVITE) { /* RFC 3261 14.2. A UAS that receives a second INVITE before it sends the final response to a first INVITE with a lower CSeq sequence number on the same dialog MUST return a 500 (Server Internal Error) response to the second INVITE and MUST include a Retry-After header field with a randomly chosen value of between 0 and 10 seconds. A UAS that receives an INVITE on a dialog while an INVITE it had sent on that dialog is in progress MUST return a 491 (Request Pending) response to the received INVITE. */ if (m_pActiveInvite != null && m_pActiveInvite is SIP_ServerTransaction && (m_pActiveInvite).Request.CSeq.SequenceNumber < e.Request.CSeq.SequenceNumber) { SIP_Response response = Stack.CreateResponse( SIP_ResponseCodes.x500_Server_Internal_Error + ": INVITE with a lower CSeq is pending(RFC 3261 14.2).", e.Request); response.RetryAfter = new SIP_t_RetryAfter("10"); e.ServerTransaction.SendResponse(response); return true; } if (m_pActiveInvite != null && m_pActiveInvite is SIP_ClientTransaction) { e.ServerTransaction.SendResponse( Stack.CreateResponse(SIP_ResponseCodes.x491_Request_Pending, e.Request)); return true; } // Force server transaction creation and set it as active INVITE transaction. m_pActiveInvite = e.ServerTransaction; m_pActiveInvite.StateChanged += delegate { if (m_pActiveInvite.State == SIP_TransactionState.Terminated) { m_pActiveInvite = null; } }; // Once we send 2xx response, we need to retransmit it while get ACK or timeout. (RFC 3261 13.3.1.4.) ((SIP_ServerTransaction) m_pActiveInvite).ResponseSent += delegate(object s, SIP_ResponseSentEventArgs a) { if (a.Response.StatusCodeType == SIP_StatusCodeType.Success) { m_pUasInvite2xxRetransmits.Add(new UasInvite2xxRetransmit(this, a.Response)); } }; OnReinvite(((SIP_ServerTransaction) m_pActiveInvite)); return true; } #endregion #region ACK else if (e.Request.RequestLine.Method == SIP_Methods.ACK) { // Search corresponding INVITE 2xx retransmit entry and dispose it. foreach (UasInvite2xxRetransmit t in m_pUasInvite2xxRetransmits) { if (t.MatchAck(e.Request)) { t.Dispose(); if (State == SIP_DialogState.Early) { SetState(SIP_DialogState.Confirmed, true); // TODO: If Terminating } return true; } } return false; } #endregion #region UPDATE //else if(request.RequestLine.Method == SIP_Methods.UPDATE){ // TODO: //} #endregion // RFC 5057 5.6. Refusing New Usages. Decline(603 Decline) new dialog usages. else if (SIP_Utils.MethodCanEstablishDialog(e.Request.RequestLine.Method)) { e.ServerTransaction.SendResponse( Stack.CreateResponse( SIP_ResponseCodes.x603_Decline + " : New dialog usages not allowed (RFC 5057).", e.Request)); return true; } else { return false; } }
/// <summary> /// Processes specified request through this dialog. /// </summary> /// <param name="e">Method arguments.</param> /// <returns>Returns true if this dialog processed specified request, otherwise false.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>e</b> is null reference.</exception> protected internal override bool ProcessRequest(SIP_RequestReceivedEventArgs e) { if (e == null) { throw new ArgumentNullException("e"); } if (base.ProcessRequest(e)) { return(true); } // We must support: INVITE(re-invite),UPDATE,ACK, [BYE will be handled by base class] #region INVITE if (e.Request.RequestLine.Method == SIP_Methods.INVITE) { /* RFC 3261 14.2. * A UAS that receives a second INVITE before it sends the final * response to a first INVITE with a lower CSeq sequence number on the * same dialog MUST return a 500 (Server Internal Error) response to the * second INVITE and MUST include a Retry-After header field with a * randomly chosen value of between 0 and 10 seconds. * * A UAS that receives an INVITE on a dialog while an INVITE it had sent * on that dialog is in progress MUST return a 491 (Request Pending) * response to the received INVITE. */ if (m_pActiveInvite != null && m_pActiveInvite is SIP_ServerTransaction && (m_pActiveInvite).Request.CSeq.SequenceNumber < e.Request.CSeq.SequenceNumber) { SIP_Response response = Stack.CreateResponse( SIP_ResponseCodes.x500_Server_Internal_Error + ": INVITE with a lower CSeq is pending(RFC 3261 14.2).", e.Request); response.RetryAfter = new SIP_t_RetryAfter("10"); e.ServerTransaction.SendResponse(response); return(true); } if (m_pActiveInvite != null && m_pActiveInvite is SIP_ClientTransaction) { e.ServerTransaction.SendResponse( Stack.CreateResponse(SIP_ResponseCodes.x491_Request_Pending, e.Request)); return(true); } // Force server transaction creation and set it as active INVITE transaction. m_pActiveInvite = e.ServerTransaction; m_pActiveInvite.StateChanged += delegate { if (m_pActiveInvite.State == SIP_TransactionState.Terminated) { m_pActiveInvite = null; } }; // Once we send 2xx response, we need to retransmit it while get ACK or timeout. (RFC 3261 13.3.1.4.) ((SIP_ServerTransaction)m_pActiveInvite).ResponseSent += delegate(object s, SIP_ResponseSentEventArgs a) { if (a.Response.StatusCodeType == SIP_StatusCodeType.Success) { m_pUasInvite2xxRetransmits.Add(new UasInvite2xxRetransmit(this, a.Response)); } }; OnReinvite(((SIP_ServerTransaction)m_pActiveInvite)); return(true); } #endregion #region ACK else if (e.Request.RequestLine.Method == SIP_Methods.ACK) { // Search corresponding INVITE 2xx retransmit entry and dispose it. foreach (UasInvite2xxRetransmit t in m_pUasInvite2xxRetransmits) { if (t.MatchAck(e.Request)) { t.Dispose(); if (State == SIP_DialogState.Early) { SetState(SIP_DialogState.Confirmed, true); // TODO: If Terminating } return(true); } } return(false); } #endregion #region UPDATE //else if(request.RequestLine.Method == SIP_Methods.UPDATE){ // TODO: //} #endregion // RFC 5057 5.6. Refusing New Usages. Decline(603 Decline) new dialog usages. else if (SIP_Utils.MethodCanEstablishDialog(e.Request.RequestLine.Method)) { e.ServerTransaction.SendResponse( Stack.CreateResponse( SIP_ResponseCodes.x603_Decline + " : New dialog usages not allowed (RFC 5057).", e.Request)); return(true); } else { return(false); } }
/// <summary> /// Raises <b>TerminatedByRemoteParty</b> event. /// </summary> /// <param name="bye">BYE request.</param> private void OnTerminatedByRemoteParty(SIP_RequestReceivedEventArgs bye) { if (TerminatedByRemoteParty != null) { TerminatedByRemoteParty(this, bye); } }
/// <summary> /// Raises <b>RequestReceived</b> event. /// </summary> /// <param name="e">Event data.</param> internal void OnRequestReceived(SIP_RequestReceivedEventArgs e) { if (RequestReceived != null) { RequestReceived(this, e); } }
/// <summary> /// Processes specified request through this dialog. /// </summary> /// <param name="e">Method arguments.</param> /// <returns>Returns true if this dialog processed specified response, otherwise false.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>e</b> is null reference.</exception> protected internal virtual bool ProcessRequest(SIP_RequestReceivedEventArgs e) { if (e == null) { throw new ArgumentNullException("e"); } if (e.Request.RequestLine.Method == SIP_Methods.BYE) { e.ServerTransaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x200_Ok, e.Request)); m_IsTerminatedByRemoteParty = true; OnTerminatedByRemoteParty(e); SetState(SIP_DialogState.Terminated, true); return true; } return false; }