RFC 3841
Caller Preferences for the Session Initiation Protocol (SIP)
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 ๐
Copyright Notice ๐
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-ContactandReject-Contactheader fields ๐ฆ - Request Handling Preferences: caller preferences describing the desired request treatment at a server. these are carried in the
Request-Dispositionheader 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-ContactorReject-Contactheader 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 theINVITEmethod ๐ง
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:
- Create an initial, empty list of feature parameters.
- 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 ๐ - 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 thatother-paramwas 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
16. Full Copyright Statement ยฉ
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
- ietf: rfc3841 2004-08
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms