Commit 12b195dd authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Still making progress on the dbg_interactive interface.

parent bcdce685
......@@ -94,7 +94,7 @@ d.dump()
v = dict_vendor_data()
v.vendor_id = 123
v.vendor_name = "My test vendor"
r, my_vendor = fd_dict_new(d, DICT_VENDOR, v, None)
my_vendor = d.new_obj(DICT_VENDOR, v)
del v
d.dump()
d.vendors_list()
......@@ -103,29 +103,29 @@ d.vendors_list()
a = dict_application_data()
a.application_id = 99
a.application_name = "My test appl"
r, my_appl = fd_dict_new(d, DICT_APPLICATION, a, my_vendor)
my_appl = d.new_obj(DICT_APPLICATION, a, my_vendor)
del a
# New type (callbacks are not supported yet...)
t = dict_type_data()
t.type_base = AVP_TYPE_INTEGER32
t.type_name = "My integer AVP"
r, my_type_int = fd_dict_new(d, DICT_TYPE, t, my_appl)
my_type_int = d.new_obj(DICT_TYPE, t, my_appl)
t.type_base = AVP_TYPE_OCTETSTRING
t.type_name = "My binary buffer AVP"
r, my_type_os = fd_dict_new(d, DICT_TYPE, t, my_appl)
my_type_os = d.new_obj(DICT_TYPE, t, my_appl)
del t
# Constants
c = dict_enumval_data()
c.enum_name = "AVP_VALUE_TROIS"
c.enum_value.i32 = 3
fd_dict_new(d, DICT_ENUMVAL, c, my_type_int)
d.new_obj(DICT_ENUMVAL, c, my_type_int)
c.enum_name = "A_BUFFER_CONSTANT"
c.enum_value.os = "This is a very long AVP value that we prefer to represent as a constant"
c.enum_value.os.dump()
fd_dict_new(d, DICT_ENUMVAL, c, my_type_os)
d.new_obj(DICT_ENUMVAL, c, my_type_os)
del c
# AVP
......@@ -134,14 +134,14 @@ a.avp_code = 234
a.avp_name = "my integer avp"
a.avp_flag_mask = AVP_FLAG_MANDATORY
a.avp_basetype = AVP_TYPE_INTEGER32
r, my_avp_int = fd_dict_new(d, DICT_AVP, a, my_type_int)
my_avp_int = d.new_obj(DICT_AVP, a, my_type_int)
a.avp_vendor = 123
a.avp_name = "my OS avp"
a.avp_flag_mask = AVP_FLAG_MANDATORY + AVP_FLAG_VENDOR
a.avp_flag_val = AVP_FLAG_VENDOR
a.avp_basetype = AVP_TYPE_OCTETSTRING
r, my_avp_os = fd_dict_new(d, DICT_AVP, a, my_type_os)
my_avp_os = d.new_obj(DICT_AVP, a, my_type_os)
del a
# Command
......@@ -150,24 +150,24 @@ c.cmd_code = 345
c.cmd_name = "My-Python-Request"
c.cmd_flag_mask = CMD_FLAG_REQUEST + CMD_FLAG_PROXIABLE
c.cmd_flag_val = CMD_FLAG_REQUEST + CMD_FLAG_PROXIABLE
r, my_req = fd_dict_new(d, DICT_COMMAND, c, my_appl)
my_req = d.new_obj(DICT_COMMAND, c, my_appl)
c.cmd_name = "My-Python-Answer"
c.cmd_flag_val = CMD_FLAG_PROXIABLE
r, my_ans = fd_dict_new(d, DICT_COMMAND, c, my_appl)
my_ans = d.new_obj(DICT_COMMAND, c, my_appl)
del c
# Rule
rd = dict_rule_data()
rd.rule_avp = my_avp_int
rd.rule_position = RULE_REQUIRED
rd.rule_min = -1
rd.rule_max = -1
r, my_rule1 = fd_dict_new(d, DICT_RULE, rd, my_req)
r, my_rule2 = fd_dict_new(d, DICT_RULE, rd, my_ans)
rd.rule_avp = my_avp_os
r, my_rule3 = fd_dict_new(d, DICT_RULE, rd, my_req)
r, my_rule4 = fd_dict_new(d, DICT_RULE, rd, my_ans)
del rd
r = dict_rule_data()
r.rule_avp = my_avp_int
r.rule_position = RULE_REQUIRED
r.rule_min = -1
r.rule_max = -1
d.new_obj(DICT_RULE, r, my_req)
d.new_obj(DICT_RULE, r, my_ans)
r.rule_avp = my_avp_os
d.new_obj(DICT_RULE, r, my_req)
d.new_obj(DICT_RULE, r, my_ans)
del r
d.dump()
del d
......@@ -177,70 +177,70 @@ del d
gdict = cvar.fd_g_config.cnf_dict
r, appl = fd_dict_search ( gdict, DICT_APPLICATION, APPLICATION_BY_ID, 3, -1 )
obj.dump()
r, avp = fd_dict_search( gdict, DICT_AVP, AVP_BY_NAME, "Origin-Host", -1)
obj.dump()
r, errcmd = fd_dict_get_error_cmd( gdict )
appl = gdict.search ( DICT_APPLICATION, APPLICATION_BY_ID, 3 )
appl.dump()
avp = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host")
avp.dump()
errcmd = gdict.error_cmd()
data = dict_avp_data()
fd_dict_getval(avp, data)
print data.avp_code
del data
v = avp.getval()
print v.avp_code
del v
r, t = fd_dict_gettype(appl)
t = avp.gettype()
print t
del t
r, dict = fd_dict_getdict(avp)
dict = avp.getdict()
del dict
############# Sessions ############
# handler
def my_cleanup(state,sid):
print "Cleaning up python state for session:", sid
print "Received state:", state
del state
hdl = session_handler(my_cleanup)
hdl.dump()
del hdl
hdl = session_handler(my_cleanup)
# Session
hdl = session_handler(my_cleanup)
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.settimeout(30) # the python wrapper takes a number of seconds as parameter for simplicity
s4.dump()
# states
mystate = [ 34, "blah", [ 32, 12 ] ]
s1.store(hdl, mystate)
del mystate
gotstate = s1.retrieve(hdl)
print gotstate
del gotstate
# state
mystate = [ 34, "clah", [ 32, 12 ] ]
s4.store(hdl, mystate)
############# Routing ############
rd = rt_data()
## TODO : debug the following (segfault)
rd.add("p1.testbed.aaa", "testbed.aaa")
rd.add("p2.testbed.aaa", "testbed.aaa")
rd.add("p3.testbed.aaa", "testbed.aaa")
rd.add("p4.testbed.aaa", "testbed.aaa")
def my_cleanup(state,sid):
print "Cleaning up python state for session:", sid
print "Received state:", state
hdl = session_handler(my_cleanup)
s4 = session("host.id", "opt.part")
mystate = [ 34, "clah", [ 32, 12 ] ]
s4.store(hdl, mystate)
del hdl
rd.remove("p2.testbed.aaa")
rd.error("p3.testbed.aaa", "relay.testbed.aaa", 3002)
list = rd.extract(-1)
list[0].dump()
......@@ -249,22 +249,6 @@ del hdl
######################### old stuff (need update) ######################
# Routing data
prtd = new_rt_data_pptr()
fd_rtd_init(prtd)
fd_rtd_candidate_add(rt_data_pptr_value(prtd), "p1.testbed.aaa", "testbed.aaa")
fd_rtd_candidate_add(rt_data_pptr_value(prtd), "p2.testbed.aaa", "testbed.aaa")
fd_rtd_candidate_add(rt_data_pptr_value(prtd), "p3.testbed.aaa", "testbed.aaa")
fd_rtd_candidate_del(rt_data_pptr_value(prtd), "p2.testbed.aaa", 0)
pcands = new_fd_list_pptr()
fd_rtd_candidate_extract(rt_data_pptr_value(prtd), pcands, 0)
li = fd_list_pptr_value(pcands)
li = fd_list_next_get(li)
c = fd_list_to_rtd_candidate(li)
rtd_candidate_diamid_get(c)
li = fd_list_next_get(li)
c = fd_list_to_rtd_candidate(li)
rtd_candidate_diamid_get(c)
# Messages
......
......@@ -50,9 +50,10 @@
%include <cstring.i>
%include <typemaps.i>
/* Some functions are not available through the wrapper, or accessed differently */
/* 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;
......@@ -63,7 +64,13 @@
%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__
......@@ -74,30 +81,77 @@
%immutable peer_state_str;
/* Create a generic error handling mechanism so that functions can provoke an exception */
%{
/* This is not thread-safe etc. but it should work /most of the time/. */
static int wrapper_errno;
static PyObject* wrapper_errno_py;
static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
#define DI_ERROR(code, pycode, str) { \
fd_log_debug("[dbg_interactive] ERROR: %s: %s\n", __PRETTY_FUNCTION__, str ? str : strerror(code)); \
wrapper_errno = code; \
wrapper_errno_py = pycode; \
wrapper_error_txt = str; \
}
#define DI_ERROR_MALLOC \
DI_ERROR(ENOMEM, PyExc_MemoryError, NULL)
%}
%exception {
/* reset the errno */
wrapper_errno = 0;
/* Call the function -- it will use DI_ERROR macro in case of error */
$action
/* Now, test for error */
if (wrapper_errno) {
char * str = wrapper_error_txt ? wrapper_error_txt : strerror(wrapper_errno);
PyObject * exc = wrapper_errno_py;
if (!exc) {
switch (wrapper_errno) {
case ENOMEM: exc = PyExc_MemoryError; break;
case EINVAL: exc = PyExc_ValueError; break;
default: exc = PyExc_RuntimeError;
}
}
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_SetString(exc, str);
SWIG_fail;
SWIG_PYTHON_THREAD_END_BLOCK;
}
}
/***********************************
Some types & typemaps for usability
***********************************/
/* for fd_hash */
%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) };
/* for dictionary functions */
%typemap(in, numinputs=0,noblock=1) SWIGTYPE ** OUTPUT (void *temp = NULL) {
$1 = (void *)&temp;
}
%typemap(argout,noblock=1) SWIGTYPE ** OUTPUT {
%append_output(SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
}
%apply SWIGTYPE ** OUTPUT { struct dict_object ** ref };
%apply SWIGTYPE ** OUTPUT { struct dict_object ** obj };
%apply SWIGTYPE ** OUTPUT { struct dict_object ** result };
%apply SWIGTYPE ** OUTPUT { struct dictionary ** dict }; /* this is for fd_dict_getdict, not fd_dict_init (use constructor) */
%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 */
%typemap(in) PyObject *PyCb {
if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Need a callable object!");
SWIG_fail;
}
$1 = $input;
}
/*********************************************************
Now, create wrappers for (almost) all objects from fD API
*********************************************************/
......@@ -120,8 +174,7 @@ extensions to the freeDiameter API.
struct fd_list * li;
li = (struct fd_list *) malloc(sizeof(struct fd_list));
if (!li) {
fd_log_debug("Out of memory!\n");
PyErr_SetString(PyExc_MemoryError,"Not enough memory");
DI_ERROR_MALLOC;
return NULL;
}
fd_list_init(li, o);
......@@ -152,43 +205,80 @@ struct dictionary {
struct dictionary * r = NULL;
int ret = fd_dict_init(&r);
if (ret != 0) {
fd_log_debug("Error: %s\n", strerror(ret));
PyErr_SetString(PyExc_MemoryError,"Not enough memory");
DI_ERROR(ret, NULL, NULL);
return NULL;
}
return r;
}
~dictionary() {
if (self) {
struct dictionary *d = self;
int ret = fd_dict_fini(&d);
if (ret != 0) {
fd_log_debug("Error: %s\n", strerror(ret));
}
return;
struct dictionary *d = self;
int ret = fd_dict_fini(&d);
if (ret != 0) {
DI_ERROR(ret, NULL, NULL);
}
return;
}
void dump() {
if ($self) {
fd_dict_dump($self);
}
fd_dict_dump($self);
}
PyObject * vendors_list() {
uint32_t *list = NULL, *li;
PyObject * ret;
if (!$self) {
PyErr_SetString(PyExc_SyntaxError,"dict_object cannot be created directly. Use fd_dict_new.");
return NULL;
}
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 {
......@@ -196,34 +286,80 @@ struct dict_object {
%extend dict_object {
dict_object() {
fd_log_debug("Error: dict_object cannot be created directly. Use fd_dict_new\n");
PyErr_SetString(PyExc_SyntaxError,"dict_object cannot be created directly. Use fd_dict_new.");
DI_ERROR(EINVAL, PyExc_SyntaxError, "dict_object cannot be created directly. Use fd_dict_new().");
return NULL;
}
~dict_object() {
fd_log_debug("Error: dict_object cannot be destroyed directly. Destroy the parent dictionary.\n");
DI_ERROR(EINVAL, PyExc_SyntaxError, "dict_object cannot be destroyed directly. Destroy the parent dictionary.");
return;
}
void dump() {
if ($self) {
fd_dict_dump_object($self);
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;
}
}
/* overload the search function to allow passing integers & string criteria directly */
%rename(fd_dict_search) fd_dict_search_int;
%inline %{
int fd_dict_search_int ( struct dictionary * dict, enum dict_object_type type, int criteria, int what_by_val, struct dict_object ** result, int retval ) {
return fd_dict_search ( dict, type, criteria, &what_by_val, result, retval );
}
%}
%rename(fd_dict_search) fd_dict_search_string;
%inline %{
int fd_dict_search_string ( struct dictionary * dict, enum dict_object_type type, int criteria, char * what_by_string, struct dict_object ** result, int retval ) {
return fd_dict_search ( dict, type, criteria, what_by_string, result, retval );
}
%}
/* The following wrapper leaks memory each time an union avp_value is assigned an octet string.
TODO: fix this leak by better understanding SWIG...
......@@ -243,8 +379,7 @@ int fd_dict_search_string ( struct dictionary * dict, enum dict_object_type type
/* 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) {
fd_log_debug("Out of memory!\n");
PyErr_SetString(PyExc_MemoryError,"Not enough memory");
DI_ERROR_MALLOC;
return;
}
memcpy($self->os.data, STRING, LENGTH);
......@@ -254,8 +389,7 @@ int fd_dict_search_string ( struct dictionary * dict, enum dict_object_type type
/* 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) {
fd_log_debug("Out of memory!\n");
PyErr_SetString(PyExc_MemoryError,"Not enough memory");
DI_ERROR_MALLOC;
return;
}
memcpy($self->os.data, os->data, os->len);
......@@ -265,33 +399,33 @@ int fd_dict_search_string ( struct dictionary * dict, enum dict_object_type type
%extend avp_value_os {
void dump() {
if ($self) {
%#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 ? "..." : "");
}
%#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 *********/
%{
/* At the moment, only 1 callback is supported... */
/* 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;
}
%}
......@@ -301,47 +435,39 @@ struct session_handler {
%extend session_handler {
session_handler() {
fd_log_debug("Error: a cleanup callback parameter is required.\n");
PyErr_SetString(PyExc_SyntaxError,"Error: a cleanup callback parameter is required.\n");
DI_ERROR(EINVAL, PyExc_SyntaxError, "a cleanup callback parameter is required.");
return NULL;
}
session_handler(PyObject * PyCleanupCb) {
session_handler(PyObject * PyCb) {
struct session_handler * hdl = NULL;
int ret;
if (py_cleanup_cb) {
fd_log_debug("dbg_interactive supports only 1 session handler in python at the moment\n");
PyErr_SetString(PyExc_SyntaxError,"dbg_interactive supports only 1 session handler in python at the moment\n");
return NULL;