private SipContactValue clientLocalContact; // Contact header for messages to the client /// <summary> /// Constructor. /// </summary> /// <param name="id">The process local unique session ID.</param> /// <param name="clientDialog">The upstream client <see cref="SipDialog" />.</param> /// <param name="defLocalContact">The default local contact for the session.</param> public SipB2BUASession(long id, SipB2BUADialog <TState> clientDialog, SipContactValue defLocalContact) { this.id = id; this.clientDialog = clientDialog; this.serverLocalContact = defLocalContact; this.clientLocalContact = defLocalContact; }
/// <summary> /// Initializes a <see cref="SipDialog" /> instance. /// </summary> /// <param name="core">The <see cref="SipCore" /> that owns this dialog.</param> /// <param name="inviteRequest">The INVITE <see cref="SipRequest" /> received by the accepting dialog or being sent by the initiating dialog.</param> /// <param name="localContact">The <see cref="SipContactValue" /> for the local side of the dialog.</param> /// <param name="acceptingTransaction"> /// The initial transaction for INVITE requests received by accepting dialogs or <c>null</c> for /// initiating dialogs. /// </param> /// <param name="state">Derived class specific state (or <c>null</c>).</param> /// <remarks> /// <para> /// Derived classes can override this method to intialize any internal state using information /// from the derived class specific <paramref name="state" /> parameter. /// </para> /// <para> /// For accepting dialog requests, this method expects the <paramref name="inviteRequest" /> to already /// have reasonable <b>Call-ID</b>, <b>To</b>, <b>From</b>, and <b>CSeq</b> headers and the /// <b>From</b> header must have a <b>tag</b> parameter. /// </para> /// <para> /// For initiating dialog requests,this method expects the <paramref name="inviteRequest" /> to already /// have reasonable <b>To</b>, <b>From</b> and headers but the method will generate and assign /// the <b>From</b> header's <b>tag</b> parameter. The method will set a <b>Call-ID</b> header /// if necessary and will always set a new <b>CSeq</b> header. /// </para> /// <para> /// <paramref name="acceptingTransaction"/> must be passed as the server transaction the INVITE /// was received on for accepting dialogs. This will be passed as <c>null</c> for initiating /// dialogs (note that the <see cref="SipClientAgent" /> will eventually set the <see cref="SipDialog.InitiatingTransaction" /> /// property to the initial <see cref="SipClientTransaction" /> just before the transaction /// is started). /// </para> /// <note> /// The derived class MUST call the base <see cref="Initialize" /> method passing the parameters /// before returning. /// </note> /// </remarks> public override void Initialize(SipCore core, SipRequest inviteRequest, SipContactValue localContact, SipServerTransaction acceptingTransaction, object state) { base.Initialize(core, inviteRequest, localContact, acceptingTransaction, state); // $hack(jeff.lill): // // This is a bit of a hack that initializes the downstream dialog to the // server's Session property and also initializes the session's ServerDialog // property. I'm relying on the fact that state is passed as non-null // only when the B2BUA creates the downstream dialog. SipB2BUASession <TState> session = state as SipB2BUASession <TState>; if (session != null) { this.session = session; session.ServerDialog = this; } }
/// <summary> /// Converts a contact style header value into the <see cref="NetworkBinding" /> /// and optional <see cref="SipTransportType" /> to be used when figuring out /// how to deliver an outbound SIP message. /// </summary> /// <param name="contactText">The <b>Contact</b> header text.</param> /// <param name="binding">Returns as the <see cref="NetworkBinding" /> to use.</param> /// <param name="transportType">Returns the <see cref="SipTransportType" /> to use</param> /// <returns></returns> /// <remarks> /// <para> /// The <paramref name="contactText" /> parameter should be passed as the SIP request URI, /// or the value of a <b>To</b>, <b>From</b>, or a <b>Contact</b> header value. The method /// parses this value, looking for the IP address, port, and transport information to be used /// when selecting a transport to communicate with this entity. The method will perform an /// necessary DNS lookups to resolve host names into IP addresses. /// </para> /// <para> /// If the operation was successful, the method returns <c>true</c> and sets the <paramref name="binding" /> /// and <paramref name="transportType" /> values. /// </para> /// <note> /// <paramref name="transportType" /> will return as <see cref="SipTransportType.Unspecified" /> if the /// contact information didn't explicitly specify a transport. /// </note> /// </remarks> public static bool TryGetRemoteBinding(string contactText, out NetworkBinding binding, out SipTransportType transportType) { SipContactValue v = new SipContactValue(contactText); IPAddress address; int port; SipUri uri; string transport; string sHost, sPort; int p; binding = null; transportType = SipTransportType.Unspecified; // First try to parse the text as a SIP URI. if (SipUri.TryParse(v.Uri, out uri)) { if (!IPAddress.TryParse(uri.Host, out address)) { try { address = Dns.GetHostEntry(uri.Host).AddressList[0]; } catch { return(false); } } binding = new NetworkBinding(address, uri.Port); if (uri.Parameters.TryGetValue("transport", out transport)) { switch (transport.ToUpper()) { case "UDP": transportType = SipTransportType.UDP; break; case "TCP": transportType = SipTransportType.TCP; break; case "TLS": transportType = SipTransportType.TLS; break; } } return(true); } // Now look for <ip-address> [":" <port>] p = v.Uri.IndexOf(':'); if (p == -1) { if (!IPAddress.TryParse(v.Uri, out address)) { try { address = Dns.GetHostEntry(v.Uri).AddressList.IPv4Only()[0]; } catch { return(false); } } binding = new NetworkBinding(address, NetworkPort.SIP); return(true); } sHost = v.Uri.Substring(0, p).Trim(); sPort = v.Uri.Substring(p + 1).Trim(); if (sHost.Length == 0 || sPort.Length == 0) { return(false); } if (!int.TryParse(sPort, out port) || port <= 0 || port > ushort.MaxValue) { return(false); } if (IPAddress.TryParse(sHost, out address)) { binding = new NetworkBinding(address, port); return(true); } // The host portion is not an IP address so perform a host lookup if (!IPAddress.TryParse(sHost, out address)) { try { address = Dns.GetHostEntry(sHost).AddressList.IPv4Only()[0]; } catch { return(false); } } binding = new NetworkBinding(address, port); return(true); }