SIP系列四:SIP扩展消息及rport机制(NAT穿越)

        我的音视频/流媒体开源项目(github)

        SIP系列目录

目录

一、扩展方法        

1、PRACK

2、SUBSCRIBE、NOTIFY、PUBLISH

3、REFER

二、SIP的rport机制


 

一、扩展方法        

        SIP消息分核心方法和扩展方法,核心方法包括:INVITE、ACK、BYE、CANCEL、REGISTER、OPTIONS。扩展方法包括:SUBSCRIBE、NOTIFY、PUBLISH、REFER、INFO、UPDATE、PRACK、MESSAGE。MESSAGE在之前的系列已经介绍过了,接下来对几个比较常用的扩展方法进行介绍。

1、PRACK

        参考:SIP:100rel 扩展-CSDN博客

        PRACK属于SIP:100rel扩展,100rel扩展即是对中间状态响应的确认(即1xx的响应码)。原先在sip里,只有针对invite请求的200 OK响应才会有ack,那么当中间状态响应携带重要的会话参数信息时,例如183响应,客户端是否收到响应就没有ack请求了,于是就定义了prack这一请求消息,即对中间状态响应的确认请求。当sip发送者支持这一扩展时即在support头域增加这个100rel消息,当server端给与1xx响应时,可以在头域里的require字段要求这一100rel的能力。此时,sip发送者,需要发送prack消息对1xx进行响应。

        PRACK用于保证1xx(除100外)的可靠传输,如果1xx响应中的的Require头部中带有100rel这个参数,那么client端收到这个1xx后,就需要发PRACK保证这个1xx的可靠传输,当server端收到PRACK后,说对端已经收到了这个1**,此时server需要回PRACK的200响应。

        uac如果不支持100rel,但uas要求支持100rel(Require:100rel),uac 发送CANCEL,切断会话。
        uac如果不支持100rel,uas也不支持或不要求支持100rel,在后面的过程中,uac对应接收到的临时响应,如180,183等,就不需要发送prack回应。

        100rel扩展有两种格式:

        supported:100rel 表示支持这个扩展功能。

        required:100rel 表示要求对方必须发送prack响应1xx消息,否则通话无法建立。

        UAC收到临时应答时,如果消息中包含RSeq可靠序列号和Supported:100rel或者required:100rel头域字段,那么应当生成PRACK。PRACK消息中携带一个RAck头域,并在这个头域中回显RSeq和CSeq的序列号。下图是信令交换的流程。在这个实例中,UAS发的180 Ringing中包含RSeq头域,启用临时应答可靠性机制。如果UAS直到定时器超时也没有收到PRACK(图中的“X”表示消息丢失),那么重发之前的临时应答。收到PRACK确认后发送应答消息并停止后续的(临时应答)重传。

        信令交互示如下:

SIP/2.0 180 Ringing
Via: SIP/2.0/UDP lucasian.cambridge.example.org;branch=z9hG4bK452352;received=1.2.3.4
To: Descartes <sip:rene.descartes@metaphysics.example.com>;tag=12323
From: Newton <sip:newton@kings.cambridge.example.org>;tag=981
Call-ID: da6fa909f1c0188c539feb08d4496eb7
RSeq: 314
CSeq: 10 INVITE
Content-Length: 0
 
PRACK sip:rene.descartes@metaphysics.example.org SIP/2.0
Via: SIP/2.0/UDP lucasian.trinity.cambridge.example.com;branch=z9hG4bKdtyw Max-Forwards: 70
To: Descartes <sip:rene.descartes@metaphysics.example.com>;tag=12323
From: Newton <sip:newton@kings.cambridge.example.org>;tag=981
Call-ID: da6fa909f1c0188c539feb08d4496eb7
CSeq: 2 PRACK
RAck: 314 10 INVITE
Supported: 100rel
Content-Length: 0
 
 
SIP/2.0 200 OK
Via: SIP/2.0/UDP lucasian.trinity.cambridge.example.org;branch=z9hG4bKdtyw ;received=1.2.3.4
To: Descartes <sip:rene.descartes@metaphysics.example.com>;tag=12323
From: Newton <sip:newton@kings.cambridge.example.org>;tag=981
Call-ID: da6fa909f1c0188c539feb08d4496eb7
CSeq: 2 PRACK
Require: 100rel
 
Content-Length: 0

2、SUBSCRIBE、NOTIFY、PUBLISH

        参考:【SIP基础】SIP协议消息-掌握SIP的核心方法_sip replace-CSDN博客

        这三个方法用于SIP中的事件订阅、通知、发布。

        SUBSCRIBE订阅特定事件。

  • 它有一个时间周期,在Expires头字段,指示存在一个订阅的所需的持续时间。
  • 在指定的时间段过后,订阅将自动终止。 
  • 订阅可以通过发送到期时间之前对话框中的另一个订阅刷新。
  • 服务器接受订阅返回一个200 OK。 
  • 用户可以通过发送另一个使用订阅方法退订,过期值为0(零)。

        NOTIFY通知SUBSCRIBE订阅的事件。

  • 200 OK响应被接收为每个NOTIFY以指示它已收到。
  • NOTIFY请求包含指示,指示订阅的当前状态的包和订阅的状态报头字段的Event报头字段。
  • NOTIFY总是在订阅开始和订阅终止之间发送。

        PUBLISH发布事件。

  • PUBLISH请求类似于一个NOTIFY,不同之处在于PUBLISH可以随时发送,而NOTIFY在有用户SUBSCRIBE之后才会发送。
  • 一个PUBLISH请求必须包含一个Expires头字段和Min-Expires头字段域。

        如下图所示,为SIP的事件流程:

 

           SUBSCRIBE中最常用的事件是“ reg”(用于注册状态检查),还有其他事件,如下图所示。

        NOTIFY通知的时候需要通过Subscription-State表示订阅的状态

        下面是订阅通知的示例:

SUBSCRIBE sip:+11234567890@test.3gpp.com SIP/2.0
Via: SIP/2.0/UDP 10.133.202.46:50997;branch=z9hG4bK2968d27245f17c7bcae38c31991bfdaa
Max-Forwards: 70
Contact: <sip:+11234567890@10.133.202.46:50997>;+sip.instance="<urn:gsma:imei:00440113-904785-0>"
To: <sip:+11234567890@test.3gpp.com>
From: <sip:+11234567890@test.3gpp.com>;tag=210a54
Call-ID: d57a0b04-785ba328-13a4d876@10.133.202.46
CSeq: 14534 SUBSCRIBE
Expires: 600000
User-Agent: IM-client/OMA1.0 DUT-IMS
Event: reg
Accept: application/reginfo+xml
P-Access-Network-Info: 3GPP-E-UTRAN-FDD;utran-cell-id-3gpp="0010100010000000"
P-Preferred-Identity: <sip:+11234567890@test.3gpp.com>
Content-Length: 0


SIP/2.0 200 OK
Via: SIP/2.0/UDP 10.133.202.46:50997;branch=z9hG4bK2968d27245f17c7bcae38c31991bfdaa
From: <sip:+11234567890@test.3gpp.com>;tag=210a54
To: <sip:+11234567890@test.3gpp.com>;tag=987654321
Call-ID: d57a0b04-785ba328-13a4d876@10.133.202.46
CSeq: 14534 SUBSCRIBE
Expires: 600000
Contact: <sip:10.133.202.47:5060>
Record-Route: <sip:10.133.202.47;lr>
Content-Length: 0

NOTIFY sip:+11234567890@test.3gpp.com SIP/2.0
Via: SIP/2.0/UDP 10.133.202.47:5060;branch=z9hG4bK-d1e4c4961ca9d523ae76b67e088589cd
Call-ID: d57a0b04-785ba328-13a4d876@10.133.202.46
From: <sip:+11234567890@test.3gpp.com>;tag=987654321
To: <sip:+11234567890@test.3gpp.com>;tag=210a54
Subscription-State: active;expires=600000
Event: reg
CSeq: 14534 NOTIFY
Contact: <sip:10.133.202.47:5060>
Max-Forwards: 70
Content-Type: application/reginfo+xml
Content-Length: 340
 
<?xml version="1.0" encoding="UTF-8"?>
<reginfo xmlns="urn:ietf:params:xml:ns:reginfo" version="0" state="full">
<registration aor="sip:+11234567890@test.3gpp.com" id="12345" state="active">
<contact id="100" state="active" event="registered" expires="600000">
<uri>sip:+11234567890@10.133.202.46:50997</uri>
</contact>
</registration>
</reginfo>

SIP/2.0 200 OK
Via: SIP/2.0/UDP 10.133.202.47:5060;branch=z9hG4bK-d1e4c4961ca9d523ae76b67e088589cd
Max-Forwards: 70
Contact: <sip:+11234567890@10.133.202.46:50997>;+sip.instance="<urn:gsma:imei:00440113-904785-0>"
To: <sip:+11234567890@test.3gpp.com>;tag=210a54
From: <sip:+11234567890@test.3gpp.com>;tag=987654321
Call-ID: d57a0b04-785ba328-13a4d876@10.133.202.46
CSeq: 14534 NOTIFY
Allow: NOTIFY,SUBSCRIBE
Content-Length: 0



3、REFER

        参考:SIP 请求方法(7)- REFER_sip refer-CSDN博客

        RFC3515中定义了REFER方法,UA使用REFER方法请求另一个UA访问一个URI或URL资源。资源内容由Refer-To头域指定,通常是URI或URL,Refer-To头域对REFER请求来说是必须的。这里的URI或URL可以是任何类型的URI:sip, sips, http, pres等等。URI是sip或sips时,REFER可以实现呼叫转移服务。还可以用REFER实现P2P(peer-to-peefr)呼叫控制。

        既可以在dialog内,也可以在dialog外发起REFER请求。下图是一个典型的呼叫流程。在这个例子中,UAC向UAS发一条REFER消息,在执行认证及授权之后,UAS决定接受REFER请求,它回应一条202 Accepted (或 200 OK)消息。请注意,响应是即时的,不需要等待触发的请求完成。这一点很重要,因为REFER使用非INVITE方法状态机,它要求立刻给出最终应答,这和INVITE不同,INVITE可能需要几秒钟(甚至几分钟)才能完成。示例中的Refer-To URI是sip URI,因此它变身UAC,发一条INVITE消息,Request-URI设置为Refer-To URI。这个INVITE最终处理成功,返回200 OK。成功的结果通过NOTIFY方法反馈给REFER事务的UAC。NOTIFY消息的消息体包含所触发请求的最终应答的副本。在本例中,它拷贝了应答消息的起始行:SIP/2.0 200 OK。SIP消息的这一部分在Content-Type头域中描述为message/sipfrag 。请注意,这个隐式订阅可以取消,如果不希望订阅,在REFER请求中携带一个头域:Refer-Sub: false,这样对方就不会发NOTIFY了。REFER消息中存在Require: nosub表示不创建隐式订阅。REFER消息中存在Require: explicitsub表示不创建隐式订阅,而是向Refer-Events-At头域中指定的URI发SUBSCRIBE请求进行显式订阅。

        REFER 消息实例:

REFER sip:m.rejewski@biuroszyfrow.example.com SIP/2.0
Via SIP/2.0/UDP lab34.bletchleypark.example.org:5060;branch=z9hG4bK932039
Max-Forwards: 69
To: <sip:m.rejewski@biuroszyfrow.example.com>;tag=ACEBDC
From: Alan Turing <sip:turing@bletchleypark.example.org> ;tag=213424
Call-ID: 3419fak3kFD23s1A9dkl
CSeq: 5412 REFER
Refer-To: <sip:info@scherbius-ritter.example.com>
Content-Length: 0

        REFER的另一种用法是“推送”Web页面。下图所示,UAC向UAS发一条REFER消息,Refer-To头域描述一个HTTP URL或Web页面。UAS回应202 Accepted,然后向URL所标识的Web服务器发HTTP GET请求。页面加载之后,UAS发一条NOTIFY反馈消息,消息体内容HTTP/1.0 200 OK。

        REFER请求及它所触发的SIP请求中可以包含Referred-By头域,说明发起者的信息。

 

二、SIP的rport机制

        参考:SIP穿越NAT的rport机制

        UAC发起INVITE请求报文是这样的:

INVITE sip:user@example.com SIP/2.0
Via: SIP/2.0/UDP 10.1.1.1:4540;rport;branch=z9hG4bKkjshdyff

        Proxy把请求转发给UAS是这样的:

INVITE sip:user@example.com SIP/2.0
Via: SIP/2.0/UDP proxy.example.com;branch=z9hG4bKkjsh77
Via: SIP/2.0/UDP 10.1.1.1:4540;received=192.0.2.1;rport=9988;branch=z9hG4bKkjshdyff

        这里面的received,rport就是SIP的NAT穿越机制,UAC请求的时候加一个rport属性,Proxy看到Via中有rport的时候,就会在这条Via里面加上received,rport并赋值,就是Proxy看到的消息来源地址和端口(如果有NAT等地址转换设备,则即为转换后的IP和port)。

        当Proxy把UAS响应转发给UAC的时候,按照rport中的ip和端口转发SIP 响应。也就是说IP和端口均完全遵照从哪里来的,发回哪里去的原则。NAT设备再把发往公网地址192.0.2.1的包发往内网地址10.1.1.1。

SIP/2.0 200 OK
Via: SIP/2.0/UDP 10.1.1.1:4540;received=192.0.2.1;rport=9988;branch=z9hG4bKkjshdyff

注意!

  • SIP的路由机制和rport机制是解决SIP的消息传递,并不能解决媒体通信问题(P2P)。
  • SIP建立连接之后,两个用户之间的媒体交互是P2P,和SIP是不同的通道,需要使用ICE框架让两个用户进行P2P通话。
posted @   BreakingY  阅读(56)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示