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扩展模块的实现)
比较常用注册消息的callback的api是
fd_rt_fwd_register
fd_rt_out_register
注册routing
out
的msg的handler
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里面找到说明。
可以通过里面提供的各种api和freediameter进行交互。
比如可以使用这两个函数可以发送消息,这个有个回调函数参数,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函数链接到
when的list上面去而已。
------------------------
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 调用各种回调函数。
--------------------
本文介绍FreeDiameter中扩展插件的加载流程与开发方式,包括如何注册消息处理回调函数、使用API与核心框架交互等关键技术点。

1234

被折叠的 条评论
为什么被折叠?



