Anatomy of a SIP message
SIP looks like HTTP. There are requests and responses. Three sections every time: request line, headers, optional body (the SDP). Click any header below — the inspector explains what it does and why you care.
INVITE sip:+905374705251@93.180.132.170 SIP/2.0 Via: SIP/2.0/UDP 185.199.89.19:10499;branch=z9hG4bK-37d2c1 From: <sip:908502427127@sip.verimor.com.tr>;tag=4f9a2b To: <sip:+905374705251@93.180.132.170> Call-ID: 1a4c8e07-eaa5-470c-b011-c0924df33967 CSeq: 23070 INVITE Contact: <sip:asterisk@185.199.89.19:10499> Max-Forwards: 70 Content-Type: application/sdp Content-Length: 348 v=0 o=- 1234 1234 IN IP4 185.199.89.19 s=- c=IN IP4 185.199.89.19 t=0 0 m=audio 10042 RTP/AVP 0 8 101 a=rtpmap:0 PCMU/8000 a=sendrecv
kkbfcfreyasrv01 from a Verimor → Asterisk leg.The six SIP methods
Six verbs cover everything you will see in production. INVITE, ACK, BYE, CANCEL handle a call's lifecycle; REGISTER and OPTIONS handle presence and liveness.
| Method | Purpose | Where you see it |
|---|---|---|
INVITE | Start a call | Outbound from Asterisk to Verimor; inbound from Genesys to us |
ACK | Confirm a 2xx response to INVITE | Always after a 200 OK; if it goes missing, channel dies in 60 s |
BYE | End a call | Either side can send; receiver replies 200 OK |
CANCEL | Abort an INVITE before it's answered | Caller hangs up while phone is still ringing → 487 on the original |
REGISTER | Tell a registrar where you are | SIP phones; not used for IP-auth carrier trunks |
OPTIONS | "Are you alive?" / capability discovery | Asterisk pings the trunk on a heartbeat — keeps NAT bindings warm |
$ ssh freya@192.168.35.197 \ "docker exec freya-asterisk asterisk -rx 'pjsip set logger on'" $ docker logs -f freya-asterisk # every INVITE / 100 / 200 / ACK $ ssh freya@192.168.35.197 \ "docker exec freya-asterisk asterisk -rx 'pjsip set logger off'" # turn off — chatty
Request and response
For every request, the receiver replies with one or more responses. The first 1xx is provisional; the final response (2xx, 4xx, 5xx, 6xx) closes the transaction.
The happy path of an INVITE looks like this:
Caller Callee ----- INVITE ------> (1) <--- 100 Trying --- (2) optional, hop-by-hop <--- 180 Ringing --- (3) <--- 200 OK ------- (4) callee picked up ------ ACK ------> (5) caller confirms <==== RTP audio ====> (6) ... call is live ... ------ BYE ------> (7) <--- 200 OK ------- (8)
The INVITE → 200 OK → ACK triangle is the most important shape in SIP. If ACK is missing, the call dies in 60 seconds — see step 25 and Part 6 step 77.
Status code families
Same idea as HTTP, with two extras (6xx for global errors). The 4xx-vs-6xx distinction matters: a 6xx tells upstream proxies do not try this anywhere else; a 4xx is local-failure scoped and forking can continue.
| Family | Meaning | Examples |
|---|---|---|
| 1xx | Provisional | 100 Trying, 180 Ringing, 183 Session Progress |
| 2xx | Success | 200 OK, 202 Accepted |
| 3xx | Redirection | 301 Moved Permanently, 302 Moved Temporarily |
| 4xx | Client error | 400, 401, 403, 404, 408, 480, 486, 487 |
| 5xx | Server error | 500, 503, 504 |
| 6xx | Global error | 603 Decline, 604 Does Not Exist Anywhere |
The rejection codes you will fight
Memorize these. The carrier will hand you a SIP code + a Q.850 reason header — the pair tells you whether it's a customer problem, a number problem, or a carrier-side block.
The KKB tests we just analyzed showed 603 / cause 41 consistently on the same five numbers. That is not transient congestion — it would vary across runs. It is a stable carrier-side block.
Headers you must know
Six headers carry the entire dialog state. Memorize the one-liner; click into the inspector at step 11 to see them in a real INVITE.
tag parameters identify the dialog (From-tag set by caller, To-tag set by callee).When debugging, the Call-ID is your friend. Every line in freya-asterisk log carries it (or can be made to with pjsip set logger on).
Via vs Record-Route vs Route
- Via answers how did this request get here?. Reverses on the response.
- Record-Route asks future requests in this dialog should also pass through me. The proxy adds it on the INVITE.
- Route is what UAs add to subsequent in-dialog requests, derived from Record-Route.
If a SIP proxy is in light/stateless mode, it does not add Record-Route. That means ACK and BYE bypass the proxy and go end-to-end. This is the Garanti M08 root cause — see Part 9 step 97.
Branch parameters and transactions
Every Via has branch=z9hG4bK<random>. Two requests with the same branch parameter belong to the same transaction. Asterisk uses the branch to decide "is this a retransmission of an INVITE I already answered?"
You normally do not touch this. But when matching messages in a pcap, branch= lets you correlate request and response without ambiguity.
Dialogs vs transactions
- A transaction is one request and all its responses.
- A dialog is the long-lived call relationship: the INVITE transaction + later in-dialog requests (re-INVITE, BYE) + their responses.
The triple Call-ID + From-tag + To-tag uniquely identifies a dialog. ACK is special: in 2xx ACK it is a new transaction in the same dialog; in non-2xx ACK it is part of the INVITE transaction.
SDP — the body of an INVITE
Session Description Protocol. The body of the INVITE (and the answering 200 OK). It tells the callee three things: I want audio, these codecs I support, send media to this IP and port.
v=0 (version) o=- 0 0 IN IP4 185.199.89.19 (origin) s=- (session name) c=IN IP4 185.199.89.19 (connection IP) t=0 0 (timing) m=audio 10042 RTP/AVP 0 8 101 (media line) a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-16 a=sendrecv
The c= line carries the IP. The m= line carries the port. NAT breaks both — Part 3 covers the fix.
Offer / answer
The party who sends SDP first is the offerer. The other party answers with their compatible subset. Both must agree on at least one codec or the call fails with 488 Not Acceptable Here.
Mismatched offer/answer = silent call. Codec misnegotiation = silent call. SDP IP unreachable = one-way audio. They look identical from outside — only a pcap of RTP tells you which one it is.
Forking
A proxy receiving an INVITE can fork: send copies to multiple destinations.
- Sequential — try cell, then desk, then voicemail.
- Parallel — ring all of them; the first to answer wins, the rest get
487.
Asterisk's Dial(SIP/a&SIP/b&SIP/c) is parallel forking inside Asterisk. Carrier proxies fork transparently — you might see one INVITE go out and three 487s come back as the carrier cancels the losing legs.
REGISTER and authentication
REGISTER is how a phone tells the world "I am here at IP 1.2.3.4 until you hear otherwise." Two auth modes:
- Digest auth — username + password challenge/response (RFC 2617). Default for handsets and softphones.
- IP auth — the
identifyblock inpjsip.confmatches by source IP. No credentials. Used for trusted carrier trunks.
Our trunk endpoints are IP-auth only. The Garanti [providers] endpoint uses identify_by = ip and a [providers-identify] block lists the SIP-proxy IP. Same shape for Anadolu (Genesys) and KKB (Verimor).
The INVITE handshake in detail
Real-life INVITE flow with reliability timers:
- UA sends
INVITE(Timer A starts; retransmit at 500 ms, 1 s, 2 s, ...). - Receives
100 Trying→ stops Timer A. - Receives
180/183→ still waiting, but progress. - Receives
200 OK→ must reply withACKas a new transaction. - RTP starts.
Timer B (default 32 s, the "no answer" timer) terminates the INVITE if no final response arrives. That is what your 408 Request Timeout means.
Teardown
Either party sends BYE. The other responds 200 OK. Done. There is no four-way handshake like TCP — SIP teardown is fast and unilateral.
If the BYE is lost on the wire, Asterisk's RTP-timeout safety (60 s of media inactivity, see Part 3 step 35 and Part 6 step 77) saves the day. The same safety also catches the missing-ACK case shown in the ladder demo above: if media never starts, rtptimeout=60 fires and the channel is torn down.
A call connects fine but drops exactly 60 seconds in. Which SIP message is most likely missing?
Show answer
The ACK. After the callee's 200 OK, the caller must reply with ACK as a new transaction. If that ACK is lost (NAT, broken Record-Route, dropped UDP packet), no media flows. Asterisk's rtptimeout=60 safety then kills the channel exactly 60 seconds in. Same shape catches a lost BYE: it is the universal "media stopped" backstop.