Commit 37f3b35c authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Split interface file in modules

parent 12b195dd
......@@ -65,18 +65,40 @@ r = fd_event_send(cvar.fd_g_config.cnf_main_ev, FDEV_DUMP_EXT, 0, None)
# Display the local Diameter Identity:
print "Local Diameter Identity:", cvar.fd_g_config.cnf_diamid
# Display realm, without using the low-level functions (skip proxy classe definitions):
# Display realm, using the low-level functions (skip proxy classe definitions):
print "Realm:", _fDpy.fd_config_cnf_diamrlm_get(_fDpy.cvar.fd_g_config)
############# Lists ############
l1 = fd_list() # The creator has an implicit fd_list_init call
# Note: we use different names from the C API here, for usability.
l1 = fd_list() # Will be our sentinel
l2 = fd_list()
fd_list_insert_after(l1, l2)
l1.dump()
del l2 # The destructor has an implicit fd_list_unlink call
l3 = fd_list()
l1.isempty()
l1.insert_next(l2) # l1 -> l2
l1.isempty()
l1.insert_prev(l3) # l1 -> l2 -> l3 (circular list)
l1.dump()
l3.detach() # l1 -> l2
l4=fd_list()
l5=fd_list()
l3.insert_next(l4) # l3 -> l4
l3.insert_next(l5) # l3 -> l5 -> l4
l1.concat(l3) # l1 -> l2 -> l5 -> l4
elements = l1.enum_as() # default: enumerates as fd_list. Warning: this a copy, changing the python list has no effect on the underlying list.
for li in elements:
li.dump()
del elements
del l2
del l3
del l4
del l5
l1.isempty() # The destructor has an implicit fd_list_unlink call
del l1
......@@ -213,7 +235,7 @@ s1 = session()
s1.getsid()
s2 = session("this.is.a.full.session.id")
r,s3,isnew = fd_sess_fromsid("this.is.a.full.session.id")
s4 = session("host.id", "opt.part")
s4 = session("host.id", "optional.part")
s4.settimeout(30) # the python wrapper takes a number of seconds as parameter for simplicity
s4.dump()
......@@ -240,51 +262,142 @@ rd.remove("p2.testbed.aaa")
rd.error("p3.testbed.aaa", "relay.testbed.aaa", 3002)
list = rd.extract(-1)
list[0].dump()
for c in list.enum_as("struct rtd_candidate *"):
print "%s (%s): %s" % (c.diamid, c.realm, c.score)
############# Messages, AVPs ############
## AVP
# Create empty (as for messages, pass None or a dictionary object as 1st param, and flags as optional 2nd param)
blank_avp = avp()
del blank_avp
######################### old stuff (need update) ######################
oh = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host")) # Octet String
vi = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Vendor-Id")) # U32
vsai = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Vendor-Specific-Application-Id")) # Grouped
# Set values
val = avp_value()
val.u32 = 123
vi.setval(None) # this cleans a previous value (not needed)
vi.setval(val)
val.os = "my.origin.host"
oh.setval(val)
vsai.add_child(vi) # call as add_child(vi, 1) to add the new AVP at the beginning, default is at the end
## Messages
# Create empty
a_msg = msg()
a_msg.dump()
del a_msg
# It is also possible to pass MSGFL_* flags in second parameter (ALLOC_ETEID is default)
msg_no_eid = msg(None, 0)
msg_no_eid.dump()
del msg_no_eid
# Create from dictionary
dwr_dict = cvar.fd_g_config.cnf_dict.search ( DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request" )
dwr = msg(dwr_dict)
dwr.dump()
# Create msg from a binary buffer (then you should call parse_dict and parse_rules methods)
dwr2 = msg("\x01\x00\x00\x14\x80\x00\x01\x18\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xf0\x00\x01")
# Create answer from request (optional parameters: dictionary to use, and flags):
dwr3 = msg(cvar.fd_g_config.cnf_dict.search ( DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request" ))
dwa3 = dwr3.create_answer()
dwr3cpy = dwa3.get_query()
## Other functions with AVPs & messages
# Add the AVPs in the message
dwr.add_child(oh)
oh.add_next(vsai) # equivalent to add_child on the parent
# Create a network byte buffer from the message
dwr.bufferize()
# Get first child AVP (fast)
avp = dwr.first_child()
# then:
avp = avp.get_next() # when last AVP, returns None
# Get all 1st level children (slower) -- warning, changes to the python list will not be reflected on the underlying message. read-only use.
dwr.children()
# example use:
for a in dwr.children()
a.dump(0) # 0 means: dump only this object, do not walk the tree
# Search the first AVP of a given type
oh_dict = cvar.fd_g_config.cnf_dict.search( DICT_AVP, AVP_BY_NAME, "Origin-Host")
oh = dwr.search( oh_dict )
# After adding AVPs, the length in the message header is outdated, refresh as follow:
dwr.update_length()
# Get dictionary model for a message or avp
dwr.model()
oh.model().dump()
# Messages
gdict = fd_config_cnf_dict_get(cvar.fd_g_config)
pobj = new_dict_object_pptr()
fd_dict_search ( gdict, DICT_COMMAND, CMD_BY_NAME, char_to_void("Capabilities-Exchange-Request"), pobj, -1 )
cerdict = dict_object_pptr_value(pobj)
fd_dict_search ( gdict, DICT_AVP, AVP_BY_NAME, char_to_void("Origin-Host"), pobj, -1 )
ohdict = dict_object_pptr_value(pobj)
delete_dict_object_pptr(pobj)
pmsg = new_msg_pptr()
fd_msg_new(cerdict, MSGFL_ALLOC_ETEID, pmsg)
msg = msg_pptr_value(pmsg);
pavp = new_avp_pptr()
fd_msg_avp_new(ohdict, 0, pavp)
avp = avp_pptr_value(pavp);
fd_msg_avp_add(msg, MSG_BRW_FIRST_CHILD, avp)
fd_msg_dump_walk(0, msg)
pahdr = new_avp_hdr_pptr()
fd_msg_avp_hdr(avp, pahdr)
ahdr = avp_hdr_pptr_value(pahdr)
delete_avp_hdr_pptr(pahdr)
avp_hdr_avp_code_get(ahdr)
os = new_avp_value_os()
avp_value_os_fromstr(os, fd_config_cnf_diamid_get(cvar.fd_g_config))
val = new_avp_value()
avp_value_os_set(val, os)
delete_avp_value_os(os)
fd_msg_avp_setvalue(avp, val)
delete_avp_value(val)
r,buf = fd_msg_bufferize_py(msg)
fd_msg_free(msg)
delete_avp_pptr(pavp)
# Retrieve the header of messages & avp:
dwr_hdr = dwr.header()
dwr_hdr.msg_version
dwr_hdr.msg_hbhid
oh_hdr = oh.header()
hex(oh_hdr.avp_flags)
oh_hdr.avp_vendor
oh_hdr.avp_value.os.dump() # The initial avp value must be set with setval(), but then this accessor is allowed.
# Get or set the routing data
rd = rt_data()
dwr.set_rtd(rd)
rd = dwr.get_rtd()
# Test if message is routable
dwr.is_routable()
# Which peer the message was received from (when received from network)
dwr.source()
# The session corresponding to this message (returns None when no Session-Id AVP is included)
dwr.get_session()
# Parse a buffer
buf = "\x01\x00\x00@\x80\x00\x01\x18\x00\x00\x00\x00\x00\x00\x00\x00N\x10\x00\x00\x00\x00\x01\x08@\x00\x00\x16my.origin.host\x00\x00\x00\x00\x01\x04@\x00\x00\x14\x00\x00\x01\n@\x00\x00\x0c\x00\x00\x00{"
mydwr = msg(buf)
# Resolve objects in the dictionary. Return value is None or a struct pei_error in case of problem.
mydwr.parse_dict() # if not using the fD global dict, pass it as parameter
err = mydwr.parse_rules()
err.pei_errcode
# Grouped AVPs are browsed with same methods as messages:
gavp = dwr.children()[1]
gavp.first_child().dump()
gavp.children()
######################### old stuff (need update) ######################
# Create a new peer_info structure and add the peer to the framework.
......
......@@ -16,7 +16,16 @@ SET(CMAKE_SWIG_FLAGS -castmode -threads)
SET(SWIG_MODULE_fDpy_EXTRA_DEPS
${CMAKE_BINARY_DIR}/include/freeDiameter/freeDiameter-host.h
${CMAKE_SOURCE_DIR}/include/freeDiameter/libfreeDiameter.h
${CMAKE_SOURCE_DIR}/include/freeDiameter/freeDiameter.h)
${CMAKE_SOURCE_DIR}/include/freeDiameter/freeDiameter.h
lists.i
dictionary.i
sessions.i
routing.i
messages.i
dispatch.i
queues.i
peers.i
)
SET_SOURCE_FILES_PROPERTIES(dbg_interactive.i PROPERTIES SWIG_MODULE_NAME fDpy)
# The following code is inspired from SWIG_ADD_MODULE, but we do only what we need
......
......@@ -46,42 +46,23 @@
/* Include standard types & functions used in freeDiameter headers */
%include <stdint.i>
%include <cdata.i>
//%include <cdata.i>
%include <cstring.i>
%include <typemaps.i>
/* Some functions are not available through the wrapper */
%ignore fd_lib_init;
%ignore fd_lib_fini;
/* -- the following functions are better accessed differently, but we leave their definitions just in case
%ignore fd_dict_init;
%ignore fd_dict_fini;
%ignore fd_sess_handler_create_internal;
%ignore fd_sess_handler_destroy;
%ignore fd_sess_new;
%ignore fd_sess_getsid;
%ignore fd_sess_destroy;
%ignore fd_sess_reclaim;
%ignore fd_sess_state_store_internal;
%ignore fd_sess_state_retrieve_internal;
%ignore fd_rtd_init;
%ignore fd_rtd_free;
%ignore fd_rtd_candidate_add;
%ignore fd_rtd_candidate_del;
%ignore fd_rtd_candidate_extract;
%ignore fd_rtd_error_add;
*/
/* Inline functions seems to give problems to SWIG -- just remove the inline definition */
%define __inline__
%enddef
/* Make some global-variables read-only (mainly to avoid warnings) */
%immutable fd_g_config;
%immutable peer_state_str;
/* Create a generic error handling mechanism so that functions can provoke an exception */
/*****************
* Exceptions *
*****************/
%{
/* This is not thread-safe etc. but it should work /most of the time/. */
static int wrapper_errno;
......@@ -127,8 +108,9 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
Some types & typemaps for usability
***********************************/
%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) };
%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) }; /* fd_hash */
/* Generic typemap for functions that create something */
%typemap(in, numinputs=0,noblock=1) SWIGTYPE ** OUTPUT (void *temp = NULL) {
$1 = (void *)&temp;
}
......@@ -136,12 +118,7 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
%append_output(SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
}
%apply int * OUTPUT { enum dict_object_type * type };
%apply (char *STRING, size_t LENGTH) { (char * sid, size_t len) };
%apply SWIGTYPE ** OUTPUT { struct session ** session };
%apply int * OUTPUT { int * new };
/* Callbacks defined in python */
/* To allow passing callback functions defined in python */
%typemap(in) PyObject *PyCb {
if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Need a callable object!");
......@@ -151,7 +128,6 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
}
/*********************************************************
Now, create wrappers for (almost) all objects from fD API
*********************************************************/
......@@ -159,567 +135,17 @@ static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
%include "freeDiameter/libfreeDiameter.h"
%include "freeDiameter/freeDiameter.h"
/* Most of the functions from the API are not directly usable "as is".
See the specific following files and the dbg_interactive.py.sample file
for more usable python-style versions.
*/
%include "lists.i"
%include "dictionary.i"
%include "sessions.i"
%include "routing.i"
%include "messages.i"
%include "dispatch.i"
%include "queues.i"
/**********************************************************/
/* The remaining of this file allows easier manipulation of
the structures and functions of fD by providing wrapper-specific
extensions to the freeDiameter API.
/****** LISTS *********/
%extend fd_list {
/* allow a parameter in the constructor, and perform the fd_list_init operation */
fd_list(void * o = NULL) {
struct fd_list * li;
li = (struct fd_list *) malloc(sizeof(struct fd_list));
if (!li) {
DI_ERROR_MALLOC;
return NULL;
}
fd_list_init(li, o);
return li;
}
/* Unlink before freeing */
~fd_list() {
fd_list_unlink($self);
free($self);
}
/* For debug, show the values of the list */
void dump() {
fd_log_debug("list: %p\n", $self);
fd_log_debug(" - next: %p\n", $self->next);
fd_log_debug(" - prev: %p\n", $self->prev);
fd_log_debug(" - head: %p\n", $self->head);
fd_log_debug(" - o : %p\n", $self->o);
}
};
/****** DICTIONARY *********/
struct dictionary {
};
%extend dictionary {
dictionary() {
struct dictionary * r = NULL;
int ret = fd_dict_init(&r);
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return r;
}
~dictionary() {
struct dictionary *d = self;
int ret = fd_dict_fini(&d);
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
}
return;
}
void dump() {
fd_dict_dump($self);
}
PyObject * vendors_list() {
uint32_t *list = NULL, *li;
PyObject * ret;
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
ret = PyList_New(0);
list = fd_dict_get_vendorid_list($self);
for (li = list; *li != 0; li++) {
PyList_Append(ret, PyInt_FromLong((long)*li));
}
free(list);
SWIG_PYTHON_THREAD_END_BLOCK;
return ret;
}
struct dict_object * new_obj(enum dict_object_type type, void * data, struct dict_object * parent = NULL) {
struct dict_object * obj = NULL;
int ret = fd_dict_new($self, type, data, parent, &obj);
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return obj;
}
struct dict_object * search(enum dict_object_type type, int criteria, int what_by_val) {
struct dict_object * obj = NULL;
int ret = fd_dict_search ( $self, type, criteria, &what_by_val, &obj, ENOENT );
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return obj;
}
struct dict_object * search(enum dict_object_type type, int criteria, char * what_by_string) {
struct dict_object * obj = NULL;
int ret = fd_dict_search ( $self, type, criteria, what_by_string, &obj, ENOENT );
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return obj;
}
struct dict_object * search(enum dict_object_type type, int criteria, void * what) {
struct dict_object * obj = NULL;
int ret = fd_dict_search ( $self, type, criteria, what, &obj, ENOENT );
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return obj;
}
struct dict_object * error_cmd() {
struct dict_object * obj = NULL;
int ret = fd_dict_get_error_cmd ( $self, &obj );
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return obj;
}
}
struct dict_object {
};
%extend dict_object {
dict_object() {
DI_ERROR(EINVAL, PyExc_SyntaxError, "dict_object cannot be created directly. Use fd_dict_new().");
return NULL;
}
~dict_object() {
DI_ERROR(EINVAL, PyExc_SyntaxError, "dict_object cannot be destroyed directly. Destroy the parent dictionary.");
return;
}
void dump() {
fd_dict_dump_object($self);
}
enum dict_object_type gettype() {
enum dict_object_type t;
int ret = fd_dict_gettype ( $self, &t);
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return 0;
}
return t;
}
struct dictionary * getdict() {
struct dictionary *d;
int ret = fd_dict_getdict ( $self, &d );
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return d;
}
/* Since casting the pointer requires intelligence, we do it here instead of giving it to SWIG */
PyObject * getval() {
/* first, get the type */
enum dict_object_type t;
int ret = fd_dict_gettype ( $self, &t);
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
return NULL;
}
switch (t) {
%define %GETVAL_CASE(TYPE,STRUCT)
case TYPE: {
PyObject * v = NULL;
struct STRUCT * data = NULL;
data = malloc(sizeof(struct STRUCT));
if (!data) {
DI_ERROR_MALLOC;
return NULL;
}
ret = fd_dict_getval($self, data);
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
free(data);
return NULL;
}
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
v = SWIG_NewPointerObj((void *)data, SWIGTYPE_p_##STRUCT, SWIG_POINTER_OWN );
Py_XINCREF(v);
SWIG_PYTHON_THREAD_END_BLOCK;
return v;
} break
%enddef
%GETVAL_CASE( DICT_VENDOR, dict_vendor_data );
%GETVAL_CASE( DICT_APPLICATION, dict_application_data );
%GETVAL_CASE( DICT_TYPE, dict_type_data );
%GETVAL_CASE( DICT_ENUMVAL, dict_enumval_data );
%GETVAL_CASE( DICT_AVP, dict_avp_data );
%GETVAL_CASE( DICT_COMMAND, dict_cmd_data );
%GETVAL_CASE( DICT_RULE, dict_rule_data );
default:
DI_ERROR(EINVAL, PyExc_SystemError, "Internal error: Got invalid object type");
}
return NULL;
}
}
/* The following wrapper leaks memory each time an union avp_value is assigned an octet string.
TODO: fix this leak by better understanding SWIG...
-- the alternative is to uncomment the "free" statements bellow, but then it is easy to
create a segmentation fault by assigning first an integer, then an octetstring.
*/
%extend avp_value {
/* The following hack in the proxy file allows assigning the octet string directly like this:
avp_value.os = "blabla"
*/
%pythoncode
{
__swig_setmethods__["os"] = _fDpy.avp_value_os_set
if _newclass:os = _swig_property(_fDpy.avp_value_os_get, _fDpy.avp_value_os_set)
}
void os_set(char *STRING, size_t LENGTH) {
/* free($self->os.data); -- do not free, in case the previous value was not an OS */
$self->os.data = malloc(LENGTH);
if (!$self->os.data) {
DI_ERROR_MALLOC;
return;
}
memcpy($self->os.data, STRING, LENGTH);
$self->os.len = LENGTH;
}
void os_set(avp_value_os * os) {
/* free($self->os.data); -- do not free, in case the previous value was not an OS */
$self->os.data = malloc(os->len);
if (!$self->os.data) {
DI_ERROR_MALLOC;
return;
}
memcpy($self->os.data, os->data, os->len);
$self->os.len = os->len;
}
};
%extend avp_value_os {
void dump() {
%#define LEN_MAX 20
int i, n=LEN_MAX;
if ($self->len < LEN_MAX)
n = $self->len;
fd_log_debug("l:%u, v:[", $self->len);
for (i=0; i < n; i++)
fd_log_debug("%02.2X", $self->data[i]);
fd_log_debug("] '%.*s%s'\n", n, $self->data, n == LEN_MAX ? "..." : "");
}
}
/****** SESSIONS *********/
%{
/* store the python callback function here */
static PyObject * py_cleanup_cb = NULL;
/* call it (might be called from a different thread than the interpreter, when session times out) */
static void call_the_python_cleanup_callback(session_state * state, char * sid) {
PyObject *result;
if (!py_cleanup_cb)
return;
/* Call the function */
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
result = PyEval_CallFunction(py_cleanup_cb, "(Os)", state, sid);
Py_XDECREF(result);
SWIG_PYTHON_THREAD_END_BLOCK;
return;
}
%}
struct session_handler {
};