freeDiameter源码阅读之 dictionary树和消息的合法性检查(rule)

http://gmd20.blog.163.com/blog/static/168439232013381193653/

freediameter里面预先使用c的描述结构,构建全局的avp dictionary树。
extensions 下面很多 dict 开头的模块都是用于提供各种协议的avp的定义的。 运行时可以选择需要的模块加载。加载完成之后,一个dictionary树就建好了,有avp的合法规则等描述,解析msg的时候,就可以根据这个dict来做合法性检查,avp是不是能识别出来之

类的。很多功能都依赖于这个 dict树。 什么command或者avp的,extensioncallback函数啦,等等也都是注册到这个 dict树里面的(这个可以查看我前面写的文章)。
这个dict里面不同类型的节点,应该查找时可以用不同的函数的,管理应该也不太一样,具体细节没怎么看。

http://www.freediameter.net/trac/wiki/Dev/API The freeDiameter API  对dictionary的类型等作了大概的介绍。

 

下面看看dict的构建和 使用来做 msg ,avp有效性检查的相关代码。


定义dictrule的例子
http://www.freediameter.net/trac/browser/freeDiameter/extensions/dict_dcca/dict_dcca.c

---------------avpdict的定义
#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 additional AVPs { "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, const struct 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 }
-------------------------------------------



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值