大家好,又见面了,我是你们的朋友全栈君。
1. oSIP介绍
oSIP是按照RFC3261(SIP)和RFC2327(SDP)标准,并使用标准c编写的一个SIP协议栈。它是一个公开源码的免费协议栈。oSIP协议栈结构简单而小巧,它并不提供高层的SIP会话控制的API,它主要提供一些解析SIP/SDP消息的API和事务处理的状态机。
oSIP支持线程安全,既可以用于多线程的编程模式,也可以用于单线程的编程模式;oSIP可以用来开发User Agent,IP soft-phone和SIP Proxy等等。
oSIP目前最后版本为V 0.9.7,不久oSIP版本将升级至oSIP2(V 1.99.7)。oSIP2主要调整了一些函数和结构名称,以及一些头文件的名称、内容结构的调整,整体的构架和功能不变。
本文以下描述都基于oSIP V0.9.6版本。
2. oSIP结构分析
2.1 oSIP结构
oSIP主要包括三大部分的内容:状态机模块、解析器模块和工具模块。
状态机模块的功能:
完成对某个事务(注册过程,呼叫过程等等)状态记录,并在特定状态下触发相应的事件或回调函数。
解析器模块的功能:
该模块主要完成对SIP消息结构剖析、SDP消息的结构剖析以及URI结构的剖析;
工具模块的功能:
该模块提供一些SDP等处理的一些工具。
oSIP的模块结构图如下(图2-1):
| SIP parser |
| URL parser |
| SDP parser |
Finite State Machines |
| Dialogue Facilities |
SDP negotiation Facilities |
| Application |
| 状态机模块 |
| 解析器模块 |
工具模块(可选项) |
|
oSIP模块
|
|
图2-1 oSIP结构
|
2.2 状态机(Finite State Machines)模块
2.2.1 概述
oSIP状态机(Finite State Machines)主要分为四类,分别为:
Ø
ICT — Invite Client (outgoing) Transaction
ICT — Invite Client (outgoing) Transaction
Ø
NICT — Non-Invite Client (outgoing) Transaction
NICT — Non-Invite Client (outgoing) Transaction
Ø
IST — Invite Server (incoming) Transaction
IST — Invite Server (incoming) Transaction
Ø
NIST — Non-Invite Server (incoming) Transaction
NIST — Non-Invite Server (incoming) Transaction
2.2.2 ICT状态机
| ICT_PRE_CALLING |
| ICT_COMPLETED |
| ICT_PROCEEDING |
| ICT_TERMINATED |
Transaction initialization |
| ICT_CALLING |
cb_ict_transport_error |
cb_ict_invite_sent |
| cb_ict_invite_sent2 |
cb_ict_transport_error |
图 2-2: ICT State Machine |
cb_ict_kill_transaction |
cb_ict_transport_error |
cb_ict_1xx_received |
cb_ict_2xx_received |
| cb_ict_transport_error |
| cb_ict_1xx_received |
cb_ict_Nxx_received |
cb_ict_Nxx_received |
cb_ict_3456xx_received2 cb_ict_ack_sent2 |
cb_ict_xxx_xxxx |
| 表示从一种状态转换到另一种状态时将调用该回调函数 |
| 表示从一种状态转换到另一种状态时不调用任何回调函数 |
注:
cb_ict_Nxx_received:其中N表示一下几个值
3 — cb_ict_3xx_received
4 — cb_ict_4xx_received
5 — cb_ict_5xx_received
6 — cb_ict_6xx_received
2.2.3 NICT状态机
| NICT_PRE_TRYING |
| NICT_COMPLETED |
| NICT_PROCEEDING |
| NICT_TERMINATED |
Transaction initialization |
| NICT_TRYING |
cb_nict_transport_error |
cb_nict_XXX_sent |
| cb_nict_request_sent2 |
cb_nict_1xx_received |
图2-3: NICT State Machine |
cb_nict_Nxx_received |
cb_nict_kill_transaction |
cb_nict_transport_error |
| cb_nict_request_sent2 |
cb_nict_1xx_received |
cb_nict_Nxx_received |
cb_nict_transport_error |
cb_nict_xxx_xxxx |
| 表示从一种状态转换到另一种状态时将调用该回调函数 |
| 表示从一种状态转换到另一种状态时不调用任何回调函数 |
注:
cb_nict_XXX_sent:其中XXX表示一下几种消息类型,
register — cb_nict_register_sent
bye — cb_nict_bye_sent
options — cb_nict_options_sent
info — cb_nict_info_sent
cancel — cb_nict_cancel_sent
notify — cb_nict_notify_sent
subscribe — cb_nict_subscribe_sent
unknown — cb_nict_unknown_sent
cb_nict_Nxx_received:其中N表示一下几个值
2 — cb_nict_2xx_received
3 — cb_nict_3xx_received
4 — cb_nict_4xx_received
5 — cb_nict_5xx_received
6 — cb_nict_6xx_received
2.2.4 IST状态机
| IST_PRE_PROCEEDING |
| IST_CONFIRMED |
| IST_COMPLETED |
| IST_TERMINATED |
Transaction initialization |
| IST_PROCEEDING |
cb_ist_invite_received |
cb_ist_Nxx_sent |
图2-4: IST State Machine |
cb_ist_ack_received |
cb_ist_1xx_sent |
cb_ist_transport_error |
cb_ist_2xx_sent |
cb_ist_ack_received2 |
| cb_ist_3456xx_sent2 |
| cb_ist_invite_received2 |
cb_ist_kill_transaction |
cb_ist_transport_error |
cb_ist_xxx_xxxx |
| 表示从一种状态转换到另一种状态时将调用该回调函数 |
| 表示从一种状态转换到另一种状态时不调用任何回调函数 |
注:
cb_ist_Nxx_sent:其中N表示一下几个值,
3 — cb_ist_3xx_sent
4 — cb_ist_4xx_sent
5 — cb_ist_5xx_sent
6 — cb_ist_6xx_sent
2.2.5 NIST状态机
| NIST_PRE_TRYING |
| NIST_COMPLETED |
| NIST_PROCEEDING |
| NIST_TERMINATED |
Transaction initialization |
| NIST_TRYING |
cb_nist_XXX_ received |
cb_nist_1xx_sent |
图2-5: NIST State Machine |
cb_nist_Nxx_sent |
cb_nist_kill_transaction |
cb_nist_transport_error |
cb_nist_1xx_sent |
cb_nist_Nxx_sent |
cb_nist_transport_error |
| cb_nist_request_received2 |
cb_nist_request_received2 |
cb_nist_xxx_xxxx |
| 表示从一种状态转换到另一种状态时将调用该回调函数 |
| 表示从一种状态转换到另一种状态时不调用任何回调函数 |
注:
cb_nist_XXX_ received:其中XXX表示一下几种消息类型,
register — cb_nist_register_received
bye — cb_nist_bye_received
options — cb_nist_options_received
info — cb_nist_info_received
cancel — cb_nist_cancel_received
notify — cb_nist_notify_received
subscribe — cb_nist_subscribe_received
unknown — cb_nist_unknown_received
cb_nist_Nxx_ sent:其中N表示一下几个值
2 — cb_nist_2xx_sent
3 — cb_nist_3xx_sent
4 — cb_nist_4xx_sent
5 — cb_nist_5xx_sent
6 — cb_nist_6xx_sent
2.3 解析器(Parsers)模块
oSIP的SIP Parser处理的SIP头域(SIP Header fields)及其相应的操作功能列表如下:
| SIP Header(头域) | Functions(函数名称—简写) | |
| Accept | set(),get() | ☆ |
| Accept-Encoding | set(),get(),init(),parse(),2char(),free(),clone() Getelement(),setelement() | ☆ |
| Accept-Language | set(),get() | ☆ |
| Alert-Info | set(),get() | ☆ |
| Allow | set(),get() | ☆ |
| Authentication-Info | ||
| Authorization | Init(),set(),parse(),get(),getauth_type(),setauth_type(), Getusername(),setusername(),getrealm(),setrealm(), Getnonce(),setnonce(),geturi(),seturi(),getresponse(), Setresponse(),getdigest(),setdigest(),getalgorithm(), Setalgorithm(),getcnonce(),setcnonce(),getopaque(), Setopaque(),getmessage_qop(),setmessage_qop(), getnonce_count(),setnonce_count(),2char(),free(), clone() | ☆ |
| Call-ID | set(),get(),parse(),2char(),free(),clone(),getnumber(), setnumber(),gethost(),sethost() | ☆ |
| Call-Info | set(),get(),init(),parse(),2char(),free(),clone(), geturi(),seturi() | ☆ |
| Contact | set(),get(),init(),parse(),2char(),free(),clone() | ☆ |
| Content-Disposition | set(),get(),parse() | ☆ |
| Content-Encoding | set(),get() | ☆ |
| Content-Language | ||
| Content-Length | set(),get(),init(),parse(),2char(),free(),clone() | ☆ |
| Content-Type | set(),get(),init(),parse(),2char(),free(),clone() | ☆ |
| CSeq | set(),get(),init(),parse(),2char(),free(),clone(), getnumber(),setnumber(),getmethod(),setmethod() | ☆ |
| Date | ||
| Error-Info | set(),get() | ☆ |
| Expires | ||
| From | set(),get(),init(),parse(),2char(),free(),clone(), getdisplayname(),setdisplayname(),geturl(),seturl(), param_get(),param_parseall(),param_setvalue(), param_getvalue(),param_getname(),param_setname(), compare() | ☆ |
| In-Reply-To | ||
| Max-Forwards | ||
| Min-Expires | ||
| MIME-Version | set(),get() | ☆ |
| Organization | ||
| Priority | ||
| Proxy-Authenticate | set(),get() | ☆ |
| Proxy-Authorization | set(),get() | ☆ |
| Proxy-Require | ||
| Record-Route | set(),get(),init(),parse(),2char(),free() | ☆ |
| Reply-To | ||
| Require | ||
| Retry-After | ||
| Route | set(),get(),init(),parse(),2char(),free() | ☆ |
| Server | ||
| Subject | ||
| Supported | ||
| Timestamp | ||
| To | set(),get(),init(),parse(),2char(),free(),clone() | ☆ |
| Unsupported | ||
| User-Agent | ||
| Via | set(),append(),get(),init(),free(),parse(),2char(), setversion(),getversion(),setprotocol(),getprotocol(), sethost(),gethost(),setport(),getport(),setcomment(), getcomment(),clone() | ☆ |
| Warning | ||
| WWW-Authenticate | Init(),set(),quoted_string_set(),token_set(),parse(), get(),getauth_type(),setauth_type(),getrealm(),setrealm(), getdomain(),setdomain(),getnonce(),setnonce(),getstale(), setstale(),getopaque(),setopaque(),getalgorithm(), setalgorithm(),getqop_options(),setqop_options(),2char(), free(),clone() | ☆ |
注:标示“☆”表示oSIP支持该头域(SIP Header fields)解析处理,未注的表示目前还没有解析处理(这些被保存在字符串中,可自行处理分析),可能会在后续版本中逐步补充。
SDP的格式一般为:
<type>=<value>
type通常为一个英文字母,其取值如下(按照RFC2327,带“*”的表示为可选条目):
Session description
v= (protocol version)
o= (owner/creator and session identifier).
s= (session name)
i=* (session information)
u=* (URI of description)
e=* (email address)
p=* (phone number)
c=* (connection information – not required if included in all media)
b=* (bandwidth information)
One or more time descriptions (see below)
z=* (time zone adjustments)
k=* (encryption key)
a=* (zero or more session attribute lines)
Zero or more media descriptions (see below)
Time description
t= (time the session is active)
r=* (zero or more repeat times)
Media description
m= (media name and transport address)
i=* (media title)
c=* (connection information – optional if included at session-level)
b=* (bandwidth information)
k=* (encryption key)
a=* (zero or more media attribute lines)
在oSIP中处理的type和相应操作功能如下:
| type(类型) | Functions(函数名称—简写) |
| v | version_set(),version_get() |
| o | origin_set(),username_get(),sess_id_get(), sess_version_get(),nettype_get(),addrtype_get(), addr_get() |
| s | name_set(),name_get() |
| i | info_set(),info_get() |
| u | uri_set(),uri_get() |
| e | email_add(),email_get() |
| p | phone_add(),phone_get() |
| c | connection_add(),connection_get(),nettype_get(), addrtype_get(),addr_get(),addr_multicast_ttl_get(), addr_multicast_int_get() |
| b | bandwidth_add(),bwtype_get(),bandwidth_get() |
| t | time_descr_add(),start_time_get(),stop_time_get() |
| r | repeat_add(),repeat_get() |
| z | adjustments_set(),adjustments_get() |
| k | key_set(),keytype_get(),keydata_get() |
| a | attribute_add(),att_field_get(),att_value_get() |
| m | media_add(),media_get(),port_get(),number_of_port_get(), proto_get(),payload_add(),payload_get(), |
另外,oSIP还包含对SDP包的一些基本操作[set(), get(), init(), parse(), 2char(), free(), clone()],及对各类type的init()和free()操作
这里的URL是指SIP中的URI,URI有很多参数格式,在RFC3261中列举了一些比较例子:
The URIs within each of the following sets are equivalent:
sip:alice@atlanta.com;transport=TCP
sip:alice@AtLanTa.CoM;Transport=tcp
sip:carol@chicago.com
sip:carol@chicago.com;newparam=5
sip:carol@chicago.com;security=on
sip:biloxi.com;transport=tcp;method=REGISTER?to=sip:bob@biloxi.com
sip:biloxi.com;method=REGISTER;transport=tcp?to=sip:bob@biloxi.com
sip:alice@atlanta.com?subject=project x&priority=urgent
sip:alice@atlanta.com?priority=urgent&subject=project x
The URIs within each of the following sets are not equivalent:
SIP:ALICE@AtLanTa.CoM;Transport=udp (different usernames)
sip:alice@AtLanTa.CoM;Transport=UDP
sip:bob@biloxi.com (can resolve to different ports)
sip:bob@biloxi.com:5060
sip:bob@biloxi.com (can resolve to different transports)
sip:bob@biloxi.com;transport=udp
sip:bob@biloxi.com (can resolve to different port and transports)
sip:bob@biloxi.com:6000;transport=tcp
sip:carol@chicago.com (different header component)
sip:carol@chicago.com?Subject=next%20meeting
sip:bob@phone21.boxesbybob.com (even though that’s what
sip:bob@192.0.2.4 phone21.boxesbybob.com resolves to)
在oSIP中处理SIP URI有比较多的操作函数提供,主要有对host,port,username,password, scheme的get()和set(),以及对参数的初始化设置和剖析处理。详细函数名称请参考源代码中的url.h。
2.4 工具(Facilities)模块
SDP
协商工具
(SDP negotiator)
帮助
end point提供协商codec等功能
协商工具
(SDP negotiator)
帮助
end point提供协商codec等功能
对话管理工具(Dialog management)是oSIP提供的一个比较强大的辅助工具,主要用于有能力应答呼叫的end point。
对话管理工具(Dialog management)能够帮助记录请求和响应消息,利用这个工具使end point能够快速准确的作出应答。
3. oSIP特点
3.1 oSIP的优点
n
Osip没有给开发者限定在特定的某个执行模式下,能够使开发者选定一个比较适合自己的模式。
Osip没有给开发者限定在特定的某个执行模式下,能够使开发者选定一个比较适合自己的模式。
n
Osip的各个模块是相对清晰、独立的,因而去掉某个模块时也比较容易。
Osip的各个模块是相对清晰、独立的,因而去掉某个模块时也比较容易。
n
Osip的解析器提供了较为完善的API,包含了消息的构造、修改和产生等。
Osip的解析器提供了较为完善的API,包含了消息的构造、修改和产生等。
3.2 oSIP的缺点
¨
oSIP目前版本源代码结构、定义比较混乱,并且缺乏文档,阅读比较困难;该问题将在oSIP2中得到改善。
oSIP目前版本源代码结构、定义比较混乱,并且缺乏文档,阅读比较困难;该问题将在oSIP2中得到改善。
¨
oSIP不提供任何快速产生请求消息和响应消息的方法,所有请求消息和响应消息的形成必须调用一组sip message api来手动组装完成,关于这方面的缺陷,osip作者可能在以后会开发一个eXoSIP的API来完成。
oSIP不提供任何快速产生请求消息和响应消息的方法,所有请求消息和响应消息的形成必须调用一组sip message api来手动组装完成,关于这方面的缺陷,osip作者可能在以后会开发一个eXoSIP的API来完成。
¨
由于oSIP结构简单,外围相关模块需要用户自己开发,如SIP消息的接收和发送,RTP/RTCP的语音数据的处理等。
由于oSIP结构简单,外围相关模块需要用户自己开发,如SIP消息的接收和发送,RTP/RTCP的语音数据的处理等。
4. oSIP应用结构图
Receive/Send SIP Messages |
| SIP parser |
| URL parser |
| SDP parser |
Finite State Machines |
| Dialogue Facilities |
SDP negotiation Facilities |
| Main thread |
| 状态机模块 |
| 解析器模块 |
工具模块(可选项) |
|
oSIP模块
|
|
图4-1 oSIP应用
|
|
Receive/Send
RTP/RTCP
|
|
oSIP
Instance
|
|
Transaction
Context
|
|
①
|
|
②
|
|
③
|
|
⑥
|
|
④
|
|
⑤
|
|
⑦
|
|
B
|
|
A
|
|
Application
|
其中:
①:初始化oSIP和注册CALL BACK函数;
②:添加事件A;
③:执行事务
④:取消事件A
⑤:解析消息
⑥:触发CALL BACK函数
⑦:接收/发送消息
A:保存状态
B:接收/发送语音包
5. oSIP使用概述
5.1 初始化oSIP
在使用oSIP前必须先初始化oSIP,主要调用函数
osip_global_init()和osip_init(),具体操作代码如下:
osip_t *osip;
// initialise internal element first
if (0!=osip_global_init())
return -1;
// allocate a global osip element.
if (0!=osip_init(&osip))
return -1;
|
5.2 注册CALL BACK函数
需要注册的call back函数主要包含发送消息、结束事务、发送失败、4个状态机(ICT、NICT、IST、NIST)相关函数。
注册发送消息的CALL BACK函数:
|
osip_setcb_send_message(osip, &application_cb_snd_message);
|
注册结束事务的CALL BACK函数:
|
osip_setcb_ict_kill_transaction(osip,&application_cb_ict_kill_transaction);
osip_setcb_ist_kill_transaction(osip,&application_cb_ist_kill_transaction);
osip_setcb_nict_kill_transaction(osip,&application_cb_nict_kill_transaction);
osip_setcb_nist_kill_transaction(osip,&application_cb_nist_kill_transaction);
|
注册发送失败的CALL BACK函数:
|
osip_setcb_ict_transport_error(osip,&application_cb_transport_error);
osip_setcb_ist_transport_error(osip,&application_cb_transport_error);
osip_setcb_nict_transport_error(osip,&application_cb_transport_error);
osip_setcb_nist_transport_error(osip,&application_cb_transport_error);
|
注册ICT、NICT、IST、NIST CALL BACK函数
osip_setcb_ict_2xx_received2(osip,&application_cb_rcvresp_retransmission); osip_setcb_ict_3456xx_received2(osip,&application_cb_rcvresp_retransmission); osip_setcb_ict_invite_sent2(osip,&application_cb_sndreq_retransmission); osip_setcb_ist_2xx_sent2(osip,&application_cb_sndresp_retransmission); osip_setcb_ist_3456xx_sent2(osip,&application_cb_sndresp_retransmission); osip_setcb_ist_invite_received2(osip,&application_cb_rcvreq_retransmission); osip_setcb_nict_2xx_received2(osip,&application_cb_rcvresp_retransmission); osip_setcb_nict_3456xx_received2(osip,&application_cb_rcvresp_retransmission); osip_setcb_nict_request_sent2(osip,&application_cb_sndreq_retransmission); osip_setcb_nist_2xx_sent2(osip,&application_cb_sndresp_retransmission); osip_setcb_nist_3456xx_sent2(osip,&application_cb_sndresp_retransmission); osip_setcb_nist_request_received2(osip,&application_cb_rcvreq_retransmission); osip_setcb_ict_invite_sent (osip,&application_cb_sndinvite); osip_setcb_ict_ack_sent (osip,&application_cb_sndack); osip_setcb_nict_register_sent(osip,&application_cb_sndregister); osip_setcb_nict_bye_sent (osip,&application_cb_sndbye); osip_setcb_nict_cancel_sent (osip,&application_cb_sndcancel); osip_setcb_nict_info_sent (osip,&application_cb_sndinfo); osip_setcb_nict_options_sent (osip,&application_cb_sndoptions); osip_setcb_nict_subscribe_sent (osip,&application_cb_sndoptions); osip_setcb_nict_notify_sent (osip,&application_cb_sndoptions); osip_setcb_nict_unknown_sent(osip,&application_cb_sndunkrequest); osip_setcb_ict_1xx_received(osip,&application_cb_rcv1xx); osip_setcb_ict_2xx_received(osip,&application_cb_rcv2xx); osip_setcb_ict_3xx_received(osip,&application_cb_rcv3xx); osip_setcb_ict_4xx_received(osip,&application_cb_rcv4xx); osip_setcb_ict_5xx_received(osip,&application_cb_rcv5xx); osip_setcb_ict_6xx_received(osip,&application_cb_rcv6xx); osip_setcb_ist_1xx_sent(osip,&application_cb_snd1xx); osip_setcb_ist_2xx_sent(osip,&application_cb_snd2xx); osip_setcb_ist_3xx_sent(osip,&application_cb_snd3xx); osip_setcb_ist_4xx_sent(osip,&application_cb_snd4xx); osip_setcb_ist_5xx_sent(osip,&application_cb_snd5xx); |
osip_setcb_ist_6xx_sent(osip,&application_cb_snd6xx); osip_setcb_nict_1xx_received(osip,&application_cb_rcv1xx); osip_setcb_nict_2xx_received(osip,&application_cb_rcv2xx); osip_setcb_nict_3xx_received(osip,&application_cb_rcv3xx); osip_setcb_nict_4xx_received(osip,&application_cb_rcv4xx); osip_setcb_nict_5xx_received(osip,&application_cb_rcv5xx); osip_setcb_nict_6xx_received(osip,&application_cb_rcv6xx); osip_setcb_nist_1xx_sent(osip,&application_cb_snd1xx); osip_setcb_nist_2xx_sent(osip,&application_cb_snd2xx); osip_setcb_nist_3xx_sent(osip,&application_cb_snd3xx); osip_setcb_nist_4xx_sent(osip,&application_cb_snd4xx); osip_setcb_nist_5xx_sent(osip,&application_cb_snd5xx); osip_setcb_nist_6xx_sent(osip,&application_cb_snd6xx); osip_setcb_ist_invite_received (osip,&application_cb_rcvinvite); osip_setcb_ist_ack_received (osip,&application_cb_rcvack); osip_setcb_ist_ack_received2 (osip,&application_cb_rcvack2); osip_setcb_nist_register_received(osip,&application_cb_rcvregister); osip_setcb_nist_bye_received (osip,&application_cb_rcvbye); osip_setcb_nist_cancel_received (osip,&application_cb_rcvcancel); osip_setcb_nist_info_received (osip,&application_cb_rcvinfo); osip_setcb_nist_options_received (osip,&application_cb_rcvoptions); osip_setcb_nist_subscribe_received(osip,&application_cb_rcvoptions); osip_setcb_nist_notify_received (osip,&application_cb_rcvoptions); osip_setcb_nist_unknown_received (osip,&application_cb_rcvunkrequest); |
在注册完CALL BACK函数后,应用程序可以建立Transaction来调用oSIP的解析器和状态机模块的操作,来实现不同应用程序的需求。
6. 参考
[1] SIP — RFC3261 (http://www.ietf.org)
[2] SDP — RFC2327(http://www.ieft.org)
[3] oSIP Library — http://www.gnu.org/software/osip/
[4] oSIP mailing list — http://www.atosc.org/pipermail/public/osip/
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/148657.html原文链接:https://javaforall.net
