目录
前言
1、lumps system简介
2、lumps system函数接口
2.1创建指定被操作lumps的函数
2.2创建用于新插入或替换lumps的函数
3、修改Contact头域与lump操作图解
3.1 使用lumps实现FixContact函数
3.2图解FixContact函数的lumps操作过程
小结
前言
SIP消息交互的过程中,经常需要对sip消息进行修改,如修改/添加SIP头域,修改SDP内容等,在使用过程中多少也会遇到需要开发来修改信令实现功能的情况。在OpenSIPS中对SIP消息执行更改的标准机制是使用所谓的块系统(lumps system)。
1、lumps system简介
OpenSIPS的lumps system效率很高,这也是opensips性能高效的一个原因之一。这些要修改的块(lumps)存储在一个列表中,并且只在OpenSIPS脚本执行完毕之后并且在SIP消息被转发之前应用到消息中(重新组包)。因此,对SIP消息所做的更改在进一步检查时不会立即反映在SIP消息中。
lumps system虽然设计巧妙,但是使用起来不容易理解,我也是用过几次之后,专门翻了下代码实现来研究,才慢慢理解lumps操作的。
Lumps分为两种,SIP消息块(SIP Message Lumps)和SIP响应块(SIP Reply Lumps)。这里主要介绍常会用到的SIP消息块操作。将“lumps”直接翻译为“块”对于后文的叙述而言容易造成意义不清,后面的叙述将都使用lumps来说明。
2、lumps system函数接口
SIP消息块这种类型的lumps用于操作当前SIP消息。从操作的角度来看,SIP消息块也分为两类:删除lumps(Delete Lumps)和添加lumps(Add Lumps)。但从函数接口角度来分又可以分为两类:创建指定被操作lumps的函数和创建插入或替换lumps的函数。
下面从函数接口角度对几个常用的具有代表性的lumps操作函数进行分类介绍。
2.1创建指定被操作lumps的函数
del_lump函数接口:
del_lump函数用于指定在当前sip_msg buffer中要删除的消息块的内存位置和删除长度。del_lump函数创建一个lump对象,指定删除的lump在sip_msg buffer中的位移(offset)以及删除长度(len)、lump类型LUMP_DEL(函数内部指定,不是参数type指定,下同)等,并将lump对象插入到sip_msg中的lump链表中,最后返回该lump对象的指针。
anchor_lump函数接口:
anchor_lump函数创建(malloc)一个lump对象,用于保存该lump插入点在sip_msg buffer中的位移(offset),lump操作类型设置为LUMP_NOP等,并将该lump对象插入到sip_msg中的lump链表,最后返回该lump对象的指针。
2.2创建用于新插入或替换lumps的函数
insert_new_lump_after和insert_new_lump_before接口:
insert_new_lump_after和insert_new_lump_before这两个函数分别用于创建用于新插入或替换原有内容的lumps。
insert_new_lump_after函数传入一个指定了新插入(或删除)位置的lumpafter(del_lump和anchor_lump函数返回的lump),并创建一个新的lumptmp,lump tmp用于保存新插入(或替换)内容的buffer指针以及buffer长度,lumps操作类型设置为LUMP_ADD,最后将after->after指向tmp,并返回tmp对象。
insert_new_lump_before函数操作和insert_new_lump_after函数基本相同,只是最后将传入的指定了新插入(或删除)位置的lump tmp赋值给了before->before。
这两个函数实现上和功能上区别不大,大部分场景这两个函数调用效果都是一样的,唯一的区别只是在消息重新组包的时候,insert_new_lump_before创建的lump比insert_new_lump_after创建的lump先被执行。
lumps system提供的所有接口都声明在data_lump.h头文件中,这里只介绍了常用的几个。
下面举例讲解lumps操作。
3、使用lump实现FixContact函数
以下图场景为例,OpenSIPS收到的SIP消息中,Contact头域中URI地址是无效的“o8kvkeft9oak.invalid”字符串:
如果需要从OpenSIPS上修复这个问题,就需要用到lumps system。
3.1 FixContact函数实现
该函数可以实现为模块导出函数,在脚本中调用。实际上nat_traversal模块已经实现同名且功能相同的导出函数,这里做了修改,以更好的说明。
FixContact函数实现
如果在脚本逻辑对应位置中调用了该函数,则当前消息将会在转发修正这个问题,也就是contact URI中的“o8kvkeft9oak.invalid”被替换为了UAC的源地址,然后再转发给下一跳服务器。
3.2 图解FixContact函数lumps操作过程
第一步,FixContact函数从消息包中解析获得Contact头域对象,然后再解析Contact头域,获得头域中发URI对象。
第二步,计算contact URI在于消息 buffer中的偏移量,并计算要替换的字符串长度,调用del_lump函数创建指定删除字符串的lump,并保存返回的lump指针对象anchor。
第三步,使用正确的IP:Port填充addr_buf,然后调用insert_new_lump_after函数,传入anchor,addr_buf地址和addr_buf长度。
最后在消息转发前,会基于msg消息的lump链表重新进行组包,才最终将修改应用到消息中。
这里图解lumps只展示了一个概略的组包流程,实际代码实现包含很多实现细节,这里都没有展示,毕竟讲解lumps system源码实现不是本篇的目的(lumps system的源码实现还是值得学习的,如果哪天我有心情有时间也许会写一篇源码实现的介绍呢~)。
小结
OpenSIPS的lumps system从实现的很巧妙,代码应用上也经常会用到。如果需要了解更多实现细节可以去查看lumps实现源码和消息组包源码。如果需要知道其他lumps函数的使用方法也可以去查看OpenSIPS模块的源码,看是怎么使用的,毕竟这方面文档太少。
(全文完)
更多查看官方文档
http://www.opensips.org/Documentation/Development-Manual#toc11
Code Too Funny
长按订阅Code2Fun,获取更多内容
领取专属 10元无门槛券
私享最新 技术干货