SIP/SDP Message Grammar

Compiled by Arjun Roychowdhury and Henning Schulzrinne.

Not up-to-date; use current Internet draft instead for definitive reference. Better tools are now available, such as abnf2html. Volunteers to convert the RFC 3261 grammar are solicited.

Based on RFC 2543,RFC 2327,  RFC 2616, RFC 1123, RFC 2234, and RFC 2396, Sip Notes and Clarifications.

SIP-message = Request | Response
Request = Request-Line
*( general-header | request-header | entity-header ) double-return     [message-body]
; Note - each header ends with a return and the end of headers is a double return. For line folding, the folded header must begin with  1*( SP | HT )

 

message-body = // Note: This is typically SDP
Request-Line = Method SP Request-URI SP SIP-Version return
SIP-URL = "sip:" [userinfo "@" ] hostport url-parameters [ headers] 
userinfo = user [ ":" password ] 
user = *( unreserved | escaped | "&" | "=" | "+" | "$" | "," ) 
password = *( unreserved | escaped | "&" | "=" | "+" | "$" | "," ) 
hostport = host [ ":" port ] 
host = hostname | IPv4address
hostname = *(domainlabel "." ) toplabel [ "." ] 
domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
toplabel = alpha | alpha *( alphanum | "-" ) alphanum
IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
port = * digit ; empty port field is allowed 
url-parameters = *( ";" url-parameter ) 
url-parameter = transport-param | user-param | method-param| ttl-param | maddr-param | other-param
transport-param = "transport=" ( "udp" | "tcp" ) 
ttl-param = "ttl=" ttl
ttl = 1*3 DIGIT ; 0 to 255 
maddr-param = "maddr=" host
user-param = "user=" ( "phone" | "ip" ) 
method-param = "method=" Method
tag-param = "tag=" UUID
UUID = 1*( hex | "-" ) 
other-param = ( token | ( token "=" ( token | quoted-string ))) 
headers = "?"header *( "&" header ) 
header = hname "=" hvalue
hname = 1*uric
hvalue = *uric
uric = reserved | unreserved | escaped
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," 
digits = 1*DIGIT
telephone-subscriber = global-phone-number | local-phone-number
global-phone-number = "+" 1*phonedigit [isdn-subaddress] [post-dial] 
local-phone-number = 1*(phonedigit | dtmf-digit | pause-character) [isdn-subaddress] [post-dial] 
isdn-subaddress = ";isub=" 1*phonedigit
post-dial = ";postd=" 1*(phonedigit | dtmf-digit | pause-character) 
phonedigit = DIGIT | visual-separator
visual-separator = "-" | "." 
pause-character = one-second-pause | wait-for-dial-tone
one-second-pause = "p" 
wait-for-dial-tone = "w" 
dtmf-digit = "*" | "#" | "A" | "B" | "C" | "D" 
general-header = Accept
| Accept-Encoding
| Accept-Language
| Call-ID
| Contact
| CSeq
| Date
| Encryption
| Expires
| From
| Record-Route
| Timestamp
| To
| Via
entity-header = Content-Encoding
| Content-Length
| Content-Type
request-header =

Authorization
| Contact
| Hide
| Max-Forwards
| Organization
| Priority
| Proxy-Authorization
| Proxy-Require
| Route
| Require
| Response-Key
| Subject
| User-Agent
|WWW-Authenticate

response-header = Allow
| Authorization
| Proxy-Authenticate
| Retry-After
| Server
| Unsupported
| Warning
| WWW-Authenticate
Method = "INVITE" | "ACK" | "OPTIONS" | "BYE" | "CANCEL" | "REGISTER" 
Accept = "Accept" ":" #( media-range [ accept-params ] ) 
media-range = ( "*/*" | ( type "/" "*" ) | ( type "/" subtype ) ) *( ";" parameter ) 
parameter = attribute "=" value
attribute = token
value = token | quoted-string
accept-params = ";" "q" "=" qvalue *( accept-extension ) 
accept-extension = ";" token [ "=" (token | quoted-string ) ] 
Accept-Encoding = "Accept-Encoding" ":" 1#( content-coding ) 
codings = ( content-coding | "*" ) 
content-coding = token
Accept-Language = "Accept-Language" ":" 1#( language-range [ ";" "q" "=" qvalue ] ) 
language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) 
Proxy-Authorization = "Proxy-Authorization" ":" credentials
Proxy-Authenticate = "Proxy-Authenticate" ":" 1#challenge
User-Agent = "User-Agent" ":" 1*( product | comment ) 
Server = "Server" ":" 1*( product | comment ) 
Response = Status-Line *( general-header | response-header | entity-header ) double-return [ message-body ] ; Note - each header ends with a return and the end of headers is a double return. For line folding, the folded header must begin with  1*( SP | HT )
Status-Line = SIP-version SP Status-Code     SP Reason-Phrase
SIP-version = "SIP/2.0" 
Status-Code = Informational
| Success
| Redirection
| Client-Error
| Server-Error
| Global-Failure
| extension-code
extension-code = 3 DIGIT
Reason-Phrase = *<TEXT-UTF8, excluding CR, LF > 
Informational = "100" Trying 
| "180" ; Ringing 
| "181"  ; Call Is Being Forwarded 
| "182"  ; Queued 
Success = "200" ; OK 
Redirection = "300" ; Multiple Choices 
| "301" ; Moved Permanently 
| "302" ; Moved Temporarily 
| "303" ; See Other 
| "305" ; Use Proxy 
| "380" ; Alternative Service 
Client-Error = "400"  ; Bad Request 
| "401"  ; Unauthorized 
| "402"  ; Payment Required 
| "403" ; Forbidden 
| "404" ; Not Found 
| "405"  ; Method Not Allowed 
| "406"  ; Not Acceptable 
| "407"  ; Proxy Authentication Required 
| "408"  ; Request Timeout 
| "409"  ; Conflict 
| "410"  ; Gone 
| "411"  ; Length Required 
| "413"  ; Request Entity Too Large 
| "414"  ; Request-URI Too Large 
| "415"  ; Unsupported Media Type 
| "420"  ; Bad Extension 
| "480"  ; Temporarily not available 
| "481"  ; Call Leg/Transaction Does Not Exist 
| "482"  ; Loop Detected 
| "483"  ; Too Many Hops 
| "484" ; Address Incomplete 
| "485"  ; Ambiguous 
| "486" ; Busy Here 
Server-Error = "500" ; Internal Server Error 
| "501" ; Not Implemented 
| "502"  ; Bad Gateway 
| "503"  ; Service Unavailable 
| "504"  ; Gateway Time-out 
| "505"  ; SIP Version not supported 
Global-Failure = "600" ; Busy Everywhere 
| "603"  ; Decline 
| "604"  ; Does not exist anywhere 
| "606" ; Not Acceptable 
message-header = field-name ":" [ field-value ] CRLF
field-name = token
field-value = *(field-content | LWS ) 
field-content = <the OCTETs making up the field-value and consisting of either *TEXT-UTF8 or combinations of token, separators, and quoted-string > 
Allow = "Allow" ":" 1#Method
Call-ID = ( "Call-ID" | "i" ) ":" token
local-id = 1*uric
Contact = ( "Contact" | "m" ) ":" ("*" | (1# ((name-addr | addr-spec ) [ *( ";" contact-params ) ] [ comment ] ))) 
name-addr = [ display-name ] "<" addr-spec ">" 
addr-spec = SIP-URL | URI
display-name = *token | quoted-string
contact-params = "q" "=" qvalue| ("action" "=" "proxy" | "redirect") |( "expires" "=" delta-seconds | <"> SIP-date <">) | extension-attribute
extension-attribute = extension-name [ "=" extension-value ]
Content-Encoding = ( "Content-Encoding" | "e" ) ":" 1#content-coding
Content-Length = ( "Content-Length" | "l" ) ":" 1*DIGIT
Content-Type = ( "Content-Type" | "c" ) ":"media-type
media-type = type "/"subtype *( ";" parameter ) 
type = token
subtype = token
CSeq = "CSeq" ":" 1*DIGIT Method
Date = "Date:" SIP-date
SIP-date = rfc1123-date
Encryption = "Encryption" ":"encryption-scheme 1*SP #encryption-params
encryption-scheme = token
encryption-params = token "=" ( token | quoted-string ) 
Expires = "Expires" ":" ( SIP-date | delta-seconds ) 
From = ( "From" | "f" ) ":" ( name-addr | addr-spec ) *( ";" addr-params )  *(";" extension-params)
addr-params = tag-param
tag-param = "tag="UUID
Hide = "Hide" ":" ( "route" | "hop" ) 
Max-Forwards = "Max-Forwards" ":" 1*DIGIT
Organization = "Organization" ":" *TEXT-UTF8
Priority = "Priority" ":"priority-value
priority-value = "emergency" | "urgent" | "normal" | "non-urgent" 
Record-Route = "Record-Route" ":" 1# name-addr
Require = "Require" ":" 1#option-tag
Proxy-Require = "Proxy-Require" ":" 1#option-tag
option-tag = token
Response-Key = "Response-Key" ":" key-scheme 1*SP #key-param
key-scheme = token
key-param = token "=" ( token | quoted-string ) 
Retry-After = "Retry-After" ":"( SIP-date | delta-seconds ) [ comment ] [ ";" "duration" "=" delta-seconds ] 
Route = "Route" ":" 1#name-addr
Subject = ( "Subject" | "s" ) ":" *TEXT-UTF8
Timestamp = "Timestamp" ":" *(DIGIT) [ "." *(DIGIT) ] [ delay ] 
delay = *(DIGIT) [ "." *(DIGIT) ] 
To = ( "To" | "t" ) ":" (name-addr | addr-spec ) *( ";" addr-params ) *(";" extension-params) // Extension params are allowed in From to and Via
Unsupported = "Unsupported" ":" 1#option-tag
Via = ( "Via" | "v") ":" 1#(sent-protocol sent-by *( ";" via-params ) [ comment ] ) *(";" extension-params) // Extension params are allowed in From to and Via
via-params = via-hidden | via-ttl | via-maddr| via-received | via-branch
via-hidden = "hidden" 
via-ttl = "ttl" "=" ttl
via-maddr = "maddr" "=" maddr // Note: maddr not defined but it should be host
via-received = "received" "="host
via-branch = "branch" "=" token
sent-protocol = protocol-name "/" protocol-version "/" transport
protocol-name = "SIP" | token
protocol-version = token
transport = "UDP" | "TCP" | token
sent-by = (host [ ":" port ] ) | ( concealed-host ) 
concealed-host = token
Warning = "Warning" ":" 1#warning-value
warning-value = warn-code SP warn-agent SP warn-text
warn-code = 3 DIGIT
warn-agent = (host [ ":" port ] ) | pseudonym ; the name or pseudonym of the server adding the Warning header, for use in debugging 
pseudonym = token
warn-text = quoted-string
WWW-Authenticate = "WWW-Authenticate" ":"  1#challenge
auth-scheme = token
challenge = auth-scheme 1*SP realm *("," auth-param)
realm = "realm" "=" realm-value
auth-param = token "=" string
credentials = basic-credentials | (auth-scheme #(auth-params))
basic-credentials = "Basic" SP basic-cookie
basic-cookie = <encrypted string>
pgp-challenge = * (pgp-params ) 
pgp-params = realm | pgp-version | pgp-algorithm | nonce
realm = "realm" "="realm-value
realm-value = quoted-string
pgp-version = "version" "=" <"> digit *( "." digit ) *letter <">
pgp-algorithm = "algorithm" "=" ( "md5" | "sha1" |token ) 
nonce = "nonce" "=" nonce-value
nonce-value = quoted-string
Authorization = "Authorization" ":" credentials 
pgp-response = realm | pgp-version | pgp-signature| signed-by | nonce
pgp-signature = "signature" "="quoted-string
signed-by = "signed-by" "=" <"> URI <">
pgp-eparams = 1# ( pgp-version | pgp-encoding| pgp-key ) 
pgp-encoding = "encoding" "=" "ascii" | token
pgp-key = "key" "=" quoted-string
OCTET = %x00-ff ; any 8-bit sequence of data 
CHAR = %x00-7f ; any US-ASCII character (octets 0 - 127) 
upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" 
lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" 
alpha = lowalpha | upalpha
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" 
alphanum = alpha | digit
CTL = %x00-1f | 0x7f ; any US-ASCII control character (octets 0 -- 31) and DEL (127) 
CR = %d13  ; US-ASCII CR, carriage return character 
LF = %d10  ; US-ASCII LF, line feed character 
SP = %d32  ; US-ASCII SP, space character 
HT = %d09 ; US-ASCII HT, horizontal tab character 
return = CR | LF | CRLF ; typically the end of a line 
unreserved = alphanum | mark
double-return = (CR CR) | (LF LF) | (CR LF CR LF)
mark = "-" | "_" | "." | "!" | "~" | "*" | " ' " | "(" | ")" 
escaped = "%"hex hex
LWS = [CRLF] 1*( SP | HT ) ; linear whitespace 
TEXT-UTF8 = <any UTF-8 character encoding, except CTLs, but including LWS
hex = "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" | digit
token = 1* (alphanum | "-" | "." | "$" | "%" | "*" | "_" | "+" | "~" | "`" | "'") 
separators = "(" | ")" | "<" | "" | "@" | "," | ";" | ":" | "\" | "<" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
comment = "(" *(ctext| quoted-pair | comment) ")" 
ctext = <anyTEXT-UTF8 excluding "(" and ")" >
quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) 
qdtext = <anyTEXT-UTF8 except <"> > 
quoted-pair = "\"CHAR
delta-seconds = 1*DIGIT // This is not spec. in 2543 and no reference is given (its in H.3.3.2) 
qvalue = ( "0" [ "." 0*3 DIGIT ] ) | ( "1" [ "." 0*3("0") ] ) 
URI-reference = ([ absoluteURI | relativeURI] [ "#" fragment] ) | (sip-url )  // According to 2453:4.3 - ReqURI is SIPUri (without certain tokens) or GeneralURI 
absoluteURI = scheme":" ( hier_part | opaque_part ) 
relativeURI = (net_path | abs_path | rel_path ) [ "?" query ] 
hier_part = ( net_path | abs_path ) [ "?" query ] 
opaque_part = uric_no_slash *uric
uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," 
net_path = "//"authority [ abs_path ] 
abs_path = "/"path_segments
rel_path = rel_segment [ abs_path ] 
rel_segment = 1*(unreserved | escaped | ";" | "@" | "&" | "=" | "+" | "$" | "," ) 
scheme = alpha *( alpha | digit | "+" | "-" | "." ) 
authority = server_H | reg_name
reg_name = 1*( unreserved | escaped | "$" | "," | ";" | ":" | "@" | "&" | "=" | "+" ) 
server_H = [ [ userinfo_H "@" ] hostport ] 
userinfo_H = *( unreserved | escaped | ";" | ":" | "&" | "=" | "+" | "$" | "," ) 
path = [ abs_path | opaque_part ] 
path_segments = segment *( "/" segment ) 
segment = *pchar *( ";" param ) 
param = *pchar
pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | "," 
query = *uric
fragment = *uric
product = token ["/" product-version] 
product-version = token
rfc1123-date = wkday "," SP date1SP time SP "GMT" 
date1 = 2DIGIT SP month SP 4DIGIT ; day month year (e.g., 02 Jun 1982) 
time = 2 DIGIT ":" 2 DIGIT ":" 2DIGIT ; 00:00:00 - 23:59:59 
wkday = "Mon" | "Tue" | "Wed"| "Thu" | "Fri" | "Sat" | "Sun" 
month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"
announcement = proto-version
origin-field
session-name-field
information-field
uri-field
email-fields
phone-fields
connection-field
bandwidth-fields
time-fields
key-field
attribute-fields
media-descriptions
proto-version
= "v=" 1*DIGIT return ;this memo describes version 0
origin-field = "o=" username space sess-id space sess-version space
nettype space addrtype space
addr return
session-name-field
= "s=" text return
information-field
=   ["i=" text return]
uri-field = ["u=" uri return]
email-fields
= *("e=" email-address return)
phone-fields
= *("p=" phone-number return)
connection-field  
= ["c=" nettype space addrtype space
connection-address return]
;a connection field must be present
;in every media description or at the
;session-level
bandwidth-fields
= *("b=" bwtype ":" bandwidth return)
time-fields
= 1*( "t=" start-time space stop-time
*(return repeat-fields) return)
[zone-adjustments return]
repeat-fields
= "r=" repeat-interval space typed-time
1*(space typed-time)
zone-adjustments
= time space ["-"] typed-time
*(space time space ["-"] typed-time)
key-field
= ["k=" key-type return]
key-type
= "prompt" | "clear:" key-data | "base64:" key-data |"uri:" uri
key-data
= email-safe | "~" | "
attribute-fields = *("a=" attribute return)
media-field = "m=" media space port ["/" integer]
space proto 1*(space fmt) return
media-descriptions
= *( media-field
information-field
*(connection-field)
bandwidth-fields
key-field
attribute-fields )
media = 1*(alpha-numeric) ;typically "audio", "video", "application"
;or "data"
fmt
= 1*(alpha-numeric) ;typically an RTP payload type for audio
;and video media
proto

= 1*(alpha-numeric) ;typically "RTP/AVP" or "udp" for IP4
port
= 1*(DIGIT) ;should in the range "1024" to "65535" inclusive
;for UDP based media
attribute
= (att-field ":" att-value) | att-field
att-field
= 1*(alpha-numeric)
att-value
= byte-string
sess-id 
= 1*(DIGIT) ;should be unique for this originating username/host
sess-version
= 1*(DIGIT) ;0 is a new session
connection-address
= multicast-address
| addr
multicast-address  
= 3*(decimal-uchar ".") decimal-uchar "/" ttl
[ "/" integer ]
;multicast addresses may be in the range
;224.0.0.0 to 239.255.255.255
start-time = time | "0"
stop-time = time | "0"
time = POS-DIGIT 9*(DIGIT) ;sufficient for 2 more centuries
repeat-interval
= typed-time
typed-time
= 1*(DIGIT) [fixed-len-time-unit]
fixed-len-time-unit = "d" | "h" | "m" | "s"
bwtype
= 1*(alpha-numeric)
bandwidth
= 1*(DIGIT)
username
= safe ;pretty wide definition, but doesn't include space
email-address
= email | email "(" email-safe ")" |
email-safe "<" email ">"
email
= ; defined in RFC822
phone-number
= phone | phone "(" email-safe ")" |
email-safe "<" phone ">"
phone
= "+" POS-DIGIT 1*(space | "-" | DIGIT) ;there must be a space or hyphen between the
;international code and the rest of the number.
nettype = "IN" ;list to be extended
addrtype = "IP4" | "IP6" ;list to be extended
addr
= FQDN | unicast-address
FQDN
= 4*(alpha-numeric|"-"|".") ;fully qualified domain name as specified in RFC1035
unicast-address
= IP4-address | IP6-address
IP4-address
= b1 "." decimal-uchar "." decimal-uchar "." b4
b1
= decimal-uchar   ;less than "224"; not "0" or "127"
b4
= decimal-uchar    ;not "0"
IP6-address
= ;to be defined
text


= byte-string ;default is to interpret this as I0-10646 UTF8
;ISO 8859-1 requires a "a=charset:ISO-8859-1"
;session-level attribute to be used
byte-string
= 1*(0x01..0x09|0x0b|0x0c|0x0e..0xff) ;any byte except NUL, CR or LF
decimal-uchar = DIGIT
| POS-DIGIT DIGIT
| ("1" 2*(DIGIT))
| ("2" ("0"|"1"|"2"|"3"|"4") DIGIT)
| ("2" "5" ("0"|"1"|"2"|"3"|"4"|"5"))
integer
= POS-DIGIT *(DIGIT)
POS-DIGIT
= "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
email-safe
= safe | space | tab
safe
= alpha-numeric |
"'" | "'" | "-" | "." | "/" | ":" | "?" | """ |
"#" | "$" | "&" | "*" | ";" | "=" | "@" | "[" |
"]" | "^" | "_" | "`" | "{" | "|" | "}" | "+" |
"~" | "
space = SP

 


Last updated  by Henning Schulzrinne