SIP Telephony — Zero to Hero v1 · 2026-04-25
PART 02 · STEPS 11–25

The SIP Protocol, Deeply

SIP looks like HTTP and behaves like a telephone exchange. This part dissects the wire format — methods, status codes, headers, dialogs, SDP, the INVITE handshake, and the rejection codes you will fight on Verimor, Genesys, and the Garanti trunk.

15 steps 3 demos ~30 minutes
11anatomy

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.

request line
METHOD sip:user@host SIP/2.0
headers
Via, From, To, Call-ID, CSeq, Contact, Max-Forwards, Content-Type, Content-Length
blank line
CRLF — separates headers from body
body
SDP for INVITE/200 OK; empty for ACK/BYE/REGISTER
SIP message inspector — real INVITE captured on KKB
Click a header
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
Captured on kkbfcfreyasrv01 from a Verimor → Asterisk leg.
12methods

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.

MethodPurposeWhere you see it
INVITEStart a callOutbound from Asterisk to Verimor; inbound from Genesys to us
ACKConfirm a 2xx response to INVITEAlways after a 200 OK; if it goes missing, channel dies in 60 s
BYEEnd a callEither side can send; receiver replies 200 OK
CANCELAbort an INVITE before it's answeredCaller hangs up while phone is still ringing → 487 on the original
REGISTERTell a registrar where you areSIP phones; not used for IP-auth carrier trunks
OPTIONS"Are you alive?" / capability discoveryAsterisk pings the trunk on a heartbeat — keeps NAT bindings warm
Try this on KKB
$ 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
13req/resp

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.

14status families

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.

FamilyMeaningExamples
1xxProvisional100 Trying, 180 Ringing, 183 Session Progress
2xxSuccess200 OK, 202 Accepted
3xxRedirection301 Moved Permanently, 302 Moved Temporarily
4xxClient error400, 401, 403, 404, 408, 480, 486, 487
5xxServer error500, 503, 504
6xxGlobal error603 Decline, 604 Does Not Exist Anywhere
15rejections

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.

100
Trying
180
Ringing
183
Session Progress
200
OK
401
Unauthorized
403
Forbidden
404
Not Found
408
Timeout
480
Temp. Unavail.
486
Busy Here
487
Terminated
500
Server Error
503
Unavailable
603
Decline
1xx provisional 2xx success 4xx client 5xx server 6xx global

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.

16headers

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.

Via
The route the request took. Proxies prepend on the way down; responses unwind in reverse.
From / To
Logical addresses. tag parameters identify the dialog (From-tag set by caller, To-tag set by callee).
Call-ID
Unique per call. Your master correlation key in Asterisk logs.
CSeq
Sequence number + method. Detects retransmissions; same number used for matching ACK.
Contact
Direct address to reach this UA without traversing proxies.
Max-Forwards
TTL. Decremented at each hop; hits zero → 483 Too Many Hops.

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).

17via vs route

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.

18branches

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.

19dialogs

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.

Call-ID 1a4c8e07-…-c0924df33967 From-tag tag=4f9a2b To-tag tag=8c3e7d = unique dialog
20SDP

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.

21offer/answer

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.

22forking

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.

23register/auth

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 identify block in pjsip.conf matches 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).

24handshake

The INVITE handshake in detail

Real-life INVITE flow with reliability timers:

  1. UA sends INVITE (Timer A starts; retransmit at 500 ms, 1 s, 2 s, ...).
  2. Receives 100 Trying → stops Timer A.
  3. Receives 180/183 → still waiting, but progress.
  4. Receives 200 OK → must reply with ACK as a new transaction.
  5. 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.

INVITE ladder — happy path vs missing ACK
Happy path: INVITE → 100 → 180 → 200 OK → ACK → media → BYE → 200 OK. Click Drop ACK to see what step 25 / step 77 of the curriculum is about.
25teardown

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.

Checkpoint 2

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.