RFC 5589
Session Initiation Protocol (SIP) Call Control - Transfer
Status of This Memo ๐
This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements. Distribution of this memo is unlimited. ๐
Copyright Notice ยฉ๏ธ
Copyright (c) 2009 IETF Trust and the persons identified as the document authors. All rights reserved. ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents in effect on the date of publication of this document (http://trustee.ietf.org/license-info). Please review these documents carefully, as they describe your rights and restrictions with respect to this document.
This document may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. The person(s) controlling the copyright in some of this material may not have granted the IETF Trust the right to allow modifications of such material outside the IETF Standards Process. Without obtaining an adequate license from the person(s) controlling the copyright in such materials, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process, except to format it for publication as an RFC or to translate it into languages other than English.
Abstract ๐ฆ
Okay so this doc is all about getting Call Transfer working in the Session Initiation Protocol (SIP) ๐โจ. The extensions doing the heavy lifting are REFER and Replaces, and together they cover blind transfer, consultative transfer, and attended transfer ๐. And it's part of the SIP multiparty call control framework, so it's giving big-picture energy ๐ง.
Table of Contents ๐
1. Overview ........................................................3
2. Actors and Roles ................................................3
3. Terminology .....................................................4
4. Requirements ....................................................4
5. Using REFER to Achieve Call Transfer ............................5
6. Basic Transfer ..................................................6
6.1. Successful Transfer ........................................8
6.2. Transfer with Dialog Reuse ................................11
6.3. Failed Transfer ...........................................15
6.3.1. Target Busy ........................................16
6.3.2. Transfer Target Does Not Answer ....................17
7. Transfer with Consultation Hold ................................18
7.1. Exposing Transfer Target ..................................18
7.2. Protecting Transfer Target ................................19
7.3. Attended Transfer .........................................24
7.4. Recovery When One Party Does Not Support REFER ............28
7.5. Attended Transfer When Contact URI Is Not Known to
Route to a User Agent .....................................29
7.6. Semi-Attended Transfer ....................................37
7.7. Attended Transfer Fallback to Basic Transfer ..............42
8. Transfer with Referred-By ......................................45
9. Transfer as an Ad Hoc Conference ...............................49
10. Transfer with Multiple Parties ................................52
11. Gateway Transfer Issues .......................................54
11.1. Coerce Gateway Hairpins to the Same Gateway ..............54
11.2. Consultative Turned Blind Gateway Glare ..................55
12. Security Considerations .......................................55
13. Acknowledgments ...............................................56
14. References ....................................................56
14.1. Normative References .....................................56
14.2. Informative References ...................................57
1. Overview โจ
Okay, first things first! ๐ธ This doc describes providing Call Transfer capabilities and requirements in SIP [RFC3261]. It's part of the multiparty call control framework [CC-FRMWRK], so it's all connected, bestie ๐ซถ.
The mechanisms here are most closely related to traditional, basic, and consultation hold transfers ๐.
This document details the use of the REFER method [RFC3515] and Replaces [RFC3891] header field to achieve call transfer. Main character energy ๐.
A User Agent (UA) that fully supports the transfer mechanisms described in this document supports REFER [RFC3515] and Replaces [RFC3891] in addition to RFC 3261 [RFC3261]. A User Agent should use a Contact URI that meets the requirements in Section 8.1.1.8 of RFC 3261. A compliant User Agent supports the Target-Dialog header field [RFC4538]. It's giving checklist vibes ๐ .
2. Actors and Roles ๐ญ
There are three actors in a given transfer event, each playing one of the following roles. Think of it like a little cast list ๐:
- Transferee: the party being transferred to the Transfer Target.
- Transferor: the party initiating the transfer.
- Transfer Target: the new party being introduced into a call with the Transferee.
The following roles are used to describe transfer requirements and scenarios. These are the extra characters for the storyline ๐ฆ:
- Originator: wishes to place a call to the Recipient. This actor is the source of the first
INVITEin a session, to either a Facilitator or a Screener. - Facilitator: receives a call or out-of-band request from the Originator, establishes a call to the Recipient through the Screener, and connects the Originator to the Recipient. Typically, a Facilitator acts on behalf of the Originator. ๐ง
- Screener: receives a call ultimately intended for the Recipient and transfers the calling party to the Recipient if appropriate. Typically, a Screener acts on behalf of the Recipient. ๐ก๏ธ
- Recipient: the party to which the Originator is ultimately connected. ๐
3. Terminology ๐
Okay, the key words here are the important ones ๐ฅ. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14, RFC 2119 [RFC2119]. Read those carefully, they're not just vibes ๐.
4. Requirements ๐
Here are the requirements the transfer mechanism has to hit. Each one is its own little goal ๐ฏ:
- Any party in a SIP session must be able to transfer any other party in that session at any point in that session. ๐ซ
- The Transferor and the Transferee must not be removed from a session as part of a transfer transaction.
Ngl, requirement 2 might make you think the user experience in a transfer has to be super different from what a current Private Branch Exchange (PBX) or Centrex user expects. But as the call flows in this document show, that's not the case. A client can keep the current experience. Honestly, without this requirement, some forms of the current experience (ringback on transfer failure, for instance) would be lost ๐ญ๐.
- The Transferor must know whether or not the transfer was successful. โ
- The Transferee must be able to replace an existing dialog with a new dialog. ๐ฆ
- The Transferor and Transferee should indicate their support for the primitives required to achieve transfer. ๐ซถ
- The Transferor should provide the Transfer Target and Transferee with information about the nature and progress of the transfer operation being attempted. ๐
To meet this requirement, the transfer operation can be modeled as an ad hoc conference between three parties, as discussed in Section 9. It's literally the same vibe as a group chat, iykyk ๐.
5. Using REFER to Achieve Call Transfer โจ
okay so a REFER [RFC3515] can be sent by the Transferor to tell the Transferee to send an INVITE to the Transfer Target ๐ ngl this is where it gets fun. A successful REFER transaction does not end the session between the Transferor and the Transferee ๐ if those two want to end their session, they must do that with a separate BYE request. The media negotiated between the Transferee and the Transfer Target is totally independent from the media that was negotiated between the Transferor and the Transferee ๐ฆ the INVITE the Transferee sends will have the same Session Description Protocol (SDP) body it would have had if the Transferee had started that INVITE on its own. And the REFER method doesn't change how the media streams between the Transferor and the Transferee are set up ๐
agents can change a session's media through extra signaling, though ๐ for example, they can use the SIP hold re-INVITE [RFC3261] or the conferencing extensions in the conferencing framework [RFC4353]. iconic.
now, to do the transfer, the Transferor and Transferee could reuse an existing dialog that was set up by an INVITE to send the REFER ๐ธ that would give you one dialog doing double duty as an invite usage and a subscription usage. the call flows for that are laid out in Section 6.2 โจ BUT this document goes with avoiding dialog reuse instead. if you want the drama on dialog reuse, it's covered in [RFC5057] ๐ง
so why would anyone reuse the dialog? here's the tea ๐ซ
- there was no reliable way to make sure a REFER sent on a new dialog would reach the exact endpoint involved in the transfer ๐ญ so many things could mess with it, like implementation details or proxy routing changing between the
INVITEand the REFER, and then the REFER ends up at the wrong place. sending the REFER down the existing dialog made sure it got to the endpoint we were already talking to. literally the safest move. - it wasn't clear how to match an existing invite usage with a REFER arriving on a new dialog ๐ but when the REFER came in on the
INVITEusage's dialog, the connection was super obvious. - people had concerns about authorizing out-of-dialog REFERs ๐ most implementations basically piggyback the REFER authorization on the
INVITEauthorization, and that's usually just "I placed or answered this call" ๐
Globally Routable UA URIs (GRUUs) [SIP-GRUU] can fix problem 1 ๐ฆ and problem 2 can be handled with the Target-Dialog header field defined in [RFC4538] ๐ for now, this fix for problem 2 means the existing REFER authorization policy can keep getting reused, which is so convenient bestie ๐ซถ
so here's the rule of thumb ๐ฅ if the Transferee supports the target-dialog extension and the Transferor knows the Contact URI is routable outside the dialog, the REFER SHOULD be sent in a new dialog. if the nature of the Contact URI isn't known, or if support for the target-dialog extension isn't known, the REFER SHOULD be sent inside the existing dialog. and a Transferee MUST be ready to receive a REFER either inside or outside a dialog ๐ one way a Transferor could figure out that a Contact URI is routable outside a dialog is by validating it (for example, sending an OPTIONS and getting a response back), or if it meets the properties described in the GRUU specification [SIP-GRUU] โจ
this document doesn't require the flows and examples to look exactly like they're shown ๐ the flows are there to illustrate the principles of best practice for the transfer feature. they're well-reviewed examples of SIP usage for doing transfer with REFER, and they count as Best Common Practice according to IETF consensus ๐ slay.
in most of the examples that follow, the Transferor lives in the atlanta.example.com domain ๐ the Transferee is in biloxi.example.com, and the Transfer Target is in chicago.example.com ๐
6. Basic Transfer ๐
basic transfer is giving simple: the Transferor hands the Transfer Target's contact over to the Transferee ๐ the Transferee tries to set up a session with that contact and then reports how that attempt went back to the Transferor. the signaling relationship between the Transferor and the Transferee doesn't get terminated, so the call can still be recovered if the Transfer Target can't be reached ๐ซถ heads up though: the Transfer Target's contact info has been exposed to the Transferee, and that contact can be used to make new calls in the future ๐
the participants in a basic transfer SHOULD indicate support for the REFER and NOTIFY methods in Allow header fields in INVITE, 200 OK to INVITE, and OPTIONS messages โจ they SHOULD also indicate support for Target-Dialog in the Supported header field ๐ง
the diagrams are about to be super readable ๐ each one shows the first line of every message, and the first column shows which dialog that message is using. in these diagrams, media is handled with re-INVITE holds, but other mechanisms are valid too, like mixing multiple media streams at the UA or using the conferencing extensions ๐ธ the important messages get labeled F1, F2, and so on.
in each of the flows below, the dialog between the Transferor and the Transferee stays connected (on hold) while the REFER process happens ๐ this gives the best flexibility for recovering from failure, but it's not required ๐คทโโ๏ธ if the Transferor's agent doesn't want to stick around for the rest of the REFER process and has no plans to help with recovering from a failed transfer, it could send a BYE to the Transferee as soon as the REFER transaction is done โ๏ธ this is sometimes called "unattended transfer" or "blind transfer" ๐ฆ
Figure 1 shows a transfer where the Transferee uses a GRUU, supports the target-dialog extension, and tells the Transferor about it ๐ because of that, the Transferor sends the REFER outside the INVITE dialog. the Transferee can match that REFER to the existing dialog using the Target-Dialog header field in the REFER, which references that existing dialog ๐ฅ it's a whole main character moment.
6.1. Successful Transfer ๐
okay bestie, this is the whole glow-up ๐ the full successful transfer, start to finish. three dialogs are doing the work here, so watch the labels ๐
Transferor Transferee Transfer
| | Target
| INVITE F1 | |
dialog1 |<-------------------| |
| 200 OK F2 | |
dialog1 |------------------->| |
| ACK | |
dialog1 |<-------------------| |
| INVITE (hold) | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| ACK | |
dialog1 |------------------->| |
| REFER F3 (Target-Dialog:1) |
dialog2 |------------------->| |
| 202 Accepted | |
dialog2 |<-------------------| |
| NOTIFY (100 Trying) F4 |
dialog2 |<-------------------| |
| 200 OK | |
dialog2 |------------------->| |
| | INVITE F5 |
dialog3 | |------------------->|
| | 200 OK |
dialog3 | |<-------------------|
| | ACK |
dialog3 | |------------------->|
| NOTIFY (200 OK) F6| |
dialog2 |<-------------------| |
| 200 OK | |
dialog2 |------------------->| |
| BYE | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| | BYE |
dialog3 | |<-------------------|
| | 200 OK |
dialog3 | |------------------->|
Figure 1: Basic Transfer Call Flow ๐ฆ
now let's look at each message one at a time, because the details are the whole point โจ
F1 INVITE Transferee -> Transferor ๐
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee ๐ซถ
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 REFER Transferor -> Transferee ๐ฅ
this is the big one, the REFER that actually kicks off the transfer ๐ญ
REFER sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKna9
Max-Forwards: 70
To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: tdialog
Refer-To: <sips:transfertarget@chicago.example.com>
Target-Dialog: 090459243588173445;local-tag=7553452
;remote-tag=31kdl4i3k
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F4 NOTIFY Transferee -> Transferor ๐ธ
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 73 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, tdialog
Event: refer
Subscription-State: active;expires=60
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 100 Trying
F5 INVITE Transferee -> Transfer Target ๐ง
the transferee now calls the transfer target on its own, so this one lives on dialog3 ๐
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas41234
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferee@biloxi.example.com>;tag=j3kso3iqhq
Call-ID: 90422f3sd23m4g56832034
CSeq: 521 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F6 NOTIFY Transferee -> Transferor ๐
the final update to the transferor, and this one says the subscription is done ๐ฅน
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 74 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, tdialog
Event: refer
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 200 OK
and that's the whole successful transfer, bestie!! ๐โจ the Subscription-State flips to terminated in F6, which is the last thing the transferor hears from the transferee ๐
6.2. Transfer with Dialog Reuse ๐ฆ
okay so in this one, the Transferor doesn't know the properties of the Transferee's Contact URI, or doesn't know that the Transferee supports the Target-Dialog header field. ๐ญ So the REFER gets sent inside the INVITE dialog instead. no cap, that's the whole plot twist.
Transferor Transferee Transfer
| | Target
| INVITE F1 | |
dialog1 |<-------------------| |
| 200 OK F2 | |
dialog1 |------------------->| |
| ACK | |
dialog1 |<-------------------| |
| INVITE (hold) | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| ACK | |
dialog1 |------------------->| |
| REFER F3 | |
dialog1 |------------------->| |
| 202 Accepted | |
dialog1 |<-------------------| |
| NOTIFY (100 Trying) F4 |
dialog1 |<-------------------| |
| 200 OK | |
dialog1 |------------------->| |
| | INVITE F5 |
dialog2 | |------------------->|
| | 200 OK |
dialog2 | |<-------------------|
| | ACK |
dialog2 | |------------------->|
| NOTIFY (200 OK) F6| |
dialog1 |<-------------------| |
| 200 OK | |
dialog1 |------------------->| |
| BYE | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| | BYE |
dialog2 | |<-------------------|
| | 200 OK |
dialog2 | |------------------->|
Figure 2: Transfer with Dialog Reuse
F1 INVITE Transferee -> Transferor
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferee@192.0.2.4>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 REFER Transferor -> Transferee
REFER sips:transferee@192.0.2.4 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKna9
Max-Forwards: 70
To: <sips:transferee@biloxi.example.com>;tag=7553452
From: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
Call-ID: 090459243588173445
CSeq: 314159 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Refer-To: <sips:transfertarget@chicago.example.com>
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F4 NOTIFY Transferee -> Transferor
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29888 INVITE
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer
Subscription-State: active;expires=60
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 100 Trying
F5 INVITE Transferee -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas41234
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferee@biloxi.example.com>;tag=j3kso3iqhq
Call-ID: 90422f3sd23m4g56832034
CSeq: 521 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferee@192.0.2.4>
Content-Type: application/sdp
Content-Length: ...
F6 NOTIFY Transferee -> Transferor
NOTIFY sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=31kdl4i3k
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29889 INVITE
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 200 OK
6.3. Failed Transfer ๐
this section walks through transfers that don't work out, and the drama is real. ๐ฉ once the failure happens, the Transferor takes the Transferee off hold and picks the session back up. ๐
6.3.1. Target Busy ๐
Transferor Transferee Transfer
| | Target
| | |
| INVITE | |
dialog1 |<-------------------| |
| 200 OK | |
dialog1 |------------------->| |
| ACK | |
dialog1 |<-------------------| |
| INVITE (hold) | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| ACK | |
dialog1 |------------------->| |
| REFER (Target-Dialog:1) |
dialog2 |------------------->| |
| 202 Accepted | |
dialog2 |<-------------------| |
| NOTIFY (100 Trying)| |
dialog2 |<-------------------| |
| 200 OK | |
dialog2 |------------------->| |
| | INVITE |
dialog3 | |------------------->|
| | 486 Busy Here |
dialog3 | |<-------------------|
| | ACK |
dialog3 | |------------------->|
| NOTIFY (486 Busy Here) |
dialog2 |<-------------------| |
| 200 OK | |
dialog2 |------------------->| |
| INVITE (unhold) | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| ACK | |
dialog1 |------------------->| |
| BYE | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
Figure 3: Failed Transfer - Target Busy
6.3.2. Transfer Target Does Not Answer โจ
Okay so this one is the "the target just never picks up" scenario ๐. Here's the whole flow, with the transferee getting bored and cancelling the call to the target:
Transferor Transferee Transfer
| | Target
| INVITE | |
dialog1 |<-------------------| |
| 200 OK | |
dialog1 |------------------->| |
| ACK | |
dialog1 |<-------------------| |
| INVITE (hold) | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| ACK | |
dialog1 |------------------->| |
| REFER | |
dialog2 |------------------->| |
| 202 Accepted | |
dialog2 |<-------------------| |
| NOTIFY (100 Trying)| |
dialog2 |<-------------------| |
| 200 OK | |
dialog2 |------------------->| |
| | INVITE |
dialog3 | |------------------->|
| | 180 Ringing |
dialog3 | |<-------------------|
| (Transferee gets tired of waiting)
| | CANCEL |
dialog3 | |------------------->|
| | 200 OK (CANCEL) |
dialog3 | |<-------------------|
| 487 Request Cancelled (INVITE)
dialog3 | |<-------------------|
| | ACK |
dialog3 | |------------------->|
| NOTIFY (487 Request Cancelled) |
dialog2 |<-------------------| |
| 200 OK | |
dialog2 |------------------->| |
| INVITE (unhold) | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
| ACK | |
dialog1 |------------------->| |
| BYE | |
dialog1 |------------------->| |
| 200 OK | |
dialog1 |<-------------------| |
Figure 4: Failed Transfer - Target Does Not Answer
7. Transfer with Consultation Hold ๐
Okay, so transfer with consultation hold is when the Transferor has a little chat with the Transfer Target before the transfer actually happens ๐. It's built with the SIP Hold and Transfer stuff we already covered above, so nothing brand new here, just a cute new combo ๐.
A super nice feature is that the Transferor can let the target know the session is about an intended transfer ๐ซถ. Since a lot of UAs show the display name from the From header field to the user, a consultation INVITE could carry a string like Incoming consultation from Transferor with intent to transfer Transferee, with the display names of the transferor and transferee dropped right into it. Iconic, right? ๐ญ
7.1. Exposing Transfer Target ๐ฆ
Here's the vibe: the Transferor puts the Transferee on hold, calls the Transfer Target to give them a heads-up about the incoming transfer, hangs up on the Transfer Target, and then just carries on with the transfer like before ๐. This version is giving the same experience that PBX and Centrex users are used to ๐.
To (hopefully) make things clearer โจ, the non-REFER transactions are squished into one indicator, with the arrow showing which way the request is going ๐.
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK | |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE/200 OK/ACK | |
|---------------------------------------->|
dialog2 | BYE/200 OK | |
|---------------------------------------->|
dialog3 | REFER | |
|------------------->| |
dialog3 | 202 Accepted | |
|<-------------------| |
dialog3 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog4 | | INVITE/200 OK/ACK |
| |------------------->|
dialog3 | NOTIFY (200 OK) | |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog4 | | BYE/200 OK |
| |<-------------------|
Figure 5: Transfer with Consultation Hold - Exposing Transfer Target
7.2. Protecting Transfer Target โจ
okay so this one is giving secret agent ๐ต๏ธโโ๏ธ. The Transferor puts the Transferee on hold, calls the Transfer Target, and then they swap roles, so the original Transfer Target gets transferred over to the original Transferee. The big perk is that the Transferee never sees who the original Transfer Target was ๐. The tradeoff is that the Transferee's experience is different from what people are used to, because they're basically getting "called back" by the Transfer Target ๐.
ngl there's a catch with the simplest version of this protecting-target trick. The Transferee gets a brand new call from the Transfer Target. Unless the Transferee's agent has a reliable way to link that new call to the call it already has with the Transferor, it has to ring the new call on another appearance ๐ . If there's no other line and no call-waiting-style UI, the Transferee could end up sending a Busy-Here back to the Transfer Target, which basically blocks the whole transfer ๐. There are lots of ways to do that correlation. For example, the dialog parameters could go straight into the header parameters of the Refer-To URI. The Replaces mechanism [RFC3891] does exactly that and handles this problem so cleanly ๐ญ๐ซถ.
For the flow below, dialog1 means dialog identifier 1. It's made up of the parameters from the Replaces header for dialog 1. In [RFC3891], those are the Call-ID, To-tag, and From-tag ๐.
Also, the Transferee's agent sends a BYE to the Transferor's agent right away, as an immediate result of processing the Replaces header ๐.
The Transferor knows both the Transferee and the Transfer Target support the Replaces header, because the Supported: replaces header shows up in the 200 OK responses from both of them โจ.
In this scenario, the Transferee uses a GRUU as its Contact URI. The reason for that is covered in Section 6.3 ๐ฆ.
Heads up: the conventions from the SIP Torture Test Messages [RFC4475] document are reused here, specifically the <allOneLine> tag ๐ง.
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK F1 F2 |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE/200 OK/ACK F3 F4 |
|---------------------------------------->|
dialog2 | INVITE (hold)/200 OK/ACK |
|---------------------------------------->|
dialog3 | REFER (Target-Dialog:2, |
| Refer-To:sips:Transferee?Replaces=1) F5|
|---------------------------------------->|
dialog3 | 202 Accepted | |
|<----------------------------------------|
dialog3 | NOTIFY (100 Trying)| |
|<----------------------------------------|
dialog3 | | 200 OK |
|---------------------------------------->|
dialog4 | INVITE (Replaces:dialog1)/200 OK/ACK F6
| |<-------------------|
dialog1 | BYE/200 OK | |
|<-------------------| |
dialog3 | NOTIFY (200 OK) | |
|<----------------------------------------|
dialog3 | | 200 OK |
|---------------------------------------->|
dialog2 | BYE/200 OK | |
|---------------------------------------->|
| (Transferee and target converse)
dialog4 | | BYE/200 OK |
| |------------------->|
Figure 6: Transfer Protecting Transfer Target ๐ธ
F1 INVITE Transferee -> Transferor ๐
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee ๐
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31431
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 INVITE Transferor -> Transfer Target ๐ฆ
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: replaces
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=384i32lw3>
Content-Type: application/sdp
Content-Length: ...
F4 200 OK Transfer Target -> Transferor ๐ง
SIP/2.0 200 OK
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
;received=192.0.2.1
To: <sips:transfertarget@chicago.example.com>;tag=9m2n3wq
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
Content-Type: application/sdp
Content-Length: ...
F5 REFER Transferor -> Transfer Target ๐
REFER sips:482n4z24kdg@chicago.example.com;gr=8594958 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 REFER
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: tdialog
<allOneLine>
Refer-To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha
?Replaces=090459243588173445%3Bto-tag%3D7553452%3Bfrom-tag%3D31431>
</allOneLine>
Target-Dialog: 592435881734450904;local-tag=9m2n3wq
;remote-tag=763231
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F6 INVITE Transfer Target -> Transferee ๐ซถ
INVITE sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha SIP/2.0
Via: SIP/2.0/TLS client.chicago.example.com;branch=z9hG4bKnaslu84
Max-Forwards: 70
To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
From: <sips:transfertarget@chicago.example.com>;tag=341234
Call-ID: kmzwdle3dl3d08
CSeq: 41 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Contact: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
Replaces: 090459243588173445;to-tag=7553452;from-tag=31431
Content-Type: application/sdp
Content-Length: ...
7.3. Attended Transfer
okay so attended transfer is the glow-up version ๐
The Transferor puts the Transferee on hold, calls the Transfer Target to give them a heads up ๐ that a transfer is coming, puts the target on hold too, and then goes for it with an escaped Replaces header field tucked inside the Refer-To header ๐ฆ. This is literally another classic that PBX and Centrex users expect ๐
The Contact URI of the Transfer Target SHOULD be used by the Transferor as the Refer-To URI, unless the URI is suspected or known to not be routable outside the dialog. Otherwise, the Address of Record (AOR) of the Transfer Target SHOULD be used. That is, the same URI that the Transferor used to establish the session with the Transfer Target should be used. In case the triggered INVITE is routed to a different User Agent than the Transfer Target, the Require: replaces header field SHOULD be used in the triggered INVITE. (This is to prevent an incorrect User Agent that does not support Replaces from ignoring the Replaces and answering the INVITE without a dialog match ๐
โโ๏ธ)
It is possible that proxy/service routing may prevent the triggered INVITE from reaching the same User Agent. If this occurs, the triggered invite will fail with a timeout, 403, 404, etc. error. The Transferee MAY then retry the transfer with the Refer-To URI set to the Contact URI ๐
Here's the call flow, bestie ๐ง
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK F1 F2 |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE/200 OK/ACK F3 F4 |
|---------------------------------------->|
dialog2 | INVITE (hold)/200 OK/ACK |
|---------------------------------------->|
dialog3 | REFER (Target-Dialog:1, |
| Refer-To:sips:TransferTarget?Replaces=2) F5
|------------------->| |
dialog3 | 202 Accepted | |
|<-------------------| |
dialog3 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog4 | INVITE (Replaces:dialog2)/200 OK/ACK F6
| |------------------->|
dialog2 | BYE/200 OK | |
|<----------------------------------------|
dialog3 | NOTIFY (200 OK) | |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog4 | | BYE/200 OK |
| |<-------------------|
Figure 7: Attended Transfer Call Flow
F1 INVITE Transferee -> Transferor
INVITE sips:transferor@atlanta.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transferor -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
To: <sips:transferor@atlanta.example.com>;tag=31431
From: <sips:transferee@biloxi.example.com>;tag=7553452
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu, tdialog
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: application/sdp
Content-Length: ...
F3 INVITE Transferor -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Require: replaces
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=384i32lw3>
Content-Type: application/sdp
Content-Length: ...
F4 200 OK Transfer Target -> Transferor
SIP/2.0 200 OK
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
;received=192.0.2.1
To: <sips:transfertarget@chicago.example.com>;tag=9m2n3wq
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 592435881734450904
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces, gruu
Contact: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
Content-Type: application/sdp
Content-Length: ...
F5 REFER Transferor -> Transferee
REFER sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 REFER
Require: tdialog
<allOneLine>
Refer-To: <sips:482n4z24kdg@chicago.example.com;gr=8594958?
Replaces=592435881734450904%3Bto-tag%3D9m2n3wq%3Bfrom-tag3D763231>
</allOneLine>
Target-Dialog: 592435881734450904;local-tag=9m2n3wq
;remote-tag=763231
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Length: 0
F6 INVITE Transferee -> Transfer Target
INVITE sips:482n4z24kdg@chicago.example.com;gr=8594958 SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnaslu82
Max-Forwards: 70
To: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
From: <sips:transferee@biloxi.example.com>;tag=954
Call-ID: kmzwdle3dl3d08
CSeq: 41 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: gruu, replaces, tdialog
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Replaces: 592435881734450904;to-tag=9m2n3wq;from-tag=763231
Content-Type: application/sdp
Content-Length: ...
7.4. Recovery When One Party Does Not Support REFER
If protecting or exposing the Transfer Target is not a concern, it is possible to complete a transfer with consultation hold when only the transferor and one other party support REFER. Note that a 405 Method Not Allowed might be returned instead of the 501 Not Implemented response ๐
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK | |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE/200 OK/ACK | |
|---------------------------------------->|
dialog2 | INVITE (hold)/200 OK/ACK |
|---------------------------------------->|
dialog3 | REFER (Target-Dialog:1, |
| Refer-To:sips:TransferTarget?Replaces=2)
|------------------->| |
dialog3 | 501 Not Implemented |
|<-------------------| |
dialog4 | REFER (Refer-To:sips:Transferee?Replaces=dialog1)
|---------------------------------------->|
dialog4 | 202 Accepted | |
|<----------------------------------------|
dialog4 | NOTIFY (100 Trying)| |
|<----------------------------------------|
dialog4 | | 200 OK |
|---------------------------------------->|
dialog5 | INVITE (Replaces:dialog1)/200 OK/ACK
| |<-------------------|
dialog4 | NOTIFY (200 OK) | |
|<----------------------------------------|
dialog4 | | 200 OK |
|---------------------------------------->|
dialog1 | BYE/200 OK | |
|<-------------------| |
dialog2 | BYE/200 OK | |
|---------------------------------------->|
dialog5 | | BYE/200 OK |
| |------------------->|
Figure 8: Recovery When One Party Does Not Support REFER
7.5. Attended Transfer When Contact URI Is Not Known to Route to a Unique User Agent
Okay, this one is a bit of a plot twist ๐ญ It is a requirement of RFC 3261 that a Contact URI be globally routable even outside the dialog. However, due to RFC 2543 User Agents and some architectures (NAT/Firewall traversal, screening proxies, Application Layer Gateways (ALGs), etc.) this will not always be the case. As a result, the method of attended transfer shown in Figures 6, 7, and 8 SHOULD only be used if the Contact URI is known to be routable outside the dialog.
Figure 9 shows such a scenario where the Transfer Target Contact URI is not routable outside the dialog, so the triggered INVITE is sent to the AOR of the Transfer Target ๐
Okay bestie, here's the first call flow where the Contact URI is not known to be globally routable ๐
Transferor Transferee Screening Transfer
| | Proxy Target
| | | |
dialog1 | INVITE/200 OK/ACK| | |
|<-----------------| | |
dialog1 | INVITE (hold)/200 OK/ACK | |
|----------------->| | |
dialog2 | INVITE/200 OK/ACK F1 F2 | |
|--------------------------------|------------>|
dialog2 | INVITE (hold)/200 OK/ACK |
|--------------------------------|------------>|
dialog1 | REFER (Refer-To:sips:TargetAOR |
| ?Replaces=dialog2&Require=replaces) F3
|----------------->| | |
dialog1 | 202 Accepted | | |
|<-----------------| | |
dialog1 | NOTIFY (100 Trying) | |
|<-----------------| | |
dialog1 | 200 OK | | |
|----------------->| | |
dialog4 |INVITE (Replaces:dialog2,Require:replaces)/200 OK/ACK F6
| |------------>|------------>|
dialog2 | BYE/200 OK | | |
|<-------------------------------|<------------|
dialog1 | NOTIFY (200 OK) F7 | |
|<-----------------| | |
dialog1 | 200 OK | | |
|----------------->| | |
dialog1 | BYE/200 OK | | |
|----------------->| | |
dialog3 | | | BYE/200 OK |
| |<------------|-------------|
Figure 9: Attended Transfer Call Flow with a Contact URI Not Known to Be Globally Routable
F1 INVITE Transferor -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bK76
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferor@pc33.atlanta.example.com>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transfer Target -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
;received=192.0.2.1
To: <sips:transfertarget@chicago.example.com>;tag=9m2n3wq
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transfertarget@client.chicago.example.com>
Content-Type: application/sdp
Content-Length: ...
F3 REFER Transferor -> Transferee
REFER sips:transferee@192.0.2.4 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:transferee@biloxi.example.com>;tag=a6c85cf
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314160 REFER
<allOneLine>
Refer-To: <sips:transfertarget@chicago.example.com?Replaces=
090459243588173445%3Bto-tag%3D9m2n3wq%3Bfrom-tag%3D763231
&Require=replaces>
<allOneLine>
Contact: <sips:transferor@pc33.atlanta.example.com>
Content-Length: 0
F4 INVITE Transferee -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnaslu82
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferee@biloxi.example.com>;tag=954
Call-ID: 20482817324945934422930
CSeq: 42 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferee@192.0.2.4>
Replaces: 090459243588173445;to-tag=9m2n3wq;from-tag=763231
Require: replaces
Content-Type: application/sdp
Content-Length: ...
F5 NOTIFY Transferee -> Transferor
NOTIFY sips:transferor@pc33.atlanta.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:transferee@biloxi.example.com>;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 76 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer;id=98873867
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 200 OK
Figure 10 shows a failure case in which the AOR URI fails to reach the Transfer Target, so the transfer gets retried with the Contact URI, and at that point it succeeds โจ
Note that there is still no guarantee that the correct endpoint will be reached, and the result of this second REFER may also be a failure. In that case, the Transferor could fall back to unattended transfer or give up on the transfer entirely ๐ฅบ Since two REFERs are sent within the dialog, creating two distinct subscriptions, the Transferee uses the id parameter in the Event header field to tell the notifications for the two subscriptions apart ๐
Transferor Transferee Screening Transfer
| | Proxy Target
| | | |
dialog1 | INVITE/200 OK/ACK| | |
|<-----------------| | |
dialog1 | INVITE (hold)/200 OK/ACK | |
|----------------->| | |
dialog2 | INVITE/200 OK/ACK F1 F2 | |
|--------------------------------|------------>|
dialog2 | INVITE (hold)/200 OK/ACK |
|--------------------------------|------------>|
dialog1 | REFER (Refer-To:sips:TargetAOR? |
| Replaces=dialog2&Require=replaces) F3 |
|----------------->| | |
dialog1 | 202 Accepted | | |
|<-----------------| | |
dialog1 | NOTIFY (100 Trying) | |
|<-----------------| | |
dialog1 | 200 OK | | |
|----------------->| | |
dialog3 | |INVITE (Replaces:dialog2, |
| | Require:replaces)/403/ACK |
| |------------>| |
dialog1 | NOTIFY (403 Forbidden) F4 | |
|<-----------------| | |
dialog1 | 200 OK | | |
|----------------->| | |
dialog1 |REFER(Refer-To:sips:TargetContact?Replaces=dialog2) F5
|----------------->| | |
dialog1 | 202 Accepted | | |
|<-----------------| | |
dialog1 | NOTIFY (100 Trying) | |
|<-----------------| | |
dialog1 | 200 OK | | |
|----------------->| | |
dialog4 | INVITE (Replaces:dialog2)/200 OK/ACK F6
| |------------>|------------>|
dialog2 | BYE/200 OK | | |
|<-------------------------------|<------------|
dialog1 | NOTIFY (200 OK) F7 | |
|<-----------------| | |
dialog1 | 200 OK | | |
|----------------->| | |
dialog1 | BYE/200 OK | | |
|----------------->| | |
dialog3 | | | BYE/200 OK |
| |<------------|-------------|
Figure 10: Attended Transfer Call Flow with Non-Routable Contact URI and AOR Failure
F1 INVITE Transferor -> Transfer Target
INVITE sips:transfertarget@chicago.example.com SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bK76
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferor@pc33.atlanta.example.com>
Content-Type: application/sdp
Content-Length: ...
F2 200 OK Transfer Target -> Transferee
SIP/2.0 200 OK
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnas432
;received=192.0.2.1
To: <sips:transfertarget@chicago.example.com>;tag=9m2n3wq
From: <sips:transferor@atlanta.example.com>;tag=763231
Call-ID: 090459243588173445
CSeq: 29887 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transfertarget@client.chicago.example.com>
Content-Type: application/sdp
Content-Length: ...
F3 REFER Transferor -> Transferee
REFER sips:transferee@192.0.2.4 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:transferee@biloxi.example.com>;tag=a6c85cf
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 REFER
<allOneLine>
Refer-To: <sips:transfertarget@chicago.example.com?Replaces=
090459243588173445%3Bto-tag%3D9m2n3wq%3Bfrom-tag%3D763231
&Require=replaces>
</allOneLine>
Contact: <sips:transferor@pc33.atlanta.example.com>
Content-Length: 0
F4 NOTIFY Transferee -> Transferor
NOTIFY sips:transferor@pc33.atlanta.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:transferee@biloxi.example.com>;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 74 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer;id=314159
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 403 Forbidden
F5 REFER Transferor -> Transferee
REFER sips:transferee@192.0.2.4 SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: <sips:transferee@biloxi.example.com>;tag=a6c85cf
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314160 REFER
<allOneLine>
Refer-To: <sips:transfertarget@client.chicago.example.com
?Replaces=090459243588173445%3Bto-tag%3D9m2n3wq
%3Bfrom-tag%3D763231>
</allOneLine>
Contact: <sips:transferor@pc33.atlanta.example.com>
Content-Length: 0
F6 INVITE Transferee -> Transfer Target
Okay bestie, so this is the picture for the scenario we were just talking about ๐ โจ The INVITE goes out to the Transfer Target first, and then the Transferee sends the NOTIFY back to the Transferor with the refer event, ๐ฆ
INVITE sips:transfertarget@client.chicago.example.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnaslu82
Max-Forwards: 70
To: <sips:transfertarget@chicago.example.com>
From: <sips:transferee@biloxi.example.com>;tag=954
Call-ID: 20482817324945934422930
CSeq: 42 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Contact: <sips:transferee@192.0.2.4>
Replaces: 090459243588173445;to-tag=9m2n3wq;from-tag=763231
Content-Type: application/sdp
Content-Length: ...
F7 NOTIFY Transferee -> Transferor
NOTIFY sips:transferor@pc33.atlanta.com SIP/2.0
Via: SIP/2.0/TLS 192.0.2.4;branch=z9hG4bKnas432
Max-Forwards: 70
To: <sips:transferor@atlanta.example.com>;tag=1928301774
From: <sips:transferee@biloxi.example.com>;tag=a6c85cf
Call-ID: a84b4c76e66710
CSeq: 76 NOTIFY
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY
Supported: replaces
Event: refer;id=314160
Subscription-State: terminated;reason=noresource
Content-Type: message/sipfrag
Content-Length: ...
SIP/2.0 200 OK
Now, the fix to dodge this whole mess ๐ The Transfer Target SHOULD use a Contact URI that is routable outside the dialog, and that's what gets you the call flow in Figure 7. Lowkey the most important bit of this whole section, so don't skip it, periodt ๐ซถ
7.6. Semi-Attended Transfer โจ
Okay so, in any of the consultation hold flows we just went through, the Transferor can totally decide to stop trying to reach the Transfer Target before that session is established ๐. Most of the time that's the end of the story, but sometimes the Transferor still wants to finish the transfer. For example, they might complete it knowing the Transferee is going to end up talking to the Transfer Target's voicemail service ๐. Some PBX systems support this, sometimes called "semi-attended transfer", and it's basically a hybrid between a fully attended transfer and an unattended transfer ๐ . The call flow is shown in Figure 11. In this flow, the Transferor's User Agent keeps the transfer going as an attended transfer even after the Transferor hangs up ๐ซถ. Note that media must be played to the Transfer Target upon answer. Otherwise the Target may hang up and the transfer operation will fail ๐ญ.
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK F1 F2 |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE | |
|---------------------------------------->|
dialog2 | | 180 Ringing |
|<----------------------------------------|
Transferor hangs up but wants transfer to continue
| | |
| User Agent continues transfer operation |
| | |
dialog2 | | 200 OK |
|<----------------------------------------|
dialog2 | ACK | |
|---------------------------------------->|
dialog2 | Media Played to keep Target from hanging up
|========================================>|
dialog3 | REFER (Target-Dialog:1, |
| Refer-To:sips:TransferTarget?Replaces=2)
|------------------->| |
dialog3 | 202 Accepted | |
|<-------------------| |
dialog3 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog4 | INVITE (Replaces:dialog2)/200 OK/ACK
| |------------------->|
dialog2 | BYE/200 OK | |
|<----------------------------------------|
dialog3 | NOTIFY (200 OK) | |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog4 | | BYE/200 OK |
| |<-------------------|
Figure 11: Recommended Semi-Attended Transfer Call Flow
Two other possible semi-attended transfer call flows are shown in Figures 12 and 13 ๐ธ. However, these call flows are NOT RECOMMENDED due to race conditions ๐. In both of these flows, when the Transferor hangs up, the Transferor tries to fall back to unattended transfer by sending a CANCEL to the target. This can cause two race conditions ๐. The first one is that the target answers despite the CANCEL, and then the resulting unattended transfer fails. This can be eliminated if the Transferor waits to send the REFER until the 487 response from the target comes back. Instead of a 487, a 200 OK may come back, which means the target answered the consultation call. In that case, the call flow in Figure 13 must be followed. In this flow, the Transferor must play some kind of media to the Target to keep the Target from hanging up, or the transfer will fail. So basically, the human at the Transfer Target hears silence from the moment they answer (message F1) until the transfer completes (F3, when they are talking to the Transferee, unless some media is played (F2)) ๐ง.
The second race condition happens in Figure 12 if the Transfer Target goes "off hook" after the CANCEL is received and the 487 is returned. This may result in a 486 Busy Here response to the unattended transfer ๐ฉ.
The recommended call flow of Figure 11 doesn't use a CANCEL at all, so it doesn't suffer from these race conditions ๐.
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK | |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE |
|---------------------------------------->|
dialog2 | 180 Ringing |
|<----------------------------------------|
| |
| Transferor gives up waiting |
| |
dialog2 | CANCEL |
|---------------------------------------->|
dialog2 | 200 OK |
|<----------------------------------------|
dialog2 | 487 Request Terminated |
|<----------------------------------------|
dialog2 | ACK |
|---------------------------------------->|
dialog3 | REFER (Target-Dialog:1) F3 |
|------------------->| |
dialog3 | 202 Accepted | |
|<-------------------| |
dialog3 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog4 | INVITE/200 OK/ACK |
| |------------------->|
dialog3 | NOTIFY (200 OK) | |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog4 | | BYE/200 OK |
| |<-------------------|
Figure 12: Semi-Attended Transfer as Blind Transfer Call Flow (Not Recommended)
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK | |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE |
|---------------------------------------->|
dialog2 | 180 Ringing |
|<----------------------------------------|
| |
|Transferor gives up waiting but Target answers
| |
dialog2 | CANCEL |
|---------------------------------------->|
dialog2 | 200 OK (CANCEL) |
|<----------------------------------------|
dialog2 | 200 OK (INVITE) F1 |
|<----------------------------------------|
dialog2 | ACK |
|---------------------------------------->|
dialog2 | INVITE (hold)/200 OK/ACK |
|---------------------------------------->|
| Tones or media played avoid silence F2 |
|========================================>|
dialog1 |REFER (Refer-To:sips:TransferTarget |
| ?Replaces=dialog2) |
|------------------->| |
dialog1 | 202 Accepted | |
|<-------------------| |
dialog1 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog1 | 200 OK | |
|------------------->| |
dialog3 | INVITE (Replaces:dialog2)/200 OK/ACK F3
| |------------------->|
dialog2 | BYE/200 OK | |
|<----------------------------------------|
dialog1 | NOTIFY (200 OK) | |
|<-------------------| |
dialog1 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog3 | | BYE/200 OK |
| |<-------------------|
Figure 13: Semi-Attended Transfer as Attended Transfer Call Flow (Not Recommended)
7.7. Attended Transfer Fallback to Basic Transfer โจ
okay so this one is about an attended transfer that justโฆ doesn't work out ๐, and the Transferor has to fall back to a basic transfer instead ๐ซถ no cap, it's giving plan B energy.
The vibe here: the Transferor shows up to do an attended transfer, but the Transfer Target says "nah, I don't do Replaces" ๐. The Transferor sent an INVITE with Require: replaces (it was totally planning on an attended transfer when it sent that INVITE ๐
), and the Target rejects it with a 420 Bad Extension response. So the Transferor immediately switches over to basic transfer. Iconic pivot ๐.
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK | |
|<-------------------| |
dialog1 | OPTIONS/200 OK | |
|------------------->| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE (Require:replaces) |
|---------------------------------------->|
dialog2 | 420 Bad Extension |
|<----------------------------------------|
dialog2 | ACK |
|---------------------------------------->|
dialog1 | REFER (Refer-To:sips:TransferTarget) |
|------------------->| |
dialog1 | 202 Accepted | |
|<-------------------| |
dialog1 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog1 | 200 OK | |
|------------------->| |
dialog3 | | INVITE/200 OK/ACK |
| |------------------->|
dialog1 | NOTIFY (200 OK) | |
|<-------------------| |
dialog1 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog3 | | BYE/200 OK |
| |<-------------------|
Figure 14: Attended Transfer Fallback to Basic Transfer Using Require:replaces
Figure 15 is the vibe check for when nobody has told anyone whether they support REFER and Replaces (no Allow or Supported headers saying so ๐ฅบ). The Transferor's plan wasn't attended transfer when the INVITE to the Target went out, so it uses OPTIONS to find out what's what. In dialog1, the Transferor learns the Transferee does support REFER and Replaces โจ, so it starts the attended transfer by putting the Transferee on hold and calling the Transfer Target. Then, using OPTIONS in dialog2, it discovers the Target supports neither REFER nor Replaces ๐, so attended transfer is off the table. The Transferor ends dialog2 with a BYE, then sends a REFER to the Transferee using the AOR URI of the Transfer Target ๐ฆ.
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK | |
|<-------------------| |
dialog1 | OPTIONS/200 OK | |
|------------------->| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE/200 OK/ACK | |
|---------------------------------------->|
dialog2 | OPTIONS/200 OK | |
|---------------------------------------->|
dialog2 | BYE/200 OK | |
|---------------------------------------->|
dialog3 |REFER (Target-Dialog:1, |
| Refer-To:sips:TransferTarget) |
|------------------->| |
dialog3 | 202 Accepted | |
|<-------------------| |
dialog3 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog4 | | INVITE/200 OK/ACK |
| |------------------->|
dialog3 | NOTIFY (200 OK) | |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog4 | | BYE/200 OK |
| |<-------------------|
Figure 15: Attended Transfer Fallback to Basic Transfer
That's the whole fallback story, bestie ๐ Next up, more transfer drama ๐
8. Transfer with Referred-By โจ
okay so, in the examples we've looked at so far, the Transfer Target has no real clue who started the transfer, or sometimes even that a transfer is happening at all ๐ซ The Referred-By mechanism [RFC3892] fixes that. It gives the Transferor a way to tell the Transfer Target who kicked off the transfer. main character energy ๐
The simplest and least secure approach is just putting the Referred-By header field in the REFER, which then gets copied into the triggered INVITE. The more secure option uses a Referred-By security token instead. The Transferor generates and signs it, then passes it in a message body to the Transferee, and the Transferee passes it on to the Transfer Target ๐
Figure 16 shows the Referred-By header field and body in the REFER F5 and the triggered INVITE F6. Heads up: the Secure/Multipurpose Internet Mail Extensions (S/MIME) signature isn't shown in the example below ๐ The example also reuses the conventions from the SIP Torture Test Messages [RFC4475] document, specifically the <hex> and <allOneLine> tags ๐
Transferor Transferee Transfer
| | Target
| | |
dialog1 | INVITE/200 OK/ACK F1 F2 |
|<-------------------| |
dialog1 | INVITE (hold)/200 OK/ACK |
|------------------->| |
dialog2 | INVITE/200 OK/ACK F3 F4 |
|---------------------------------------->|
dialog2 | INVITE (hold)/200 OK/ACK |
|---------------------------------------->|
dialog3 | REFER (Target-Dialog:1, Referred-By:Transferor,
| Refer-To:sips:TransferTarget?Replaces=2) F5
|------------------->| |
dialog3 | 202 Accepted | |
|<-------------------| |
dialog3 | NOTIFY (100 Trying)| |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog4 | INVITE (Replaces:dialog2, |
| Referred-By:Transferor )/200 OK/ACK F6
| |------------------->|
dialog2 | BYE/200 OK | |
|<----------------------------------------|
dialog3 | NOTIFY (200 OK) | |
|<-------------------| |
dialog3 | 200 OK | |
|------------------->| |
dialog1 | BYE/200 OK | |
|------------------->| |
dialog4 | | BYE/200 OK |
| |<-------------------|
Figure 16: Attended Transfer Call Flow with Referred-By
F5 REFER Transferor -> Transferee ๐ this is the REFER, and it's giving everything ๐ญ
REFER sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha SIP/2.0
Via: SIP/2.0/TLS pc33.atlanta.example.com;branch=z9hG4bK392039842
Max-Forwards: 70
To: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
From: <sips:transferor@atlanta.example.com>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314160 REFER
<allOneLine>
Refer-To: <sips:482n4z24kdg@chicago.example.com;gr=8594958
?Replaces=090459243588173445%3Bto-tag%3D9m2n3wq%3Bfrom-tag
%3D763231&Require=replaces>
</allOneLine>
Supported: gruu, replaces, tdialog
Require: tdialog
Referred-By: <sips:transferor@atlanta.example.com>
;cid="20398823.2UWQFN309shb3@atlanta.example.com"
Target-Dialog: 592435881734450904;local-tag=9m2n3wq;remote-tag=763231
Contact: <sips:4889445d8kjtk3@atlanta.example.com;gr=723jd2d>
Content-Type: multipart/mixed; boundary=unique-boundary-1
Content-Length: ...
--unique-boundary-1
Content-ID: <20398823.2UWQFN309shb3@atlanta.example.com>
Content-Length: 2961
Content-Type: multipart/signed;
protocol="application/pkcs-7-signature";
micalg=sha1;
boundary="----590F24D439B31E08745DEF0CD9397189"
------590F24D439B31E08745DEF0CD9397189
Content-Type: message/sipfrag
Date: Thu, 18 Sep 2003 13:07:43 GMT
<allOneLine>
Refer-To: <sips:482n4z24kdg@chicago.example.com;gr=8594958
?Replaces=090459243588173445%3B
to-tag%3D9m2n3wq%3Bfrom-tag%3D763231&Require=replaces>
</allOneLine>
Referred-By: <sips:transferor@atlanta.example.com>
;cid="20398823.2UWQFN309shb3@atlanta.example.com"
------590F24D439B31E08745DEF0CD9397189
Content-Type: application/pkcs-7-signature; name="smime.p7s"
Content-Transfer-Encoding: binary
Content-Disposition: attachment; filename="smime.p7s"
<hex>3082088806092A86
4886F70D010702A082087930820875020101310B300906052B0E03021A050030
. . . (Signature not shown)
8E63D306487A740A197A3970594CF47DD385643B1DC49FF767A3D2B428388966
79089AAD95767F</hex>
------590F24D439B31E08745DEF0CD9397189--
--unique_boundary-1
F6 INVITE Transferee -> Transfer Target ๐ฆ and then the triggered INVITE shows up, carrying the same Referred-By info along for the ride ๐
INVITE sips:482n4z24kdg@chicago.example.com;gr=8594958 SIP/2.0
Via: SIP/2.0/TLS referee.example;branch=z9hG4bKffe209934aac
To: <sips:482n4z24kdg@chicago.example.com;gr=8594958>
From: <sips:transferee@biloxi.example.com>;tag=2909034023
Call-ID: fe9023940-a3465@referee.example
CSeq: 889823409 INVITE
Max-Forwards: 70
Contact: <sips:3ld812adkjw@biloxi.example.com;gr=3413kj2ha>
Referred-By: <sips:transferor@atlanta.example.com>
;cid="20398823.2UWQFN309shb3@atlanta.example.com"
Replaces:090459243588173445;to-tag=9m2n3wq;from-
tag=76323
Require: replaces
Supported: gruu, replaces, tdialog
Content-Type: multipart/mixed; boundary=my-boundary-9
Content-Length: ...
--my-boundary-9
Content-Type: application/sdp
Content-Length: 156
v=0
o=referee 2890844526 2890844526 IN IP4 referee.example
s=Session SDP
c=IN IP4 referee.example
t=0 0
m=audio 49172 RTP/AVP 0
a=rtpmap:0 PCMU/8000
--my-boundary-9
Content-Length: 2961
Content-Type: multipart/signed;
protocol="application/pkcs-7-signature";
micalg=sha1;
boundary="----590F24D439B31E08745DEF0CD9397189"
------590F24D439B31E08745DEF0CD9397189
Content-Type: message/sipfrag
Date: Thu, 18 Sep 2003 13:07:43 GMT
<allOneLine>
Refer-To: <sips:transfertarget@chicago.example.com;
Replaces=090459243588173445%3B
to-tag%3D9m2n3wq%3Bfrom-tag%3D763231&Require=replaces>
</allOneLine>
Referred-By: <sips:transferor@atlanta.example.com>
;cid="20398823.2UWQFN309shb3@atlanta.example.com"
------590F24D439B31E08745DEF0CD9397189
Content-Type: application/pkcs-7-signature; name="smime.p7s"
Content-Transfer-Encoding: binary
Content-Disposition: attachment; filename="smime.p7s"
<hex>3082088806092A86
4886F70D010702A082087930820875020101310B300906052B0E03021A050030
. . . (Signature not shown)
8E63D306487A740A197A3970594CF47DD385643B1DC49FF767A3D2B428388966
79089AAD95767F</hex>
------590F24D439B31E08745DEF0CD9397189--
--my-boundary-9--
9. Transfer as an Ad Hoc Conference โจ
Okay so, in this flow (see Figure 17 ๐ ), Bob does an attended transfer of Alice to Carol. To keep both Alice and Carol fully in the loop about what's happening, Bob acts as a focus [RFC4579] and hosts an ad hoc conference with Alice, Bob, and Carol ๐. Alice and Carol both subscribe to the conference package [RFC4575] on Bob's focus, so they can see the exact status of the operation ๐. Once the transfer is done, Bob deletes the conference ๐ซถ.
This call flow meets requirement 6 of Section 4 ๐. NOTIFY messages for the refer package are labelled NOTIFY (refer), and the NOTIFYs for the Conference Info package are labelled NOTIFY (Conf-Info) ๐ธ.
Note that any type of semi-attended transfer in which media mixing or relaying could be implemented using this model. โจ On top of simple mixing, the focus could add extra media signals, like a simulated ring tone or on-hold announcements, to make the experience way better for users ๐ฆ.
Alice Bob Carol
| | |
| INVITE | |
|------------------->| |
| 180 Ringing | |
|<-------------------| |
| 200 OK | |
|<-------------------| |
| ACK | |
|------------------->| |
| RTP | |
|<==================>| |
| | |
Bob places Alice on hold and begins acting like a focus
| | |
| INVITE (hold) Contact:Conf-ID;isfocus |
|<-------------------| |
| 200 OK | |
|------------------->| |
| ACK | |
|<-------------------| |
| | |
| Alice subscribes to the conference package
| | |
| SUBSCRIBE sip:Conf-ID |
|------------------->| |
| 200 OK | |
|<-------------------| |
| NOTIFY (Conf-Info) | |
|<-------------------| |
| 200 OK | |
|------------------->| |
| | |
| Bob begins consultation operation |
| | |
|INVITE Require:replaces Contact:Conf-ID;isfocus
| |------------------->|
| | 180 Ringing |
| |<-------------------|
| | 200 OK |
| |<-------------------|
| | ACK |
| |------------------->|
| | RTP |
| |<==================>|
| | |
|Carol subscribes to the conference package
| - learns Bob is on hold |
| | |
| |SUBSCRIBE sip:Conf-ID
| |<-------------------|
| | 200 OK |
| |------------------->|
| | NOTIFY (Conf-Info) |
| |------------------->|
| | 200 OK |
| |<-------------------|
| | |
| Alice learns that Bob is talking to Carol
| | |
| NOTIFY (Conf-Info) | |
|<-------------------| |
| 200 OK | |
|------------------->| |
| | INVITE (hold) |
| |------------------->|
| | 200 OK |
| |<-------------------|
| | ACK |
| |------------------->|
| | |
| Alice learns that Carol is now on hold |
| | |
| NOTIFY (Conf-Info) | |
|<-------------------| |
| 200 OK | |
|------------------->| |
| | |
| Bob begins transfer operation |
| | |
| REFER Refer-To: Carol |
|<-------------------| |
| 202 Accepted | |
|------------------->| |
| NOTIFY (Refer) | |
|------------------->| |
| 200 OK | |
|<-------------------| |
| INVITE Replaces:B-C Contact:Alice |
|---------------------------------------->|
| 200 OK |
|<----------------------------------------|
| ACK |
|---------------------------------------->|
| RTP |
|<=======================================>|
| | BYE |
| |<-------------------|
| | 200 OK |
| |------------------->|
| NOTIFY (Refer) | |
|------------------->| |
| 200 OK | |
|<-------------------| |
| | |
| Bob terminates the ad-hoc conference |
| | |
| BYE | |
|<-------------------| |
| 200 OK | |
|------------------->| |
| | NOTIFY (Conf-Info) |
| |------------------->|
| | 200 OK |
| |<-------------------|
| NOTIFY (Conf-Info) | |
|<-------------------| |
| 200 OK | |
|------------------->| |
Figure 17: Attended Transfer as an Ad Hoc Conference
10. Transfer with Multiple Parties ๐ง
Okay, this example (Figure 18 ๐) has the Originator calling the Facilitator, who reaches the Recipient through the Screener. The Recipient's contact information gets exposed to the Facilitator and the Originator ๐. Heads up: this example is only there to clarify what the REFER method means ๐, and it should not be used as the design of an implementation ๐.
Originator Facilitator Screener Recipient
| | | |
1 |INVITE/200 OK/ACK | |"Get Fred for me!"
|----------->| | | "Right away!"
2 |INVITE (hold)/200 OK/ACK | |
|<-----------| | |
2 | |INVITE/200 OK/ACK |"I have a call
| |----------->| |from Mary for Fred"
2 | |INVITE (hold)/200 OK/ACK "Hold please"
| |<-----------| |
3 | | |INVITE/200 OK/ACK
| | |--------->|"You have a call
| | | |from Mary"
| | | | "Put her through"
3 | | |INVITE (hold)/200 OK/ACK
| | |--------->|
4 | |REFER | |
| |<-----------| |
4 | |202 Accepted| |
| |----------->| |
4 | |NOTIFY (100 Trying) |
| |----------->| |
4 | |200 OK | |
| |<-----------| |
5 | |INVITE/200 OK/ACK |
| |---------------------->|"This is Fred"
4 | |NOTIFY (200 OK) | "Please hold for
| |----------->| | Mary"
4 | |200 OK | |
| |<-----------| |
2 | |BYE/200 OK | |
| |<-----------| |
3 | | |BYE/200 OK|
| | |--------->|
5 | |INVITE (hold)/200 OK/ACK
| |---------------------->|
6 |REFER | | |
|<-----------| | |
6 |202 Accepted| | |
|----------->| | |
6 |NOTIFY (100 Trying) | |
|----------->| | |
6 |200 OK | | |
|<-----------| | |
7 |INVITE/200 OK/ACK | |
|----------------------------------->| "Hey Fred"
6 |NOTIFY (200 OK) | | "Hello Mary"
|----------->| | |
6 |200 OK | | |
|<-----------| | |
1 |BYE/200 OK | | |
|<-----------| | |
5 | |BYE/200 OK | |
| |---------------------->|
7 |BYE/200 OK | | |
|<-----------------------------------| "See you later"
Figure 18: Transfer with Multiple Parties Example
11. Gateway Transfer Issues ๐
So a gateway in SIP acts as a User Agent ๐. That means everything we've covered so far, all the call flows included, applies just as well to gateways as it does to native SIP endpoints โจ. There are still some gateway-specific issues, though, and this section covers them ๐ซถ. The focus here is on the common cases with Public Switched Telephone Network (PSTN) gateways, but similar situations come up for other gateways too, like H.323/SIP gateways ๐.
11.1. Coerce Gateway Hairpins to the Same Gateway ๐
okay so let's talk about how a hairpin can happen during a transfer ๐ฆ. The original call starts with the Transferee on the PSTN side of a SIP gateway. The Transferor is a SIP phone living purely in the IP space ๐ฑ. The Transfer Target is also on the PSTN side of a SIP gateway ๐ธ. After the transfer happens (consultative or blind, it's giving the same problem either way ๐ ), the Transferee is in a call with the Transfer Target, and both of them are on the PSTN side of a gateway. It's often desirable to take the gateway(s) out of the loop ๐. That's only likely to work if both legs of the target call go through the same gateway. Then the analogous transfer can maybe be invoked on the PSTN side, and the target call wouldn't involve the gateway at all โจ.
So the real question is how to give the proxy enough info to know it should route the call to the same gateway ๐ซถ. With a simple single call that hairpins, the incoming and outgoing legs have the same dialog. The proxy should have enough information to optimize the routing ๐.
In the consultative transfer scenario, it's desirable to coerce the consultative INVITE out the same gateway as the original call being transferred ๐. The catch is there's no way to relate the consultation to the original call ๐ญ. The target call INVITE does include the Replaces header, which has dialog information that relates it to the consultation. But there's no information that relates the target call back to the original ๐.
In the blind transfer scenario, it's desirable to coerce the target call onto the same gateway as the original call ๐. Same problem though: the target dialog can't be related to the original dialog ๐.
In either transfer scenario, it may be desirable to push the transfer operation onto the non-SIP side of the gateway ๐ง. Presumably that isn't possible unless all of the legs go out the same gateway. And if the gateway supports more than one trunk group, you might also need every leg on the same trunk group before you can do the transfer on the non-SIP side ๐.
Solutions to these gateway-specific issues may involve new extensions to SIP in the future ๐ฎ.
11.2. Consultative Turned Blind Gateway Glare ๐ฅ
the consultative-turned-blind case has a glare-like problem, and it's kind of a mess ๐ฑ. The Transferor starts the consultation INVITE, gets impatient, and hangs up. That turns the whole thing into a blind transfer ๐. The Transfer Target on the gateway (connected through a PSTN switch to a single line or "dumb" analog phone) starts ringing ๐. The user picks up just after the CANCEL reaches the Transfer Target ๐ณ. Then the REFER and INVITE for the target call get sent. The Transferee tries to set up the call on the PSTN side, but gets either a busy response or lands in the user's voicemail, because the user already has the handset in hand and off hook ๐ต.
This is another example of a race condition that this call flow can cause ๐โโ๏ธ. The recommended behavior is to use the approach described in Section 7.6 ๐ .
12. Security Considerations ๐จ
bestie, this section is SERIOUS, so let's be careful ๐ซถ. The call transfer flows in this document are implemented using the REFER and Replaces call control primitives in SIP. That means the security considerations in the REFER [RFC3515] and Replaces [RFC3891] documents MUST be followed. I'll give you the short version in the paragraphs below ๐. This document also deals with protecting the Address of Record URI of a Transfer Target, and that's covered in Sections 7.1 and 7.2 ๐ฆ.
Any REFER request MUST be appropriately authenticated and authorized using standard SIP mechanisms, or else calls may be hijacked ๐ฑ. A User Agent may use local policy or human intervention to decide whether or not to accept a REFER ๐โโ๏ธ. When you generate NOTIFY responses based on the outcome of the triggered request, take care when constructing the message/sipfrag body so that no private information is leaked ๐คซ.
An INVITE containing a Replaces header field SHOULD only be accepted if it has been properly authenticated and authorized using standard SIP mechanisms, and the requestor is authorized to perform dialog replacement ๐. Special care is needed if the replaced dialog uses additional media streams compared to the original dialog ๐๏ธ. In this case, the user MUST authorize the addition of new media streams in a dialog replacement. For example, the same mechanism used to authorize the addition of a media stream in a re-INVITE could be used ๐.
13. Acknowledgments ๐
This document is a collaborative product of the SIP working group ๐. Thanks to Rohan Mahy for his input on the use of Replaces in transfer ๐.
14. References ๐
14.1. Normative References โจ
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC3261] 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.
[RFC3515] Sparks, R., "The Session Initiation Protocol (SIP) Refer
Method", RFC 3515, April 2003.
[RFC3891] Mahy, R., Biggs, B., and R. Dean, "The Session
Initiation Protocol (SIP) "Replaces" Header", RFC 3891,
September 2004.
[RFC3892] Sparks, R., "The Session Initiation Protocol (SIP)
Referred-By Mechanism", RFC 3892, September 2004.
[RFC4538] Rosenberg, J., "Request Authorization through Dialog
Identification in the Session Initiation Protocol
(SIP)", RFC 4538, June 2006.
14.2. Informative References ๐ง
[CC-FRMWRK] Mahy, R., Sparks, R., Rosenberg, J., Petrie, D., and A.
Johnston, "A Call Control and Multi-party usage
framework for the Session Initiation Protocol (SIP)",
Work in Progress, March 2009.
[RFC4353] Rosenberg, J., "A Framework for Conferencing with the
Session Initiation Protocol (SIP)", RFC 4353,
February 2006.
[RFC4475] Sparks, R., Hawrylyshen, A., Johnston, A., Rosenberg,
J., and H. Schulzrinne, "Session Initiation Protocol
(SIP) Torture Test Messages", RFC 4475, May 2006.
[RFC4575] Rosenberg, J., Schulzrinne, H., and O. Levin, "A Session
Initiation Protocol (SIP) Event Package for Conference
State", RFC 4575, August 2006.
[RFC4579] Johnston, A. and O. Levin, "Session Initiation Protocol
(SIP) Call Control - Conferencing for User Agents",
BCP 119, RFC 4579, August 2006.
[RFC5057] Sparks, R., "Multiple Dialog Usages in the Session
Initiation Protocol", RFC 5057, November 2007.
[SIP-GRUU] Rosenberg, J., "Obtaining and Using Globally Routable
User Agent (UA) URIs (GRUU) in the Session Initiation
Protocol (SIP)", Work in Progress, October 2007.
Authors' Addresses ๐
Robert Sparks
Tekelec
17210 Campbell Road
Suite 250
Dallas, Texas 75252
USA
EMail: RjS@nostrum.com
Alan Johnston (editor)
Avaya
St. Louis, MO
EMail: alan@sipstation.com
Daniel Petrie
SIPez LLC
Arlington, MA 02476
US
Phone: +1 617 273 4000
EMail: dan.ietf@SIPez.com
URI: http://www.SIPez.com/
๐ฆ where this page comes from
- ietf: rfc5589 2009-06
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms