/// <summary> /// Create a request /// </summary> /// <remarks> /// <para> /// 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. /// <para></para> /// Examples of requests sent outside of a dialog include an INVITE to /// establish a session (RFC3261 - Section 13) and an OPTIONS to query for /// capabilities (RFC3261 - Section 11). /// </para> /// <para> /// Read section 8.1.1 in RFC3261 for more information /// </para> /// </remarks> private IRequest CreateRequest(string method, Contact from, Contact to) { Request request = new Request(method, to.Uri, "SIP/2.0"); request.To = to; request.From = from; request.From.Parameters["tag"] = CreateRandomString(8); request.CallId = method == SipMethod.REGISTER ? _registerCallId : CreateRandomString(); request.CSeq = new CSeq(GetNextSequenceNumber(), method); request.MaxForwards = 70; request.Contact = _contact; if (_defaultRoute != null && _defaultRoute.Items.Count > 0) request.Headers.Add(Route.ROUTE_NAME, (IHeader)_defaultRoute.Clone()); return request; }
/// <summary> /// Create a new request within this dialog. /// </summary> /// <returns>Created request.</returns> /// <remarks> /// <para>Described in RFC3261 Section 12.2.1.1 "Generating the Request".</para> /// </remarks> public IRequest CreateRequest(string method) { // The URI in the To field of the request MUST be set to the remote URI // from the dialog state. The tag in the To header field of the request // MUST be set to the remote tag of the dialog ID. The From URI of the // request MUST be set to the local URI from the dialog state. The tag // in the From header field of the request MUST be set to the local tag // of the dialog ID. If the value of the remote or local tags is null, // the tag parameter MUST be omitted from the To or From header fields, // respectively. // Usage of the URI from the To and From fields in the original // request within subsequent requests is done for backwards // compatibility with RFC 2543, which used the URI for dialog // identification. In this specification, only the tags are used for // dialog identification. It is expected that mandatory reflection // of the original To and From URI in mid-dialog requests will be // deprecated in a subsequent revision of this specification. var request = new Request(method, RemoteUri, "SIP/2.0"); request.To.Uri = RemoteUri; request.To.Parameters["tag"] = RemoteTag; request.From.Uri = LocalUri; request.From.Parameters["tag"] = LocalTag; // The Call-ID of the request MUST be set to the Call-ID of the dialog. // Requests within a dialog MUST contain strictly monotonically // increasing and contiguous CSeq sequence numbers (increasing-by-one) // in each direction (excepting ACK and CANCEL of course, whose numbers // equal the requests being acknowledged or cancelled). Therefore, if // the local sequence number is not empty, the value of the local // sequence number MUST be incremented by one, and this value MUST be // placed into the CSeq header field. If the local sequence number is // empty, an initial value MUST be chosen using the guidelines of // Section 8.1.1.5. The method field in the CSeq header field value // MUST match the method of the request. // With a length of 32 bits, a client could generate, within a single // call, one request a second for about 136 years before needing to // wrap around. The initial value of the sequence number is chosen // so that subsequent requests within the same call will not wrap // around. A non-zero initial value allows clients to use a time- // based initial sequence number. A client could, for example, // choose the 31 most significant bits of a 32-bit second clock as an // initial sequence number. request.CallId = CallId; if (LocalSequenceNumber > 0) { LocalSequenceNumber += 1; request.CSeq.Method = method; request.CSeq.Number = LocalSequenceNumber; } // The UAC uses the remote target and route set to build the Request-URI // and Route header field of the request. // If the route set is empty, the UAC MUST place the remote target URI // into the Request-URI. The UAC MUST NOT add a Route header field to // the request. if (RouteSet.Items.Count > 0) { // If the route set is not empty, and the first URI in the route set // contains the lr parameter (see Section 19.1.1), the UAC MUST place // the remote target URI into the Request-URI and MUST include a Route // header field containing the route set values in order, including all // parameters. if (RouteSet.First.IsLoose) { request.Uri = RemoteTarget.FirstContact.Uri; request.Headers[Route.ROUTE_NAME] = RouteSet; } // If the route set is not empty, and its first URI does not contain the // lr parameter, the UAC MUST place the first URI from the route set // into the Request-URI, stripping any parameters that are not allowed // in a Request-URI. The UAC MUST add a Route header field containing // the remainder of the route set values in order, including all // parameters. The UAC MUST then place the remote target URI into the // Route header field as the last value. else { request.Uri = RouteSet.First.Uri; // not cloning since same routing will always be used. request.Uri.Parameters.Remove("method"); var route = new Route(Route.ROUTE_NAME); request.Headers.Add(Route.ROUTE_NAME, route); for (int i = 1; i < RouteSet.Items.Count; ++i) route.Items.Add(RouteSet.Items[i]); route.Items.Add(new RouteEntry {Uri = RemoteTarget.FirstContact.Uri}); } } // A UAC SHOULD include a Contact header field in any target refresh // requests within a dialog, and unless there is a need to change it, // the URI SHOULD be the same as used in previous requests within the // dialog. If the "secure" flag is true, that URI MUST be a SIPS URI. // As discussed in Section 12.2.2, a Contact header field in a target // refresh request updates the remote target URI. This allows a UA to // provide a new contact address, should its address change during the // duration of the dialog. //request.Contact = Local // However, requests that are not target refresh requests do not affect // the remote target URI for the dialog. // The rest of the request is formed as described in Section 8.1.1. // Once the request has been constructed, the address of the server is // computed and the request is sent, using the same procedures for // requests outside of a dialog (Section 8.1.2). // The procedures in Section 8.1.2 will normally result in the // request being sent to the address indicated by the topmost Route // header field value or the Request-URI if no Route header field is // present. Subject to certain restrictions, they allow the request // to be sent to an alternate address (such as a default outbound // proxy not represented in the route set). return request; }