RFC 3841

Caller Preferences for the Session Initiation Protocol (SIP)

๐Ÿ“… published August 2004, from ietf

RFC 3841: Caller Preferences for the Session Initiation Protocol (SIP) ๐Ÿ’–

okay bestie, this is the RFC that lets the caller have a say in how their call gets routed ๐Ÿ“žโœจ it's a Standards Track spec from August 2004, written by three people: J. Rosenberg (dynamicsoft), H. Schulzrinne (Columbia University), and P. Kyzivat (Cisco Systems). it doesn't list anything it obsoletes or updates in its header, so it's standing on its own ๐Ÿฆ‹

  • RFC number: 3841
  • Title: Caller Preferences for the Session Initiation Protocol (SIP)
  • Authors: J. Rosenberg (dynamicsoft), H. Schulzrinne (Columbia University), P. Kyzivat (Cisco Systems)
  • Category: Standards Track
  • Date: August 2004
  • Obsoletes: nothing listed
  • Updates: nothing listed

Status of this Memo ๐ŸŒธ

so the status part is giving formal, but the gist is this: it's an Internet standards track protocol for the Internet community, and they're literally asking for discussion and suggestions for improvements ๐Ÿซถ if you want to know where it stands officially, you check the "Internet Official Protocol Standards" (STD 1) doc, and the distribution of this memo is unlimited, so go wild ๐Ÿ’…

the copyright line is Copyright (C) The Internet Society (2004). nothing too spicy here ๐Ÿ’œ

Abstract โœจ

this doc is all about a set of extensions to the Session Initiation Protocol (SIP) that let a caller express preferences about how servers handle their request ๐Ÿ”ฅ the preferences cover picking which Uniform Resource Identifiers (URI) a request gets routed to, plus certain request handling directives for proxies and redirect servers. the way it pulls this off is by defining three brand new request header fields, Accept-Contact, Reject-Contact, and Request-Disposition, which carry the caller's preferences ๐Ÿฆ‹

Table of Contents ๐Ÿงš

1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  2
2.  Terminology  . . . . . . . . . . . . . . . . . . . . . . . . .  4
3.  Definitions  . . . . . . . . . . . . . . . . . . . . . . . . .  4
4.  Overview of Operation  . . . . . . . . . . . . . . . . . . . .  4
5.  UAC Behavior . . . . . . . . . . . . . . . . . . . . . . . . .  5
    5.1.  Request Handling Preferences . . . . . . . . . . . . . .  6
    5.2.  Feature Set Preferences  . . . . . . . . . . . . . . . .  6
6.  UAS Behavior . . . . . . . . . . . . . . . . . . . . . . . . .  8
7.  Proxy Behavior . . . . . . . . . . . . . . . . . . . . . . . .  9
    7.1.  Request-Disposition Processing . . . . . . . . . . . . .  9
    7.2.  Preference and Capability Matching . . . . . . . . . . .  9
          7.2.1. Extracting Explicit Preferences . . . . . . . . . 10
          7.2.2. Extracting Implicit Preferences . . . . . . . . . 10
                 7.2.2.1. Methods. . . . . . . . . . . . . . . . . 10
                 7.2.2.2. Event Packages . . . . . . . . . . . . . 11
          7.2.3. Constructing Contact Predicates . . . . . . . . . 11
          7.2.4. Matching. . . . . . . . . . . . . . . . . . . . . 12
          7.2.5. Example . . . . . . . . . . . . . . . . . . . . . 16
8.  Mapping Feature Parameters to a Predicate. . . . . . . . . . . 17
9.  Header Field Definitions . . . . . . . . . . . . . . . . . . . 19
    9.1.  Request Disposition  . . . . . . . . . . . . . . . . . . 20
    9.2.  Accept-Contact and Reject-Contact Header Fields  . . . . 21
10. Augmented BNF  . . . . . . . . . . . . . . . . . . . . . . . . 22
11. Security Considerations  . . . . . . . . . . . . . . . . . . . 22
12. IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 23
13. Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . . 23
14. References . . . . . . . . . . . . . . . . . . . . . . . . . . 24
    14.1. Normative References . . . . . . . . . . . . . . . . . . 24
    14.2. Informative References . . . . . . . . . . . . . . . . . 24
15. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 25
16. Full Copyright Statements. . . . . . . . . . . . . . . . . . . 26

1. Introduction ๐Ÿ’–

okay so when a Session Initiation Protocol (SIP) [1] server gets a request, it has a bunch of decisions it can make about processing it ๐Ÿง  like:

  • whether to proxy or redirect the request
  • which URIs to proxy or redirect to
  • whether to fork or not
  • whether to search recursively or not
  • whether to search in parallel or sequentially

the server can base all of these on whatever local policy it has ๐Ÿ’… that policy can be set up statically, or it can come from running a program or doing a database lookup.

BUT the server admin isn't the only one who cares about what happens to a request ๐Ÿ‘€ there are at least three parties with a stake: (1) the admin of the server, (2) the user who sent the request, and (3) the user the request is aimed at. the admin's wishes live in the server's policy. the wishes of the user being called (the callee, even if the request method isn't INVITE) can be expressed most easily through a script in some scripting language, like the Call Processing Language (CPL) [11]. however, there's no mechanism for the wishes of the user who sent the request (the caller, even if the method isn't INVITE) to get incorporated ๐Ÿ˜ญ that's the gap this spec fills.

for example, a caller might want to talk to a specific person but only reach them at work, because it's a business call ๐Ÿ’ผ or a caller might want to reach someone but NOT their voicemail, because it's important that they actually talk to the person ๐Ÿ™ˆ in both cases, the caller's preference boils down to having a proxy make a particular routing choice based on what the caller wants.

this extension lets the caller get those preferences met ๐ŸŽ€ it does this by specifying how a caller can provide preferences on request processing. there are two types of preferences. the first, called request handling preferences, lives in the Request-Disposition header field, and gives specific request handling directives for a server. the second, called feature preferences, shows up in the Accept-Contact and Reject-Contact header fields. these let the caller provide a feature set [2] describing the characteristics of the UA they want to reach. those get matched against a feature set that a UA provides to its registrar [3]. the whole thing is super general purpose and isn't tied to any one service. it's a tool people can use to build all kinds of services ๐Ÿงš

one example of a service this enables is a "one number" service ๐Ÿ“ฑ a user can have a single identity (their SIP URI) for all their devices: cell phone, PDA, work phone, home phone, and so on. if the caller wants to reach the user at their business phone, they just pick "business phone" from a pull-down menu when calling that URI ๐Ÿ“ users wouldn't need to maintain and distribute a separate identity for every device anymore. iconic ๐Ÿ‘‘

2. Terminology ๐ŸŒˆ

okay the key words are the important part here, so pay attention ๐Ÿซถ in this document, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in BCP 14, RFC 2119 [4], and they indicate requirement levels for compliant implementations โœจ

3. Definitions ๐Ÿ’œ

a lot of the terminology here is already presented in [3] ๐Ÿ“š this spec adds the following extra terms:

  • Caller: within this spec, a caller is the user on whose behalf a UAC is operating. it isn't limited to a user whose UAC sends an INVITE request ๐Ÿ’…
  • Feature Preferences: caller preferences describing the desired properties of a UA that the request should be routed to. feature preferences can be made explicit with the Accept-Contact and Reject-Contact header fields ๐Ÿฆ‹
  • Request Handling Preferences: caller preferences describing the desired request treatment at a server. these are carried in the Request-Disposition header field ๐Ÿ”ฅ
  • Target Set: a target set is a set of candidate URIs that a proxy or redirect server can send or redirect a request to. usually target sets come from a registration, but they don't have to ๐ŸŒธ
  • Explicit Preference: a caller preference indicated explicitly in the Accept-Contact or Reject-Contact header fields ๐ŸŽ€
  • Implicit Preference: a caller preference that's implied by other aspects of a request. for example, if the request method is INVITE, that's an implicit caller preference to route the request to a UA that supports the INVITE method ๐Ÿง 

4. Overview of Operation ๐Ÿ“

so when a caller sends a request, it can optionally include new header fields asking for certain handling at a server โœจ these preferences come in two categories.

the first category is request handling preferences, carried in the Request-Disposition header field. it describes specific behavior that's wanted at a server. these include whether the caller wants the server to proxy or redirect, and whether sequential or parallel search is desired. these preferences can be applied at every proxy or redirect server on the call signaling path ๐Ÿ’–

the second category is feature preferences, carried in the Accept-Contact and Reject-Contact header fields. these hold feature sets, represented by the same feature parameters used to indicate capabilities [3]. here, the feature parameters represent the caller's preferences. the Accept-Contact header field has feature sets describing UAs the caller would like to reach. the Reject-Contact header field has feature sets that, if matched by a UA, mean the request should NOT be routed to that UA ๐Ÿ™…โ€โ™€๏ธ

proxies use the info in Accept-Contact and Reject-Contact to pick among contacts in their target set ๐ŸŽฏ when neither header field is present, the proxy computes implicit preferences from the request. these are caller preferences that aren't explicitly placed in the request, but can be inferred from other message components. as an example, if the request method is INVITE, that's an implicit preference to route the call to a UA that supports the INVITE method ๐Ÿฆ‹

both request handling and feature preferences can show up in any request, not just INVITE ๐Ÿ’… BUT they're only useful in requests where proxies need to determine a request target. if the domain in the request URI isn't owned by any proxies along the request path, those proxies will never touch a location service, so they'll never get the chance to apply the caller preferences ๐Ÿ˜ญ that makes sense, because usually the request URI identifies a UAS for mid-dialog requests. in those cases, the routing decisions were already made on the initial request, so it makes zero sense to redo them for every later request in the dialog ๐ŸŒˆ

5. UAC Behavior ๐Ÿ“žโœจ

okay so if a caller wants to tell the network what they're into, they just add an Accept-Contact, Reject-Contact, or Request-Disposition header field to the request, depending on their vibe ๐Ÿ’…. once the request is sent? nothing else is needed, bestie ๐Ÿซถ

The Accept-Contact, Reject-Contact, and Request-Disposition header fields in an ACK for a non-2xx final response, or in a CANCEL request, MUST be equal to the values in the original request being acknowledged or cancelled. no switching it up mid-call ๐Ÿ™…โ€โ™€๏ธ this is what keeps everything working properly through stateless proxies ๐Ÿฆ‹

okay, now for the Proxy-Require check ๐Ÿ”. if a UAC wants to find out whether the servers along the path understand these header fields, it includes a Proxy-Require header field with a value of "pref" [3] in its request. if the request fails with a 420 response code, the UAC knows the extension isn't supported. in that case, it SHOULD retry, and may decide whether or not to use caller preferences. a UA should only use Proxy-Require if knowing about support is essential for handling the request. and ngl, caller preferences can only ever be preferences ๐Ÿฅบ. there is no guarantee the requested service will actually happen. so putting Proxy-Require in there doesn't mean the preferences will be executed, it just means the proxies understand the caller preferences extension โœจ

5.1. Request Handling Preferences

the Request-Disposition header field is where callers say how they'd like a server to process their request ๐ŸŽ€. its value is a list of tokens, and each token is a particular processing directive. the syntax lives in Section 10, and what the directives actually mean is covered in Section 9.1 ๐Ÿ“–

5.2. Feature Set Preferences

this is the big one, bestie ๐Ÿ‘‘. a UAC can say which capabilities of a UA it wants to be reached by, or not reached by, as a result of sending a SIP request. to do that, it adds one or more Accept-Contact and Reject-Contact header field values. each value holds a set of feature parameters that define a feature set. the syntax is in Section 10, and how they get used is in Section 9.2 ๐Ÿงš

each feature set is built as described in Section 5 of [3]. the feature sets in these header fields MAY overlap, meaning a UA MAY indicate preferences for feature sets that match according to the matching algorithm of RFC 2533 [2] ๐ŸŒˆ

a UAC can also express explicit preferences for the methods and event packages a UA supports ๐Ÿ’œ. it is RECOMMENDED that a UA include a term in an Accept-Contact feature set with the sip.methods feature tag (fun fact, even though it's called sip.methods, it gets encoded into the Accept-Contact header field as just methods) and a value that includes the method of the request. when a UA sends a SUBSCRIBE request, it is RECOMMENDED that it include a term in an Accept-Contact feature set with the sip.events feature tag, with a value that includes the event package of the request. whether these terms go into a brand new feature set, or into each feature set, is up to the implementor ๐Ÿคทโ€โ™€๏ธ. in most cases, the right effect comes from putting a term in each feature set ๐Ÿ’–

here's an example. this Accept-Contact header field says "I'd really like this call to reach a mobile device," using feature parameters taken from [3] ๐Ÿ“ฑ

Accept-Contact: *;mobility="mobile";methods="INVITE"

the Reject-Contact header field lets the UAC say a UA should NOT be contacted if it matches any of the values in the header field ๐Ÿ™…โ€โ™€๏ธ. each value contains a *, purely so the syntax lines up with the guidelines for SIP extensions [12], and it's parameterized by a set of feature parameters. any UA whose capabilities match that feature set matches the value ๐Ÿ’…

the Accept-Contact header field is the opposite energy ๐Ÿฅฐ. it lets the UAC say a UA SHOULD be contacted if it matches some or all of the values in the header field. each value contains a * and is parameterized by a set of feature parameters, and any UA whose capabilities match that feature set matches the value. how this plays out depends heavily on whether the require and explicit parameters are there ๐Ÿ˜ญ. when both are present, a proxy will only forward the request to contacts that have explicitly said they support the desired feature set, and everyone else gets discarded. so a UAC should only use require and explicit together when it wants the call to fail unless a contact definitively matches. tea: a UA might support the feature but just not have mentioned it in its registration. when a UAC uses both explicit and require, that contact wouldn't get reached, so this combo is often not the one a UAC actually wants ๐Ÿ™ˆ

when only require is present, a contact won't be used if it doesn't match. if it does match, or if it's unknown whether it's a complete match, the contact still gets used ๐ŸŽฏ. a UAC would use require alone when a non-matching contact is totally useless, which is common for services that just can't happen without the right features. think specific methods or event packages. with only require, the proxy will also prefer routing to the UA that's the "best" match, meaning the one that has explicitly indicated support for more of the desired features than anyone else ๐Ÿ‘‘. but this preference never overrides an ordering the called party already provided, so it only chooses between contacts with an equal q-value โœจ

when only explicit is present, every contact the callee provided will be used ๐Ÿซง. however, a contact that isn't an explicit match is tried last among all the other contacts with the same q-value. the main difference between this setup and using both require and explicit is what happens to non-matching contacts. with explicit alone, they're tried as a last resort, and if require is also present, they're never tried at all ๐Ÿฆ‹

finally, if neither require nor explicit is present, all contacts the callee provided will be used ๐ŸŒธ. if a contact doesn't match, it's tried last among the other contacts with the same q-value. if it does match, the request gets routed preferentially to the "best" match. this is a super common setup for preferences that, if not honored, still allow a successful call, and the bigger the match, the better ๐Ÿ’…๐Ÿ“

6. UAS Behavior ๐Ÿ–ฅ๏ธ๐Ÿ’–

when a UAS that complies with this specification gets a request whose request-URI matches one of its registered contacts, it SHOULD apply the behavior from Section 7.2 as if it were a proxy for the domain in the request-URI ๐Ÿงšโ€โ™€๏ธ. the UAS acts as if its location database holds a single request target for that request-URI, and that target is tied to a feature set. the feature set is the same one placed in the registration of the URI in the request-URI. if a UA registered against multiple separate addresses-of-record, and the contacts for each had different capabilities, it would've used a different URI for each registration, so it can figure out which feature set to use ๐Ÿ”‘

this processing happens after the client has been authenticated and authorized, but before the rest of the general UAS processing described in Section 8.2.1 of RFC 3261 ๐Ÿ”

if there are no URIs left in the target set after doing this processing, the UA SHOULD reject the request with a 480 response ๐Ÿ˜ต. if there's a URI remaining (there was only one to begin with), the UA carries on with request processing as per RFC 3261 ๐Ÿƒโ€โ™€๏ธ

the nice part? having a UAS do the matching as if it were a proxy lets certain caller preferences get honored even if the proxy doesn't support the extension ๐ŸŽ€

a UAS SHOULD process any queue directive in a Request-Disposition header field in the request. all other directives MUST be ignored ๐Ÿ™ƒ

7. Proxy Behavior ๐ŸŒ๐Ÿ’ซ

proxy behavior is made of two orthogonal sets of rules ๐Ÿงฉ. one set handles the Request-Disposition header field, and the other handles the URI and feature set preferences in the Accept-Contact and Reject-Contact header fields.

besides processing those headers, a proxy MAY add one if it's not present, or add a value to an existing header field, as if it were a UAC ๐Ÿ™Œ. this is handy when a proxy wants downstream proxies to do some processing for a feature. BUT a proxy MUST NOT modify or remove an existing header field value ๐Ÿšซ. this matters a lot when S/MIME is in use ๐Ÿ”. the message signature can include the caller preferences header fields, so the UAS can verify that, even though proxies may have added header fields, the original caller preferences are still there ๐Ÿฅน

7.1. Request-Disposition Processing

if the request has a Request-Disposition header field and the server owns the domain in the Request URI, the server SHOULD execute the directives described in Section 9.1, unless its local policy says to do something different ๐Ÿ“‹

7.2. Preference and Capability Matching

this is the matching deep dive, so grab a snack ๐Ÿฟ. a proxy that complies with this specification MUST NOT apply the preferences matching operation described here to a request unless it owns the domain in the request URI and is accessing a location service that has capabilities associated with request targets ๐Ÿ™…โ€โ™€๏ธ. but if it does own the domain and is accessing that kind of location service, it SHOULD apply the processing described in this section ๐Ÿ’…. usually this is a proxy using a registration database to figure out the request targets. if a proxy knows about capabilities some other way, it SHOULD apply the processing defined here too. and if it does perform the processing, it MUST do so exactly as described below ๐Ÿ“

the processing is described by converting the syntax from this specification into RFC 2533 [2] syntax, then doing a matching operation, then sorting the resulting contact values ๐Ÿง . using RFC 2533 syntax as an intermediate step isn't required. it's just a useful tool for describing the behavior a proxy needs to have ๐Ÿ› ๏ธ. a proxy can use any steps it likes, as long as the results are identical to what the processing described here would produce โœจ

7.2.1. Extracting Explicit Preferences

Okay, so step one of proxy processing is to dig up the explicit preferences ๐Ÿ”๐Ÿ’– The proxy goes looking for the Accept-Contact and Reject-Contact header fields, bestie โœจ

For each value in those header fields, it pulls out the feature parameters. These are the header field parameters named "audio", "automata", "class", "duplex", "data", "control", "mobility", "description", "events", "priority", "methods", "extensions", "schemes", "application", "video", "language", "type", "isfocus", "actor", or "text", or any parameter whose name begins with a plus (+) [3] ๐ŸŽ€ The proxy converts all of those parameters to the syntax of RFC 2533, following the rules in Section 8 ๐Ÿ’…

The result is a set of feature set predicates in conjunctive normal form. Each one is tied to one of the two preference header fields ๐Ÿงš If there was a req-parameter on a value in the Accept-Contact header field, the predicate made from that value gets its require flag set. Same idea for an explicit-param: that predicate gets its explicit flag set ๐Ÿฆ‹

7.2.2. Extracting Implicit Preferences

If, and only if, the proxy didn't find any explicit preferences in the request (because there was no Accept-Contact or Reject-Contact header field), then it goes hunting for implicit preferences ๐Ÿ•ต๏ธโ€โ™€๏ธโœจ These are the ones implied by other info already sitting in the request.

First, the proxy makes a conjunction with no terms. This conjunction stands in for a feature set that gets associated with the Accept-Contact header field, as if it had been included there ๐ŸŒธ Note that the message itself isn't modified at all. It's only an association for processing purposes, no cap ๐Ÿ™ˆ This feature set has its require flag set, but not its explicit flag.

Then the proxy adds terms to the conjunction for the two implicit preference types below ๐Ÿ’œ

7.2.2.1. Methods

One implicit preference is the method. When a UAC sends a request with a specific method, that's an implicit preference to have the request routed only to UAs that support that method ๐Ÿ’… To support this, the proxy adds a term to the conjunction that looks like this:

(sip.methods=[method of request])

7.2.2.2. Event Packages

For requests that establish a subscription [5], the Event header field is another way of expressing an implicit preference ๐Ÿซถ It says the request should only be routed to a server that supports the given event package. To support this, the proxy adds a term to the conjunction that looks like this:

(sip.events=[value of the Event header field])

7.2.3. Constructing Contact Predicates

Next, the proxy takes each URI in the target set (the set of URIs it's about to proxy or redirect to) and grabs its capabilities as an RFC 2533 formatted feature set predicate. This is called a contact predicate ๐Ÿ‘‘ If the target URI came from a registration, the proxy works out the contact predicate by pulling the feature parameters out of the Contact header field [3] and turning them into a feature predicate. To extract those feature parameters, the proxy follows these steps:

  1. Create an initial, empty list of feature parameters.
  2. If the Contact URI parameters included the "audio", "automata", "class", "duplex", "data", "control", "mobility", "description", "events", "priority", "methods", "schemes", "application", "video", "actor", "language", "isfocus", "type", "extensions", or "text" parameters, those get copied into the list ๐ŸŽ€
  3. If any Contact URI parameter name begins with a "+", it gets copied into the list if the list doesn't already contain that name with the plus removed. So if the "video" feature parameter is already in the list, a "+video" parameter wouldn't be added. This conflict should never come up if the client is compliant to [3], since it's illegal to use the + form for encoding a feature tag in the base set ๐Ÿ™ˆ

If the URI in the target set had no feature parameters, it's said to be immune to caller preference processing ๐Ÿ›ก๏ธ That means the URI gets pulled out of the target set temporarily, the caller preferences processing described below runs, and then the URI gets added back in ๐Ÿฆ‹

Assuming the URI does have feature parameters, they get converted to RFC 2533 syntax using the rules of Section 8 โœจ

The resulting predicate is associated with a q-value. If the contact predicate was learned through a REGISTER request, the q-value equals the q-value in the Contact header field parameter. Otherwise it's "1.0" if not specified ๐ŸŒˆ

Here's an example with a registered Contact header field, bestie ๐Ÿ’–

  Contact: <sip:user@example.com>;audio;video;mobility="fixed";
      +sip.message="TRUE";other-param=66372;
      methods="INVITE,OPTIONS,BYE,CANCEL,ACK";schemes="sip,http"

That would get converted into this predicate:

   (& (sip.audio=TRUE)
      (sip.video=TRUE)
      (sip.mobility=fixed)
      (sip.message=TRUE)
      (| (sip.methods=INVITE) (sip.methods=OPTIONS) (sip.methods=BYE)
         (sip.methods=CANCEL) (sip.methods=ACK))
      (| (sip.schemes=sip) (sip.schemes=http)))
Note that other-param was not considered a feature parameter, since it's neither a base tag nor does it begin with a leading + ๐Ÿ™ˆ๐Ÿ’…

7.2.4. Matching โœจ

okay so the proxy does NOT need to know what any feature tag means to do the matching ๐Ÿง  it just looks at the syntax hints in each value. like a predicate such as (foo>=4) tells you "foo" is numeric, bc of the >=. the matching rules in RFC 2533 only need to know if a tag is a numeric, a token, or a quoted string (booleans can be treated as tokens) ๐Ÿ’…

quoted strings are ALWAYS case-sensitive ๐Ÿ™…โ€โ™€๏ธ tokens are case-insensitive ๐ŸŒธ and you can tell them apart by the angle brackets around the value. when the brackets are there (like ;+sip.foo="<value>"), it means case-sensitive string comparison. when they're NOT there (like ;+sip.bar="val"), it means case-insensitive. numerics just get normal math comparisons ๐Ÿ”ข bestie this is giving clean and simple

first up, the proxy applies the predicates from the Reject-Contact header field ๐Ÿšซ

for each contact predicate, each Reject-Contact predicate (aka each predicate attached to the Reject-Contact header field) gets checked. if that Reject-Contact predicate has a filter for a feature tag, and that feature tag isn't anywhere in the contact predicate, then that Reject-Contact predicate gets tossed for processing that contact predicate ๐Ÿ—‘๏ธ if it survives, it gets matched against the contact predicate using the matching operation of RFC 2533 [2]. if it's a match, the URI for that contact predicate gets discarded from the target set. bye bye ๐Ÿ‘‹

the result? Reject-Contact will ONLY discard URIs where the UA has explicitly said it supports the features that aren't wanted. that's the whole vibe ๐ŸŽ€

next, the proxy applies the predicates from the Accept-Contact header field ๐Ÿ’– for each contact still in the target set, the proxy builds a matching set, Ms. at first this set has ALL the Accept-Contact predicates. each one gets examined and matched against the contact predicate with the RFC 2533 [2] matching operation. if it's NOT a match AND that Accept-Contact predicate had its require flag set, the URI for that contact predicate is dropped from the target set ๐Ÿ’€ if it's NOT a match but there was NO require flag, the contact URI stays in the target set, BUT that Accept-Contact predicate gets removed from the matching set for that contact ๐Ÿซถ

for each contact still in the target set, the proxy computes a score against each predicate in that contact's matching set. say the Accept-Contact predicate conjunction has N terms. each term has ONE feature tag. if the contact predicate has a term with that same feature tag, the score goes up by 1/N ๐Ÿ“ˆ if the feature tag wasn't in the contact predicate, the score stays put. so the score can land anywhere from zero to one ๐Ÿฆ‹

                                                    T
                                              +----------> DROP Contact
                                              |
                                              |
                                             / \
                                            /   \
                                        T  /     \   F
                                    +---->/require\------> Set score=0
                                    |     \      /
                                    |      \    /
                                   / \      \  /
                                  /   \      \/
                       score<1   /     \
                      +-------> /explicit----> Score unchanged
                      |         \      /    F
                      |          \    /
                     / \          \  /
                    /   \          \/
    +--------+     /     \
 -->|Compute |--> /Score  \ --------> Score unchanged
    |  Score |    \      /  score=1
    +--------+     \    /
                    \  /
                     \/

Figure 1: Applying the Score ๐Ÿ—บ๏ธ

next up, the require and explicit tags get applied, and that can change the score AND the target set ๐Ÿ”ฅ (Figure 1 is the cheat sheet, trust me). if the score for the contact predicate against that Accept-Contact predicate was less than one, the Accept-Contact predicate had an explicit tag, AND it also had a require tag, then the Contact URI for that contact predicate gets dropped. if there's NO require tag, the score gets set to zero instead. and if there was no explicit tag at all, the score just stays the same ๐Ÿ™ˆ

then we combine the scores and the q-values from the predicates in the matching set to get one overall caller preference, Qa ๐Ÿ‘‘ for the URIs still in the target set, there's a score for EACH Accept-Contact predicate in the matching set. if there are M Accept-Contact predicates in the matching set, each contact gets M scores, S1 through SM. Qa is the arithmetic average of S1 through SM. easy peasy ๐Ÿงฎ

now, any URIs that got removed from the target set bc they were immune from caller preferences get added back in, and their Qa is set to 1.0 โœจ main character moment for them

so what's Qa even for? it gives an ordering for the contacts still in the target set, but ONLY if the callee didn't already give an ordering ๐Ÿ’… the contacts get sorted by the q-value the callee provided. then they're grouped into equivalence classes, so every contact with the same q-value lands in the same class. inside each class, contacts get ordered by their Qa values. the result is an ordered list of contacts that the proxy uses ๐Ÿ“‹

If there were no URIs left in the target set after all of the above, AND the caller preferences were based on implicit preferences (Section 7.2.2), then this whole section gets thrown out, and the original target set, ordered by its original q-values, gets used instead. ๐Ÿ”„

this is for when implicit preferences for the method or event packages wiped out every potential target ๐Ÿงน by going back to the original target set, those URIs get tried, and the result is a 405 or 489 response. the UAC can use that to try again or tell the user what went wrong ๐Ÿ™ without the fallback, the UAC would just see a 480 response and have zero clue why the request failed ๐Ÿ˜ญ now, the target set can also end up empty after explicit preferences get applied. that results in a 480 from the proxy. this is totally acceptable, and honestly desirable, for explicit preferences. when the caller makes an explicit preference, it's basically agreeing that its request might fail bc of a preference mismatch ๐Ÿค someone might think "just return an error that lists the callee's capabilities so the caller can retry!" but that would leak potentially sensitive info to the caller without the callee's permission ๐Ÿ”’ so this spec does NOT provide a way to do that. bestie, privacy wins ๐Ÿ’œ

if a proxy server is recursing, it adds the Contact header fields from the redirect responses into the target set, and then re-applies the caller preferences algorithm ๐Ÿ”

if the server is redirecting, it returns ALL entries in the target set ๐Ÿ“ฌ it assigns q-values to those entries so the ordering matches what the processing above came up with. BUT it MUST NOT include the feature parameters for the entries in the target set ๐Ÿšซ if it did, the upstream proxy server would apply the same caller preferences again, and those preferences would get applied twice ๐Ÿ˜ตโ€๐Ÿ’ซ and if the redirect server really does want to include the feature parameters in the Contact header field, it MUST redirect using the original target set and original q-values, from BEFORE the caller preferences were applied ๐ŸŽ€

7.2.5. Example ๐ŸŒˆ

okay let's walk through this one. it's contrived, but it shows off all the pieces of the matching process ๐Ÿงš there are five registered Contacts for sip:user@example.com. they are:

Contact: sip:u1@h.example.com;audio;video;methods="INVITE,BYE";q=0.2
Contact: sip:u2@h.example.com;audio="FALSE";
  methods="INVITE";actor="msg-taker";q=0.2
Contact: sip:u3@h.example.com;audio;actor="msg-taker";
  methods="INVITE";video;q=0.3
Contact: sip:u4@h.example.com;audio;methods="INVITE,OPTIONS";q=0.2
Contact: sip:u5@h.example.com;q=0.5

an INVITE sent to sip:user@example.com came with these caller preference header fields:

Reject-Contact: *;actor="msg-taker";video
Accept-Contact: *;audio;require
Accept-Contact: *;video;explicit
Accept-Contact: *;methods="BYE";class="business";q=1.0

there are NO implicit preferences in this example, bc explicit preferences were provided ๐Ÿ™…โ€โ™€๏ธ

step one: the proxy yeets u5 from the target set, since it's immune from caller preferences processing ๐Ÿซก

step two: the proxy processes Reject-Contact. it matches all four remaining contacts, but it's only an EXPLICIT match for u3 ๐Ÿ˜ค that's bc u3 is the ONLY one that explicitly said it supports video AND that it's a message taker. so u3 gets discarded, and the others stay ๐Ÿ’–

step three: each of the three remaining contacts gets compared against each of the three Accept-Contact predicates. u1 matches all three ๐ŸŽ‰ it earns a score of 1.0 for the first two predicates, and 0.5 for the third (bc the methods feature tag was in the contact predicate, but the class tag wasn't). u2 doesn't match the first predicate, and since that predicate has a require tag, u2 gets discarded ๐Ÿ’€ u4 matches the first predicate and earns a score of 1.0. u4 also matches the second predicate, but the match isn't explicit (the score is 0.0, actually), so the score gets set to zero (it was already zero, so nothing changes ๐Ÿ™ƒ). u4 doesn't match the third predicate.

step four: u1 and u4 are left. u1 matched all three Accept-Contact predicates, so its matching set has all three, with scores of 1, 1, and 0.5. u4 matches the first two predicates, with scores of 1.0 and 0.0. Qa for u1 comes out to 0.83 and Qa for u4 comes out to 0.5. then u5 gets added back in with a Qa of 1.0 ๐ŸŒธ

step five: the remaining contacts get sorted by q-value. u5 has 0.5, u1 has 0.2, and so does u4. that makes two equivalence classes ๐Ÿง the first has a q-value of 0.5 and is just u5. since it's the only member, sorting inside that class does nothing. the second class has a q-value of 0.2, and inside it, u1 and u4 get ordered by Qa. u1 has 0.83 and u4 has 0.5, so u1 comes first, then u4 ๐Ÿ†

so the final ordered set in the target set is u5, then u1, then u4. โœจ bestie we did it ๐Ÿ’–

8. Mapping Feature Parameters to a Predicate โœจ

okay so turning feature params into a feature set predicate, using the RFC 2533 [2] syntax, is literally trivial ๐Ÿ’… It's basically the reverse of the process in Section 5 of [3] ๐Ÿ”„

Starting from a set of feature-param, here's the move. You build a conjunction ๐Ÿ‘‘ Each term in that conjunction comes from one feature-param. If a feature-param has no value, it gets treated exactly as if it had a value of "TRUE" ๐Ÿ’– (for the processing that comes next, anyway)

If the feature-param value is a tag-value-list, then that element of the conjunction becomes a disjunction ๐Ÿฆ‹ You get one term in the disjunction for each tag-value in the tag-value-list.

Now let's build a filter from a tag-value ๐Ÿงš If the tag-value starts with an exclamation mark (!), the filter looks like this:

(! <filter from remainder>)

where <filter from remainder> is the filter you'd get from the tag-value if the exclamation mark wasn't there at all ๐Ÿ™ˆ

If the tag-value starts with an octothorpe (#), it's a numeric comparison ๐Ÿ”ข The comparator is =, >=, <=, or a range, depending on the next characters. If the next characters are =, >=, or <=, the filter is:

(name comparator compare-value)

Here name is the feature parameter name after it's been decoded (more on that below), and the comparator is =, >=, or <= depending on those first characters. If the rest of the tag-value after the equal sign has a decimal point (so it's a rational number), you shift the decimal point right N times until it's a plain integer, I. Then compare-value is set to I / 10**N, where 10**N means 10 to the Nth power ๐Ÿค“

If the value after the octothorpe is a number, the filter is a range:

   (name=<remainder>)

where name is the feature-tag after it's been decoded (see below), and <remainder> is whatever comes after the # in the tag-value. Any decimal numbers get converted to rational form, and the colon gets swapped for a double dot (..) ๐ŸŒˆ

If the tag-value doesn't start with an octothorpe (so it's a token-nobang or a boolean), the filter is:

   (name=tag-value)

where name is the feature-tag after it's been decoded (see below) ๐ŸŽ€

If the feature-param has a string-value (you can spot it because it starts with a left angle bracket ("<") and ends with a right angle bracket (">")), the filter is:

   (name="qdtext")

Notice those quotes around the qdtext ๐Ÿ‘€ They're there to show the value is a string. In RFC 2533, strings get compared with case sensitive rules, while tokens get compared with case insensitive rules. Main character energy for strings, lowkey chill for tokens โœจ

Now, feature tags from RFC 2506 [13] can't be used directly as header field parameters in the Contact, Accept-Contact, and Reject-Contact header fields ๐Ÿ˜ญ That's because of an inconsistency in the grammars, plus the need to tell feature parameters apart from parameters that other extensions use. So feature tag values get encoded from RFC 2506 format into an enc-feature-tag, and then they get decoded back into RFC 2506 format. The decoding is simple, I promise ๐Ÿซถ If there's a leading plus (+) sign, you remove it. Any exclamation point (!) becomes a colon (:), and any single quote (') becomes a forward slash (/). If there was no leading plus sign, and the rest of the encoded name is "audio", "automata", "class", "duplex", "data", "control", "mobility", "description", "events", "priority", "methods", "schemes", "application", "video", "actor", "isfocus", "extensions", or "text", then you add the prefix "sip." to the rest of the encoded name to get the feature tag name ๐Ÿ’…

Here's an example. This Accept-Contact header field:

   Accept-Contact:*;mobility="fixed"
     ;events="!presence,message-summary"
     ;language="en,de";description="<PC>";+sip.newparam
     ;+rangeparam="#-4:+5.125"

would get converted into this feature predicate ๐Ÿฆ‹

      (& (sip.mobility=fixed)
         (| (! (sip.events=presence)) (sip.events=message-summary))
         (| (language=en) (language=de))
         (sip.description="PC")
         (sip.newparam=TRUE)
         (rangeparam=-4..5125/1000))

9. Header Field Definitions ๐ŸŽ€

okay this section defines three new header fields: Accept-Contact, Reject-Contact, and Request-Disposition ๐Ÿ’–

Figure 2 and Figure 3 extend Tables 2 and 3 in RFC 3261 [1] so they cover Accept-Contact, Reject-Contact, and Request-Disposition. The column "INF" is for the INFO method [6], "PRA" is for the PRACK method [7], "UPD" is for the UPDATE method [8], "SUB" is for the SUBSCRIBE method [5], "NOT" is for the NOTIFY method [5], "MSG" is for the MESSAGE method [9], and "REF" is for the REFER method [10] ๐Ÿ“‹

Header field          where  proxy  ACK BYE CAN INV OPT REG

Accept-Contact          R      ar    o   o   o   o   o   -
Reject-Contact          R      ar    o   o   o   o   o   -
Request-Disposition     R      ar    o   o   o   o   o   o

Figure 2: Accept-Contact, Reject-Contact, and Request-Disposition
          header fields
Header field          where  proxy  PRA UPD SUB NOT INF MSG REF

Accept-Contact          R      ar    o   o   o   o   o   o   o
Reject-Contact          R      ar    o   o   o   o   o   o   o
Request-Disposition     R      ar    o   o   o   o   o   o   o

Figure 3: Accept-Contact, Reject-Contact, and Request-Disposition
          header fields

9.1. Request Disposition

The Request-Disposition header field is where callers say how they'd like a server to handle their request ๐Ÿ“ž Its value is a list of tokens, and each token is a directive. The syntax lives in Section 10. Heads up, there's a compact form using the letter d ๐Ÿ“ The directives are sorted into types, and you can only have one directive of each type per request. So no sneaking in both "proxy" and "redirect" in the same Request-Disposition header field, bestie ๐Ÿ™…โ€โ™€๏ธ

When the caller sends a directive, the server SHOULD honor it ๐Ÿซถ

Here are the types of directives:

proxy-directive: this one says whether the caller wants each server to proxy ("proxy") or redirect ("redirect") ๐Ÿ”€

cancel-directive: this one says whether the caller wants each proxy server to send a CANCEL request downstream ("cancel") after a 200 OK comes back from the downstream server. That's the normal way things work, so it's kinda redundant. Or the caller can leave that job to themselves ("no-cancel"). If a proxy gets a request with "no-cancel" set, it SHOULD NOT CANCEL any outstanding branches when it receives a 2xx. It would still send CANCEL on outstanding branches when it gets a 6xx though ๐Ÿ˜ค

fork-directive: this decides whether a proxy should fork a request ("fork"), or only proxy to a single address ("no-fork"). If the server's been asked not to fork, the server SHOULD proxy the request to the "best" address, which is usually the one with the highest q-value ๐ŸŽฏ If several addresses tie for the highest q-value, the server picks one based on its local policy. This directive gets ignored if "redirect" was requested ๐Ÿ™ƒ

recurse-directive: this one is about a proxy server that gets a 3xx response. The caller can say the server should send requests to the addresses listed in that response ("recurse"), or forward the list of addresses upstream toward the caller ("no-recurse"). It gets ignored if "redirect" was requested ๐ŸŒธ

parallel-directive: for a forking proxy server, this says whether the caller wants the proxy to reach all the known addresses at once ("parallel"), or go through them one by one, only contacting the next address after the previous one returns a non-2xx or non-6xx final response ("sequential"). It gets ignored if "redirect" was requested ๐Ÿƒโ€โ™€๏ธ

queue-directive: say the called party is temporarily unreachable, like because they're on another call. The caller can ask for the call to be queued ("queue") or rejected right away ("no-queue"). If the call gets queued, the server returns "182 Queued" โณ A queued call can be terminated the way described in [1] ๐Ÿ’€

Example:

   Request-Disposition: proxy, recurse, parallel

The set of request disposition directives is deliberately not extensible ๐Ÿ”’ The point is to stop a pile of new SIP extensions from getting "tunneled" through this header field. Nobody wants that mess, periodt ๐Ÿ™…โ€โ™€๏ธ

9.2. Accept-Contact and Reject-Contact Header Fields

The syntax for these header fields is in Section 10 โœจ The compact form for Accept-Contact uses the letter a, and the compact form for Reject-Contact uses the letter j ๐Ÿ’œ


10. Augmented BNF ๐Ÿ’…

The BNF for the Request-Disposition header field looks like this ๐Ÿ‘‘

Request-Disposition   =   ( "Request-Disposition" / "d" ) HCOLON
                          directive *(COMMA directive)
directive             =   proxy-directive / cancel-directive /
                          fork-directive / recurse-directive /
                          parallel-directive / queue-directive
proxy-directive       =  "proxy" / "redirect"
cancel-directive      =  "cancel" / "no-cancel"
fork-directive        =  "fork" / "no-fork"
recurse-directive     =  "recurse" / "no-recurse"
parallel-directive    =  "parallel" / "sequential"
queue-directive       =  "queue" / "no-queue"

The BNF for the Accept-Contact and Reject-Contact header fields is:

Accept-Contact  =  ("Accept-Contact" / "a") HCOLON ac-value
                   *(COMMA ac-value)
Reject-Contact  =  ("Reject-Contact" / "j") HCOLON rc-value
                   *(COMMA rc-value)
ac-value        =  "*" *(SEMI ac-params)
rc-value        =  "*" *(SEMI rc-params)
ac-params       =  feature-param / req-param
                      / explicit-param / generic-param
                    ;;feature param from RFC 3840
                    ;;generic-param from RFC 3261
rc-params       =  feature-param / generic-param
req-param       =  "require"
explicit-param  =  "explicit"

Despite the BNF, there MUST NOT be more than one req-param or explicit-param in an ac-params ๐Ÿšซ And there can only be one instance of any feature tag in feature-param. No duplicates, no drama ๐ŸŽ€


11. Security Considerations ๐Ÿ”

Okay, this part is serious, so listen up ๐Ÿ˜ญ Caller preferences in a request change the way that request gets handled at a server. Because of that, requests with caller preferences SHOULD be integrity-protected with the sips mechanism specified in RFC 3261, Section 26 ๐Ÿ›ก๏ธ

Processing caller preferences takes set operations and searches, and those can need a fair bit of computing power ๐Ÿฅต That opens the door to a DOS attack, where a user sends requests stuffed with tons of caller preferences in the hopes of overloading the server. To stop that, servers SHOULD reject requests with too many rules ๐Ÿ™…โ€โ™€๏ธ A reasonable number is around 20 ๐ŸŒˆ

12. IANA Considerations โœจ

okay so IANA gets to add three new SIP header fields to the registry, and this spec is the one that makes them official ๐ŸŽ€ The rules come from RFC 3261 [1], so that's the process we follow.

Here's the registration for Accept-Contact ๐Ÿ’–

RFC Number: RFC 3841

Header Field Name: Accept-Contact

Compact Form: a

Next up is Reject-Contact ๐Ÿซถ

RFC Number: RFC 3841

Header Field Name: Reject-Contact

Compact Form: j

And last but definitely not least, Request-Disposition ๐Ÿ’…

RFC Number: RFC 3841

Header Field Name: Request-Disposition

Compact Form: d

13. Acknowledgments ๐ŸŒธ

the initial set of media feature tags in this spec was inspired by Scott Petrack's CMA design, so big shoutout to him โœจ Jonathan Lennox, Bob Penfield, Ben Campbell, Mary Barnes, Rohan Mahy, and John Hearty all gave super helpful comments ๐Ÿ™Œ and Graham Klyne helped out with how to use RFC 2533 ๐Ÿงš

14. References ๐Ÿ“š

14.1. Normative References

[1] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A., Peterson, J., Sparks, R., Handley, M., and E. Schooler, "SIP: Session Initiation Protocol", RFC 3261, June 2002.

[2] Klyne, G., "A Syntax for Describing Media Feature Sets", RFC 2533, March 1999.

[3] Rosenberg, J., Schulzrinne, J., and P. Kyzivat, "Indicating User Agent Capabilities in the Session Initiation Protocol (SIP)", RFC 3840, August 2004.

[4] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[5] Roach, A.B., "Session Initiation Protocol (SIP)-Specific Event Notification", RFC 3265, June 2002.

[6] Donovan, S., "The SIP INFO Method", RFC 2976, October 2000.

[7] Rosenberg, J. and H. Schulzrinne, "Reliability of Provisional Responses in Session Initiation Protocol (SIP)", RFC 3262, June 2002.

[8] Rosenberg, J., "The Session Initiation Protocol (SIP) UPDATE Method", RFC 3311, October 2002.

[9] Campbell, B., Ed., Rosenberg, J., Schulzrinne, H., Huitema, C., and D. Gurle, "Session Initiation Protocol (SIP) Extension for Instant Messaging", RFC 3428, December 2002.

[10] Sparks, R., "The Session Initiation Protocol (SIP) Refer Method", RFC 3515, April 2003.

14.2. Informative References

[11] Lennox, J. and H. Schulzrinne, "Call Processing Language Framework and Requirements", RFC 2824, May 2000.

[12] Rosenberg, J., "Guidelines for Authors of Extensions to the Session Initiation Protocol (SIP)", Work in Progress, November 2002.

[13] Holtman, K., Muntz, A., and T. Hardie, "Media Feature Tag Registration Procedure", BCP 31, RFC 2506, March 1999.

15. Authors' Addresses ๐Ÿฆ‹

here are the contact details for our authors, exactly as they appear in the spec ๐Ÿ’œ

Jonathan Rosenberg
dynamicsoft
600 Lanidex Plaza
Parsippany, NJ  07054
US

Phone: +1 973 952-5000
EMail: jdrosen@dynamicsoft.com
URI:   http://www.jdrosen.net


Henning Schulzrinne
Columbia University
M/S 0401
1214 Amsterdam Ave.
New York, NY  10027
US

EMail: schulzrinne@cs.columbia.edu
URI:   http://www.cs.columbia.edu/~hgs


Paul Kyzivat
Cisco Systems
1414 Massachusetts Avenue
BXB500 C2-2
Boxboro, MA  01719
US

EMail: pkyzivat@cisco.com

Copyright (C) The Internet Society (2004). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property ๐Ÿ”ฅ

The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79.

Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.

Acknowledgement ๐ŸŒˆ

Funding for the RFC Editor function is currently provided by the Internet Society. โœจ

๐Ÿ“ฆ where this page comes from