The Via header only has parameters, no headers. Parameters of from ...;name=value;name2=value2 Specific parameters: ttl, maddr, received, branch. From page 179 of RFC3261: "Even though this specification mandates that the branch parameter be present in all requests, the BNF for the header field indicates that it is optional." The branch parameter on a Via therefore appears to be optionally mandatory?! Any SIP application element that uses transactions depends on the branch parameter for transaction matching. Only the top Via header branch is used for transactions though so if the request has made it to this stack with missing branches then in theory it should be safe to proceed. It will be left up to the SIPTransaction class to reject any SIP requests that are missing the necessary branch.
        private SIPRequest GetByeRequest(SIPEndPoint localSIPEndPoint)
        {
            SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, RemoteTarget);
            SIPFromHeader byeFromHeader = SIPFromHeader.ParseFromHeader(LocalUserField.ToString());
            SIPToHeader byeToHeader = SIPToHeader.ParseToHeader(RemoteUserField.ToString());
            int cseq = CSeq + 1;

            SIPHeader byeHeader = new SIPHeader(byeFromHeader, byeToHeader, cseq, CallId);
            byeHeader.CSeqMethod = SIPMethodsEnum.BYE;
            byeRequest.Header = byeHeader;
            byeRequest.Header.Routes = RouteSet;
            byeRequest.Header.ProxySendFrom = ProxySendFrom;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            byeRequest.Header.Vias.PushViaHeader(viaHeader);

            return byeRequest;
        }
        /// <summary>
        /// Used to send a request from an internal server agent to an external SIP user agent. The difference between this method and
        /// the SendTransparent method is that this one will set Via headers in accordance with RFC3261.
        /// </summary>
        /// <param name="receivedOnEP">The proxy SIP end point the request was received on.</param>
        /// <param name="dstSocket">The SIP end point the request is being sent to.</param>
        /// <param name="sipRequest">The SIP request to send.</param>
        /// <param name="proxyBranch">The branch parameter for the top Via header that has been pre-calculated by the proxy core.</param>
        /// <param name="sendFromSocket">The proxy SIP end point to send this request from. If the SIP request has its ProxySendFrom header
        /// value set that will overrule this parameter.</param>
        public void SendExternal(SIPEndPoint receivedOnEP, SIPEndPoint dstSIPEndPoint, SIPRequest sipRequest, string proxyBranch, IPAddress publicIPAddress)
        {
            try
            {
                if (!IsDestinationValid(sipRequest, dstSIPEndPoint))
                {
                    logger.Debug("SendExternal failed destination check.");
                    return;
                }

                // Determine the external SIP endpoint that the proxy will use to send this request.
                SIPEndPoint localSIPEndPoint = m_sipTransport.GetDefaultSIPEndPoint(dstSIPEndPoint);
                if (!sipRequest.Header.ProxySendFrom.IsNullOrBlank())
                {
                    SIPChannel proxyChannel = m_sipTransport.FindSIPChannel(SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxySendFrom));
                    if (proxyChannel == null)
                    {
                        logger.Warn("No SIP channel could be found for\n" + sipRequest.ToString());
                    }
                    localSIPEndPoint = (proxyChannel != null) ? proxyChannel.SIPChannelEndPoint : localSIPEndPoint;
                }

                if (receivedOnEP != localSIPEndPoint)
                {
                    // The proxy is being requested to send the request on a different socket to the one it was received on.
                    // A second Via header is added to ensure the response can navigate back the same path. The calculated branch
                    // parameter needs to go on the top Via header so that whichever internal socket the request is being sent to can
                    // determine re-transmits.
                    SIPViaHeader via = new SIPViaHeader(receivedOnEP, CallProperties.CreateBranchId());
                    sipRequest.Header.Vias.PushViaHeader(via);

                    SIPViaHeader externalVia = new SIPViaHeader(localSIPEndPoint, proxyBranch);
                    sipRequest.Header.Vias.PushViaHeader(externalVia);
                }
                else
                {
                    // Only a single Via header is required as any response to this request will be sent from the same socket it gets received on.
                    SIPViaHeader via = new SIPViaHeader(localSIPEndPoint, proxyBranch);
                    sipRequest.Header.Vias.PushViaHeader(via);
                }

                if (sipRequest.Method != SIPMethodsEnum.REGISTER)
                {
                    AdjustContactHeader(sipRequest.Header, localSIPEndPoint, publicIPAddress);
                }

                sipRequest.LocalSIPEndPoint = localSIPEndPoint;

                // Proxy sepecific headers that don't need to be seen by external UAs.
                sipRequest.Header.ProxyReceivedOn = null;
                sipRequest.Header.ProxyReceivedFrom = null;
                sipRequest.Header.ProxySendFrom = null;

                m_sipTransport.SendRequest(dstSIPEndPoint, sipRequest);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPRequest SendExternal. " + excp.Message);
                logger.Error(sipRequest.ToString());
                throw;
            }
        }
 public void AddBottomViaHeader(SIPViaHeader viaHeader)
 {
     m_viaHeaders.Add(viaHeader);
 }
        public static SIPViaHeader[] ParseSIPViaHeader(string viaHeaderStr)
        {
            List<SIPViaHeader> viaHeadersList = new List<SIPViaHeader>();

            if (!viaHeaderStr.IsNullOrBlank())
            {
                viaHeaderStr = viaHeaderStr.Trim();

                // Multiple Via headers can be contained in a single line by separating them with a comma.
                string[] viaHeaders = SIPParameters.GetKeyValuePairsFromQuoted(viaHeaderStr, ',');

                foreach (string viaHeaderStrItem in viaHeaders)
                {
                    if (viaHeaderStrItem == null || viaHeaderStrItem.Trim().Length == 0)
                    {
                        throw new SIPValidationException(SIPValidationFieldsEnum.ViaHeader, "No Contact address.");
                    }
                    else
                    {
                        SIPViaHeader viaHeader = new SIPViaHeader();
                        string header = viaHeaderStrItem.Trim();

                        int firstSpacePosn = header.IndexOf(" ");
                        if (firstSpacePosn == -1)
                        {
                            throw new SIPValidationException(SIPValidationFieldsEnum.ViaHeader, "No Contact address.");
                        }
                        else
                        {
                            string versionAndTransport = header.Substring(0, firstSpacePosn);
                            viaHeader.Version = versionAndTransport.Substring(0, versionAndTransport.LastIndexOf('/'));
                            viaHeader.Transport = SIPProtocolsType.GetProtocolType(versionAndTransport.Substring(versionAndTransport.LastIndexOf('/') + 1));

                            string nextField = header.Substring(firstSpacePosn, header.Length - firstSpacePosn).Trim();

                            int delimIndex = nextField.IndexOf(';');
                            string contactAddress = null;

                            // Some user agents include branch but have the semi-colon missing, that's easy to cope with by replacing "branch" with ";branch".
                            if (delimIndex == -1 && nextField.Contains(m_branchKey))
                            {
                                nextField = nextField.Replace(m_branchKey, ";" + m_branchKey);
                                delimIndex = nextField.IndexOf(';');
                            }

                            if (delimIndex == -1)
                            {
                                //logger.Warn("Via header missing semi-colon: " + header + ".");
                                //parserError = SIPValidationError.NoBranchOnVia;
                                //return null;
                                contactAddress = nextField.Trim();
                            }
                            else
                            {
                                contactAddress = nextField.Substring(0, delimIndex).Trim();
                                viaHeader.ViaParameters = new SIPParameters(nextField.Substring(delimIndex, nextField.Length - delimIndex), m_paramDelimChar);
                            }

                            if (contactAddress == null || contactAddress.Trim().Length == 0)
                            {
                                // Check that the branch parameter is present, without it the Via header is illegal.
                                //if (!viaHeader.ViaParameters.Has(m_branchKey))
                                //{
                                //    logger.Warn("Via header missing branch: " + header + ".");
                                //    parserError = SIPValidationError.NoBranchOnVia;
                                //    return null;
                                //}

                                throw new SIPValidationException(SIPValidationFieldsEnum.ViaHeader, "No Contact address.");
                            }

                            // Parse the contact address.
                            int colonIndex = contactAddress.IndexOf(m_hostDelimChar);
                            if (colonIndex != -1)
                            {
                                viaHeader.Host = contactAddress.Substring(0, colonIndex);

                                if (!Int32.TryParse(contactAddress.Substring(colonIndex + 1), out viaHeader.Port))
                                {
                                    throw new SIPValidationException(SIPValidationFieldsEnum.ViaHeader, "Non-numeric port for IP address.");
                                }
                                else if (viaHeader.Port > SIPConstants.MAX_SIP_PORT)
                                {
                                    throw new SIPValidationException(SIPValidationFieldsEnum.ViaHeader, "The port specified in a Via header exceeded the maximum allowed.");
                                }
                            }
                            else
                            {
                                viaHeader.Host = contactAddress;
                            }

                            viaHeadersList.Add(viaHeader);
                        }
                    }
                }
            }

            if (viaHeadersList.Count > 0)
            {
                return viaHeadersList.ToArray();
            }
            else
            {
                throw new SIPValidationException(SIPValidationFieldsEnum.ViaHeader, "Via list was empty."); ;
            }
        }
        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;

                SIPViaHeader viaHeader = new SIPViaHeader(m_sipTransport.GetDefaultSIPEndPoint(), CallProperties.CreateBranchId());
                request.Header.Vias.PushViaHeader(viaHeader);

                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.Error("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.Error("Exception SIPNonInviteClientUserAgent GetRequest. " + excp.Message);
                throw excp;
            }
        }
        /// <summary>
        /// New transaction ACK requests are for 2xx responses, i.e. INVITE accepted and 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.
        /// 
        /// 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 GetNewTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());
            ackRequest.LocalSIPEndPoint = 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.ProxySendFrom = base.TransactionRequest.Header.ProxySendFrom;

            if (sipResponse.Header.RecordRoutes != null)
            {
                header.Routes = sipResponse.Header.RecordRoutes.Reversed();
            }

            ackRequest.Header = header;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return ackRequest;
        }
        private SIPRequest GetInviteRequest(SIPDialogue dialogue, SIPEndPoint localSIPEndPoint, string body)
        {
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, dialogue.RemoteTarget);

            SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader(dialogue.LocalUserField.ToString()), SIPToHeader.ParseToHeader(dialogue.RemoteUserField.ToString()), dialogue.CSeq, dialogue.CallId);
            SIPURI contactURI = new SIPURI(dialogue.RemoteTarget.Scheme, localSIPEndPoint);
            inviteHeader.Contact = SIPContactHeader.ParseContactHeader("<" + contactURI.ToString() + ">");
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteRequest.Header = inviteHeader;
            inviteRequest.Header.Routes = dialogue.RouteSet;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            inviteRequest.Body = body;
            inviteRequest.Header.ContentLength = body.Length;
            inviteRequest.Header.ContentType = "application/sdp";

            return inviteRequest;
        }
            private SIPRequest GetInviteRequest(IPEndPoint localContact, string inviteBody, IPEndPoint dstEndPoint)
            {
                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI("sip:" + dstEndPoint));

                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader("<sip:" + localContact + ">"), SIPToHeader.ParseToHeader("<sip:" + dstEndPoint + ">"), 1, CallProperties.CreateNewCallId());
                inviteHeader.From.FromTag = CallProperties.CreateNewTag();
                inviteHeader.Contact = SIPContactHeader.ParseContactHeader("sip:" + localContact);
                inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
                inviteHeader.UserAgent = "unit test";
                inviteRequest.Header = inviteHeader;

                SIPViaHeader viaHeader = new SIPViaHeader(localContact.Address.ToString(), localContact.Port,CallProperties.CreateBranchId(), SIPProtocolsEnum.udp);
                inviteRequest.Header.Vias.PushViaHeader(viaHeader);

                //inviteRequest.Body = inviteBody;
                //inviteRequest.Header.ContentLength = inviteBody.Length;
                inviteRequest.Header.ContentType = "application/sdp";

                return inviteRequest;
            }
        private SIPRequest GetCallbackInviteRequest(IPEndPoint localSIPEndPoint, string sdp)
        {
            string callBackURI = "sip:[email protected]";
            string callBackUserField = "<" + callBackURI + ">";
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, callBackURI);
            SIPHeader inviteHeader = new SIPHeader(callBackUserField, callBackUserField, 1, CallProperties.CreateNewCallId());
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteHeader.ContentType = "application/sdp";
            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            inviteHeader.Vias.PushViaHeader(viaHeader);
            inviteRequest.Header = inviteHeader;

            if (sdp == null)
            {
                sdp =
                   "v=0" + CRLF +
                    "o=- " + Crypto.GetRandomInt(1000, 5000).ToString() + " 2 IN IP4 " + localSIPEndPoint.Address.ToString() + CRLF +
                    "s=session" + CRLF +
                    "c=IN IP4 " + localSIPEndPoint.Address.ToString() + CRLF +
                    "t=0 0" + CRLF +
                    "m=audio " + Crypto.GetRandomInt(10000, 20000).ToString() + " RTP/AVP 0 18 101" + CRLF +
                    "a=rtpmap:0 PCMU/8000" + CRLF +
                    "a=rtpmap:18 G729/8000" + CRLF +
                    "a=rtpmap:101 telephone-event/8000" + CRLF +
                    "a=fmtp:101 0-16" + CRLF +
                    "a=recvonly";
            }
            inviteHeader.ContentLength = sdp.Length;
            inviteRequest.Body = sdp;

            return inviteRequest;
        }
        /// <summary>
        /// Constructs a NOTIFY request to send within the implicit subscription created when processing a REFER request.
        /// </summary>
        /// <remarks>
        /// From RFC 3515 2.4.5:
        /// The body of a NOTIFY MUST begin with a SIP Response Status-Line...
        /// </remarks>
        /// <param name="referRequest">The REFER request that created the implicit refer event subscription.</param>
        /// <param name="referDialogue">The dialogue that the REFER request has been received within.</param>
        /// <param name="referResponse">The response that has been received to whatever is doing the post-REFER processing.</param>
        /// <param name="localEndPoint">The local SIP end point that the NOTIFY request will be sent from.</param>
        /// <returns>A NOTIFY request suitable for sending to the remote end of the REFER initiating dialogue.</returns>
        private SIPRequest GetNotifyRequest(SIPRequest referRequest, SIPDialogue referDialogue, SIPResponse referResponse, SIPEndPoint localEndPoint)
        {
            try
            {
                SIPRequest notifyRequest = new SIPRequest(SIPMethodsEnum.NOTIFY, referRequest.Header.Contact[0].ContactURI);
                notifyRequest.Header = new SIPHeader(SIPFromHeader.ParseFromHeader(referDialogue.LocalUserField.ToString()), SIPToHeader.ParseToHeader(referDialogue.RemoteUserField.ToString()), referDialogue.CSeq, referDialogue.CallId);
                notifyRequest.Header.Event = m_referNotifyEventValue; // + ";id=" + referRequest.Header.CSeq;
                notifyRequest.Header.CSeqMethod = SIPMethodsEnum.NOTIFY;
                notifyRequest.Header.SubscriptionState = (referResponse.StatusCode >= 200) ? "terminated;reason=noresource" : "active;expires=60";
                notifyRequest.Header.ContentType = m_referNotifyContentType;

                SIPViaHeader viaHeader = new SIPViaHeader(localEndPoint, CallProperties.CreateBranchId());
                notifyRequest.Header.Vias.PushViaHeader(viaHeader);

                notifyRequest.Body = (referResponse.SIPVersion + " " + referResponse.StatusCode + " " + referResponse.ReasonPhrase).Trim();
                notifyRequest.Header.ContentLength = notifyRequest.Body.Length;

                return notifyRequest;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetNotifyRequest. " + excp.Message);
                throw;
            }
        }
        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));
            if (!String.IsNullOrWhiteSpace(m_contactGruu))
            {
                contactHeader.ContactURI.Parameters.Set("gr", m_contactGruu);
            }

            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;

            if (m_serviceRoute != null)
                header.Routes.AddBottomRoute(m_serviceRoute);

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            header.Vias.PushViaHeader(viaHeader);

            return request;
        }
        public void ProcessNotifyRequest(SIPRequest sipRequest)
        {
            try
            {
                // Hack to work around MWI request from callcentric not having a trailing CRLF and breaking some softphones like the Bria.
                if (sipRequest.Header.Event == MWI_EVENT_TYPE && sipRequest.Body.NotNullOrBlank() && sipRequest.Body.Substring(sipRequest.Body.Length - 2) != m_crlf)
                {
                    sipRequest.Body += m_crlf;
                }

                string fromURI = (sipRequest.Header.From != null && sipRequest.Header.From.FromURI != null) ? sipRequest.Header.From.FromURI.ToString() : "unknown";

                string domain = GetCanonicalDomain_External(sipRequest.URI.Host, true);
                if (domain != null)
                {
                    SIPAccount sipAccount = GetSIPAccount_External(s => s.SIPUsername == sipRequest.URI.User && s.SIPDomain == domain);

                    if (sipAccount != null)
                    {
                        List<SIPRegistrarBinding> bindings = GetSIPAccountBindings_External(b => b.SIPAccountId == sipAccount.Id, null, 0, MAX_FORWARD_BINDINGS);

                        if (bindings != null)
                        {
                            foreach (SIPRegistrarBinding binding in bindings)
                            {
                                SIPURI dstURI = binding.MangledContactSIPURI;
                                SIPEndPoint localSIPEndPoint = (m_outboundProxy != null) ? m_sipTransport.GetDefaultSIPEndPoint(m_outboundProxy.Protocol) : m_sipTransport.GetDefaultSIPEndPoint(dstURI.Protocol);

                                SIPEndPoint dstSIPEndPoint = null;

                                // If the outbound proxy is a loopback address, as it will normally be for local deployments, then it cannot be overriden.
                                if(m_outboundProxy != null && IPAddress.IsLoopback(m_outboundProxy.Address))
                                {
                                    dstSIPEndPoint = m_outboundProxy;
                                }
                                else if (binding.ProxySIPEndPoint != null)
                                {
                                    // If the binding has a specific proxy end point sent then the request needs to be forwarded to the proxy's default end point for it to take care of.
                                    dstSIPEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(binding.ProxySIPEndPoint.Address, m_defaultSIPPort));
                                }
                                else if (m_outboundProxy != null)
                                {
                                    dstSIPEndPoint = m_outboundProxy;
                                }
                                else
                                {
                                    SIPDNSLookupResult lookupResult = m_sipTransport.GetURIEndPoint(dstURI, false);
                                    if(lookupResult.LookupError != null)
                                    {
                                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "A NOTIFY request from " + fromURI + " was not forwarded due to DNS failure for " + dstURI.Host + ", " + lookupResult.LookupError + ".", sipAccount.Owner));
                                    }
                                    else
                                    {
                                        dstSIPEndPoint = lookupResult.GetSIPEndPoint();
                                    }
                                }

                                if (dstSIPEndPoint != null)
                                {
                                    // Rather than create a brand new request copy the received one and modify the headers that need to be unique.
                                    SIPRequest notifyRequest = sipRequest.Copy();
                                    notifyRequest.URI = dstURI;
                                    notifyRequest.Header.Contact = SIPContactHeader.CreateSIPContactList(new SIPURI(dstURI.Scheme, localSIPEndPoint));
                                    notifyRequest.Header.To = new SIPToHeader(null, dstURI, null);
                                    notifyRequest.Header.CallId = CallProperties.CreateNewCallId();
                                    SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
                                    notifyRequest.Header.Vias = new SIPViaSet();
                                    notifyRequest.Header.Vias.PushViaHeader(viaHeader);

                                    // If the binding has a proxy socket defined set the header to ask the upstream proxy to use it.
                                    if (binding.ProxySIPEndPoint != null)
                                    {
                                        notifyRequest.Header.ProxySendFrom = binding.ProxySIPEndPoint.ToString();

                                        // If the binding has a specific proxy end point sent then the request needs to be forwarded to the proxy's default end point for it to take care of.
                                        dstSIPEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(binding.ProxySIPEndPoint.Address, m_defaultSIPPort));
                                    }

                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "Forwarding NOTIFY request from " + fromURI + " to registered binding at " + dstURI.ToString() + ", proxy " + dstSIPEndPoint.ToString() + ".", sipAccount.Owner));
                                    SIPNonInviteTransaction notifyTransaction = m_sipTransport.CreateNonInviteTransaction(notifyRequest, dstSIPEndPoint, localSIPEndPoint, dstSIPEndPoint);
                                    notifyTransaction.SendReliableRequest();
                                }
                                else
                                {
                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "A NOTIFY request from " + fromURI + " was not forwarded as no destination end point was resolved.", sipAccount.Owner));
                                }
                            }

                            // Send OK response to server.
                            SIPResponse okResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                            m_sipTransport.SendResponse(okResponse);
                        }
                        else
                        {
                            // Send unavailable response to server.
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "NOTIFY request from " + fromURI + " for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " but no bindings available, responding with temporarily unavailable.", sipAccount.Owner));
                            SIPResponse notAvailableResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.TemporarilyUnavailable, null);
                            m_sipTransport.SendResponse(notAvailableResponse);
                        }
                    }
                    else
                    {
                        // Send Not found response to server.
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "NOTIFY request from " + fromURI + " for " + sipRequest.URI.ToString() + " but no matching SIP account, responding with not found.", null));
                        SIPResponse notFoundResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, null);
                        m_sipTransport.SendResponse(notFoundResponse);
                    }
                }
                else
                {
                    // Send Not Serviced response to server.
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "NOTIFY request from " + fromURI + " for a non-serviced domain responding with not found.", null));
                    SIPResponse notServicedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, "Domain not serviced");
                    m_sipTransport.SendResponse(notServicedResponse);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPNotifyManager ProcessNotifyRequest. " + excp.Message);
            }
        }
            private SIPRequest GetDummyINVITERequest(SIPURI dummyURI)
            {
                string dummyFrom = "<sip:[email protected]>";
                string dummyContact = "sip:127.0.0.1:1234";
                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 = SIPContactHeader.ParseContactHeader(dummyContact);
                inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
                inviteHeader.UserAgent = "unittest";
                inviteRequest.Header = inviteHeader;

                SIPViaHeader viaHeader = new SIPViaHeader("127.0.0.1", 1234, CallProperties.CreateBranchId(), SIPProtocolsEnum.udp);
                inviteRequest.Header.Vias.PushViaHeader(viaHeader);

                inviteRequest.Body = "dummy";
                inviteRequest.Header.ContentLength = inviteRequest.Body.Length;
                inviteRequest.Header.ContentType = "application/sdp";

                return inviteRequest;
            }
        /// <summary>
        /// Used to send a SIP request received from an external user agent to an internal SIP server agent.
        /// </summary>
        /// <param name="receivedFromEP">The SIP end point the proxy received the request from.</param>
        /// <param name="receivedOnEP">The SIP end point the proxy received the request on.</param>
        /// <param name="dstSocket">The internal socket to send the request to.</param>
        /// <param name="sipRequest">The SIP request to send.</param>
        /// <param name="proxyBranch">The branch to set on the Via header when sending the request. The branch should be calculated
        /// by the proxy core so that looped requests can be detected.</param>
        /// <param name="sendFromSocket">The proxy socket to send the request from.</param>
        public void SendInternal(SIPEndPoint receivedFromEP, SIPEndPoint receivedOnEP, string dstSocket, SIPRequest sipRequest, string proxyBranch, string sendFromSocket)
        {
            try
            {
                if (!IsDestinationValid(sipRequest, dstSocket))
                {
                    logger.Debug("SendInternal failed destination check.");
                    return;
                }

                sipRequest.Header.ProxyReceivedFrom = receivedFromEP.ToString();
                sipRequest.Header.ProxyReceivedOn = receivedOnEP.ToString();

                SIPEndPoint dstSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(dstSocket);
                SIPEndPoint localSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(sendFromSocket);

                if (receivedOnEP != localSIPEndPoint)
                {
                    // The proxy is being requested to send the request on a different socket to the one it was received on.
                    // A second Via header is added to ensure the response can navigate back the same path. The calculated branch
                    // parameter needs to go on the top Via header so that whichever internal socket the request is being sent to can
                    // determine re-transmits.
                    SIPViaHeader via = new SIPViaHeader(receivedOnEP, CallProperties.CreateBranchId());
                    sipRequest.Header.Vias.PushViaHeader(via);

                    SIPViaHeader topVia = new SIPViaHeader(localSIPEndPoint, proxyBranch);
                    sipRequest.Header.Vias.PushViaHeader(topVia);
                }
                else
                {
                    // Only a single Via header is required as any response to this request will be sent from the same socket it gets received on.
                    SIPViaHeader via = new SIPViaHeader(localSIPEndPoint, proxyBranch);
                    sipRequest.Header.Vias.PushViaHeader(via);
                }

                sipRequest.LocalSIPEndPoint = localSIPEndPoint;

                m_sipTransport.SendRequest(dstSIPEndPoint, sipRequest);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPRequest SendInternal. " + excp.Message);
                logger.Error(sipRequest.ToString());
                throw;
            }
        }
        private SIPRequest GetByeRequest(SIPResponse inviteResponse, SIPURI byeURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, byeURI);
            byeRequest.LocalSIPEndPoint = 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;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            byeRequest.Header.Vias.PushViaHeader(viaHeader);

            return byeRequest;
        }
        /// <summary>
        /// Forwards a SIP request through the Proxy. This method differs from the standard Send in that irrespective of whether the Proxy is
        /// receiving and sending on different sockets only a single Via header will ever be allowed on the request. It is then up to the
        /// response processing logic to determine from which Proxy socket to forward the request and to add back on the Via header for the 
        /// end agent. This method is only ever used for requests destined for EXTERNAL SIP end points. 
        /// </summary>
        /// <param name="dstSIPEndPoint">The destination SIP socket to send the request to.</param>
        /// <param name="sipRequest">The SIP request to send.</param>
        /// default channel that matches the destination end point should be used.</param>
        public void SendTransparent(SIPEndPoint dstSIPEndPoint, SIPRequest sipRequest, IPAddress publicIPAddress)
        {
            try
            {
                if (!IsDestinationValid(sipRequest, dstSIPEndPoint))
                {
                    logger.Debug("SendTransparent failed destination check.");
                    return;
                }

                // Determine the external SIP endpoint that the proxy will use to send this request.
                SIPEndPoint localSIPEndPoint = null;
                if (!sipRequest.Header.ProxySendFrom.IsNullOrBlank())
                {
                    SIPChannel proxyChannel = m_sipTransport.FindSIPChannel(SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxySendFrom));
                    localSIPEndPoint = (proxyChannel != null) ? proxyChannel.SIPChannelEndPoint : null;
                }
                localSIPEndPoint = localSIPEndPoint ?? m_sipTransport.GetDefaultSIPEndPoint(dstSIPEndPoint);

                // Create the single Via header for the outgoing request. It uses the passed in branchid which has been taken from the
                // request that's being forwarded. If this proxy is behind a NAT and the public IP is known that's also set on the Via.
                string proxyBranch = sipRequest.Header.Vias.PopTopViaHeader().Branch;
                sipRequest.Header.Vias = new SIPViaSet();
                SIPViaHeader via = new SIPViaHeader(localSIPEndPoint, proxyBranch);
                if (publicIPAddress != null)
                {
                    via.Host = publicIPAddress.ToString();
                }
                sipRequest.Header.Vias.PushViaHeader(via);

                if (sipRequest.Method != SIPMethodsEnum.REGISTER)
                {
                    AdjustContactHeader(sipRequest.Header, localSIPEndPoint, publicIPAddress);
                }

                // If dispatcher is being used record the transaction so responses are sent to the correct internal socket.
                if (m_dispatcher != null && sipRequest.Method != SIPMethodsEnum.REGISTER && sipRequest.Method != SIPMethodsEnum.ACK && sipRequest.Method != SIPMethodsEnum.NOTIFY)
                {
                    //Log("RecordDispatch for " + sipRequest.Method + " " + sipRequest.URI.ToString() + " to " + sipRequest.RemoteSIPEndPoint.ToString() + ".");
                    m_dispatcher.RecordDispatch(sipRequest, sipRequest.RemoteSIPEndPoint);
                }

                // Proxy sepecific headers that don't need to be seen by external UAs.
                sipRequest.Header.ProxyReceivedOn = null;
                sipRequest.Header.ProxyReceivedFrom = null;
                sipRequest.Header.ProxySendFrom = null;

                sipRequest.LocalSIPEndPoint = localSIPEndPoint;
                m_sipTransport.SendRequest(dstSIPEndPoint, sipRequest);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SendTransparent. " + excp.Message);
                logger.Error(sipRequest.ToString());
                throw;
            }
        }
        //private void ByeFinalResponseReceived(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        //{
        //    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "BYE response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + ".", Owner));
        //}
        private SIPRequest GetInviteRequest(SIPCallDescriptor sipCallDescriptor, string branchId, string callId, SIPEndPoint localSIPEndPoint, SIPRouteSet routeSet, string content, string contentType)
        {
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, sipCallDescriptor.Uri);
            inviteRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader inviteHeader = new SIPHeader(sipCallDescriptor.GetFromHeader(), SIPToHeader.ParseToHeader(sipCallDescriptor.To), 1, callId);

            inviteHeader.From.FromTag = CallProperties.CreateNewTag();

            // For incoming calls forwarded via the dial plan the username needs to go into the Contact header.
            inviteHeader.Contact = new List<SIPContactHeader>() { new SIPContactHeader(null, new SIPURI(inviteRequest.URI.Scheme, localSIPEndPoint)) };
            inviteHeader.Contact[0].ContactURI.User = sipCallDescriptor.Username;
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteHeader.UserAgent = m_userAgent;
            inviteHeader.Routes = routeSet;
            inviteRequest.Header = inviteHeader;

            if (!sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
            {
                inviteHeader.ProxySendFrom = sipCallDescriptor.ProxySendFrom;
            }

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, branchId);
            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            inviteRequest.Body = content;
            inviteRequest.Header.ContentLength = (inviteRequest.Body != null) ? inviteRequest.Body.Length : 0;
            inviteRequest.Header.ContentType = contentType;

            // Add custom switchboard headers.
            if (CallDescriptor.SwitchboardHeaders != null)
            {
                inviteHeader.SwitchboardOriginalCallID = CallDescriptor.SwitchboardHeaders.SwitchboardOriginalCallID;
                //inviteHeader.SwitchboardCallerDescription = CallDescriptor.SwitchboardHeaders.SwitchboardCallerDescription;
                inviteHeader.SwitchboardLineName = CallDescriptor.SwitchboardHeaders.SwitchboardLineName;
                //inviteHeader.SwitchboardOwner = CallDescriptor.SwitchboardHeaders.SwitchboardOwner;
                //inviteHeader.SwitchboardOriginalFrom = CallDescriptor.SwitchboardHeaders.SwitchboardOriginalFrom;
            }

            // Add custom CRM headers.
            if (CallDescriptor.CRMHeaders != null)
            {
                inviteHeader.CRMPersonName = CallDescriptor.CRMHeaders.PersonName;
                inviteHeader.CRMCompanyName = CallDescriptor.CRMHeaders.CompanyName;
                inviteHeader.CRMPictureURL = CallDescriptor.CRMHeaders.AvatarURL;
            }

            try
            {
                if (sipCallDescriptor.CustomHeaders != null && sipCallDescriptor.CustomHeaders.Count > 0)
                {
                    foreach (string customHeader in sipCallDescriptor.CustomHeaders)
                    {
                        if (customHeader.IsNullOrBlank())
                        {
                            continue;
                        }
                        else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
                        {
                            inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
                        }
                        else
                        {
                            inviteRequest.Header.UnknownHeaders.Add(customHeader);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception Parsing CustomHeader for GetInviteRequest. " + excp.Message + sipCallDescriptor.CustomHeaders);
            }

            return inviteRequest;
        }
            private SIPRequest GetOptionsRequest(SIPURI serverURI, int cseq, IPEndPoint contact)
            {
                SIPRequest optionsRequest = new SIPRequest(SIPMethodsEnum.OPTIONS, serverURI);

                SIPFromHeader fromHeader = new SIPFromHeader(null, SIPURI.ParseSIPURI("sip:" + contact.ToString()), null);
                SIPToHeader toHeader = new SIPToHeader(null, serverURI, null);

                string callId = CallProperties.CreateNewCallId();
                string branchId = CallProperties.CreateBranchId();

                SIPHeader header = new SIPHeader(fromHeader, toHeader, cseq, callId);
                header.CSeqMethod = SIPMethodsEnum.OPTIONS;
                header.MaxForwards = 0;

                SIPViaHeader viaHeader = new SIPViaHeader(contact.Address.ToString(), contact.Port, branchId);
                header.Vias.PushViaHeader(viaHeader);

                optionsRequest.Header = header;

                return optionsRequest;
            }
        private SIPRequest GetUpdateRequest(SIPRequest inviteRequest, CRMHeaders crmHeaders)
        {
            SIPRequest updateRequest = new SIPRequest(SIPMethodsEnum.UPDATE, inviteRequest.URI);
            updateRequest.LocalSIPEndPoint = inviteRequest.LocalSIPEndPoint;

            SIPHeader inviteHeader = inviteRequest.Header;
            SIPHeader updateHeader = new SIPHeader(inviteHeader.From, inviteHeader.To, inviteHeader.CSeq + 1, inviteHeader.CallId);
            inviteRequest.Header.CSeq++;
            updateRequest.Header = updateHeader;
            updateHeader.CSeqMethod = SIPMethodsEnum.UPDATE;
            updateHeader.Routes = inviteHeader.Routes;
            updateHeader.ProxySendFrom = inviteHeader.ProxySendFrom;

            SIPViaHeader viaHeader = new SIPViaHeader(inviteRequest.LocalSIPEndPoint, CallProperties.CreateBranchId());
            updateHeader.Vias.PushViaHeader(viaHeader);

            // Add custom CRM headers.
            if (crmHeaders != null)
            {
                updateHeader.CRMPersonName = crmHeaders.PersonName;
                updateHeader.CRMCompanyName = crmHeaders.CompanyName;
                updateHeader.CRMPictureURL = crmHeaders.AvatarURL;
            }

            return updateRequest;
        }
        /// <summary>
        /// In transaction ACK requests are for non-2xx responses, i.e. INVITE rejected and no dialogue being created.
        /// </summary>
        private SIPRequest GetInTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());
            ackRequest.LocalSIPEndPoint = 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;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, sipResponse.Header.Vias.TopViaHeader.Branch);
            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return ackRequest;
        }
        private SIPRequest GetRegistrationRequest(SIPProvider sipProvider, SIPProviderBinding binding, SIPEndPoint localSIPEndPoint, int expiry, SIPEndPoint registrarEndPoint)
        {
            try
            {
                if (!binding.BindingSIPURI.Parameters.Has(m_regAgentContactId))
                {
                    binding.BindingSIPURI.Parameters.Set(m_regAgentContactId, Crypto.GetRandomString(6));
                }

                string realm = binding.RegistrarRealm;

                SIPURI registerURI = SIPURI.ParseSIPURIRelaxed(realm);
                SIPURI regUserURI = SIPURI.ParseSIPURIRelaxed(sipProvider.ProviderUsername + "@" + realm);

                SIPFromHeader fromHeader = new SIPFromHeader(null, regUserURI, CallProperties.CreateNewTag());
                SIPToHeader toHeader = new SIPToHeader(null, regUserURI, null);
                SIPContactHeader contactHeader = new SIPContactHeader(null, binding.BindingSIPURI);
                //contactHeader.Expires = binding.BindingExpiry;
                string callId = binding.Id.ToString();
                int cseq = ++binding.CSeq;

                SIPRequest registerRequest = new SIPRequest(SIPMethodsEnum.REGISTER, registerURI);
                registerRequest.LocalSIPEndPoint = localSIPEndPoint;
                SIPHeader header = new SIPHeader(contactHeader, fromHeader, toHeader, cseq, callId);
                header.CSeqMethod = SIPMethodsEnum.REGISTER;
                header.UserAgent = m_userAgentString;
                header.Expires = binding.BindingExpiry;

                SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
                header.Vias.PushViaHeader(viaHeader);

                SIPRoute registrarRoute = new SIPRoute(new SIPURI(binding.RegistrarServer.Scheme, registrarEndPoint), true);
                header.Routes.PushRoute(registrarRoute);

                if (sipProvider != null && !sipProvider.CustomHeaders.IsNullOrBlank())
                {
                    string[] customerHeadersList = sipProvider.CustomHeaders.Split(SIPProvider.CUSTOM_HEADERS_SEPARATOR);

                    if (customerHeadersList != null && customerHeadersList.Length > 0)
                    {
                        foreach (string customHeader in customerHeadersList)
                        {
                            if (customHeader.IndexOf(':') == -1)
                            {
                                logger.Debug("Skipping custom header due to missing colon, " + customHeader + ".");
                                continue;
                            }
                            else
                            {
                                string headerName = customHeader.Substring(0, customHeader.IndexOf(':'));
                                if (headerName != null && Regex.Match(headerName.Trim(), "(Via|From|To|Contact|CSeq|Call-ID|Max-Forwards|Content)", RegexOptions.IgnoreCase).Success)
                                {
                                    logger.Debug("Skipping custom header due to an non-permitted string in header name, " + customHeader + ".");
                                    continue;
                                }
                                else
                                {
                                    if (headerName == SIPConstants.SIP_USERAGENT_STRING)
                                    {
                                        header.UserAgent = customHeader.Substring(customHeader.IndexOf(':') + 1);
                                    }
                                    else
                                    {
                                        header.UnknownHeaders.Add(customHeader.Trim());
                                    }
                                }
                            }
                        }
                    }
                }

                registerRequest.Header = header;
                return registerRequest;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetRegistrationRequest. " + excp.Message);
                throw excp;
            }
        }
Beispiel #22
0
        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 void MultipleForwardsWithLocalUnitTest()
            {
                Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);

                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI("sip:1234@localhost"));
                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader("<sip:joe@localhost>"), SIPToHeader.ParseToHeader("<sip:jane@localhost>"), 23, CallProperties.CreateNewCallId());
                SIPViaHeader viaHeader = new SIPViaHeader("127.0.0.1", 5060, CallProperties.CreateBranchId());
                inviteHeader.Vias.PushViaHeader(viaHeader);
                inviteRequest.Header = inviteHeader;

                List<SIPProvider> providers = new List<SIPProvider>();
                SIPProvider provider = new SIPProvider("test", "provider1", "user", "password", SIPURI.ParseSIPURIRelaxed("sip.blueface.ie"), null, null, null, null, 3600, null, null, null, false, false);
                SIPProvider provider2 = new SIPProvider("test", "provider2", "user", "password", SIPURI.ParseSIPURIRelaxed("sip.blueface.ie"), null, null, null, null, 3600, null, null, null, false, false);
                providers.Add(provider);
                providers.Add(provider2);

                DialStringParser dialStringParser = new DialStringParser(null, "test", null, providers, (where) => { return null; }, (where, offset, count, orderby) => { return null; }, (host, wildcard) => { return null; }, null);
                Queue<List<SIPCallDescriptor>> callQueue = dialStringParser.ParseDialString(DialPlanContextsEnum.Script, inviteRequest, "local&1234@provider2", null, null, null, null, null);

                Assert.IsNotNull(callQueue, "The call list should have contained a call.");
                Assert.IsTrue(callQueue.Count == 1, "The call queue list should have contained one leg.");

                List<SIPCallDescriptor> firstLeg = callQueue.Dequeue();

                Assert.IsNotNull(firstLeg, "The first call leg should exist.");
                Assert.IsTrue(firstLeg.Count == 2, "The first call leg should have had two switch calls.");

                Console.WriteLine("First destination uri=" + firstLeg[0].Uri.ToString());
                Console.WriteLine("Second destination uri=" + firstLeg[1].Uri.ToString());

                Console.WriteLine("---------------------------------");
            }
 /// <summary>
 /// Pushes a new Via header onto the top of the array.
 /// </summary>
 public void PushViaHeader(SIPViaHeader viaHeader)
 {
     m_viaHeaders.Insert(0, viaHeader);
 }
            public void NoMatchingProviderUnitTest()
            {
                Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);

                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI("sip:1234@localhost"));
                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader("<sip:joe@localhost>"), SIPToHeader.ParseToHeader("<sip:jane@localhost>"), 23, CallProperties.CreateNewCallId());
                SIPViaHeader viaHeader = new SIPViaHeader("127.0.0.1", 5060, CallProperties.CreateBranchId());
                inviteHeader.Vias.PushViaHeader(viaHeader);
                inviteRequest.Header = inviteHeader;

                List<SIPProvider> providers = new List<SIPProvider>();
                SIPProvider provider = new SIPProvider("test", "blueface", "test", "password", SIPURI.ParseSIPURIRelaxed("sip.blueface.ie"), null, null, null, null, 3600, null, null, null, false, false);
                providers.Add(provider);

                DialStringParser dialStringParser = new DialStringParser(null, "test", null, providers, delegate { return null; }, null, (host, wildcard) => { return null; }, null);
                Queue<List<SIPCallDescriptor>> callQueue = dialStringParser.ParseDialString(DialPlanContextsEnum.Script, inviteRequest, "303@noprovider", null, null, null, null, null);

                Assert.IsNotNull(callQueue, "The call list should be returned.");
                Assert.IsTrue(callQueue.Count == 1, "The call queue list should not have contained one leg.");
                List<SIPCallDescriptor> firstLeg = callQueue.Dequeue();

                Assert.IsNotNull(firstLeg, "The first call leg should exist.");
                Assert.IsTrue(firstLeg.Count == 1, "The first call leg should have had one switch call.");
                Assert.IsTrue(firstLeg[0].Username == DialStringParser.m_anonymousUsername, "The username for the first call leg was not correct.");
                Assert.IsTrue(firstLeg[0].Uri.ToString() == "sip:303@noprovider", "The destination URI for the first call leg was not correct.");

                Console.WriteLine("---------------------------------");
            }
            public void CreateNewViaHeaderTest()
            {
                Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);

                SIPViaHeader viaHeader = new SIPViaHeader("192.168.1.2", 5063, "abcdefgh");

                Assert.IsTrue(viaHeader.Host == "192.168.1.2", "Incorrect Host for Via header.");
                Assert.IsTrue(viaHeader.Port == 5063, "Incorrect Port for Via header.");
                Assert.IsTrue(viaHeader.Branch == "abcdefgh", "Incorrect Branch for Via header.");

                Console.WriteLine("---------------------------------------------------");
            }
        private SIPRequest GetReferRequest(SIPEndPoint localSIPEndPoint, SIPURI referTo)
        {
            SIPRequest referRequest = new SIPRequest(SIPMethodsEnum.REFER, RemoteTarget);
            SIPFromHeader referFromHeader = SIPFromHeader.ParseFromHeader(LocalUserField.ToString());
            SIPToHeader referToHeader = SIPToHeader.ParseToHeader(RemoteUserField.ToString());
            int cseq = ++CSeq;

            SIPHeader referHeader = new SIPHeader(referFromHeader, referToHeader, cseq, CallId);
            referHeader.CSeqMethod = SIPMethodsEnum.REFER;
            referRequest.Header = referHeader;
            referRequest.Header.ReferTo = referTo.ToString();
            referRequest.Header.Routes = RouteSet;
            referRequest.Header.ProxySendFrom = ProxySendFrom;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            referRequest.Header.Vias.PushViaHeader(viaHeader);

            return referRequest;
        }