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的,extensioncallback函数啦,等等也都是注册到这个 dict树里面的(这个可以查看我前面写的文章)。
这个dict里面不同类型的节点,应该查找时可以用不同的函数的,管理应该也不太一样,具体细节没怎么看。

http://www.freediameter.net/trac/wiki/Dev/APIThe 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 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定义的minmax个数比较。检查固定的头部,尾部的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 }
-------------------------------------------



0 0
原创粉丝点击