8.1 A transaction: one request and all its responses
SIP does its work in small exchanges. Each exchange is a transaction:
“Specifically, a SIP transaction consists of a single request and any responses to that request, which include zero or more provisional responses and one or more final responses.”Read the section ↗
A transaction has two sides. The client transaction sends the request and receives the responses. The server transaction receives the request and sends the responses. Above each side sits the transaction user (TU): the UA core in a phone, or the proxy core in a stateful proxy. The TU decides what to send; the transaction makes sure it arrives.
Transactions exist hop by hop. In a call from Alice through Proxy B to Bob, there are two INVITE transactions: Alice’s client transaction with Proxy B’s server transaction, and Proxy B’s client transaction with Bob’s server transaction. A stateless proxy is not part of either:
“A stateless proxy does not contain a client or server transaction.”Read the section ↗
| Transaction | Dialog (Module 9) | |
|---|---|---|
| What it is | One request and its responses | A relationship between two UAs, made of many transactions |
| Named by | The top Via branch (and the method) |
Call-ID + From tag + To tag |
| Lives | Seconds | Minutes or hours — as long as the call |
| Exists at | Each hop: UAs and stateful proxies | Only the two UAs (and B2BUAs) |
8.2 How elements match a transaction
Every request carries a branch in its top Via. The branch names the transaction, so it must be new for every new request:
“The branch parameter value MUST be unique across space and time for all requests sent by the UA. The exceptions to this rule are CANCEL and ACK for non-2xx responses.”Read the section ↗
The branch starts with the magic cookie z9hG4bK. The cookie tells the receiver that the sender follows RFC 3261, so the branch is unique and can be used as the key:
“The branch ID inserted by an element compliant with this specification MUST always begin with the characters "z9hG4bK".”Read the section ↗
“If it is present and begins with the magic cookie "z9hG4bK", the request was generated by a client transaction compliant to this specification.”Read the section ↗
The two sides match differently:
| Receiver | Compares | Why |
|---|---|---|
| Server (a request arrives) | Top Via branch, top Via sent-by, method | Sent-by, because another client could pick the same branch. Method, so that a CANCEL with the same branch is not taken for the INVITE. |
| Client (a response arrives) | Top Via branch, CSeq method | The CSeq method separates the response to a CANCEL from the response to the INVITE it cancels. |
There is one exception for the method: an ACK matches the INVITE transaction it acknowledges.
“the method of the request matches the one that created the transaction, except for ACK, where the method of the request that created the transaction is INVITE.”Read the section ↗
“The method is needed since a CANCEL request constitutes a different transaction, but shares the same value of the branch parameter.”Read the section ↗
Pick a message below and watch Bob — or Alice — look for its transaction.
Transaction matcher
Which transaction does this message belong to?
Arriving message
Via: SIP/2.0/UDP 192.0.2.10:5060;branch=z9hG4bK74bf9 CSeq: 1 INVITE
| Transaction | Branch | Sent-by | Method | Result |
|---|---|---|---|---|
| INVITEz9hG4bK74bf9 · 192.0.2.10:5060Proceeding (ringing) | ✓ | ✓ | ✓ | match |
| OPTIONSz9hG4bK1c33 · 198.51.100.10:5060Completed | ✗ | ✗ | ✗ | — |
Matches the INVITE transaction
A retransmission. Bob sends the last provisional response (180) again. The TU does not see the copy.
8.3 Four state machines
RFC 3261 defines a state machine for each side of each kind of transaction. INVITE is different because a person must answer it: it can take many seconds, so it uses a three-way handshake (INVITE, final response, ACK). Every other method is a quick two-way exchange.
| Machine | States |
|---|---|
| INVITE client | Calling → Proceeding → Completed → Terminated |
| INVITE server | Proceeding → Completed → Confirmed → Terminated |
| Non-INVITE client | Trying → Proceeding → Completed → Terminated |
| Non-INVITE server | Trying → Proceeding → Completed → Terminated |
The player shows one hop: Alice’s client transaction on the left, Bob’s server transaction on the right, and the messages between them. Step through the call, then press Lose this… on any message and watch the timers take over.
Transaction player
One hop: two state machines and their timers
- SIP
- Failure response
- ✕Lost
- Current state
Alice · INVITE client transaction
- Timer A fires at 0.5 s in 0.5 s
- Timer B fires at 32 s in 32 s
Bob · INVITE server transaction
- No timer runs.
1/7
Alice's TU starts an INVITE client transaction (Calling). Timer A (0.5 s) and Timer B (32 s) start. Bob creates a server transaction (Proceeding) and passes the INVITE to the TU.
Alicenew → Calling on INVITE from TU
Bobnew → Proceeding on request
Things to try:
- INVITE, 486, lose the 486. Timer G sends it again after 500 ms; Alice’s transaction, already waiting in Completed, ACKs the copy.
- INVITE, Bob is down, UDP. Seven INVITEs, then Timer B ends the attempt at 32 s. Switch to TCP: the connection fails at once.
- OPTIONS, answers after 6 s. Bob sends 100 Trying at 3.5 s, and Alice’s retransmissions slow down to one every 4 s.
- INVITE, 200 OK, every ACK lost. The 32-second drop — see Common mistakes below.
8.4 Timers
All the timers grow from three values:
| Value | Default | Meaning |
|---|---|---|
| T1 | 500 ms | Estimate of the round-trip time |
| T2 | 4 s | Longest interval between retransmissions of a non-INVITE request or an INVITE response |
| T4 | 5 s | Longest time a message stays in the network |
“T1 is an estimate of the round-trip time (RTT), and it defaults to 500 ms.”Read the section ↗
Retransmit timers start at T1 and double. For an INVITE, there is no cap:
“When timer A fires, the client transaction MUST retransmit the request by passing it to the transport layer, and MUST reset the timer with a value of 2*T1.”Read the section ↗
For everything else, the interval stops growing at T2:
“For the default values of T1 and T2, this results in intervals of 500 ms, 1 s, 2 s, 4 s, 4 s, 4 s, etc.”Read the section ↗
Timeout timers are 64×T1 — 32 seconds by default:
“The value of 64*T1 is equal to the amount of time required to send seven requests in the case of an unreliable transport.”Read the section ↗
| Timer | Side | Value | Job |
|---|---|---|---|
| A | INVITE client | T1, doubling | Send the INVITE again (UDP) |
| B | INVITE client | 64×T1 | Give up: no response |
| D | INVITE client | ≥ 32 s UDP, 0 TCP | Absorb copies of the 300–699 response |
| E | Non-INVITE client | T1, doubling to T2 | Send the request again (UDP) |
| F | Non-INVITE client | 64×T1 | Give up: no final response |
| G | INVITE server | T1, doubling to T2 | Send the 300–699 response again (UDP) |
| H | INVITE server | 64×T1 | Give up: no ACK |
| I | INVITE server | T4 UDP, 0 TCP | Absorb copies of the ACK |
| J | Non-INVITE server | 64×T1 UDP, 0 TCP | Answer copies of the request |
| K | Non-INVITE client | T4 UDP, 0 TCP | Absorb copies of the response |
| L, M | INVITE server, client | 64×T1 | Stay in Accepted after a 2xx (RFC 6026, §8.8) |
Timer C is a proxy timer: a stateful proxy uses it to give up on an INVITE branch that has no final response after more than 3 minutes.
“The client transaction SHOULD start timer D when it enters the "Completed" state, with a value of at least 32 seconds for unreliable transports, and a value of zero seconds for reliable transports.”Read the section ↗
Change T1 below and see every schedule stretch with it. A larger T1 suits slow links, such as satellite; the RFC allows it.
Timer timeline
T1 doubles; 64×T1 (32 s) ends the attempt
- First send
- Retransmission
- Timeout
Timer A starts at T1 and doubles each time, with no cap. A 1xx response stops it.
- 0 s
- 0.5 s+0.5 s
- 1.5 s+1 s
- 3.5 s+2 s
- 7.5 s+4 s
- 15.5 s+8 s
- 31.5 s+16 s
- 32 sTimer B: timeout
After the final response: the waiting timers
| Timer | Value (UDP) | State | Why it waits |
|---|---|---|---|
| Timer D | 32 s | INVITE client, Completed | absorbs copies of the 300–699 |
| Timer I | 5 s | INVITE server, Confirmed | absorbs copies of the ACK |
| Timer J | 32 s | Non-INVITE server, Completed | answers copies of the request |
| Timer K | 5 s | Non-INVITE client, Completed | absorbs copies of the response |
8.5 Retransmissions: UDP only
UDP gives no delivery guarantee, so the transaction layer retransmits. TCP and TLS deliver every byte or report an error, so the transaction layer does not:
“The request is not retransmitted over reliable transports.”Read the section ↗
A retransmission is a byte-for-byte copy: same branch, same CSeq, same everything. The receiver’s transaction absorbs it, and may answer with the last response it sent. The 100 Trying exists mainly to stop INVITE retransmissions early:
“This provisional response is needed to quench request retransmissions rapidly in order to avoid network congestion.”Read the section ↗
Call flow · retransmissions over UDP
Retransmissions over UDP
- SIP
Alice sends the INVITE over UDP and starts Timer A (500 ms). The network loses the INVITE.
All steps as text
- Alice → Bob: INVITE. Alice sends the INVITE over UDP and starts Timer A (500 ms). The network loses the INVITE.
- Alice → Bob: INVITE (again). Timer A fires. Alice sends the same INVITE again: same branch, same CSeq, same bytes.
- Bob → Alice: 100 Trying. Bob answers 100 Trying at once. Alice stops sending the INVITE.
- Bob → Alice: 180 Ringing. Bob's phone rings. The To header now has Bob's tag.
- Bob → Alice: 486 Busy Here. Bob rejects the call and starts Timer G (500 ms). The network loses the 486.
- Bob → Alice: 486 Busy Here (again). Timer G fires. Bob sends the same 486 again.
- Alice → Bob: ACK. Alice ACKs the 486 with the branch of the INVITE. Bob stops sending the 486.
8.6 ACK for a non-2xx and ACK for a 2xx
The ACK comes in two kinds, and they behave very differently:
“In the case of a transaction where the request was an INVITE (known as an INVITE transaction), the transaction also includes the ACK only if the final response was not a 2xx response. If the response was a 2xx, the ACK is not considered part of the transaction.”Read the section ↗
| ACK for 300–699 | ACK for 2xx | |
|---|---|---|
| Part of | The INVITE transaction | Its own transaction |
| Sent by | The client transaction | The UA core of the caller |
| Branch | Same as the INVITE | New |
| Travels | One hop: each stateful proxy ACKs on its own hop | End to end, to the callee’s Contact, through the route set |
| Response retransmitted by | The server transaction (Timer G) | The UA core of the callee |
“The ACK MUST contain a single Via header field, and this MUST be equal to the top Via header field of the original request. The CSeq header field in the ACK MUST contain the same value for the sequence number as was present in the original request, but the method parameter MUST be equal to "ACK".”Read the section ↗
“The UAC core MUST generate an ACK request for each 2xx received from the transaction layer.”Read the section ↗
Why the difference? A forked INVITE can be answered by several phones, and the caller must see — and ACK — every 2xx. So proxies forward each 2xx, and the 2xx and its ACK travel between the two UAs. The callee’s UA core sends the 2xx again until the ACK arrives, even over TCP, because a later hop may be UDP:
“The 2xx response is passed to the transport with an interval that starts at T1 seconds and doubles for each retransmission until it reaches T2 seconds (T1 and T2 are defined in Section 17).”Read the section ↗
ACK for 486: hop by hop
ACK for a 486: hop by hop
- SIP
Alice sends the INVITE to Proxy B. Her branch is z9hG4bK776asdhds.
All steps as text
- Alice → Proxy B: INVITE. Alice sends the INVITE to Proxy B. Her branch is z9hG4bK776asdhds.
- Proxy B → Alice: 100 Trying. Proxy B answers 100 Trying on this hop.
- Proxy B → Bob: INVITE. Proxy B forwards the INVITE. It adds its own Via, with its own branch.
- Bob → Proxy B: 180 Ringing. Bob's phone rings.
- Proxy B → Alice: 180 Ringing. Proxy B removes its Via and forwards the 180.
- Bob → Proxy B: 486 Busy Here. Bob rejects the call with 486.
- Proxy B → Bob: ACK. Proxy B ACKs the 486 itself, with the branch of its INVITE. Bob's transaction ends.
- Proxy B → Alice: 486 Busy Here. Proxy B forwards the 486 to Alice.
- Alice → Proxy B: ACK. Alice ACKs the 486 on her hop, with her own INVITE branch. Proxy B does not forward this ACK.
8.7 CANCEL: its own transaction, aimed at another
A CANCEL copies the top Via of the INVITE it cancels — with the same branch — so each hop can find that INVITE:
“A CANCEL constructed by a client MUST have only a single Via header field value matching the top Via value in the request being cancelled.”Read the section ↗
But its CSeq method is CANCEL, so it is a transaction of its own, with its own 200 OK:
“However, the method part of the CSeq header field MUST have a value of CANCEL. This allows it to be identified and processed as a transaction in its own right (See Section 17).”Read the section ↗
The result is two transactions on each hop: the CANCEL transaction, answered 200 OK, and the INVITE transaction, which ends with 487 Request Terminated and its ACK. Like the ACK for a non-2xx, a CANCEL is hop by hop: each proxy answers it and sends its own CANCEL downstream.
Call flow · CANCEL, hop by hop
Alice hangs up while Bob's phone rings
- SIP
Alice's phone calls Bob through Proxy B.
All steps as text
- Alice → Proxy B: INVITE. Alice's phone calls Bob through Proxy B.
- Proxy B → Alice: 100 Trying. Proxy B answers 100 Trying. It keeps state for the INVITE transaction.
- Proxy B → Bob: INVITE. Proxy B forwards the INVITE to Bob's phone.
- Bob → Proxy B: 180 Ringing. Bob's phone rings.
- Proxy B → Alice: 180 Ringing. Alice hears the ringback tone.
- Alice → Proxy B: CANCEL. Alice hangs up before Bob answers. The CANCEL copies the Request-URI, Call-ID, From, To, and branch of the INVITE.
- Proxy B → Alice: 200 OK (CANCEL). Proxy B answers the CANCEL itself. CANCEL is hop-by-hop.
- Proxy B → Bob: CANCEL. Proxy B sends its own CANCEL on its own hop, with the branch of its own INVITE.
- Bob → Proxy B: 200 OK (CANCEL). Bob's phone stops ringing and answers the CANCEL.
- Bob → Proxy B: 487 Request Terminated. Bob's phone ends the INVITE transaction with 487.
- Proxy B → Bob: ACK. Proxy B confirms the 487 on its hop. This ACK reuses the branch of the INVITE.
- Proxy B → Alice: 487 Request Terminated. Proxy B forwards the 487 to Alice's phone.
- Alice → Proxy B: ACK. Alice's phone confirms the 487. The call never started.
8.8 Later fixes: RFC 6026 and RFC 4320
Field experience found two problems in the RFC 3261 machines.
RFC 6026: the Accepted state. In RFC 3261, an INVITE transaction ends the moment it sends or receives a 2xx. A late copy of the INVITE then matches nothing, and a proxy may treat it as a new call:
“Once any element with a server transaction (say, a proxy in the path of the INVITE) deletes that transaction state, any retransmission of the INVITE will be treated as a new request, potentially forwarded to different locations than the original.”Read the section ↗
RFC 6026 adds an Accepted state on both sides. The transaction stays there for 64×T1 (Timer L on the server, Timer M on the client), absorbs INVITE copies, and passes each 2xx and ACK to the TU:
“To allow a SIP element to recognize retransmissions of an INVITE as retransmissions instead of new requests, a new state, "Accepted", is added to the INVITE server transaction state machine.”Read the section ↗
It also stops proxies from forwarding stray responses — responses that match no transaction — which attackers could use to bounce traffic:
“The proxy MUST NOT forward the response if there is no matching transaction state machine.”Read the section ↗
Switch the RFC 6026 box in the player above on and off to compare the two machines.
RFC 4320: non-INVITE fixes. A non-INVITE transaction must finish quickly, so RFC 4320 removes two kinds of useless messages. Only 100 is allowed as a provisional response — and over UDP, only after Timer E has grown to T2:
“An SIP element MUST NOT send any provisional response with a Status-Code other than 100 to a non-INVITE request.”Read the section ↗
And a late 408 is pointless, because the client has already timed out:
“A transaction-stateful SIP element MUST NOT send a response with Status-Code of 408 to a non-INVITE request.”Read the section ↗
Common mistakes
The 32-second drop
The call connects, both sides talk, and after about 32 seconds the call ends — every time. The 200 OK arrived, but the ACK never reached the callee. The callee’s UA core sends the 200 OK again for 64×T1 and then gives up with BYE.
“If the server retransmits the 2xx response for 64*T1 seconds without receiving an ACK, the dialog is confirmed, but the session SHOULD be terminated.”Read the section ↗
The usual cause: the ACK follows the Contact of the 2xx, and that Contact is wrong — a private address behind NAT — while no proxy record-routes to carry the ACK. In a trace, look for repeated 200 OKs, and check where each ACK goes.
Broken
Broken: the ACK never reaches Bob
- SIP
- ⚠Problem
Alice sends the INVITE to Proxy B.
All steps as text
- Alice → Proxy B: INVITE. Alice sends the INVITE to Proxy B.
- Proxy B → Alice: 100 Trying. Proxy B answers 100 Trying on this hop.
- Proxy B → Bob: INVITE. Proxy B forwards the INVITE to Bob through the NAT router. It does not add Record-Route.
- Bob → Proxy B: 180 Ringing. Bob's phone rings. Its Contact is a private address: 10.0.0.20.
- Proxy B → Alice: 180 Ringing. Proxy B forwards the 180 with the private Contact.
- Bob → Proxy B: 200 OK. Bob answers. Bob's UA core starts to send the 200 OK again until an ACK arrives.
- Proxy B → Alice: 200 OK. Proxy B forwards the 200 OK. The route set is empty: no Record-Route.
- Alice → Bob: ACK. Alice sends the ACK straight to the Contact, 10.0.0.20. That address is private, so the ACK never arrives. Problem: The ACK goes to a private address. No router on the Internet can deliver it.
- Bob → Proxy B: 200 OK (again). No ACK after 500 ms. Bob's phone sends the 200 OK again, and again, up to 32 seconds.
- Proxy B → Alice: 200 OK (again). Proxy B forwards each copy.
- Alice → Bob: ACK (again). Alice ACKs each copy. Every ACK goes to the same private address.
- Bob → Alice: BYE. After 64×T1 (32 seconds) with no ACK, Bob's phone ends the call with BYE. Problem: The call drops 32 seconds after the answer, every time.
- Alice → Bob: 200 OK. Alice answers the BYE. The NAT router lets this response through to Bob.
A new branch on the ACK for a non-2xx
The ACK for a 300–699 response belongs to the INVITE transaction, so it must reuse the INVITE’s branch. With a new branch, the server cannot match it: it keeps sending the response until Timer H, and may report a failure.
Broken
Broken: ACK for the 407 with a new branch
- SIP
- ⚠Problem
Alice sends an INVITE. It has no credentials.
All steps as text
- Alice → Proxy A: INVITE. Alice sends an INVITE. It has no credentials.
- Proxy A → Alice: 407 Proxy Auth Required. Proxy A rejects the INVITE with 407 and a challenge.
- Alice → Proxy A: ACK (new branch). Alice sends ACK with a new branch value. Problem: The branch does not match the INVITE. Proxy A cannot match this ACK to the transaction.
- Alice → Proxy A: INVITE (credentials). Alice sends a new INVITE with Proxy-Authorization. CSeq is 2 and the branch is new.
- Proxy A → Alice: 100 Trying. Proxy A accepts the credentials and continues with the call.
- Proxy A → Alice: 407 (retransmission). Timer G fires, so Proxy A sends the same 407 again. Problem: Proxy A retransmits the 407 because it has no matching ACK.
- Alice → Proxy A: ACK (new branch). Alice ACKs the retransmitted 407 with the same wrong branch. The loop continues until Timer H fires. Problem: Proxy A never matches these ACKs, so Timer H ends the transaction with a failure.
The same branch on the ACK for a 2xx
The ACK for a 2xx is a new transaction and needs a new branch. With the INVITE’s branch, an element that still holds the INVITE transaction may match the ACK to it and absorb it, instead of passing it on. The ACK never reaches the callee — and the call drops after 32 seconds.
Remember: ACK for 300–699 → same branch as the INVITE. ACK for 2xx → new branch, built like any request in the dialog.
Counting retransmissions as new calls
A monitoring tool or a script that counts every INVITE it sees reports seven “calls” for one unanswered INVITE over UDP. Retransmissions have the same Call-ID, CSeq, and branch.
Remember: count transactions (branch + method), or calls (Call-ID), not packets.
Summary
- A transaction is one request and its responses, between a client transaction and a server transaction on one hop. UAs and stateful proxies keep transactions; stateless proxies do not.
- The top Via branch, starting with z9hG4bK, names the transaction. Servers also compare the sent-by and the method; clients compare the CSeq method.
- Four state machines: INVITE and non-INVITE, client and server.
- Over UDP, requests and responses are retransmitted at T1, 2×T1, 4×T1… (capped at T2 except for Timer A). After 64×T1 = 32 s, the attempt times out. Over TCP and TLS, the transaction layer does not retransmit.
- The ACK for 300–699 is part of the INVITE transaction: same branch, hop by hop. The ACK for 2xx is a new transaction: new branch, end to end. A lost ACK for a 2xx ends the call after 32 seconds.
- CANCEL shares the INVITE’s branch but is its own transaction.
- RFC 6026 adds the Accepted state and stops stray responses; RFC 4320 removes late 408s and early provisional responses to non-INVITE requests.