Beispiel #1
0
 /// <summary>
 /// Defualt constructor.
 /// </summary>
 public SIP_t_ViaParm()
 {
     m_ProtocolName      = "SIP";
     m_ProtocolVersion   = "2.0";
     m_ProtocolTransport = "UDP";
     m_pSentBy           = new HostEndPoint("localhost",-1);
 }
        /// <summary>
        /// Sends request to the specified flow.
        /// </summary>
        /// <param name="flow">Data flow.</param>
        /// <param name="request">SIP request.</param>
        /// <param name="transaction">Owner client transaction or null if stateless sending.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments contains invalid value.</exception>
        internal void SendRequest(SIP_Flow flow,SIP_Request request,SIP_ClientTransaction transaction)
        {
            if(m_IsDisposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if(flow == null){
                throw new ArgumentNullException("flow");
            }
            if(request == null){
                throw new ArgumentNullException("request");
            }
            if(request.Via.GetTopMostValue() == null){
                throw new ArgumentException("Argument 'request' doesn't contain required Via: header field.");
            }

            // Set sent-by
            SIP_t_ViaParm via = request.Via.GetTopMostValue();
            via.ProtocolTransport = flow.Transport;
            // Via sent-by is used only to send responses when request maker data flow is not active.
            // Normally this never used, so just report first local listening point as sent-by.
            HostEndPoint sentBy = null;
            foreach(IPBindInfo bind in this.BindInfo){
                if(flow.Transport == SIP_Transport.UDP && bind.Protocol == BindInfoProtocol.UDP){
                    if(!string.IsNullOrEmpty(bind.HostName)){
                        sentBy = new HostEndPoint(bind.HostName,bind.Port);
                    }
                    else{
                        sentBy = new HostEndPoint(flow.LocalEP.Address.ToString(),bind.Port);
                    }
                    break;
                }
                else if(flow.Transport == SIP_Transport.TLS && bind.Protocol == BindInfoProtocol.TCP && bind.SslMode == SslMode.SSL){
                    if(!string.IsNullOrEmpty(bind.HostName)){
                        sentBy = new HostEndPoint(bind.HostName,bind.Port);
                    }
                    else{
                        sentBy = new HostEndPoint(flow.LocalEP.Address.ToString(),bind.Port);
                    }
                    break;
                }
                else if(flow.Transport == SIP_Transport.TCP && bind.Protocol == BindInfoProtocol.TCP){
                    if(!string.IsNullOrEmpty(bind.HostName)){
                        sentBy = new HostEndPoint(bind.HostName,bind.Port);
                    }
                    else{
                        sentBy = new HostEndPoint(flow.LocalEP.Address.ToString(),bind.Port);
                    }
                    break;
                }
            }
            // No local end point for sent-by, just use flow local end point for it.
            if(sentBy == null){
                via.SentBy = new HostEndPoint(flow.LocalEP);
            }
            else{
                via.SentBy = sentBy;
            }

            // Send request.
            flow.Send(request);

            // Log.
            if(m_pStack.Logger != null){
                byte[] requestData = request.ToByteData();

                m_pStack.Logger.AddWrite(
                    Guid.NewGuid().ToString(),
                    null,
                    0,
                    "Request [" + (transaction == null ? "" : "transactionID='" + transaction.ID + "';") + "method='" + request.RequestLine.Method + "'; cseq='" + request.CSeq.SequenceNumber + "'; " +
                    "transport='" + flow.Transport + "'; size='" + requestData.Length + "'; sent '" + flow.LocalEP + "' -> '" + flow.RemoteEP + "'.",
                    flow.LocalEP,
                    flow.RemoteEP,
                    requestData
                );
            }
        }
        /// <summary>
        /// Gets contact URI <b>host</b> parameter suitable to the specified flow.
        /// </summary>
        /// <param name="flow">Data flow.</param>
        /// <returns>Returns contact URI <b>host</b> parameter suitable to the specified flow.</returns>
        internal HostEndPoint GetContactHost(SIP_Flow flow)
        {
            if(flow == null){
                throw new ArgumentNullException("flow");
            }

            HostEndPoint retVal = null;

            // Find suitable listening point for flow.
            foreach(IPBindInfo bind in this.BindInfo){
                if(bind.Protocol == BindInfoProtocol.UDP && flow.Transport == SIP_Transport.UDP){
                    // For UDP flow localEP is also listeining EP, so use it.
                    if(bind.IP.AddressFamily == flow.LocalEP.AddressFamily && bind.Port == flow.LocalEP.Port){
                        retVal = new HostEndPoint((string.IsNullOrEmpty(bind.HostName) ? flow.LocalEP.Address.ToString() : bind.HostName),bind.Port);
                        break;
                    }
                }
                else if(bind.Protocol == BindInfoProtocol.TCP && bind.SslMode == SslMode.SSL && flow.Transport == SIP_Transport.TLS){
                    // Just use first matching listening point.
                    //   TODO: Probably we should imporve it with load-balanched local end point.
                    if(bind.IP.AddressFamily == flow.LocalEP.AddressFamily){
                        if(bind.IP == IPAddress.Any || bind.IP == IPAddress.IPv6Any){
                            retVal = new HostEndPoint((string.IsNullOrEmpty(bind.HostName) ? flow.LocalEP.Address.ToString() : bind.HostName),bind.Port);
                        }
                        else{
                            retVal = new HostEndPoint((string.IsNullOrEmpty(bind.HostName) ? bind.IP.ToString() : bind.HostName),bind.Port);
                        }
                        break;
                    }
                }
                else if(bind.Protocol == BindInfoProtocol.TCP && flow.Transport == SIP_Transport.TCP){
                    // Just use first matching listening point.
                    //   TODO: Probably we should imporve it with load-balanched local end point.
                    if(bind.IP.AddressFamily == flow.LocalEP.AddressFamily){
                        if(bind.IP.Equals(IPAddress.Any) || bind.IP.Equals(IPAddress.IPv6Any)){
                            retVal = new HostEndPoint((string.IsNullOrEmpty(bind.HostName) ? flow.LocalEP.Address.ToString() : bind.HostName),bind.Port);
                        }
                        else{
                            retVal = new HostEndPoint((string.IsNullOrEmpty(bind.HostName) ? bind.IP.ToString() : bind.HostName),bind.Port);
                        }
                        break;
                    }
                }
            }

            // We don't have suitable listening point for active flow.
            // RFC 3261 forces to have, but for TCP based protocls + NAT, server can't connect to use anyway,
            // so just ignore it and report flow local EP.
            if(retVal == null){
                retVal = new HostEndPoint(flow.LocalEP);
            }

            // If flow remoteEP is public IP and our localEP is private IP, resolve localEP to public.
            if(retVal.IsIPAddress && Core.IsPrivateIP(IPAddress.Parse(retVal.Host)) && !Core.IsPrivateIP(flow.RemoteEP.Address)){
                retVal = new HostEndPoint(Resolve(flow));
            }

            return retVal;
        }