/// <summary> /// Builds the REFER request to transfer an established call. /// </summary> /// <param name="sipDialogue">A SIP dialogue object representing the established call.</param> /// <param name="referToUri">The SIP URI to transfer the call to.</param> /// <returns>A SIP REFER request.</returns> private static SIPRequest GetReferRequest(SIPClientUserAgent uac, SIPURI referToUri) { SIPDialogue sipDialogue = uac.SIPDialogue; SIPRequest referRequest = new SIPRequest(SIPMethodsEnum.REFER, sipDialogue.RemoteTarget); referRequest.SetSendFromHints(uac.ServerTransaction.TransactionRequest.LocalSIPEndPoint); SIPFromHeader referFromHeader = SIPFromHeader.ParseFromHeader(sipDialogue.LocalUserField.ToString()); SIPToHeader referToHeader = SIPToHeader.ParseToHeader(sipDialogue.RemoteUserField.ToString()); int cseq = sipDialogue.CSeq + 1; sipDialogue.CSeq++; SIPHeader referHeader = new SIPHeader(referFromHeader, referToHeader, cseq, sipDialogue.CallId); referHeader.CSeqMethod = SIPMethodsEnum.REFER; referRequest.Header = referHeader; referRequest.Header.Routes = sipDialogue.RouteSet; referRequest.Header.ProxySendFrom = sipDialogue.ProxySendFrom; referRequest.Header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader()); referRequest.Header.ReferTo = referToUri.ToString(); referRequest.Header.Contact = new List <SIPContactHeader>() { SIPContactHeader.GetDefaultSIPContactHeader() }; return(referRequest); }
private SIPRequest GetRequest(SIPMethodsEnum method) { try { SIPURI uri = SIPURI.ParseSIPURIRelaxed(m_callDescriptor.Uri); SIPRequest request = new SIPRequest(method, uri); SIPFromHeader fromHeader = m_callDescriptor.GetFromHeader(); fromHeader.FromTag = CallProperties.CreateNewTag(); SIPToHeader toHeader = new SIPToHeader(null, uri, null); int cseq = Crypto.GetRandomInt(10000, 20000); SIPHeader header = new SIPHeader(fromHeader, toHeader, cseq, CallProperties.CreateNewCallId()); header.CSeqMethod = method; header.UserAgent = m_userAgent; request.Header = header; header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader()); try { if (m_callDescriptor.CustomHeaders != null && m_callDescriptor.CustomHeaders.Count > 0) { foreach (string customHeader in m_callDescriptor.CustomHeaders) { if (customHeader.IsNullOrBlank()) { continue; } else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT)) { request.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim(); } else { request.Header.UnknownHeaders.Add(customHeader); } } } } catch (Exception excp) { logger.LogError("Exception Parsing CustomHeader for SIPNonInviteClientUserAgent GetRequest. " + excp.Message + m_callDescriptor.CustomHeaders); } if (!m_callDescriptor.Content.IsNullOrBlank()) { request.Body = m_callDescriptor.Content; request.Header.ContentType = m_callDescriptor.ContentType; request.Header.ContentLength = request.Body.Length; } return(request); } catch (Exception excp) { logger.LogError("Exception SIPNonInviteClientUserAgent GetRequest. " + excp.Message); throw; } }
/// <summary> /// New transaction ACK requests are for 2xx responses, i.e. INVITE accepted and dialogue being created. /// </summary> /// <remarks> /// From RFC 3261 Chapter 13.2.2.4 - ACK for 2xx final responses /// /// IMPORTANT: /// an ACK for a 2xx final response is a new transaction and has a new branch ID. /// /// The UAC core MUST generate an ACK request for each 2xx received from /// the transaction layer. The header fields of the ACK are constructed /// in the same way as for any request sent within a dialog (see Section /// 12) with the exception of the CSeq and the header fields related to /// authentication. The sequence number of the CSeq header field MUST be /// the same as the INVITE being acknowledged, but the CSeq method MUST /// be ACK. The ACK MUST contain the same credentials as the INVITE. If /// the 2xx contains an offer (based on the rules above), the ACK MUST /// carry an answer in its body. If the offer in the 2xx response is not /// acceptable, the UAC core MUST generate a valid answer in the ACK and /// then send a BYE immediately. /// </remarks> private SIPRequest GetNewTransactionAcknowledgeRequest(SIPMethodsEnum method, SIPResponse sipResponse, SIPURI ackURI) { SIPRequest ackRequest = new SIPRequest(method, ackURI.ToString()); ackRequest.SetSendFromHints(sipResponse.LocalSIPEndPoint); SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId); header.CSeqMethod = method; header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader; header.ProxySendFrom = base.TransactionRequest.Header.ProxySendFrom; // If the UAS supplies a desired Record-Route list use that first. Otherwise fall back to any Route list used in the original transaction. if (sipResponse.Header.RecordRoutes != null) { header.Routes = sipResponse.Header.RecordRoutes.Reversed(); } else if (base.TransactionRequest.Header.Routes != null) { header.Routes = base.TransactionRequest.Header.Routes; } ackRequest.Header = header; ackRequest.Header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader()); return(ackRequest); }
private SIPRequest GetDummyINVITERequest(SIPURI dummyURI) { string dummyFrom = "<sip:[email protected]>"; SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, dummyURI); SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader(dummyFrom), new SIPToHeader(null, dummyURI, null), 1, CallProperties.CreateNewCallId()); inviteHeader.From.FromTag = CallProperties.CreateNewTag(); inviteHeader.Contact = new List <SIPContactHeader> { SIPContactHeader.GetDefaultSIPContactHeader() }; inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE; inviteHeader.UserAgent = "unittest"; inviteRequest.Header = inviteHeader; SIPViaHeader viaHeader = SIPViaHeader.GetDefaultSIPViaHeader(); inviteRequest.Header.Vias.PushViaHeader(viaHeader); inviteRequest.Body = "dummy"; inviteRequest.Header.ContentLength = inviteRequest.Body.Length; inviteRequest.Header.ContentType = "application/sdp"; return(inviteRequest); }
/// <summary> /// Builds a very basic SIP request. In most cases additional headers will need to be added in order for it to be useful. /// When this method is called the channel used for sending the request has not been decided. The headers below depend on /// the sending channel. By setting them to "0.0.0.0:0" the send request methods will substitute in the appropriate value /// at send time: /// - Top Via header. /// - From header. /// - Contact header. /// </summary> /// <param name="method">The method for the SIP request.</param> /// <param name="uri">The destination URI for the request.</param> /// <param name="to">The To header for the request.</param> /// <param name="from">The From header for the request.</param> /// <returns>A SIP request object.</returns> public static SIPRequest GetRequest(SIPMethodsEnum method, SIPURI uri, SIPToHeader to, SIPFromHeader from) { SIPRequest request = new SIPRequest(method, uri); SIPHeader header = new SIPHeader(from, to, 1, CallProperties.CreateNewCallId()); request.Header = header; header.CSeqMethod = method; header.Allow = m_allowedSIPMethods; header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader()); return(request); }
private SIPRequest GetByeRequest() { SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, SIPDialogue.RemoteTarget); SIPFromHeader byeFromHeader = SIPFromHeader.ParseFromHeader(SIPDialogue.LocalUserField.ToString()); SIPToHeader byeToHeader = SIPToHeader.ParseToHeader(SIPDialogue.RemoteUserField.ToString()); int cseq = SIPDialogue.CSeq + 1; SIPHeader byeHeader = new SIPHeader(byeFromHeader, byeToHeader, cseq, SIPDialogue.CallId); byeHeader.CSeqMethod = SIPMethodsEnum.BYE; byeRequest.Header = byeHeader; byeRequest.Header.Routes = SIPDialogue.RouteSet; byeRequest.Header.ProxySendFrom = SIPDialogue.ProxySendFrom; byeRequest.Header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader()); return(byeRequest); }
/// <summary> /// In transaction ACK requests are for non-2xx responses, i.e. INVITE rejected and no dialogue being created. /// </summary> /// <remarks> /// From RFC 3261 Chapter 17.1.1.3 - ACK for non-2xx final responses /// /// IMPORTANT: /// an ACK for a non-2xx response will also have the same branch ID as the INVITE whose response it acknowledges. /// /// The ACK request constructed by the client transaction MUST contain /// values for the Call-ID, From, and Request-URI that are equal to the /// values of those header fields in the request passed to the transport /// by the client transaction (call this the "original request"). The To /// header field in the ACK MUST equal the To header field in the /// response being acknowledged, and therefore will usually differ from /// the To header field in the original request by the addition of the /// tag parameter. The ACK MUST contain a single Via header field, and /// this MUST be equal to the top Via header field of the original /// request. The CSeq header field in the ACK MUST contain the same /// value for the sequence number as was present in the original request, /// but the method parameter MUST be equal to "ACK". /// /// If the INVITE request whose response is being acknowledged had Route /// header fields, those header fields MUST appear in the ACK. This is /// to ensure that the ACK can be routed properly through any downstream /// stateless proxies. /// </remarks> private SIPRequest GetInTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI) { SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString()); ackRequest.SetSendFromHints(sipResponse.LocalSIPEndPoint); SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId); header.CSeqMethod = SIPMethodsEnum.ACK; header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader; header.Routes = base.TransactionRequest.Header.Routes; header.ProxySendFrom = base.TransactionRequest.Header.ProxySendFrom; ackRequest.Header = header; ackRequest.Header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader()); return(ackRequest); }
/// <summary> /// Builds a basic SIP request with the header fields set to correctly identify it as an /// in dialog request. Calling this method also increments the dialog's local CSeq counter. /// This is safe to do even if the request does not end up being sent. /// </summary> /// <param name="method">The method of the SIP request to create.</param> /// <returns>An in dialog SIP request.</returns> public SIPRequest GetInDialogRequest(SIPMethodsEnum method) { CSeq++; SIPRequest inDialogRequest = new SIPRequest(method, RemoteTarget); SIPFromHeader fromHeader = SIPFromHeader.ParseFromHeader(LocalUserField.ToString()); SIPToHeader toHeader = SIPToHeader.ParseToHeader(RemoteUserField.ToString()); int cseq = CSeq; SIPHeader header = new SIPHeader(fromHeader, toHeader, cseq, CallId); header.CSeqMethod = method; inDialogRequest.Header = header; inDialogRequest.Header.Routes = RouteSet; inDialogRequest.Header.ProxySendFrom = ProxySendFrom; inDialogRequest.Header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader()); return(inDialogRequest); }
private SIPRequest GetByeRequest(SIPResponse inviteResponse, SIPURI byeURI) { SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, byeURI); byeRequest.SetSendFromHints(inviteResponse.LocalSIPEndPoint); SIPFromHeader byeFromHeader = inviteResponse.Header.From; SIPToHeader byeToHeader = inviteResponse.Header.To; int cseq = inviteResponse.Header.CSeq + 1; SIPHeader byeHeader = new SIPHeader(byeFromHeader, byeToHeader, cseq, inviteResponse.Header.CallId); byeHeader.CSeqMethod = SIPMethodsEnum.BYE; byeHeader.ProxySendFrom = m_serverTransaction.TransactionRequest.Header.ProxySendFrom; byeRequest.Header = byeHeader; byeRequest.Header.Routes = (inviteResponse.Header.RecordRoutes != null) ? inviteResponse.Header.RecordRoutes.Reversed() : null; byeRequest.Header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader(null)); return(byeRequest); }