freeDiameter源码阅读之 dictionary树和消息的合法性检查(rule)
来源:互联网 发布:nginx 获取二级域名 编辑:程序博客网 时间:2024/05/17 00:01
http://gmd20.blog.163.com/blog/static/168439232013381193653/
freediameter里面预先使用c的描述结构,构建全局的avp dictionary树。
extensions 下面很多 dict开头的模块都是用于提供各种协议的avp的定义的。运行时可以选择需要的模块加载。加载完成之后,一个dictionary树就建好了,有avp的合法规则等描述,解析msg的时候,就可以根据这个dict来做合法性检查,avp是不是能识别出来之
类的。很多功能都依赖于这个 dict树。什么command或者avp的,extension的callback函数啦,等等也都是注册到这个 dict树里面的(这个可以查看我前面写的文章)。
这个dict里面不同类型的节点,应该查找时可以用不同的函数的,管理应该也不太一样,具体细节没怎么看。
http://www.freediameter.net/trac/wiki/Dev/APIThe freeDiameter API 对dictionary的类型等作了大概的介绍。
下面看看dict的构建和 使用来做 msg ,avp有效性检查的相关代码。
定义dict和rule的例子
http://www.freediameter.net/trac/browser/freeDiameter/extensions/dict_dcca/dict_dcca.c
---------------avp的dict的定义
#define CHECK_dict_new( _type, _data, _parent, _ref) \
16 CHECK_FCT( fd_dict_new( fd_g_config->cnf_dict,(_type),(_data),(_parent),(_ref)));
288 /* CC-Total-Octets */
289 {
290 /*
291 Unsigned64.
292 */
293 struct dict_avp_data data= {
294 421,/* Code */
295 0,/* Vendor */
296 "CC-Total-Octets",/* Name */
297 AVP_FLAG_VENDOR| AVP_FLAG_MANDATORY,/* Fixed flags */
298 AVP_FLAG_MANDATORY,/* Fixed flag values */
299 AVP_TYPE_UNSIGNED64/* base type of data */
300 };
301 CHECK_dict_new( DICT_AVP,&data, NULL, NULL);///这里是avp类型的dict。
302 }
其实就调用fd_dict_new函数把avp的结构定义插入到全局的dictionary树里面去,然后所有的avp的判断啊,查找啊,解析啊,都根据这个dict树来做。
---------group avp的规则
/* at least three levels of grouping */
1192 /* Multiple-Services-Credit-Control */
1193 {
1194 /*
1195 Grouped
1196 */
1197 struct dict_object* avp;
1198 struct dict_avp_data data= {
1199 456,/* Code */
1200 0,/* Vendor */
1201 "Multiple-Services-Credit-Control",/* Name */
1202 AVP_FLAG_VENDOR| AVP_FLAG_MANDATORY,/* Fixed flags */
1203 AVP_FLAG_MANDATORY,/* Fixed flag values */
1204 AVP_TYPE_GROUPED/* base type of data */
1205 };
1206 struct local_rules_definition rules[]= {
1207 { "Granted-Service-Unit", RULE_OPTIONAL,-1,1 },
1208 { "Requested-Service-Unit", RULE_OPTIONAL,-1,1 },
1209 { "Used-Service-Unit", RULE_OPTIONAL,-1,-1},
1210 { "Tariff-Change-Usage", RULE_OPTIONAL,-1,1 },
1211 { "Service-Identifier", RULE_OPTIONAL,-1,-1},
1212 { "Rating-Group", RULE_OPTIONAL,-1,1 },
1213 { "G-S-U-Pool-Reference", RULE_OPTIONAL,-1,-1},
1214 { "Validity-Time", RULE_OPTIONAL,-1,1 },
1215 { "Result-Code", RULE_OPTIONAL,-1,1 },
1216 { "Final-Unit-Indication", RULE_OPTIONAL,-1,1 }
1217 /* plus any additional AVPs { "AVP", RULE_OPTIONAL, -1, -1 } */
1218 };
1219 CHECK_dict_new( DICT_AVP,&data, NULL,&avp);
1220 PARSE_loc_rules( rules, avp );
1221 }
----------------------
--------command对应的规则
*/
1336 struct dict_object * cmd;
1337 struct dict_cmd_data data = {
1338 272, /*Code*/
1339 "Credit-Control-Request", /*Name*/
1340 CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE, /*Fixed flags*/
1341 CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /*Fixed flag values*/
1342 };
1343 struct local_rules_definition rules[] =
1344 {
1345 { "Session-Id", RULE_FIXED_HEAD, -1, 1 },
1346 { "Origin-Host", RULE_REQUIRED, -1, 1 },
1347 { "Origin-Realm", RULE_REQUIRED, -1, 1 },
1348 { "Destination-Realm", RULE_REQUIRED, -1, 1 },
1349 { "Auth-Application-Id", RULE_REQUIRED, -1, 1 },
1350 { "Service-Context-Id", RULE_REQUIRED, -1, 1 },
1351 { "CC-Request-Type", RULE_REQUIRED, -1, 1 },
1352 { "CC-Request-Number", RULE_REQUIRED, -1, 1 },
1353 { "Destination-Host", RULE_OPTIONAL, -1, 1 },
1354 { "User-Name", RULE_OPTIONAL, -1, 1 },
1355 { "CC-Sub-Session-Id", RULE_OPTIONAL, -1, 1 },
1356 { "Acct-Multi-Session-Id", RULE_OPTIONAL, -1, 1 },
1357 { "Origin-State-Id", RULE_OPTIONAL, -1, 1 },
1358 { "Event-Timestamp", RULE_OPTIONAL, -1, 1 },
1359 { "Subscription-Id", RULE_OPTIONAL, -1, -1 },
1360 { "Service-Identifier", RULE_OPTIONAL, -1, 1 },
1361 { "Termination-Cause", RULE_OPTIONAL, -1, 1 },
1362 { "Requested-Service-Unit", RULE_OPTIONAL, -1, 1 },
1363 { "Requested-Action", RULE_OPTIONAL, -1, 1 },
1364 { "Used-Service-Unit", RULE_OPTIONAL, -1, -1 },
1365 { "Multiple-Services-Indicator", RULE_OPTIONAL, -1, 1 },
1366 { "Multiple-Services-Credit-Control", RULE_OPTIONAL, -1, -1 },
1367 { "Service-Parameter-Info", RULE_OPTIONAL, -1, -1 },
1368 { "CC-Correlation-Id", RULE_OPTIONAL, -1, 1 },
1369 { "User-Equipment-Info", RULE_OPTIONAL, -1, 1 },
1370 { "Proxy-Info", RULE_OPTIONAL, -1, -1 },
1371 { "Route-Record", RULE_OPTIONAL, -1, -1 }
1372 /* plus any additionalAVPs{ "AVP", RULE_OPTIONAL,-1,-1} */
1373 };
1374
1375 CHECK_dict_new( DICT_COMMAND, &data, dcca, &cmd);
1376 PARSE_loc_rules( rules, cmd );
1377 }
PARSE_loc_rules 宏是这么定义的,其实就是找到在dict树里面找到对应的avp节点,然后把每个rule的定义加到那个节点上去。
30 #define PARSE_loc_rules( _rulearray, _parent) { \
31 int __ar; \
32 for (__ar=0; __ar < sizeof(_rulearray) /sizeof((_rulearray)[0]); __ar++){ \
33 struct dict_rule_data __data= { NULL, \
34 (_rulearray)[__ar].position, \
35 0, \
36 (_rulearray)[__ar].min, \
37 (_rulearray)[__ar].max}; \
38 __data.rule_order= RULE_ORDER(__data.rule_position); \
39 CHECK_FCT( fd_dict_search( \
40 fd_g_config->cnf_dict, \
41 DICT_AVP, \
42 AVP_BY_NAME, \
43 (_rulearray)[__ar].avp_name, \
44 &__data.rule_avp,0 ) ); \
45 if (!__data.rule_avp) { \
46 TRACE_DEBUG(INFO,"AVP Not found: '%s'",(_rulearray)[__ar].avp_name); \
47 return ENOENT; \
48 } \
49 CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE,&__data, _parent, NULL), \ //这里是DICT_RULE类型的节点。
50 { \
51 TRACE_DEBUG(INFO,"Error on rule with AVP '%s'", \
52 (_rulearray)[__ar].avp_name); \
53 return EINVAL; \
54 } ); \
55 } \
56 }
57
=========================================================
http://www.freediameter.net/trac/browser/freeDiameter/libfdcore/routing_dispatch.c
static int msg_dispatch(struct msg* msg)
443 /* At this point, we need to understand the message content, so parse it */
444 CHECK_FCT_DO( ret= fd_msg_parse_or_error(&msgptr),解析消息,根据预先定义的dictionary树形结构,检查消息合法性。
445 {
446 /* in case of error */
447 if ((ret== EBADMSG)&&(msgptr!= NULL)){
448 /* msgptr now contains the answer message to send back */
449 CHECK_FCT( fd_fifo_post(fd_g_outgoing,&msgptr));上面的函数失败的answer生成,这里发送出去
450 }
451 if (msgptr){ /* another error happen'd */
452 fd_msg_log( FD_MSG_LOG_DROPPED, msgptr,"An unexpected error occurred while parsing the message (%s)", strerror(ret));
453 CHECK_FCT_DO( fd_msg_free(msgptr),/* continue */);
454 }
455 /* We're done with this one */
456 return 0;
457 } );
486 /* Retrieve the session of the message */
487 CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msgptr,&sess, NULL));
488
489 /* Now, call any callback registered for the message */
490 CHECK_FCT( fd_msg_dispatch( &msgptr, sess,&action,&ec));处理消息注册的回调。extensions扩展插件之类的
-----------------------------------------------------------------------------
http://www.freediameter.net/trac/browser/freeDiameter/libfdcore/messages.c
347 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */
348 int fd_msg_parse_or_error(struct msg** msg)
360 /* Parse the message against our dictionary */检查消息合法性
361 ret = fd_msg_parse_rules( m, fd_g_config->cnf_dict,&pei);
/* Create the error message */如果上面dictionary检查失败,生成answer返回错误
375 CHECK_FCT( fd_msg_new_answer_from_req( fd_g_config->cnf_dict, msg, pei.pei_protoerr? MSGFL_ANSW_ERROR: 0 ) );
--------------------------------------------------
http://www.freediameter.net/trac/browser/freeDiameter/libfdproto/messages.c
2345 int fd_msg_parse_rules( msg_or_avp* object,struct dictionary* dict,struct fd_pei*error_info)
2346 {
2347 TRACE_ENTRY("%p %p %p",object, dict, error_info);
2348
2349 if (error_info)
2350 memset(error_info,0,sizeof(struct fd_pei));
2351
2352 /* Resolve the dictionary objects when missing. This also validates the object. */
2353 CHECK_FCT( fd_msg_parse_dict( object, dict, error_info) ); // 检查avp的合法性
2354
2355 /* Call the recursive function */
2356 return parserules_do( dict,object, error_info,1 ) ; //检查消息的完整性等。
2357 }
-------------
// 主要检查avp的合法性
int fd_msg_parse_dict( msg_or_avp* object,struct dictionary* dict,struct fd_pei*error_info)
parsedict_do_msg ->fd_dict_search(从dict找到该msg对象,找不到就返回失败), parsedict_do_chain(为每个msg的子avp执行parsedict_do_avp)
parsedict_do_avp {
在dict中检查 avp code是否存在,vendor等值,
如果是识别不了的mandatory avp,也在这里返回失败
读出avp value,如果是group avp,递归解析子成员对每个成员做 parsedict_do_chain
}
//检查rule的合法性
parserules_do()// 检查msg ,avp,每个子avp的rule ,然后自己rule的定义。
fd_dict_iterate_rules -》 parserules_check_one_rule
parserules_check_one_rule ()统计时间的类型的avp的个数,和rule定义的min和max个数比较。检查固定的头部,尾部的avp是不是对的等等。
---------------
-------------------------------------------------------
发送msg函数
http://www.freediameter.net/trac/browser/freeDiameter/libfdcore/messages.c
331 /* The variation of the same function with a timeout callback */
332 int fd_msg_send_timeout( struct msg ** pmsg,void(*anscb)(void*,struct msg**),void* data,conststruct timespec*timeout)
333 {
334 TRACE_ENTRY("%p %p %p", pmsg, anscb, data, timeout);
335 CHECK_PARAMS( pmsg&& anscb&& timeout);
336
337 /* Save the callback in the message, with the timeout */
338 CHECK_FCT( fd_msg_anscb_associate(*pmsg, anscb, data, timeout ));注册发送request时的回调函数,其实就是把回调函数指针放到 msg结构的一个指针域里面保存起来
339
340 /* Post the message in the outgoing queue */
341 CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg));
342
343 return 0;
344 }
-------------------------------------------
- freeDiameter源码阅读之 dictionary树和消息的合法性检查(rule)
- freeDiameter源码阅读之消息队列和消息处理流程
- freeDiameter源码阅读之消息路由
- freeDiameter源码阅读之 Extensions 的实现
- 518抽奖软件源码之:检查文件名合法性
- 邮箱和手机号码合法性检查
- 检查数据库数据字段命名规范和合法性的脚本
- 阅读源码是和大师面对面交流的机会之ArrayList检查是否有重复元素
- VBA 检查IP的合法性
- 如何检查URL的合法性?
- 检查密码的规则合法性
- freediameter部分源码分析
- flex和bison的用于加载和解析配置文件(参考freeDiameter用法)
- 合法性检查
- 用freeDiameter封装Diameter消息
- ubuntu下的freeDiameter的安装和配置
- 利用正则表达式检查时间的合法性
- ABAP检查日期时间合法性的函数
- C#枚举
- 一道用冒泡排序做数组的题,求解
- BCD码与十进制
- Qt中 .pro 文件和 .pri 文件介绍
- Android服务开发——1. 尽可能运行2. 尽可能省电
- freeDiameter源码阅读之 dictionary树和消息的合法性检查(rule)
- IOS 基于APNS消息推送原理与实现(JAVA后台)
- 微信订阅号,服务号关系 一张图解释
- Centos下vsftp的配置以及错误处理
- Vision引擎中 Havok 人偶介绍
- hibernate的三种状态
- 初识压缩感知Compressive Sensing
- 配置虚拟主机
- 多线程的同步方法和具体实现