internal UASInviteTransaction( SIPTransport sipTransport, SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, SIPEndPoint outboundProxy) : base(sipTransport, sipRequest, dstEndPoint, localSIPEndPoint, outboundProxy) { TransactionType = SIPTransactionTypesEnum.Invite; m_remoteTag = sipRequest.Header.From.FromTag; if (sipRequest.Header.To.ToTag == null) { // This UAS needs to set the To Tag. m_localTag = CallProperties.CreateNewTag(); } else { // This is a re-INVITE. m_localTag = sipRequest.Header.To.ToTag; } //logger.Debug("New UASTransaction (" + TransactionId + ") for " + TransactionRequest.URI.ToString() + " to " + RemoteEndPoint + "."); CDR = new SIPCDR(SIPCallDirection.In, sipRequest.URI, sipRequest.Header.From, sipRequest.Header.CallId, LocalSIPEndPoint, dstEndPoint); //UpdateTransactionState(SIPTransactionStatesEnum.Proceeding); TransactionRequestReceived += UASInviteTransaction_TransactionRequestReceived; TransactionInformationResponseReceived += UASInviteTransaction_TransactionResponseReceived; TransactionFinalResponseReceived += UASInviteTransaction_TransactionResponseReceived; TransactionTimedOut += UASInviteTransaction_TransactionTimedOut; TransactionRemoved += UASInviteTransaction_TransactionRemoved; }
private void SIPCancelTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { try { //logger.Debug("CANCEL request received, attempting to locate and cancel transaction."); //UASInviteTransaction originalTransaction = (UASInviteTransaction)GetTransaction(GetRequestTransactionId(sipRequest.Header.Via.TopViaHeader.Branch, SIPMethodsEnum.INVITE)); SIPResponse cancelResponse; if (m_originalTransaction != null) { //logger.Debug("Transaction found to cancel " + originalTransaction.TransactionId + " type " + originalTransaction.TransactionType + "."); m_originalTransaction.CancelCall(); cancelResponse = GetCancelResponse(sipRequest, SIPResponseStatusCodesEnum.Ok); } else { cancelResponse = GetCancelResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist); } //UpdateTransactionState(SIPTransactionStatesEnum.Completed); SendFinalResponse(cancelResponse); } catch (Exception excp) { logger.Error("Exception SIPCancelTransaction GotRequest. " + excp.Message); } }
private void SIPNonInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { if (NonInviteRequestReceived != null) { NonInviteRequestReceived(localSIPEndPoint, remoteEndPoint, this, sipRequest); } }
public void RecordDispatch(SIPRequest sipRequest, SIPEndPoint internalEndPoint) { lock(m_transactionEndPoints) { if (m_transactionEndPoints.ContainsKey(sipRequest.Header.CallId)) { if (m_transactionEndPoints[sipRequest.Header.CallId] == internalEndPoint.ToString()) { // The application server end point has not changed for this Call-Id return; } else { // The application server end point has changed within the lifetime of the Call-Id. Remove the old mapping. lock (m_transactionEndPoints) { m_transactionEndPoints.Remove(sipRequest.Header.CallId); } } } m_transactionEndPoints.Add(sipRequest.Header.CallId, internalEndPoint.ToString()); m_transactionIDAddedAt.Add(sipRequest.Header.CallId, DateTime.Now); //ProxyLogger_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.SIPProxy, SIPMonitorEventTypesEnum.CallDispatcher, "Record dispatch for " + sipRequest.Method + " " + sipRequest.URI.ToString() + " to " + internalEndPoint.ToString() + " (id=" + transactionID + ").", null)); } if (m_lastRemove < DateTime.Now.AddSeconds(REMOVE_EXPIREDS_SECONDS * -1)) { RemoveExpiredDispatchRecords(); } }
internal SIPCancelTransaction(SIPTransport sipTransport, SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, UASInviteTransaction originalTransaction) : base(sipTransport, sipRequest, dstEndPoint, localSIPEndPoint, originalTransaction.OutboundProxy) { m_originalTransaction = originalTransaction; TransactionType = SIPTransactionTypesEnum.NonInvite; TransactionRequestReceived += SIPCancelTransaction_TransactionRequestReceived; TransactionFinalResponseReceived += SIPCancelTransaction_TransactionFinalResponseReceived; TransactionRemoved += SIPCancelTransaction_TransactionRemoved; }
internal SIPNonInviteTransaction(SIPTransport sipTransport, SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, SIPEndPoint outboundProxy) : base(sipTransport, sipRequest, dstEndPoint, localSIPEndPoint, outboundProxy) { TransactionType = SIPTransactionTypesEnum.NonInvite; TransactionRequestReceived += SIPNonInviteTransaction_TransactionRequestReceived; TransactionInformationResponseReceived += SIPNonInviteTransaction_TransactionInformationResponseReceived; TransactionFinalResponseReceived += SIPNonInviteTransaction_TransactionFinalResponseReceived; TransactionTimedOut += SIPNonInviteTransaction_TransactionTimedOut; TransactionRemoved += SIPNonInviteTransaction_TransactionRemoved; TransactionRequestRetransmit += SIPNonInviteTransaction_TransactionRequestRetransmit; }
internal UACInviteTransaction(SIPTransport sipTransport, SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, SIPEndPoint outboundProxy) : base(sipTransport, sipRequest, dstEndPoint, localSIPEndPoint, outboundProxy) { TransactionType = SIPTransactionTypesEnum.Invite; m_localTag = sipRequest.Header.From.FromTag; CDR = new SIPCDR(SIPCallDirection.Out, sipRequest.URI, sipRequest.Header.From, sipRequest.Header.CallId, localSIPEndPoint, dstEndPoint); TransactionFinalResponseReceived += UACInviteTransaction_TransactionFinalResponseReceived; TransactionInformationResponseReceived += UACInviteTransaction_TransactionInformationResponseReceived; TransactionTimedOut += UACInviteTransaction_TransactionTimedOut; TransactionRequestReceived += UACInviteTransaction_TransactionRequestReceived; TransactionRemoved += UACInviteTransaction_TransactionRemoved; }
public static IPAddress GetRequestIPAddress(SIPRequest sipRequest) { IPAddress requestIPAddress = null; string remoteUAStr = sipRequest.Header.ProxyReceivedFrom; if (!remoteUAStr.IsNullOrBlank()) { requestIPAddress = SIPEndPoint.ParseSIPEndPoint(remoteUAStr).Address; } else if (sipRequest.RemoteSIPEndPoint != null) { requestIPAddress = sipRequest.RemoteSIPEndPoint.Address; } return requestIPAddress; }
private SIPResponse GetCancelResponse(SIPRequest sipRequest, SIPResponseStatusCodesEnum sipResponseCode) { try { SIPResponse cancelResponse = new SIPResponse(sipResponseCode, null, sipRequest.LocalSIPEndPoint); SIPHeader requestHeader = sipRequest.Header; cancelResponse.Header = new SIPHeader(requestHeader.From, requestHeader.To, requestHeader.CSeq, requestHeader.CallId); cancelResponse.Header.CSeqMethod = SIPMethodsEnum.CANCEL; cancelResponse.Header.Vias = requestHeader.Vias; cancelResponse.Header.MaxForwards = Int32.MinValue; return cancelResponse; } catch (Exception excp) { logger.Error("Exception GetCancelResponse. " + excp.Message); throw excp; } }
/// <param name="rtpListenAddress">The local IP address to establish the RTP listener socket on.</param> /// <param name="sdpAdvertiseAddress">The public IP address to put into the SDP sent back to the caller.</param> /// <param name="request">The INVITE request that instigated the RTP diagnostics job.</param> public RTPDiagnosticsJob(IPAddress rtpListenAddress, IPAddress sdpAdvertiseAddress, SIPServerUserAgent uas, SIPRequest request) { m_request = request; m_remoteSDP = SDP.ParseSDPDescription(request.Body); RemoteRTPEndPoint = new IPEndPoint(IPAddress.Parse(m_remoteSDP.Connection.ConnectionAddress), m_remoteSDP.Media[0].Port); UAS = uas; //m_rawSourceStream = new RawSourceWaveStream(m_outStream, WaveFormat.CreateMuLawFormat(8000, 1)); //m_waveFileWriter = new WaveFileWriter("out.wav", new WaveFormat(8000, 16, 1)); m_waveFileWriter = new WaveFileWriter("out.wav", new WaveFormat(8000, 16, 1)); //m_outPCMStream = WaveFormatConversionStream.CreatePcmStream(m_rawSourceStream); //m_rawRTPPayloadWriter = new StreamWriter("out.rtp"); //m_rawRTPPayloadReader = new StreamReader("in.rtp"); //IPEndPoint rtpListenEndPoint = null; IPEndPoint rtpListenEndPoint = null; NetServices.CreateRandomUDPListener(rtpListenAddress, RTP_PORTRANGE_START, RTP_PORTRANGE_END, m_inUsePorts, out rtpListenEndPoint); RTPListenEndPoint = rtpListenEndPoint; m_inUsePorts.Add(rtpListenEndPoint.Port); //RTPListenEndPoint = new IPEndPoint(rtpListenAddress, RTP_PORTRANGE_START); m_rtpChannel = new RTPChannel(RTPListenEndPoint); m_rtpChannel.SampleReceived += SampleReceived; ThreadPool.QueueUserWorkItem(delegate { GetAudioSamples(); }); LocalSDP = new SDP() { SessionId = Crypto.GetRandomString(6), Address = sdpAdvertiseAddress.ToString(), SessionName = "sipsorcery", Timing = "0 0", Connection = new SDPConnectionInformation(sdpAdvertiseAddress.ToString()), Media = new List<SDPMediaAnnouncement>() { new SDPMediaAnnouncement() { Media = SDPMediaTypesEnum.audio, Port = RTPListenEndPoint.Port, MediaFormats = new List<SDPMediaFormat>() { new SDPMediaFormat((int)SDPMediaFormatsEnum.PCMU) } } } }; }
/// <summary> /// Used for incoming calls where an exact match is required on the sipswitch username. /// </summary> public DialPlanCommand GetDialPlanExactMatch(SIPRequest sipRequest) { try { //LastUsed = DateTime.Now; if (m_commands.Count > 0) { bool match = false; foreach (DialPlanCommand dialPlanCommand in m_commands) { switch (dialPlanCommand.Operation) { case DialPlanOpsEnum.Equals: match = (dialPlanCommand.Destination == sipRequest.URI.User); break; default: break; } if (match) { logger.Debug("Dial Plan Exact Match for " + sipRequest.URI.User + " and " + dialPlanCommand.ToString()); return dialPlanCommand; } } } return null; } catch (Exception excp) { logger.Error("Exception GetDialPlanExactMatch. " + excp.Message); throw excp; } }
public SIPEndPoint LookupTransactionID(SIPRequest sipRequest) { try { SIPEndPoint transactionEndPoint = LookupTransactionID(sipRequest.Header.CallId); if (transactionEndPoint != null) { return transactionEndPoint; } else if (sipRequest.Method == SIPMethodsEnum.INVITE && !sipRequest.URI.User.IsNullOrBlank()) { string toUser = (sipRequest.URI.User.IndexOf('.') != -1) ? sipRequest.URI.User.Substring(sipRequest.URI.User.LastIndexOf('.') + 1) : sipRequest.URI.User; if (m_userCallbacks.ContainsKey(toUser)) { SIPEndPoint callbackEndPoint = null; callbackEndPoint = SIPEndPoint.ParseSIPEndPoint(m_userCallbacks[toUser].DesintationEndPoint); RecordDispatch(sipRequest, callbackEndPoint); ProxyLogger_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.SIPProxy, SIPMonitorEventTypesEnum.DialPlan, "SIP Proxy directing incoming call for user " + toUser + " to application server " + callbackEndPoint.ToString() + ".", toUser)); lock (m_userCallbacks) { m_userCallbacks.Remove(toUser); } return callbackEndPoint; } } return null; } catch (Exception excp) { logger.Error("Exception LookupTransactionID. " + excp.Message); return null; } }
public bool DoesTransactionExist(SIPRequest sipRequest) { if (m_transactionEngine == null) { return false; } else if (m_transactionEngine.GetTransaction(sipRequest) != null) { return true; } else { return false; } }
public UACInviteTransaction CreateUACTransaction(SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, SIPEndPoint outboundProxy, bool sendOkAckManually = false) { try { if (localSIPEndPoint == null) { localSIPEndPoint = GetDefaultSIPEndPoint(); } CheckTransactionEngineExists(); UACInviteTransaction uacInviteTransaction = new UACInviteTransaction(this, sipRequest, dstEndPoint, localSIPEndPoint, outboundProxy, sendOkAckManually); m_transactionEngine.AddTransaction(uacInviteTransaction); return uacInviteTransaction; } catch (Exception excp) { logger.Error("Exception CreateUACTransaction. " + excp.Message); throw; } }
public UASInviteTransaction CreateUASTransaction(SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, SIPEndPoint outboundProxy, bool noCDR = false) { try { if (localSIPEndPoint == null) { localSIPEndPoint = GetDefaultSIPEndPoint(); } CheckTransactionEngineExists(); UASInviteTransaction uasInviteTransaction = new UASInviteTransaction(this, sipRequest, dstEndPoint, localSIPEndPoint, outboundProxy, ContactIPAddress, noCDR); m_transactionEngine.AddTransaction(uasInviteTransaction); return uasInviteTransaction; } catch (Exception excp) { logger.Error("Exception CreateUASTransaction. " + excp); throw; } }
public SIPCancelTransaction CreateCancelTransaction(SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, UASInviteTransaction inviteTransaction) { try { if (localSIPEndPoint == null) { localSIPEndPoint = GetDefaultSIPEndPoint(); } CheckTransactionEngineExists(); SIPCancelTransaction cancelTransaction = new SIPCancelTransaction(this, sipRequest, dstEndPoint, localSIPEndPoint, inviteTransaction); m_transactionEngine.AddTransaction(cancelTransaction); return cancelTransaction; } catch (Exception excp) { logger.Error("Exception CreateUASTransaction. " + excp); throw; } }
public SIPNonInviteTransaction CreateNonInviteTransaction(SIPRequest sipRequest, SIPEndPoint dstEndPoint, SIPEndPoint localSIPEndPoint, SIPEndPoint outboundProxy) { try { if (localSIPEndPoint == null) { localSIPEndPoint = GetDefaultSIPEndPoint(); } CheckTransactionEngineExists(); SIPNonInviteTransaction nonInviteTransaction = new SIPNonInviteTransaction(this, sipRequest, dstEndPoint, localSIPEndPoint, outboundProxy); m_transactionEngine.AddTransaction(nonInviteTransaction); return nonInviteTransaction; } catch (Exception excp) { logger.Error("Exception CreateNonInviteTransaction. " + excp.Message); throw; } }
public bool Exists(SIPRequest sipRequest) { return(GetTransaction(sipRequest) != null); }
public static SIPResponse GetResponse(SIPRequest sipRequest, SIPResponseStatusCodesEnum responseCode, string reasonPhrase) { try { SIPResponse response = new SIPResponse(responseCode, reasonPhrase, sipRequest.LocalSIPEndPoint); if (reasonPhrase != null) { response.ReasonPhrase = reasonPhrase; } SIPHeader requestHeader = sipRequest.Header; SIPFromHeader from = (requestHeader == null || requestHeader.From != null) ? requestHeader.From : new SIPFromHeader(null, new SIPURI(sipRequest.URI.Scheme, sipRequest.LocalSIPEndPoint), null); SIPToHeader to = (requestHeader == null || requestHeader.To != null) ? requestHeader.To : new SIPToHeader(null, new SIPURI(sipRequest.URI.Scheme, sipRequest.LocalSIPEndPoint), null); int cSeq = (requestHeader == null || requestHeader.CSeq != -1) ? requestHeader.CSeq : 1; string callId = (requestHeader == null || requestHeader.CallId != null) ? requestHeader.CallId : CallProperties.CreateNewCallId(); response.Header = new SIPHeader(from, to, cSeq, callId); response.Header.CSeqMethod = (requestHeader != null) ? requestHeader.CSeqMethod : SIPMethodsEnum.NONE; if (requestHeader == null || requestHeader.Vias == null || requestHeader.Vias.Length == 0) { response.Header.Vias.PushViaHeader(new SIPViaHeader(sipRequest.RemoteSIPEndPoint, CallProperties.CreateBranchId())); } else { response.Header.Vias = requestHeader.Vias; } response.Header.MaxForwards = Int32.MinValue; response.Header.Allow = ALLOWED_SIP_METHODS; return response; } catch (Exception excp) { logger.Error("Exception SIPTransport GetResponse. " + excp.Message); throw excp; } }
public void SendRequest(SIPRequest sipRequest) { if (m_sipChannels.Count == 0) { throw new ApplicationException("No channels are configured in the SIP transport layer. The request could not be sent."); } SIPDNSLookupResult dnsResult = GetRequestEndPoint(sipRequest, null, true); if (dnsResult.LookupError != null) { SIPResponse unresolvableResponse = GetResponse(sipRequest, SIPResponseStatusCodesEnum.AddressIncomplete, "DNS resolution for " + dnsResult.URI.Host + " failed " + dnsResult.LookupError); SendResponse(unresolvableResponse); } else if (dnsResult.Pending) { // The DNS lookup is still in progress, ignore this request and rely on the fact that the transaction retransmit mechanism will send another request. return; } else { SIPEndPoint requestEndPoint = dnsResult.GetSIPEndPoint(); if (requestEndPoint != null && requestEndPoint.Address.Equals(BlackholeAddress)) { // Ignore packet, it's destined for the blackhole. return; } else if (requestEndPoint != null) { SendRequest(requestEndPoint, sipRequest); } else { throw new ApplicationException("SIP Transport could not send request as end point could not be determined.\r\n" + sipRequest.ToString()); } } }
private void SIPNonInviteTransaction_TransactionRequestRetransmit(SIPTransaction sipTransaction, SIPRequest sipRequest, int retransmitNumber) { if (NonInviteTransactionRequestRetransmit != null) { NonInviteTransactionRequestRetransmit(sipTransaction, sipRequest, retransmitNumber); } }
public SIPRequest GetRequest(SIPMethodsEnum method, SIPURI uri, SIPToHeader to, SIPEndPoint localSIPEndPoint) { if (localSIPEndPoint == null) { localSIPEndPoint = GetDefaultSIPEndPoint(); } SIPRequest request = new SIPRequest(method, uri); request.LocalSIPEndPoint = localSIPEndPoint; SIPContactHeader contactHeader = new SIPContactHeader(null, new SIPURI(SIPSchemesEnum.sip, localSIPEndPoint)); SIPFromHeader fromHeader = new SIPFromHeader(null, contactHeader.ContactURI, CallProperties.CreateNewTag()); SIPHeader header = new SIPHeader(contactHeader, fromHeader, to, 1, CallProperties.CreateNewCallId()); request.Header = header; header.CSeqMethod = method; header.Allow = ALLOWED_SIP_METHODS; SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId()); header.Vias.PushViaHeader(viaHeader); return request; }
public SIPTransaction GetTransaction(SIPRequest sipRequest) { CheckTransactionEngineExists(); return m_transactionEngine.GetTransaction(sipRequest); }
/// <summary> /// Transaction matching see RFC3261 17.1.3 & 17.2.3 for matching client and server transactions respectively. /// IMPORTANT NOTE this transaction matching applies to all requests and responses EXCEPT ACK requests to 2xx responses see 13.2.2.4. /// For ACK's to 2xx responses the ACK represents a separate transaction. However for a UAS sending an INVITE response the ACK still has to be /// matched to an existing server transaction in order to transition it to a Confirmed state. /// /// ACK's: /// - The ACK for a 2xx response will have the same CallId, From Tag and To Tag. /// - An ACK for a non-2xx response will have the same branch ID as the INVITE whose response it acknowledges. /// /// PRACK Requests: /// (From RFC3262) /// A matching PRACK is defined as one within the same dialog as the response, and /// whose method, CSeq-num, and response-num in the RAck header field /// match, respectively, the method from the CSeq, the sequence number /// from the CSeq, and the sequence number from the RSeq of the reliable /// provisional response. /// </summary> /// <param name="sipRequest">The request to attempt to locate a matching transaction for.</param> /// <returns>A matching transaction or null if no match found.</returns> public SIPTransaction GetTransaction(SIPRequest sipRequest) { // The branch is mandatory but it doesn't stop some UA's not setting it. if (sipRequest.Header.Vias.TopViaHeader.Branch == null || sipRequest.Header.Vias.TopViaHeader.Branch.Trim().Length == 0) { return(null); } SIPMethodsEnum transactionMethod = (sipRequest.Method != SIPMethodsEnum.ACK) ? sipRequest.Method : SIPMethodsEnum.INVITE; string transactionId = SIPTransaction.GetRequestTransactionId(sipRequest.Header.Vias.TopViaHeader.Branch, transactionMethod); string contactAddress = (sipRequest.Header.Contact != null && sipRequest.Header.Contact.Count > 0) ? sipRequest.Header.Contact[0].ToString() : "no contact"; lock (m_transactions) { if (transactionId != null && m_transactions.ContainsKey(transactionId)) { return(m_transactions[transactionId]); } else { // No normal match found so look fo a 2xx INVITE response waiting for an ACK. if (sipRequest.Method == SIPMethodsEnum.ACK) { //logger.LogDebug("Looking for ACK transaction, branchid=" + sipRequest.Header.Via.TopViaHeader.Branch + "."); foreach (SIPTransaction transaction in m_transactions.Values) { // According to the standard an ACK should only not get matched by the branchid on the original INVITE for a non-2xx response. However // my Cisco phone created a new branchid on ACKs to 487 responses and since the Cisco also used the same Call-ID and From tag on the initial // unauthenticated request and the subsequent authenticated request the condition below was found to be the best way to match the ACK. /*if (transaction.TransactionType == SIPTransactionTypesEnum.Invite && transaction.TransactionFinalResponse != null && transaction.TransactionState == SIPTransactionStatesEnum.Completed) * { * if (transaction.TransactionFinalResponse.Header.CallId == sipRequest.Header.CallId && * transaction.TransactionFinalResponse.Header.To.ToTag == sipRequest.Header.To.ToTag && * transaction.TransactionFinalResponse.Header.From.FromTag == sipRequest.Header.From.FromTag) * { * return transaction; * } * }*/ // As an experiment going to try matching on the Call-ID. This field seems to be unique and therefore the chance // of collisions seemingly very slim. As a safeguard if there happen to be two transactions with the same Call-ID in the list the match will not be made. // One case where the Call-Id match breaks down is for in-Dialogue requests in that case there will be multiple transactions with the same Call-ID and tags. //if (transaction.TransactionType == SIPTransactionTypesEnum.Invite && transaction.TransactionFinalResponse != null && transaction.TransactionState == SIPTransactionStatesEnum.Completed) if ((transaction.TransactionType == SIPTransactionTypesEnum.InviteClient || transaction.TransactionType == SIPTransactionTypesEnum.InviteServer) && transaction.TransactionFinalResponse != null) { if (transaction.TransactionRequest.Header.CallId == sipRequest.Header.CallId && transaction.TransactionFinalResponse.Header.To.ToTag == sipRequest.Header.To.ToTag && transaction.TransactionFinalResponse.Header.From.FromTag == sipRequest.Header.From.FromTag && transaction.TransactionFinalResponse.Header.CSeq == sipRequest.Header.CSeq) { //logger.LogInformation("ACK for contact=" + contactAddress + ", cseq=" + sipRequest.Header.CSeq + " was matched by callid, tags and cseq."); return(transaction); } else if (transaction.TransactionRequest.Header.CallId == sipRequest.Header.CallId && transaction.TransactionFinalResponse.Header.CSeq == sipRequest.Header.CSeq && IsCallIdUniqueForPending(sipRequest.Header.CallId)) { string requestEndPoint = (sipRequest.RemoteSIPEndPoint != null) ? sipRequest.RemoteSIPEndPoint.ToString() : " ? "; //logger.LogInformation("ACK for contact=" + contactAddress + ", cseq=" + sipRequest.Header.CSeq + " was matched using Call-ID mechanism (to tags: " + transaction.TransactionFinalResponse.Header.To.ToTag + "=" + sipRequest.Header.To.ToTag + ", from tags:" + transaction.TransactionFinalResponse.Header.From.FromTag + "=" + sipRequest.Header.From.FromTag + ")."); return(transaction); } } } } else if (sipRequest.Method == SIPMethodsEnum.PRACK) { foreach (SIPTransaction transaction in m_transactions.Values) { if (transaction.TransactionType == SIPTransactionTypesEnum.InviteServer) { if (transaction.TransactionRequest.Header.CallId == sipRequest.Header.CallId && //transaction.ReliableProvisionalResponse.Header.To.ToTag == sipRequest.Header.To.ToTag && transaction.ReliableProvisionalResponse.Header.From.FromTag == sipRequest.Header.From.FromTag && transaction.ReliableProvisionalResponse.Header.CSeq == sipRequest.Header.RAckCSeq && transaction.ReliableProvisionalResponse.Header.RSeq == sipRequest.Header.RAckRSeq && transaction.ReliableProvisionalResponse.Header.CSeqMethod == sipRequest.Header.RAckCSeqMethod) { logger.LogInformation("PRACK for contact=" + contactAddress + ", cseq=" + sipRequest.Header.CSeq + " was matched by callid, tags and cseq."); return(transaction); } } } } return(null); } } }
public void ACKReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { UpdateTransactionState(SIPTransactionStatesEnum.Confirmed); // Need the ACK request in case it contains a body with an SDP answer. AckRequest = sipRequest; OnAckRequestReceived?.Invoke(localSIPEndPoint, remoteEndPoint, this, sipRequest); }
private Task <SocketError> UACInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { logger.LogWarning("UACInviteTransaction received unexpected request, " + sipRequest.Method + " from " + remoteEndPoint.ToString() + ", ignoring."); return(Task.FromResult(SocketError.Fault)); }
private Task <SocketError> UASInviteTransaction_OnAckRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { return(OnAckReceived?.Invoke(localSIPEndPoint, remoteEndPoint, this, sipRequest)); }
/// <summary> /// PRACK request received to acknowledge the last provisional response that was sent. /// </summary> /// <param name="localSIPEndPoint">The SIP socket the request was received on.</param> /// <param name="remoteEndPoint">The remote SIP socket the request originated from.</param> /// <param name="sipRequest">The PRACK request.</param> public void PRACKReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { if (m_transactionState == SIPTransactionStatesEnum.Proceeding && RSeq == sipRequest.Header.RAckRSeq) { Logger.Logger.Debug( "PRACK request matched the current outstanding provisional response, setting as delivered."); DeliveryPending = false; } // We don't keep track of previous provisional response ACK's so always return OK if the request matched the // transaction and got this far. var prackResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); _ = m_sipTransport.SendResponseAsync(prackResponse); }
/// <summary> /// Based on the information in the SIP request attempts to determine the end point the request should /// be sent to. /// </summary> public SIPDNSLookupResult GetRequestEndPoint(SIPRequest sipRequest, SIPEndPoint outboundProxy, bool async) { SIPURI lookupURI = (sipRequest.Header.Routes != null && sipRequest.Header.Routes.Length > 0) ? sipRequest.Header.Routes.TopRoute.URI : sipRequest.URI; if (outboundProxy != null) { return new SIPDNSLookupResult(lookupURI, outboundProxy); } else { //return GetURIEndPoint(sipRequest.URI, async); return GetURIEndPoint(lookupURI, async); } }
public void GotRequest(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { FireTransactionTraceMessage( $"Transaction received Request {localSIPEndPoint.ToString()}<-{remoteEndPoint.ToString()}: {sipRequest.StatusLine}"); TransactionRequestReceived?.Invoke(localSIPEndPoint, remoteEndPoint, this, sipRequest); }
/// <summary> /// This function performs processing on a request to handle any actions that need to be taken based on the Route header. /// </summary> /// <remarks> /// The main sections in the RFC3261 dealing with Route header processing are sections 12.2.1.1 for request processing and /// 16.4 for proxy processing. /// The steps to process requests for Route headers are: /// 1. If route set is empty no further action is required, forward to destination resolved from request URI, /// 2. If the request URI is identified as a value that was previously set as a Route by this SIP agent it means the /// previous hop was a strict router. Replace the reqest URI with the last Route header and go to next step, /// 3. If the top most route header was set by this SIP agent then remove it and go to next step, /// 4. If the top most route set does contain the lr parameter then forward to the destination resolved by it, /// 5. If the top most route header does NOT contain the lr parameter is must be popped and inserted as the request URI /// and the original request URI must be added to the end of the route set, forward to destination resolved from request URI, /// </remarks> public void PreProcessRouteInfo(SIPRequest sipRequest) { // If there are no routes defined then there is nothing to do. if (sipRequest.Header.Routes != null && sipRequest.Header.Routes.Length > 0) { // If this stack's route URI is being used as the request URI then it will have the loose route parameter (see remarks step 2). if (sipRequest.URI.Parameters.Has(m_looseRouteParameter)) { foreach (SIPChannel sipChannel in m_sipChannels.Values) { if (sipRequest.URI.ToSIPEndPoint() == sipChannel.SIPChannelEndPoint) { // The request URI was this router's address so it was set by a strict router. // Replace the URI with the original SIP URI that is stored at the end of the route header. sipRequest.URI = sipRequest.Header.Routes.BottomRoute.URI; sipRequest.Header.Routes.RemoveBottomRoute(); } } } // The possibility of a strict router on the previous hop has now been handled. if (sipRequest.Header.Routes != null && sipRequest.Header.Routes.Length > 0) { // Check whether the top route header belongs to this proxy (see remarks step 3). if (!sipRequest.Header.Routes.TopRoute.IsStrictRouter) { foreach (SIPChannel sipChannel in m_sipChannels.Values) { if (sipRequest.Header.Routes.TopRoute.ToSIPEndPoint() == sipChannel.SIPChannelEndPoint) { // Remove the top route as it belongs to this proxy. sipRequest.ReceivedRoute = sipRequest.Header.Routes.PopRoute(); break; } } } // Check whether the top route header is a strict router and if so adjust the request accordingly (see remarks step 5). if (sipRequest.Header.Routes != null && sipRequest.Header.Routes.Length > 0) { if (sipRequest.Header.Routes.TopRoute.IsStrictRouter) { // Put the strict router's uri into the request URI and place the original request URI at the end of the route set. SIPRoute strictRoute = sipRequest.Header.Routes.PopRoute(); SIPRoute uriRoute = new SIPRoute(sipRequest.URI); sipRequest.Header.Routes.AddBottomRoute(uriRoute); sipRequest.URI = strictRoute.URI; } } } } }
/// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="ringTimeout"></param> /// <param name="answeredCallLimit"></param> /// <param name="redirectMode"></param> /// <param name="clientTransaction"></param> /// <param name="keepScriptAlive">If false will let the dial plan engine know the script has finished and the call is answered. For applications /// like Callback which need to have two calls answered it will be true.</param> /// <returns></returns> private DialPlanAppResult Dial( string data, int ringTimeout, int answeredCallLimit, SIPRequest clientRequest, CRMHeaders contact) { if (m_dialPlanContext.IsAnswered) { Log("The call has already been answered the Dial command was not processed."); return DialPlanAppResult.AlreadyAnswered; } else if (data.IsNullOrBlank()) { Log("The dial string cannot be empty when calling Dial."); return DialPlanAppResult.Error; } else if (m_callInitialisationCount > MAX_CALLS_ALLOWED) { Log("You have exceeded the maximum allowed calls for a dialplan execution."); return DialPlanAppResult.Error; } else { Log("Commencing Dial with: " + data + "."); DialPlanAppResult result = DialPlanAppResult.Unknown; m_waitForCallCompleted = new ManualResetEvent(false); SIPResponseStatusCodesEnum answeredStatus = SIPResponseStatusCodesEnum.None; string answeredReason = null; string answeredContentType = null; string answeredBody = null; SIPDialogue answeredDialogue = null; SIPDialogueTransferModesEnum uasTransferMode = SIPDialogueTransferModesEnum.Default; int numberLegs = 0; QueueNewCallDelegate queueNewCall = (m_callManager != null) ? m_callManager.QueueNewCall : (QueueNewCallDelegate)null; m_currentCall = new ForkCall(m_sipTransport, FireProxyLogEvent, queueNewCall, m_dialStringParser, Username, m_adminMemberId, m_outboundProxySocket, m_callManager, m_dialPlanContext, out LastDialled); m_currentCall.CallProgress += m_dialPlanContext.CallProgress; m_currentCall.CallFailed += (status, reason, headers) => { LastFailureStatus = status; LastFailureReason = reason; result = DialPlanAppResult.Failed; m_waitForCallCompleted.Set(); }; m_currentCall.CallAnswered += (status, reason, toTag, headers, contentType, body, dialogue, transferMode) => { answeredStatus = status; answeredReason = reason; answeredContentType = contentType; answeredBody = body; answeredDialogue = dialogue; uasTransferMode = transferMode; result = DialPlanAppResult.Answered; m_waitForCallCompleted.Set(); }; try { Queue<List<SIPCallDescriptor>> callsQueue = m_dialStringParser.ParseDialString( DialPlanContextsEnum.Script, clientRequest, data, m_customSIPHeaders, m_customContentType, m_customContent, m_dialPlanContext.CallersNetworkId, m_customFromName, m_customFromUser, m_customFromHost, contact, ServiceLevel); List<SIPCallDescriptor>[] callListArray = callsQueue.ToArray(); callsQueue.ToList().ForEach((list) => numberLegs += list.Count); if (numberLegs == 0) { Log("The dial string did not result in any call legs."); return DialPlanAppResult.Error; } else { m_callInitialisationCount += numberLegs; if (m_callInitialisationCount > MAX_CALLS_ALLOWED) { Log("You have exceeded the maximum allowed calls for a dialplan execution."); return DialPlanAppResult.Error; } } m_currentCall.Start(callsQueue); // Wait for an answer. if (ringTimeout <= 0 || ringTimeout * 1000 > m_maxRingTime) { ringTimeout = m_maxRingTime; } else { ringTimeout = ringTimeout * 1000; } ExtendScriptTimeout(ringTimeout / 1000 + DEFAULT_CREATECALL_RINGTIME); DateTime startTime = DateTime.Now; if (m_waitForCallCompleted.WaitOne(ringTimeout, false)) { if (!m_clientCallCancelled) { if (result == DialPlanAppResult.Answered) { // The call limit duration is only used if there hasn't already been a per leg duration set on the call. if (answeredCallLimit > 0 && answeredDialogue.CallDurationLimit == 0) { answeredDialogue.CallDurationLimit = answeredCallLimit; } m_dialPlanContext.CallAnswered(answeredStatus, answeredReason, null, null, answeredContentType, answeredBody, answeredDialogue, uasTransferMode); // Dial plan script stops once there is an answered call to bridge to or the client call is cancelled. Log("Dial command was successfully answered in " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString("0.00") + "s."); // Do some Google Analytics call tracking. if (answeredDialogue.RemoteUserField != null) { SendGoogleAnalyticsEvent("Call", "Answered", answeredDialogue.RemoteUserField.URI.Host, 1); } m_executingScript.StopExecution(); } else if (result == DialPlanAppResult.Failed) { // Check whether any of the responses were redirects. if (LastDialled != null && LastDialled.Count > 0) { var redirect = (from trans in LastDialled where trans.TransactionFinalResponse != null && trans.TransactionFinalResponse.StatusCode >= 300 && trans.TransactionFinalResponse.StatusCode <= 399 && trans.TransactionFinalResponse.Header.Contact != null && trans.TransactionFinalResponse.Header.Contact.Count > 0 select trans.TransactionFinalResponse).FirstOrDefault(); if (redirect != null) { m_redirectResponse = redirect; m_redirectURI = RedirectResponse.Header.Contact[0].ContactURI; result = DialPlanAppResult.Redirect; } } } } } else { if (!m_clientCallCancelled) { // Call timed out. m_currentCall.CancelNotRequiredCallLegs(CallCancelCause.TimedOut); result = DialPlanAppResult.TimedOut; } } if (m_clientCallCancelled) { Log("Dial command was halted by cancellation of client call after " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString("#.00") + "s."); m_executingScript.StopExecution(); } return result; } catch (ThreadAbortException) { return DialPlanAppResult.Unknown; } catch (Exception excp) { logger.Error("Exception DialPlanScriptFacade Dial. " + excp.Message); return DialPlanAppResult.Error; } } }
public void SendRequest(SIPEndPoint dstEndPoint, SIPRequest sipRequest) { if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress)) { // Ignore packet, it's destined for the blackhole. return; } if (m_sipChannels.Count == 0) { throw new ApplicationException("No channels are configured in the SIP transport layer. The request could not be sent."); } SIPChannel sipChannel = null; if (sipRequest.LocalSIPEndPoint != null) { sipChannel = FindSIPChannel(sipRequest.LocalSIPEndPoint); sipChannel = sipChannel ?? GetDefaultChannel(sipRequest.LocalSIPEndPoint.Protocol); } else { sipChannel = GetDefaultChannel(dstEndPoint.Protocol); } if (sipChannel != null) { SendRequest(sipChannel, dstEndPoint, sipRequest); } else { throw new ApplicationException("A default SIP channel could not be found for protocol " + sipRequest.LocalSIPEndPoint.Protocol + " when sending SIP request."); } }
public void ACKReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { UpdateTransactionState(SIPTransactionStatesEnum.Confirmed); }
private void SendRequest(SIPChannel sipChannel, SIPEndPoint dstEndPoint, SIPRequest sipRequest) { try { if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress)) { // Ignore packet, it's destined for the blackhole. return; } if (m_sipChannels.Count == 0) { throw new ApplicationException("No channels are configured in the SIP transport layer. The request could not be sent."); } sipRequest.Header.ContentLength = (sipRequest.Body.NotNullOrBlank()) ? Encoding.UTF8.GetByteCount(sipRequest.Body) : 0; if (sipChannel.IsTLS) { sipChannel.Send(dstEndPoint.GetIPEndPoint(), Encoding.UTF8.GetBytes(sipRequest.ToString()), sipRequest.URI.Host); } else { sipChannel.Send(dstEndPoint.GetIPEndPoint(), Encoding.UTF8.GetBytes(sipRequest.ToString())); } if (SIPRequestOutTraceEvent != null) { FireSIPRequestOutTraceEvent(sipChannel.SIPChannelEndPoint, dstEndPoint, sipRequest); } } catch (ApplicationException appExcp) { logger.Warn("ApplicationException SIPTransport SendRequest. " + appExcp.Message); SIPResponse errorResponse = GetResponse(sipRequest, SIPResponseStatusCodesEnum.InternalServerError, appExcp.Message); // Remove any Via headers, other than the last one, that are for sockets hosted by this process. while (errorResponse.Header.Vias.Length > 0) { if (IsLocalSIPEndPoint(SIPEndPoint.ParseSIPEndPoint(errorResponse.Header.Vias.TopViaHeader.ReceivedFromAddress))) { errorResponse.Header.Vias.PopTopViaHeader(); } else { break; } } if (errorResponse.Header.Vias.Length == 0) { logger.Warn("Could not send error response for " + appExcp.Message + " as no non-local Via headers were available."); } else { SendResponse(errorResponse); } } }
private void UASInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { try { if (TransactionState == SIPTransactionStatesEnum.Terminated) { logger.LogDebug("Request received by UASInviteTransaction for a terminated transaction, ignoring."); } else if (sipRequest.Method != SIPMethodsEnum.INVITE) { logger.LogWarning("Unexpected " + sipRequest.Method + " passed to UASInviteTransaction."); } else { if (TransactionState != SIPTransactionStatesEnum.Trying) { SIPResponse tryingResponse = GetInfoResponse(m_transactionRequest, SIPResponseStatusCodesEnum.Trying); SendProvisionalResponse(tryingResponse); } // Notify new call subscribers. if (NewCallReceived != null) { NewCallReceived(localSIPEndPoint, remoteEndPoint, this, sipRequest); } else { // Nobody wants to answer this call so return an error response. SIPResponse declinedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Decline, "Nothing listening"); SendFinalResponse(declinedResponse); } } } catch (Exception excp) { logger.LogError("Exception UASInviteTransaction GotRequest. " + excp.Message); } }
public DialPlanScriptFacade( SIPTransport sipTransport, DialPlanExecutingScript executingScript, SIPMonitorLogDelegate logDelegate, DialogueBridgeCreatedDelegate createBridge, SIPRequest sipRequest, SIPCallDirection callDirection, DialPlanContext dialPlanContext, GetCanonicalDomainDelegate getCanonicalDomain, ISIPCallManager callManager, //SIPAssetPersistor<SIPAccount> sipAccountPersistor, //SIPAssetPersistor<SIPDialPlan> sipDialPlanPersistor, //SIPAssetPersistor<SIPDialogueAsset> sipDialoguePersistor, //SIPAssetGetListDelegate<SIPRegistrarBinding> getSIPAccountBindings, SIPSorceryPersistor sipSorceryPersistor, SIPEndPoint outboundProxySocket, DialPlanEngine dialPlanEngine ) { m_sipTransport = sipTransport; m_executingScript = executingScript; m_dialPlanLogDelegate = logDelegate; CreateBridge_External = createBridge; m_sipRequest = sipRequest; m_callDirection = callDirection; m_dialPlanContext = dialPlanContext; m_getCanonicalDomainDelegate = getCanonicalDomain; m_callManager = callManager; //m_sipAccountPersistor = sipAccountPersistor; //m_sipDialPlanPersistor = sipDialPlanPersistor; //m_sipDialoguePersistor = sipDialoguePersistor; //GetSIPAccountBindings_External = getSIPAccountBindings; m_sipSorceryPersistor = sipSorceryPersistor; m_outboundProxySocket = outboundProxySocket; m_executingScript.Cleanup = CleanupDialPlanScript; if (m_dialPlanContext != null) { m_username = dialPlanContext.Owner; m_adminMemberId = dialPlanContext.AdminMemberId; m_sipProviders = dialPlanContext.SIPProviders; m_dialPlanContext.TraceLog.AppendLine("DialPlan=> Dialplan trace commenced at " + DateTime.Now.ToString("dd MMM yyyy HH:mm:ss:fff") + "."); m_dialPlanContext.CallCancelledByClient += ClientCallTerminated; SIPAssetGetDelegate<SIPAccount> getSIPAccount = null; if (m_sipSorceryPersistor != null && m_sipSorceryPersistor.SIPAccountsPersistor != null) { getSIPAccount = m_sipSorceryPersistor.SIPAccountsPersistor.Get; } m_dialStringParser = new DialStringParser(m_sipTransport, m_dialPlanContext.Owner, m_dialPlanContext.SIPAccount, m_sipProviders, getSIPAccount, m_sipSorceryPersistor.SIPRegistrarBindingPersistor.Get, m_getCanonicalDomainDelegate, logDelegate, m_dialPlanContext.SIPDialPlan.DialPlanName); } }
private void FireSIPRequestOutTraceEvent(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { try { if (SIPRequestOutTraceEvent != null) { SIPRequestOutTraceEvent(localSIPEndPoint, remoteEndPoint, sipRequest); } } catch (Exception excp) { logger.Error("Exception FireSIPRequestOutTraceEvent. " + excp.Message); } }
private void LogSIPRequestOut(SIPEndPoint localSIPEndPoint, SIPEndPoint endPoint, SIPRequest sipRequest) { string message = "App Svr Sent: " + localSIPEndPoint.ToString() + "->" + endPoint.ToString() + "\r\n" + sipRequest.ToString(); //logger.Debug("as: request out " + sipRequest.Method + " " + localSIPEndPoint.ToString() + "->" + endPoint.ToString() + ", callid=" + sipRequest.Header.CallId + "."); string fromUser = (sipRequest.Header.From != null && sipRequest.Header.From.FromURI != null) ? sipRequest.Header.From.FromURI.User : "******"; FireSIPMonitorEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.FullSIPTrace, message, fromUser, localSIPEndPoint, endPoint)); }
private void SIPNonInviteTransaction_TransactionRequestRetransmit(SIPTransaction sipTransaction, SIPRequest sipRequest, int retransmitNumber) { NonInviteTransactionRequestRetransmit?.Invoke(sipTransaction, sipRequest, retransmitNumber); }