当前位置: 首页 >> 程序设计 >> oSIP开发者手册
 

oSIP开发者手册

作者:      来源:zz     发表时间:2007-01-16     浏览次数:      字号:    

 
第五章 有限状态机
有限状态机用以表示SIP会话过程,用数学方法表示状态的转换。每一时刻协议机(发送方或接受方)总处于一个特定的状态,其状态是由所有变量值组成的,包括计数器在内。
./libosip-x.x.x/fsm是包含有限状态机的源程序目录。
./libosip是开发库目录。
#include<osip/osip.h>是描述SIP有限状态机的API的库文件。
事务处理和事件(Events)
事务处理的定义和目的
               RFC2543中,事务处理被用于定义SIP事务处理的上下文关系。利用transaction_t结构定义事务处理信息,所以我们不需要明白每一个属性。事务处理模型如下:

Incoming msg
Timeout evt
Msg to send
User module
Timer module
Transport module
TRANSAC.
2
TRANSAC.
1
事务处理的上下文
 

 
 
 
 
 
 
 
 
 

your_instance属性没有被开发库用到,我们可以用它指向个人设定的上下文。
我们以transactionid作为事务处理链表中每个个体的唯一标识。
transactionff是一个FIFO(First In First Out先进先出)结构,用以标识此事务处理的事件(sipevent_t)
这个proxy属性指出被用于传输的主机和端口,所有的请求被强制传输到此proxy,而不论request-uri包含的是什么。
typedef struct _transaction_t{
 void *your_instance;       /*add whatever you want here. */
 int transactionid;         /*simple id used to identify the tr.*/
 fifo_t *transactionff;     /*events must be added in this fifo*/
 
 from_t *from;           /* CALL-LEG definition */
 to_t *to;
 call_id_t *callid;
 cseq_t *cseq;
 sip_t *lastrequest;        /*last request received or sent */
 sip_t *lastresponse;       /*last response received or sent */
 
 state_t state;             /*state of transaction*/
 statemachine_t *statemachine; /* state-machine of transaction*/
 
 time_t birth_time;         /*birth_date of transaction*/
 time_t completed_time;     /*end date of transaction*/
 int retransmissioncounter; /*facilities for internal timer*/
 
 url_t *proxy;              /*url used to send requests*/
 void *config;              /*transaction is managed by config*/
} transaction_t;
事件的定义和目的
sipevent目标被用于控制SIP事务处理中的元素。在有限状态机中有3种事件(Events)
接收SIP消息(请求和应答)
发送SIP消息(请求和应答)
计时器事件(重传和上下文删除或者说结束)
type总是指向事件的类型。
transactionid作为内部使用。
当事件是因为SIP消息引起的,则sip就是sip_t结构消息。
typedef struct _sipevent_t
{
 type_t type;
 int transactionid;
 sip_t *sip;
}sipevent_t;
事务处理的API
osip_init
[功能描述]
osip_t结构初始化并分配内存。
[参数描述]
int osip_init(oisp_t **osip);
成功返回0
 
osip_free
[功能描述]
释放osip结构。
[参数描述]
void osip_free(osip_t *osip);
 
osip_init_proxy
[功能描述]
设定与osip结构相关事务处理的默认代理。
[参数描述]
void osip_init_proxy(osip_t *osip,url_t *url);
 
osip_execute
[功能描述]
(仅限于非多线程的应用程序设计)执行在osip结构当中事务处理的事件(Events)
[参数描述]
int osip_execute(osip_t *osip);
成功返回0
 
osip_distribute_event
[功能描述]
分发一个SIP事件(对于接收消息事件incoming message evt)到osip结构当中的FIFO
[参数描述]
transaction_t *osip_distribute_event(osip_t *osip,sipevent_t *se);
 
osip_parse
[功能描述]
对字符串buf进行语法分析,并生成SIP到来消息事件。
[参数描述]
sipevent_t *osip_parse(char *buf);
 
osip_new_event
[功能描述]
(被计时器使用)用于创建一个新的SIP事件(event),并带有类型属性typetransactionid
[参数描述]
sipevent_t *osip_new_event(type_t type,int transactionid);
 
osip_new_incoming_event
[功能描述]
为接收SIP消息创建新的SIP事件。
[参数描述]
sipevent_t *osip_new_incoming_event(sip_t *sip);
 
sip_new_outgoing_event
[功能描述]
为发送SIP消息创建新的SIP事件。
[参数描述]
sipevent_t *osip_new_outgoing_event(sip_t *sip);
 
osip_find_asincomingmessage
[功能描述]
发现(或创建)与接收SIP消息相关事务处理。
[参数描述]
transaction_t *osip_find_adincomingmessage(osip_t *osip,sipevent_t *sipevent);
 
osip_find_asoutgoingmessage
[功能描述]
发现与发送SIP消息相关的事务处理。
[参数描述]
transaction_t *osip_find_asoutgoingmessage(osip_t *osip,sipevent_t *sipevent);
 
osip_find_byid
[功能描述]
寻找带有相同transactionid属性值的事务处理。
[参数描述]
transation_t *osip_find_byid(osip_t *osip,int transactionid);
 
osip_remove_byid
[功能描述]
删除带有相同transactionid属性值的事务处理。
[参数描述]
int osip_remove_byid(osip_t *osip,int transactionid);
 
transaction_init
[功能描述]
初始化transaction_t,并为其分配内存。
[参数描述]
int transaction_init(transaction_t **transaction);
 
transaction_free
[功能描述]
释放transaction_t结构。
[参数描述]
void transaction_free(transaction_t *transaction);
 
transaction_execute
[功能描述]
执行包含在事务处理上下文中的事件(sipevent)
[参数描述]
int transaction_execute(transaction_t *transaction);
 
回叫
oSIP使用一系列的会叫来声明SIP事务的进展。例如收到INVITE请求,开发者通过协议栈调用”osip_setcb_rcvinvite(…)”函数,使得INVITE方法被注册,产生临时应答和开始建造和发送最终响应的动作。
下面的方法允许我们去注册,初始化oSIP栈,这些方法将被用对事物的处理。一些方法是必需的(声明请求和最终响应),而另外一些是可选的(声明临时相应和重传)。
void osip_setcb_rcvinvite (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvack     (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvbye     (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvcancel (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvinfo    (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvoptions (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvregister(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvprack   (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcvunkrequest(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
 
void osip_setcb_sndinvite (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndack     (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndbye     (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndcancel (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndinfo    (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndoptions (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndregister(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndprack   (osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_sndunkrequest(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
 
void osip_setcb_rcv1xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcv2xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcv3xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcv4xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcv5xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_rcv6xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
 
void osip_setcb_snd1xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_snd2xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_snd3xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_snd4xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_snd5xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
void osip_setcb_snd6xx(osip_t *cf,void (*cb)(sipevent_t*,transaction_t*));
 
void osip_setcb_rcvresp_retransmission(osip_t *cf,void (*cb)(transaction_t*));
void osip_setcb_sndreq_retransmission (osip_t *cf,void (*cb)(transaction_t*));
void osip_setcb_sndresp_retransmission(osip_t *cf,void (*cb)(transaction_t*));
void osip_setcb_rcvreq_retransmission (osip_t *cf,void (*cb)(transaction_t*));
 
void osip_setcb_killtransaction   (osip_t *cf,void (*cb)(transaction_t*));
void osip_setcb_endoftransaction (osip_t *cf,void (*cb)(transaction_t*));
void osip_setcb_connection_refused(osip_t *cf,void (*cb)(transaction_t*));
void osip_setcb_network_error     (osip_t *cf,void (*cb)(transaction_t*));
一些有用的宏(MACROs)
    你也可以使用下面宏的列表。如果你希望你的程序在oSIP上保持完整的兼容性,你需使用他们。
/* FOR INCOMING TRANSACTION */
#define EVT_IS_RCV_INVITE(event)       (event->type==RCV_REQINVITE)
#define EVT_IS_RCV_ACK(event)          (event->type==RCV_REQACK)
#define EVT_IS_RCV_REQUEST(event)      (event->type==RCV_REQUEST)
#define EVT_IS_RCV_STATUS_1XX(event)   (event->type==RCV_STATUS_1XX)
#define EVT_IS_RCV_STATUS_23456XX(event)   (event->type==RCV_STATUS_23456XX)
 
/* FOR OUTGOING TRANSACTION */
#define EVT_IS_SND_INVITE(event)       (event->type==SND_REQINVITE)
#define EVT_IS_SND_ACK(event)          (event->type==SND_REQACK)
#define EVT_IS_SND_REQUEST(event)      (event->type==SND_REQUEST)
#define EVT_IS_SND_STATUS_1XX(event)   (event->type==SND_STATUS_1XX)
#define EVT_IS_SND_STATUS_23456XX(event)   (event->type==SND_STATUS_23456XX)
 
#define EVT_IS_INCOMINGMSG(event)      (event->type>=RCV_REQINVITE \
                                   &&event->type<=RCV_STATUS_23456XX)
#define EVT_IS_INCOMINGREQ(event)      (EVT_IS_RCV_INVITE(event) \
                                       ||EVT_IS_RCV_ACK(event) \
                                       ||EVT_IS_RCV_REQUEST(event))
#define EVT_IS_INCOMINGRESP(event)     (EVT_IS_RCV_STATUS_1XX(event) \
                                       ||EVT_IS_RCV_STATUS_23456XX(event))
#define EVT_IS_OUTGOINGMSG(event)      (event->type>=SND_REQINVITE \
                                   &&event->type<=SND_STATUS_23456XX)
#define EVT_IS_OUTGOINGREQ(event)      (EVT_IS_SND_INVITE(event) \
                                       ||EVT_IS_SND_ACK(event) \
                                       ||EVT_IS_SND_REQUEST(event))
#define EVT_IS_OUTGOINGRESP(event)     (EVT_IS_SND_STATUS_1XX(event) \
                                       ||EVT_IS_SND_STATUS_23456XX(event))
#define EVT_IS_MSG(event)              (event->type>=RCV_REQINVITE \
                                   &&event->type<=SND_STATUS_23456XX)
#define EVT_IS_KILL_TRANSACTION(event) (event->type==KILL_TRANSACTION)
#define EVT_IS_UNKNOWN_EVT(event)      (event->type==UNKNOWN_EVT)
#define EVT_IS_TIMEOUT(event)          (event->type==TIMEOUT)
有限状态机的指引
SIP定义了4种有限状态机。SIP还定义了两种事物。INVITE事务和其他非INVITE的事务差异很小。INVITEACK是成队出现的,构成了INVITE事务。并且,不同的规则应用于重传机制。
一个有限状态机是一个理想的途径,其执行于事物层。线程等待事件(events)的发生。事件来源于TU层、传输层或者时钟管理。这是通过一系列的动态回叫完成的。

User Layer
Transaction contexts
1
N
FIFO 1
FIFO N
 

 
 
 
 
 
 
 
 

初始化oSIP
oSIP栈需要在运行前初始化。在使用oSIP栈之前,下面的函数将是第一个被调用,并且只能调用一次。调用这个函也将初始化语法分析。
int osip_global_init();
分配和初始化osip_t结构
osip_t结构是一系列事物的容器。这个元素表现为sip部件的一个实例,可以用于UAS/UAC,注册服务器和重定向服务器。
下面代码用于建造一个完成的osip_t元素。首先,我们不得不注册一系列必需的或可选的回叫函数。我们也可以配置协议栈为所有的请求使用代理。
 osip_t *osip;
 
 if (-1==osip_global_init())
    return -1; /* mutex is not initialized properly */
 
 osip_init(&osip);
 osip_init_proxy(osip,url_of_proxy);
 
 osip_setcb_rcvresp_retransmission(cf,&cb_rcvresp_retransmission);
 osip_setcb_sndreq_retransmission(cf,&cb_sndreq_retransmission);
 osip_setcb_sndresp_retransmission(cf,&cb_sndresp_retransmission);
 osip_setcb_rcvreq_retransmission(cf,&cb_rcvreq_retransmission);
 
  osip_setcb_killtransaction(cf,&cb_killtransaction);
 osip_setcb_endoftransaction(cf,&cb_endoftransaction);
 
  osip_setcb_connection_refused(cf,&cb_connection_refused);
 osip_setcb_network_error(cf,&cb_network_error);
 
  osip_setcb_rcv1xx(cf,&cb_rcv1xx);
 osip_setcb_rcv2xx(cf,&cb_rcv2xx);
 osip_setcb_rcv3xx(cf,&cb_rcv3xx);
 osip_setcb_rcv4xx(cf,&cb_rcv4xx);
 osip_setcb_rcv5xx(cf,&cb_rcv5xx);
  osip_setcb_rcv6xx(cf,&cb_rcv6xx);
 
  osip_setcb_sndinvite (cf,&cb_sndinvite);
 osip_setcb_sndack     (cf,&cb_sndack);
 osip_setcb_sndbye     (cf,&cb_sndbye);
 osip_setcb_sndcancel (cf,&cb_sndcancel);
 osip_setcb_sndinfo    (cf,&cb_sndinfo);
 osip_setcb_sndoptions (cf,&cb_sndoptions);
 osip_setcb_sndregister(cf,&cb_sndregister);
 osip_setcb_sndprack   (cf,&cb_sndprack);
 osip_setcb_sndunkrequest(cf,&cb_sndunkrequest);
 
 osip_setcb_snd1xx(cf,&cb_snd1xx);
 osip_setcb_snd2xx(cf,&cb_snd2xx);
 osip_setcb_snd3xx(cf,&cb_snd3xx);
 osip_setcb_snd4xx(cf,&cb_snd4xx);
 osip_setcb_snd5xx(cf,&cb_snd5xx);
 osip_setcb_snd6xx(cf,&cb_snd6xx);
 
 osip_setcb_rcvinvite (cf,&cb_rcvinvite);
 osip_setcb_rcvack     (cf,&cb_rcvack);
 osip_setcb_rcvbye     (cf,&cb_rcvbye);
 osip_setcb_rcvcancel (cf,&cb_rcvcancel);
 osip_setcb_rcvinfo    (cf,&cb_rcvinfo);
 osip_setcb_rcvoptions (cf,&cb_rcvoptions);
 osip_setcb_rcvregister(cf,&cb_rcvregister);
 osip_setcb_rcvprack   (cf,&cb_rcvprack);
 osip_setcb_rcvunkrequest(cf,&cb_rcvunkrequest);
发送事件(events)控制事物(transaction)
    这是初始化事物的一个简单样例。初始事件发送到FIFO中,其包含最初的请求。消息的创建在这里并没有被展示。
int
create_session(osip_t *osip)
{
 sip_t         *invite;
 transaction_t *transaction;
 
 /* You must create your own SIP message. */
 msg_init (&invite);
 your_own_method_to_setup_messages(invite);
 
 /* When it is the first invite, allocate    */
 /* and start a new transaction (prepare the
 /* context and start a thread.)             */
 trn_init(&transaction,
            osip,
            invite->to,
            invite->from,
            invite->callid,
            invite->cseq);
 
 /* The thread is now waiting on its FIFO */
 /* The following method allocate an event */
 /* and send it to the transaction.        */
 osip_sendmsg(transaction,invite);
}
 
int
osip_sendmsg(transaction_t *transaction,sip_t *msg)
{
    sipevent_t *sipevent;
 
    sipevent = osip_new_outgoing_sipmessage(msg);
    sipevent->transactionid = transaction->transactionid;
 
/* depending on your application model, you can choose */
/* either to consume the event are add it in the fifo */
/* and delay the operations */
 
#ifdef OSIP_MT
    fifo_add(transaction->transactionff,sipevent);
#else
    transaction_execute(transaction,sipevent);
#endif
 
    return 0;
}
Proxy开发的注意点
oSIP提供的事务层可用于用户代理、注册服务器、重定向服务器和某些类型的会议服务器。一个有状态的代理服务器的状态机在将来将被加入进来。现在的状态机执行Proxy功能是困难的。
对于无状态的代理服务器,状态机是简单的(没有状态是需要的)。然而,当一个状态机执行时,它仅仅短时间缓存结果。
建造自己的体系结构
自从0.7.0发布以来,栈可以在没有信号量和线程的支持下使用。是否使用这些依赖于我们的设计。我们不得不选择一个适合的设计,以便完成开发我们的应用程序。这些是需要我们仔细考虑的内容:
选择传输层(SIP协议中推荐UDP
使多个事务公用一个socket,还是每个事物一个
选择多线程,或者非多线程
选择时钟
现在,UDP对与SIP系统来说是必需的,对于服务器是这样,对于用户代理亦如此。当执行一个服务器时,我们需要面对许多的并行事务。如果我们为每个事物是用一个单独的连接,应用程序或许很快就使得资源缺乏了(我们也不能总是猜测是否在同一台机器上的其他应用程序需要很多的socket)。对于服务器,当设计成对于每一个事物一个线程,我们也必须注意对多线程的使用,。对于高访问量的服务器,我们可以很快就用干了线程的资源(特别,类似于debian这样的操作系统支持很少的线程)。
如果我们的应用程序需要连接数据库和IP地址解析,这将使得程序处于一时的阻塞状态。在这种情况下,多线程将被被应用到,并来带很好的性能。对于提高我们应用程序的性能而言,如何解决好这些问题将是重中之重。
后记
    作为oSIP的翻译者,我希望这份文档会被不断的改进。这需要你的关注,任何的建议和修正都是欢迎的,哪怕仅仅是一句鼓励话。

[1] [2] [3]

编辑 webmaster

发表评论  打印本文  推荐本文  加入收藏  返回顶部  关闭窗口
 
 
 
评论更多>>
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •