/// <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; }