private ViaEntry(ViaEntry entry) { Protocol = entry.Protocol; SipVersion = entry.SipVersion; Transport = entry.Transport; Domain = entry.Domain; foreach (var pair in entry._parameters) _parameters.Add(pair.Key, pair.Value); }
private ViaEntry(ViaEntry entry) { Protocol = entry.Protocol; SipVersion = entry.SipVersion; Transport = entry.Transport; Domain = entry.Domain; foreach (var pair in entry._parameters) { _parameters.Add(pair.Key, pair.Value); } }
public static ViaEntry ParseEntry(ITextReader reader) { //SIP/2.0/UDP erlang.bell-telephone.com:5060;branch=z9hG4bK87asdks7 var entry = new ViaEntry(); // read SIP/ reader.ConsumeWhiteSpaces(); entry.Protocol = reader.ReadUntil("/ \t"); if (entry.Protocol == null) throw new FormatException("Expected Via header to start with 'SIP' or 'SIPS'."); reader.ConsumeWhiteSpaces('/'); // read 2.0/ entry.SipVersion = reader.ReadUntil("/ \t"); if (entry.SipVersion == null) throw new FormatException("Expected to find sip version in Via header."); reader.ConsumeWhiteSpaces('/'); // read UDP or TCP entry.Transport = reader.ReadWord(); if (entry.Transport == null) throw new FormatException("Expected to find transport protocol after sip version in Via header."); reader.ConsumeWhiteSpaces(); entry.Domain = reader.ReadUntil(";: \t"); if (entry.Domain == null) throw new FormatException("Failed to find domain in via header."); reader.ConsumeWhiteSpaces(); if (reader.Current == ':') { reader.Read(); reader.ConsumeWhiteSpaces(); string temp = reader.ReadToEnd("; \t"); reader.ConsumeWhiteSpaces(); int port; if (!int.TryParse(temp, out port)) throw new FormatException("Invalid port specified."); entry.Port = port; } UriParser.ParseParameters(entry.Parameters, reader); string rport = entry.Parameters["rport"]; if (!string.IsNullOrEmpty(rport)) //parameter can exist, but be empty. = rport requested. { int value; if (!int.TryParse(rport, out value)) throw new FormatException("RPORT is not a number."); entry.Rport = value; } return entry; }
/// <summary> /// Create a new request /// </summary> /// <param name="method">Sip method.</param> /// <param name="from">Who is dialing?</param> /// <param name="to">Destination</param> /// <returns>Request object.</returns> /// <seealso cref="SipMethod"/> public IRequest CreateRequest(string method, Contact from, Contact to) { // A valid SIP request formulated by a UAC MUST, at a minimum, contain // the following header fields: To, From, CSeq, Call-ID, Max-Forwards, // and Via; all of these header fields are mandatory in all SIP // requests. These six header fields are the fundamental building // blocks of a SIP message, as they jointly provide for most of the // critical message routing services including the addressing of // messages, the routing of responses, limiting message propagation, // ordering of messages, and the unique identification of transactions. // These header fields are in addition to the mandatory request line, // which contains the method, Request-URI, and SIP version. // The initial Request-URI of the message SHOULD be set to the value of // the URI in the To field. One notable exception is the REGISTER // method; behavior for setting the Request-URI of REGISTER is given in // Section 10. var request = new Request(method, from.Uri, "SIP/2.0"); request.From = from; // A request outside of a dialog MUST NOT contain a To tag; the tag in // the To field of a request identifies the peer of the dialog. Since // no dialog is established, no tag is present. // For further information on the To header field, see RFC 3261 Section 20.39. request.To = to; // The Call-ID header field acts as a unique identifier to group // together a series of messages. It MUST be the same for all requests // and responses sent by either UA in a dialog. It SHOULD be the same // in each registration from a UA. // In a new request created by a UAC outside of any dialog, the Call-ID // header field MUST be selected by the UAC as a globally unique // identifier over space and time unless overridden by method-specific // behavior. All SIP UAs must have a means to guarantee that the Call- // ID header fields they produce will not be inadvertently generated by // any other UA. request.CallId = CreateCallId(); // The CSeq header field serves as a way to identify and order // transactions. It consists of a sequence number and a method. The // method MUST match that of the request. For non-REGISTER requests // outside of a dialog, the sequence number value is arbitrary. The // sequence number value MUST be expressible as a 32-bit unsigned // integer and MUST be less than 2**31. As long as it follows the above // guidelines, a client may use any mechanism it would like to select // CSeq header field values. request.CSeq = new CSeq(GetNextSequenceNumber(), method); request.MaxForwards = 70; // When the UAC creates a request, it MUST insert a Via into that // request. The protocol name and protocol version in the header field // MUST be SIP and 2.0, respectively. The Via header field value MUST // contain a branch parameter. This parameter is used to identify the // transaction created by that request. This parameter is used by both // the client and the server. // // The branch parameter value MUST be unique across space and time for // all requests sent by the UA. The exceptions to this rule are CANCEL // and ACK for non-2xx responses. As discussed below, a CANCEL request // will have the same value of the branch parameter as the request it // cancels. As discussed in Section 17.1.1.3, an ACK for a non-2xx // response will also have the same branch ID as the INVITE whose // response it acknowledges. // // The uniqueness property of the branch ID parameter, to facilitate // its use as a transaction ID, was not part of RFC 2543. // // The branch ID inserted by an element compliant with this // specification MUST always begin with the characters "z9hG4bK". These // 7 characters are used as a magic cookie (7 is deemed sufficient to // ensure that an older RFC 2543 implementation would not pick such a // value), so that servers receiving the request can determine // specification (that is, globally unique). Beyond this requirement, // the precise format of the branch token is implementation-defined. // // The Via header maddr, ttl, and sent-by components will be set when // the request is processed by the transport layer (Section 18). // // Via processing for proxies is described in Section 16.6 Item 8 and // Section 16.7 Item 3. var viaEntry = new ViaEntry(_endPoint.Address.ToString(), CreateBranch()); viaEntry.RportWanted = true; request.Via.Add(viaEntry); // The Contact header field provides a SIP or SIPS URI that can be used // to contact that specific instance of the UA for subsequent requests. // The Contact header field MUST be present and contain exactly one SIP // or SIPS URI in any request that can result in the establishment of a // dialog. For the methods defined in this specification, that includes // only the INVITE request. For these requests, the scope of the // Contact is global. That is, the Contact header field value contains // the URI at which the UA would like to receive requests, and this URI // MUST be valid even if used in subsequent requests outside of any // dialogs. // // If the Request-URI or top Route header field value contains a SIPS // URI, the Contact header field MUST contain a SIPS URI as well. request.Contact = _contact; return request; }