Skip to content
SIP Mastery

Part 3 · SIP mechanics / Module 09

Dialogs

The relationship between two user agents that lasts for a whole call — how a dialog starts, what state each side keeps, how requests inside it are built, and what happens when an INVITE forks, when re-INVITEs cross, and when nobody refreshes the session.

IntermediateAdvancedNOC optionalDEV coredraft

After this module, you can

  • Build the dialog ID from Call-ID and tags, from both sides of the call.
  • Tell an early dialog from a confirmed dialog, and say what ends each one.
  • Follow the dialog state — CSeq numbers, remote target, route set — through a call.
  • Build the Request-URI and Route header of a request inside a dialog.
  • Explain what a caller must do when a forked INVITE gets more than one 2xx.
  • Explain glare, 491 Request Pending, and the retry timers.
  • Explain how session timers end a call that nobody refreshes.

9.1 The dialog ID: Call-ID and two tags

A transaction lasts seconds (Module 8). A call lasts minutes, and many transactions happen during it: the INVITE, a re-INVITE for hold, an INFO for a key press, the BYE. The dialog ties them together:

RFC 3261 §12 · Dialogs
“A dialog represents a peer-to-peer SIP relationship between two user agents that persists for some time.”
Read the section ↗

Each side names the dialog with three values: the Call-ID, its own tag (the local tag), and the other side’s tag (the remote tag). The two sides see the same values, with the tags swapped:

RFC 3261 §12 · Dialogs
“A dialog is identified at each UA with a dialog ID, which consists of a Call-ID value, a local tag and a remote tag. The dialog ID at each UA involved in the dialog is not the same. Specifically, the local tag at one UA is identical to the remote tag at the peer UA.”
Read the section ↗
Alice (she called) Bob (he answered)
Call-ID 3848276298220188511@192.0.2.10 3848276298220188511@192.0.2.10
Local tag 9fxced76sl — her From tag 314159 — his To tag
Remote tag 314159 — the To tag 9fxced76sl — the From tag

In every request, From carries the sender’s tag and To the receiver’s. So in Alice’s requests, From has 9fxced76sl; in Bob’s requests — a re-INVITE, or a BYE when he hangs up — From has 314159 (Module 7).

9.2 Early dialogs and confirmed dialogs

A response with a To tag creates a dialog — but only some responses:

RFC 3261 §12.1 · Creation of a Dialog
“Within this specification, only 2xx and 101-199 responses with a To tag, where the request was INVITE, will establish a dialog.”
Read the section ↗
  • A 180 Ringing or 183 Session Progress with a To tag creates an early dialog. It already has state, so requests such as PRACK and UPDATE can travel in it before the call is answered.
  • A 2xx creates a confirmed dialog, or confirms the early dialog with the same tags.
  • A 100 Trying never creates a dialog. It usually has no To tag, and it stays on one hop.
RFC 3261 §12 · Dialogs
“A dialog can also be in the "early" state, which occurs when it is created with a provisional response, and then transition to the "confirmed" state when a 2xx final response arrives. For other responses, or if no response arrives at all on that dialog, the early dialog terminates.”
Read the section ↗

9.3 What each side remembers

RFC 3261 §12 · Dialogs
“This state consists of the dialog ID, a local sequence number (used to order requests from the UA to its peer), a remote sequence number (used to order requests from its peer to the UA), a local URI, a remote URI, remote target, a boolean flag called "secure", and a route set, which is an ordered list of URIs.”
Read the section ↗
Field The caller (UAC) takes it from The callee (UAS) takes it from
Local CSeq The CSeq of its INVITE Empty, until it sends its first request
Remote CSeq Empty, until the callee sends a request The CSeq of the INVITE
Local URI / remote URI From / To of the INVITE To / From of the INVITE
Remote target Contact of the response Contact of the INVITE
Route set Record-Route of the response, reversed Record-Route of the request, in order
RFC 3261 §12.1.2 · UAC Behavior
“The route set MUST be set to the list of URIs in the Record-Route header field from the response, taken in reverse order and preserving all URI parameters.”
Read the section ↗
RFC 3261 §12.1.1 · UAS behavior
“The route set MUST be set to the list of URIs in the Record-Route header field from the request, taken in order and preserving all URI parameters.”
Read the section ↗

Each side counts its own requests. Alice’s CSeq goes 1 (INVITE), 2 (BYE); Bob starts wherever he likes — 4711 in the example — and adds one from there. ACK and CANCEL reuse the number of the request they belong to:

RFC 3261 §12.2.1.1 · Generating the Request
“Requests within a dialog MUST contain strictly monotonically increasing and contiguous CSeq sequence numbers (increasing-by-one) in each direction (excepting ACK and CANCEL of course, whose numbers equal the requests being acknowledged or cancelled).”
Read the section ↗

The remote target changes only with a target refresh request — a re-INVITE or an UPDATE — or the 2xx to one. That is how a phone that changes its address keeps the call:

RFC 3261 §12.2 · Requests within a Dialog
“Specifically, requests that are not target refresh requests do not modify the dialog's remote target URI, and requests that are target refresh requests do.”
Read the section ↗

Step through the call below. Watch both tables: the dialog appears with the 180, becomes confirmed with the 200 OK, gets a new remote target from Bob’s re-INVITE, and ends with the BYE. The panel under the player shows the four layers that each message belongs to (9.8).

Live dialog table

One dialog, from INVITE to BYE

  • +New dialog
  • ~Changed at this step
Alice192.0.2.10Proxy B203.0.113.10Bob203.0.113.2001INVITE02100 Trying03INVITE04180 Ringing05180 Ringing06200 OK07200 OK08ACK09ACK10INVITE (re-INVITE)11INVITE (re-INVITE)12200 OK13200 OK14ACK15ACK16BYE17BYE18200 OK19200 OK
01/19

Alice sends the INVITE. Her From tag is the first half of the dialog ID.

Call
Call-ID 3848276298220188511@192.0.2.10
Session
SDP o=alice 2890844526 2890844526 IN IP4 192.0.2.10
Dialog
From tag 9fxced76sl · To tag — (none yet)
Transaction
branch z9hG4bK776asdhds · INVITE

Alice0 dialogs

No dialog yet. A dialog starts with a 101–199 response that has a To tag, or with a 2xx.

Bob0 dialogs

No dialog yet. A dialog starts with a 101–199 response that has a To tag, or with a 2xx.

9.4 Requests inside a dialog

Every request inside a dialog is built from the dialog state, not from the first INVITE:

  • To and From: the remote and local URI, with the remote and local tag.
  • Call-ID: the dialog’s Call-ID.
  • CSeq: the local CSeq plus one.
  • Request-URI: the remote target.
  • Route: the route set, in order.
RFC 3261 §12.2.1.1 · Generating the Request
“If the route set is not empty, and the first URI in the route set contains the lr parameter (see Section 19.1.1), the UAC MUST place the remote target URI into the Request-URI and MUST include a Route header field containing the route set values in order, including all parameters.”
Read the section ↗
Request In a dialog it…
re-INVITE Changes the session (hold, codec, video) with a new offer. A target refresh.
UPDATE Changes the session, even before the answer (RFC 3311). A target refresh.
BYE Ends the session and the dialog.
INFO Carries application data, such as a key press (RFC 6086).
REFER Asks the other side to call someone (transfer, Module 22).
NOTIFY Reports the progress of a REFER, in the same dialog.
PRACK Acknowledges a reliable provisional response, in the early dialog (RFC 3262).
ACK Acknowledges a 2xx to INVITE or re-INVITE. Not a target refresh.

A re-INVITE goes to one device — the remote target — so it never forks:

RFC 3261 §14.1 · UAC Behavior
“Unlike an INVITE, which can fork, a re-INVITE will never fork, and therefore, only ever generate a single final response.”
Read the section ↗

A request with tags that match no dialog gets 481 Call/Transaction Does Not Exist:

RFC 3261 §12.2.2 · UAS Behavior
“If the UAS wishes to reject the request because it does not wish to recreate the dialog, it MUST respond to the request with a 481 (Call/Transaction Does Not Exist) status code and pass that to the server transaction.”
Read the section ↗
RFC 3261 §12.2.1.2 · Processing the Responses
“If the response for a request within a dialog is a 481 (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC SHOULD terminate the dialog.”
Read the section ↗

9.5 Forking: many early dialogs, and more than one 2xx

When Proxy B forks an INVITE to Bob’s three devices (Module 3), each device that rings adds its own To tag. Alice gets one early dialog per tag — all with the same Call-ID and the same local tag. If two devices answer at once, both 2xx responses reach her:

RFC 3261 §13.2.2.4 · 2xx Responses
“Multiple 2xx responses may arrive at the UAC for a single INVITE request due to a forking proxy. Each response is distinguished by the tag parameter in the To header field, and each represents a distinct dialog, with a distinct dialog identifier.”
Read the section ↗

Alice must ACK every 2xx. If she wants only one call, she then ends the others with BYE:

RFC 3261 §13.2.2.4 · 2xx Responses
“If, after acknowledging any 2xx response to an INVITE, the UAC does not want to continue with that dialog, then the UAC MUST terminate the dialog by sending a BYE request as described in Section 15.”
Read the section ↗

The early dialogs that never got a 2xx do not end at once. Alice waits 64×T1 after the first 2xx, in case another 2xx is on its way:

RFC 3261 §13.2.2.4 · 2xx Responses
“The UAC core considers the INVITE transaction completed 64*T1 seconds after the reception of the first 2xx response. At this point all the early dialogs that have not transitioned to established dialogs are terminated.”
Read the section ↗

Forking tree

Forking: one phone answers

INVITEAliceProxy BforksDesk phoneno tag yetidleMobileno tag yetidleSoftphoneno tag yetidle
01/23

Alice calls bob@biloxi.example.

Alice’s dialogs

No dialog yet: no response with a To tag has reached Alice.

9.6 Glare and 491 Request Pending

A dialog allows only one INVITE transaction at a time, in either direction:

RFC 3261 §14.1 · UAC Behavior
“Note that a UAC MUST NOT initiate a new INVITE transaction within a dialog while another INVITE transaction is in progress in either direction.”
Read the section ↗

When both sides send a re-INVITE at the same moment — glare — each side has its own INVITE in progress, so each rejects the other’s:

RFC 3261 §14.2 · UAS Behavior
“A UAS that receives an INVITE on a dialog while an INVITE it had sent on that dialog is in progress MUST return a 491 (Request Pending) response to the received INVITE.”
Read the section ↗

Both then wait a random time and try again. The side that created the Call-ID waits longer (2.1 to 4 seconds); the other side waits 0 to 2 seconds, so it usually goes first:

RFC 3261 §14.1 · UAC Behavior
“If the UAC is the owner of the Call-ID of the dialog ID (meaning it generated the value), T has a randomly chosen value between 2.1 and 4 seconds in units of 10 ms.”
Read the section ↗

Call flow · two re-INVITEs cross

Glare: two re-INVITEs cross

  • SIP
Aliceowns the Call-IDBob203.0.113.2001INVITE (hold)02INVITE (add video)03491 Request Pending04ACK05491 Request Pending06ACK07INVITE (add video)08200 OK09ACK10INVITE (hold)11200 OK12ACK
01/12

Alice puts the call on hold with a re-INVITE. Her SDP says sendonly.

All steps as text
  1. Alice → Bob: INVITE (hold). Alice puts the call on hold with a re-INVITE. Her SDP says sendonly.
  2. Bob → Alice: INVITE (add video). At the same moment, Bob adds video with his own re-INVITE.
  3. Bob → Alice: 491 Request Pending. Bob has a re-INVITE of his own in progress, so he rejects Alice's with 491.
  4. Alice → Bob: ACK. Alice ACKs the 491. Her session stays as it was.
  5. Alice → Bob: 491 Request Pending. Alice has the same problem, so she rejects Bob's re-INVITE with 491 too.
  6. Bob → Alice: ACK. Bob ACKs the 491.
  7. Bob → Alice: INVITE (add video). Bob does not own the Call-ID, so he waits 0 to 2 seconds. After 1.3 s he tries again.
  8. Alice → Bob: 200 OK. Nothing crosses this time. Alice accepts the video.
  9. Bob → Alice: ACK. Bob ACKs the 200 OK. The call now has video.
  10. Alice → Bob: INVITE (hold). Alice owns the Call-ID, so she waits 2.1 to 4 seconds. After 3.2 s she tries again.
  11. Bob → Alice: 200 OK. Bob accepts the hold.
  12. Alice → Bob: ACK. Alice ACKs the 200 OK. Both changes are now done, one after the other.

9.7 Session timers: who refreshes, and how

Module 7 introduced Session-Expires and Min-SE. In the dialog, both sides run a timer for the session interval, and one side — the refresher — must send a refresh before it runs out:

RFC 4028 §3 · Overview of Operation
“The Session-Expires header field also contains a 'refresher' parameter, which indicates who is doing the refreshing -- the UA that is currently the UAC, or the UA that is currently the UAS.”
Read the section ↗

The refresher parameter says uac or uas — relative to the current transaction. When Bob, who answered the call, sends the refresh UPDATE, he is the UAC of that UPDATE, so it says refresher=uac.

RFC 4028 §7.2 · Processing a 2xx Response
“It is RECOMMENDED that this refresh be sent once half the session interval has elapsed.”
Read the section ↗

A refresh is a re-INVITE or an UPDATE; only its 2xx restarts the timer. If no refresh arrives, the other side ends the call slightly before the session expires:

RFC 4028 §10 · Performing Refreshes
“Similarly, if the side not performing refreshes does not receive a session refresh request before the session expiration, it SHOULD send a BYE to terminate the session, slightly before the session expiration. The minimum of 32 seconds and one third of the session interval is RECOMMENDED.”
Read the section ↗

Call flow · session timer refreshes

Session timer: Bob refreshes

  • SIP
Alice192.0.2.10Bob203.0.113.2001INVITE02200 OK03ACK04UPDATE (refresh)05200 OK06UPDATE (refresh)07200 OK08BYE09200 OK
01/09

Alice supports session timers and asks for an interval of 1800 s (30 minutes).

All steps as text
  1. Alice → Bob: INVITE. Alice supports session timers and asks for an interval of 1800 s (30 minutes).
  2. Bob → Alice: 200 OK. Bob accepts 1800 s and chooses himself, the UAS, as the refresher.
  3. Alice → Bob: ACK. Alice ACKs. Both phones start a 1800 s session timer.
  4. Bob → Alice: UPDATE (refresh). At 900 s, half the interval, Bob refreshes. In this UPDATE Bob is the UAC, so refresher=uac.
  5. Alice → Bob: 200 OK. The 200 OK restarts the timer: the session now lasts until 2700 s.
  6. Bob → Alice: UPDATE (refresh). At 1800 s, Bob refreshes again.
  7. Alice → Bob: 200 OK. The session now lasts until 3600 s.
  8. Alice → Bob: BYE. At 2400 s, Alice hangs up.
  9. Bob → Alice: 200 OK. Bob ends the call.
RFC 4028 §3 · Overview of Operation
“Note that the session timer refreshes the session, not the dialog used to establish the session.”
Read the section ↗

9.8 Call, session, dialog, transaction

Four words that are easy to mix up:

What it is Named by How many in one simple call
Call Everything that belongs to one Call-ID Call-ID 1
Session The media exchange: audio, video SDP o= line (Module 15) 1
Dialog The SIP relationship between two UAs Call-ID + both tags 1 — or more after forking
Transaction One request and its responses Top Via branch + method One per request: INVITE, ACK for 2xx, BYE… on each hop

They do not always line up:

  • A forked INVITE is one call with several dialogs (9.5).
  • A B2BUA joins two dialogs, often with two Call-IDs, into one conversation (Module 3).
  • A session timer refreshes the session; a BYE ends the session and the dialog together.
  • A re-INVITE is a new transaction in the same dialog, and it changes the same session.

Common mistakes

Sending an in-dialog request to the first Request-URI

The first INVITE went to an address of record, a group, or a phone number. Requests inside the dialog must go to the remote target — the Contact — through the route set. A phone that reuses the first Request-URI sends its BYE back into routing, where it can reach another device, or no device at all.

Broken

Broken: BYE to the first Request-URI

  • SIP
  • ⚠Problem
Alice192.0.2.10Proxy B203.0.113.10Bob203.0.113.20Carol203.0.113.3001INVITE02100 Trying03INVITE04180 Ringing05180 Ringing06200 OK07200 OK08ACK09BYE⚠10BYE11481 Call Does Not Exist12481 Call Does Not Exist⚠
01/12

Alice calls the support line: sip:support@biloxi.example.

All steps as text
  1. Alice → Proxy B: INVITE. Alice calls the support line: sip:support@biloxi.example.
  2. Proxy B → Alice: 100 Trying. Proxy B answers 100 Trying on this hop.
  3. Proxy B → Bob: INVITE. Proxy B picks a free agent, Bob. It does not record-route.
  4. Bob → Proxy B: 180 Ringing. Bob's phone rings.
  5. Proxy B → Alice: 180 Ringing. Proxy B forwards the 180.
  6. Bob → Proxy B: 200 OK. Bob answers. His Contact is sip:bob@203.0.113.20.
  7. Proxy B → Alice: 200 OK. The route set is empty, and the remote target is Bob's Contact.
  8. Alice → Bob: ACK. Alice sends the ACK straight to the remote target.
  9. Alice → Proxy B: BYE. Alice hangs up. Her phone sends the BYE to sip:support@biloxi.example, the first Request-URI. Problem: The Request-URI must be the remote target from the Contact, not the first Request-URI.
  10. Proxy B → Carol: BYE. Proxy B routes the BYE like a new request to the support line. The next free agent is Carol.
  11. Carol → Proxy B: 481 Call Does Not Exist. Carol's phone has no dialog with these tags. It answers 481.
  12. Proxy B → Alice: 481 Call Does Not Exist. Alice's phone ends its dialog. Bob's phone still shows a call with nobody on it. Problem: Bob never receives the BYE.

481 Call/Transaction Does Not Exist

The receiver has no dialog with these tags. The usual causes:

  • An element restarted or failed over, and lost its dialog state.
  • A B2BUA or SBC changed the tags on one side, and a request reached the wrong leg.
  • The sender used the wrong tags, or swapped them (Module 7).
  • The request went to the wrong device (see the mistake above).

Remember: after a 481 (or a 408) to a request inside a dialog, the sender ends the dialog. Check which element answered 481, and compare its tags with the 200 OK that created the dialog.

Not ACKing and ending the extra 2xx after forking

Two devices answer at the same moment. A caller that ACKs only the first 2xx leaves the second device in a call with nobody: it sends its 200 OK for 32 seconds, then gives up with BYE. The caller must ACK every 2xx, then BYE the dialogs it does not want.

Broken

Broken: Alice ignores the second 200 OK

  • SIP
  • ⚠Problem
Alice192.0.2.10Proxy B203.0.113.10Desk phone203.0.113.20Mobile203.0.113.4001INVITE02100 Trying03INVITE04INVITE05180 Ringing06180 Ringing07180 Ringing08180 Ringing09200 OK10200 OK11200 OK12200 OK13ACK14ACK15200 OK (again)16200 OK (again)⚠17BYE18BYE19200 OK20200 OK
01/20

Alice calls bob@biloxi.example.

All steps as text
  1. Alice → Proxy B: INVITE. Alice calls bob@biloxi.example.
  2. Proxy B → Alice: 100 Trying. Proxy B answers 100 Trying on this hop.
  3. Proxy B → Desk phone: INVITE. Bob has 2 registered devices. Proxy B forks the INVITE to the desk phone, with its own branch.
  4. Proxy B → Mobile: INVITE. Proxy B also sends the INVITE to the mobile.
  5. Desk phone → Proxy B: 180 Ringing. The desk phone rings. It picks its own To tag: d7c1.
  6. Proxy B → Alice: 180 Ringing. Alice now has 1 early dialog, one for each To tag.
  7. Mobile → Proxy B: 180 Ringing. The mobile rings. It picks its own To tag: m2a8.
  8. Proxy B → Alice: 180 Ringing. Alice now has 2 early dialogs, one for each To tag.
  9. Desk phone → Proxy B: 200 OK. Bob answers on the desk phone.
  10. Proxy B → Alice: 200 OK. Proxy B forwards the 200 OK. Alice's dialog with the desk phone becomes confirmed.
  11. Mobile → Proxy B: 200 OK. At the same moment, someone answers the mobile too.
  12. Proxy B → Alice: 200 OK. Proxy B forwards every 2xx. Alice now has two confirmed dialogs.
  13. Alice → Proxy B: ACK. Alice ACKs the desk phone's 200 OK.
  14. Proxy B → Desk phone: ACK. Proxy B forwards the ACK to the desk phone.
  15. Mobile → Proxy B: 200 OK (again). No ACK reaches the mobile. It sends its 200 OK again, and again.
  16. Proxy B → Alice: 200 OK (again). Alice ignores the second 200 OK. She does not ACK it and does not end it. Problem: Every 2xx needs an ACK, even from a dialog the caller does not want.
  17. Mobile → Proxy B: BYE. After 64×T1 (32 s) with no ACK, the mobile gives up with BYE. For 32 s, it showed a call that nobody was on.
  18. Proxy B → Alice: BYE. Proxy B forwards the BYE to Alice.
  19. Alice → Proxy B: 200 OK. Alice answers the BYE.
  20. Proxy B → Mobile: 200 OK. Proxy B forwards the 200 OK to the mobile.

The call drops at the same time, every time

A call that always ends after the same time — often just under 15 or 30 minutes — is usually a session timer with no refresh. One side agreed to refresh, but its refresh never arrives, or gets a non-2xx response. The other side then ends the call with BYE, slightly before the session expires.

No refresh

Session timer: no refresh

  • SIP
  • ⚠Problem
Alice192.0.2.10Bob203.0.113.2001INVITE02200 OK03ACK04BYE⚠05200 OK
01/05

Alice supports session timers and asks for an interval of 1800 s (30 minutes).

All steps as text
  1. Alice → Bob: INVITE. Alice supports session timers and asks for an interval of 1800 s (30 minutes).
  2. Bob → Alice: 200 OK. Bob accepts 1800 s and chooses himself, the UAS, as the refresher.
  3. Alice → Bob: ACK. Alice ACKs. Both phones start a 1800 s session timer.
  4. Alice → Bob: BYE. At 1768 s, no refresh has come. Alice's phone ends the call 32 s before the session expires. Problem: The call drops at 29 min 28 s, every time.
  5. Bob → Alice: 200 OK. Bob's phone ends the call.

Summary

  • A dialog is the SIP relationship between two UAs for a whole call. Each side names it by Call-ID + local tag + remote tag; the two sides see the tags swapped.
  • A 101–199 response with a To tag creates an early dialog; a 2xx creates or confirms a confirmed dialog. A non-2xx final response ends the early dialogs; a BYE ends a confirmed one.
  • Each side keeps local and remote CSeq, local and remote URI, the remote target (the peer’s Contact), and the route set (Record-Route, reversed by the caller).
  • Requests inside a dialog go to the remote target through the route set. Only a target refresh — re-INVITE or UPDATE — changes the remote target.
  • A forked INVITE can create many early dialogs and more than one 2xx. The caller ACKs every 2xx and ends the extra dialogs with BYE.
  • Two re-INVITEs that cross get 491 Request Pending; each side retries after a random wait.
  • With session timers, the refresher refreshes at half the interval; without a refresh, the other side ends the call just before it expires.