RFC 5589

Session Initiation Protocol (SIP) Call Control - Transfer

๐Ÿ“… published June 2009, from ietf

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 (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 INVITE in 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 ๐ŸŽฏ:

  1. Any party in a SIP session must be able to transfer any other party in that session at any point in that session. ๐Ÿ’ซ
  2. 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 ๐Ÿ˜ญ๐ŸŽ€.
  1. The Transferor must know whether or not the transfer was successful. โœ…
  2. The Transferee must be able to replace an existing dialog with a new dialog. ๐Ÿฆ‹
  3. The Transferor and Transferee should indicate their support for the primitives required to achieve transfer. ๐Ÿซถ
  4. 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 ๐Ÿซ–

  1. 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 INVITE and 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.
  2. 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 INVITE usage's dialog, the connection was super obvious.
  3. people had concerns about authorizing out-of-dialog REFERs ๐Ÿ’€ most implementations basically piggyback the REFER authorization on the INVITE authorization, 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