freeDiameter源码阅读之 Extensions 的实现

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


/* List of extensions to load, from the configuration parsing */
struct fd_ext_info {
struct fd_list chain; /* link in the list */
char *filename; /* extension filename. must be a dynamic library with fd_ext_init symbol. */
char *conffile; /* optional configuration file name for the extension */
void *handler; /* object returned by dlopen() */
const char **depends; /* names of the other extensions this one depends on (if provided) */
char *ext_name; /* points to the extension name, either inside depends, or basename(filename) */
int free_ext_name; /* must be freed if it was malloc'd */
void (*fini)(void); /* optional address of the fd_ext_fini callback */
};

/* list of extensions */
static struct fd_list ext_list = FD_LIST_INITIALIZER(ext_list);

/* Add new extension */
int fd_ext_add( char * filename, char * conffile )
{
struct fd_ext_info * new;

TRACE_ENTRY("%p %p", filename, conffile);

/* Check the filename is valid */
CHECK_PARAMS( filename );

/* Create a new object in the list */
CHECK_MALLOC( new = malloc( sizeof(struct fd_ext_info) ) );
memset(new, 0, sizeof(struct fd_ext_info));
fd_list_init(&new->chain, NULL);
new->filename = filename;
new->conffile = conffile;
fd_list_insert_before( &ext_list, &new->chain );
TRACE_DEBUG (FULL, "Extension %s added to the list.", filename);
return 0;
}



/* Load all extensions in the list */
int fd_ext_load()

/* Loop on all extensions */
for (li = ext_list.next; li != &ext_list; li = li->next)
ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL);
/* Resolve the entry point of the extension */
fd_ext_init = ( int (*) (int, int, char *) )dlsym( ext->handler, "fd_ext_init" )
/* Now call the entry point to initialize the extension */
ret = (*fd_ext_init)( FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, ext->conffile );

}

可以看到整个加载流程其实就是找 so文件里面的 fd_ext_init 函数,并且调用这个函数来做 扩展插件的初始化
===================================
freeDiameter提供的扩展的快速定义的宏,可以看到展开成了 fd_ext_init 函数定义。

/* Macro that define the entry point of the extension */
#define EXTENSION_ENTRY(_name, _function, _depends...) \
const char *fd_ext_depends[] = { _name , ## _depends , NULL }; \
static int extension_loaded = 0; \
int fd_ext_init(int major, int minor, char * conffile) { \
if ((major != FD_PROJECT_VERSION_MAJOR) \
|| (minor != FD_PROJECT_VERSION_MINOR)) { \
fprintf(stderr, "This extension (" _name ") was compiled for a different version of freeDiameter.\n"); \
TRACE_DEBUG(INFO, "daemon %d.%d != ext %d.%d", \
major, minor, \
FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR); \
return EINVAL; \
} \
if (extension_loaded) { \
fprintf(stderr, "Extension (" _name ") cannot be loaded twice!\n"); \
return ENOTSUP; \
} \
extension_loaded++; \
return (_function)(conffile); \
}

====================================
看一个简单的扩展模块


static struct fd_rt_fwd_hdl * fwd_hdl = NULL;
static struct fd_rt_out_hdl * out_hdl = NULL;

/* Proxying debug callback */
static int dbgrt_fwd_cb(void * cbdata, struct msg ** msg)
{
TRACE_ENTRY("%p %p", cbdata, msg);

fd_log_debug("[dbg_rt] FWD routing message: %p\n", msg ? *msg : NULL);
if (msg)
fd_msg_dump_walk(INFO, *msg);

return 0;
}

/* Path selection debug callback */
static int dbgrt_out_cb(void * cbdata, struct msg * msg, struct fd_list * candidates)
{
struct fd_list * li;

TRACE_ENTRY("%p %p %p", cbdata, msg, candidates);

fd_log_debug("[dbg_rt] OUT routing message: %p\n", msg);
fd_msg_dump_walk(INFO, msg);
fd_log_debug("[dbg_rt] Current list of candidates (%p): (score - id)\n", msg);

for (li = candidates->next; li != candidates; li = li->next) {
struct rtd_candidate *c = (struct rtd_candidate *) li;
fd_log_debug("[dbg_rt] %d -\t%s\n", c->score, c->diamid);
}

return 0;
}

/* Register the callbacks to the daemon */
static int dbgrt_main(char * conffile)
{
TRACE_ENTRY("%p", conffile);

CHECK_FCT( fd_rt_fwd_register ( dbgrt_fwd_cb, NULL, RT_FWD_ALL, &fwd_hdl ) );
CHECK_FCT( fd_rt_out_register ( dbgrt_out_cb, NULL, -1 /* so that it is called late */, &out_hdl ) );

return 0;
}

/* Define the entry point function */
EXTENSION_ENTRY("dbg_rt", dbgrt_main);



在初始化函数中用 fd_rt_fwd_register fd_rt_out_register 注册了两个消息处理函数。
其实这个初始化函数中你可以做任何事情,比如启动另外的监控线程等等 (这个可以参考 dbg_monitor扩展模块的实现)


比较常用注册消息的callbackapi
fd_rt_fwd_register
fd_rt_out_register 注册routing out msghandler
fd_disp_register 注册某个Diameter Command 或者 AVP 的回调处理函数
fd_sess_handler_create
pthread_create(&rtr_threa //创建线程
======================================================================

libfdproto.h 里面相关函数的说明
/*
* FUNCTION: fd_disp_register
*
* PARAMETERS:
* cb : The callback function to register (see dispatch_callback description above).
* how : How the callback must be registered.
* when : Values that must match, depending on the how argument.
* opaque : A pointer that is passed back to the handler. The content is not interpreted by the framework.
* handle : On success, a handler to the registered callback is stored here if not NULL.
* This handler can be used to unregister the cb.
*
* DESCRIPTION:
* Register a new callback to handle messages delivered locally.
*
* RETURN VALUE:
* 0 : The callback is registered.
* EINVAL : A parameter is invalid.
* ENOMEM : Not enough memory to complete the operation
*/
int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *),
enum disp_how how, struct disp_when * when, void * opaque, struct disp_hdl ** handle );


---------------------
其他实现扩展插件相关的api函数都可以在 libfdproto.h libFdcore.h里面找到说明。
可以通过里面提供的各种apifreediameter进行交互。
比如可以使用这两个函数可以发送消息,这个有个回调函数参数,freediameter负责帮你发送消息之后调用你提供的回调函数
int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data );
int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, const struct timespec *timeout );


--------------
dispatch.c 文件 里面

int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *),
enum disp_how how, struct disp_when * when, void * opaque, struct disp_hdl ** handle )

3个参数when 根据前面的第二个参数how的值,对应不同的command 还是avp这个结构。
调用 fd_disp_register 之前,必须用fd_dict_search函数在全局的 dictionary 树里面找到 对应的when结构。
fd_disp_register 做的事情就是把 callback函数链接到 whenlist上面去而已。

------------------------
messages.c 接上篇文章,看看消息处理的时候是怎么调用到这个 扩展插件见注册的callback函数的。

前面说到会在这个函数里面调用回调。
------------------
fd_msg_dispatch
/* First, call the DISP_HOW_ANY callbacks */
CHECK_FCT_DO( ret = fd_disp_call_cb_int( NULL, msg, NULL, session, action, NULL, NULL, NULL, NULL ), goto out );
fd_dict_disp_cb 取出注册的 callback list
CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, avp, session, action, app, cmd, avp->avp_model, enumval ), goto out );
/* Now call command and application callbacks */
CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_COMMAND, cmd, &cb_list), goto out );
CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, NULL, session, action, app, cmd, NULL, NULL ), goto out );
TEST_ACTION_STOP();

if (app) {
CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_APPLICATION, app, &cb_list), goto out );
CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, NULL, session, action, app, cmd, NULL, NULL ), goto out );
TEST_ACTION_STOP();
}

这里面会通过 fd_disp_call_cb_int 调用各种回调函数。

--------------------

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值