changeset 635:134e4fb9eef5

Continued work on python interface
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 14 Dec 2010 17:34:46 +0900
parents 49ff9df2d008
children c23ca590fa57
files doc/dbg_interactive.py.sample extensions/dbg_interactive/dbg_interactive.i
diffstat 2 files changed, 340 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/doc/dbg_interactive.py.sample	Tue Dec 14 14:01:26 2010 +0900
+++ b/doc/dbg_interactive.py.sample	Tue Dec 14 17:34:46 2010 +0900
@@ -86,7 +86,7 @@
 
 ############# Dictionary ############
 
-# Create a dedicated dictionary for our tests
+##### Create a dedicated dictionary for our tests
 d = dictionary()
 d.dump()
 
@@ -123,57 +123,131 @@
 fd_dict_new(d, DICT_ENUMVAL, c, my_type_int)
 
 c.enum_name = "A_BUFFER_CONSTANT"
-osval = avp_value_os("This is a very long AVP value that we prefer to represent as a constant")
-c.enum_value.os = osval
+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)
+del c
+
+# AVP
+a = dict_avp_data()
+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)
+
+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)
+del a
+
+# Command
+c = dict_cmd_data()
+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)
+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)
+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
+
+d.dump()
 del d
 
-c = dict_enumval_data()
-c.enum_value.os = "coucou"
-c.enum_value.os.dump()
 
+####### Now play with the "real" dictionary
 
 gdict = cvar.fd_g_config.cnf_dict
-r, obj = fd_dict_search ( gdict, DICT_APPLICATION, APPLICATION_BY_ID, 3, -1 )
+
+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, obj = fd_dict_search( gdict, DICT_AVP, AVP_BY_NAME, "Origin-Host", -1)
-obj.dump()
+r, errcmd = fd_dict_get_error_cmd( gdict )
+
+data = dict_avp_data()
+fd_dict_getval(avp, data)
+print data.avp_code
+del data
+
+r, t = fd_dict_gettype(appl)
+del t
 
-t = new_dict_object_type_ptr()
-fd_dict_gettype(obj, t)
-dict_object_type_ptr_dump(t)
-delete_dict_object_type_ptr(t)
-objdata = new_dict_application_data()
-fd_dict_getval(obj, objdata)
-dict_application_data_application_name_get(objdata)
-delete_dict_application_data(objdata)
+r, dict = fd_dict_getdict(avp)
+del dict
+
+
+
+############# Sessions ############
 
-vd = new_dict_vendor_data()
-dict_vendor_data_vendor_id_set(vd, 123)
-dict_vendor_data_vendor_name_set(vd, "my test vendor")
-pobj = new_dict_object_pptr()
-fd_dict_new ( gdict, DICT_VENDOR, vd, None, pobj)
-delete_dict_vendor_data(vd)
-obj = dict_object_pptr_value(pobj)
-delete_dict_object_pptr(pobj)
-fd_dict_dump_object(obj)
+# handler
+def my_cleanup(state,sid):
+    print "Cleaning up python state for session:", sid
+    print "Received state:", state
+
+hdl = session_handler(my_cleanup)
+hdl.dump()
+del hdl
+
+hdl = session_handler(my_cleanup)
 
 
-# Sessions
-pmyhdl = new_session_handler_pptr()
-fd_sess_handler_create_internal(pmyhdl, None)
-### Have to work on this one, a cleanup handler is actually required.
-### How to define the handler in python ?
-myhdl = session_handler_pptr_value(pmyhdl)
-delete_session_handler_pptr(pmyhdl)
+# Session
+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()
+
+
+# state
+mystate = [ 34, "clah", [ 32, 12 ] ]
+
+s4.store(hdl, mystate)
+
+
 
-psess = new_session_pptr()
-fd_sess_new (psess, fd_config_cnf_diamid_get(cvar.fd_g_config), "dbg_interactive", 0)
-sess = session_pptr_value(psess)
-fd_sess_dump(0, sess)
-fd_sess_destroy(psess)
-delete_session_pptr(psess)
+## TODO : debug the following (segfault)
+
+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
+
+
+
+
+
+
+
+
+######################### old stuff (need update) ######################
 
 # Routing data
 prtd = new_rt_data_pptr()
--- a/extensions/dbg_interactive/dbg_interactive.i	Tue Dec 14 14:01:26 2010 +0900
+++ b/extensions/dbg_interactive/dbg_interactive.i	Tue Dec 14 17:34:46 2010 +0900
@@ -50,9 +50,20 @@
 %include <cstring.i>
 %include <typemaps.i>
 
-/* Some functions are not available through the wrapper */
+/* Some functions are not available through the wrapper, or accessed differently */
 %ignore fd_lib_init;
 %ignore fd_lib_fini;
+%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;
+
 
 /* Inline functions seems to give problems to SWIG -- just remove the inline definition */
 %define __inline__ 
@@ -79,9 +90,13 @@
 	%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 };
 
 /*********************************************************
  Now, create wrappers for (almost) all objects from fD API 
@@ -210,12 +225,45 @@
 }
 %}
 
+/* 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) {
+			fd_log_debug("Out of memory!\n");
+			PyErr_SetString(PyExc_MemoryError,"Not enough memory");
+			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) {
+			fd_log_debug("Out of memory!\n");
+			PyErr_SetString(PyExc_MemoryError,"Not enough memory");
+			return;
+		}
+		memcpy($self->os.data, os->data, os->len);
+		$self->os.len = os->len;
+	}
+};
 
 %extend avp_value_os {
-	~avp_value_os() {
-		if (self)
-			free(self->data);
-	}
 	void dump() {
 		if ($self) {
 			%#define LEN_MAX 20
@@ -230,30 +278,186 @@
 	}
 }
 
-%extend avp_value {
-	void os_set(char *STRING, size_t LENGTH) {
-		free($self->os.data);
-		$self->os.data = malloc(LENGTH);
-		if (!$self->os.data) {
-			fd_log_debug("Out of memory!\n");
+/****** SESSIONS *********/
+
+%{
+/* At the moment, only 1 callback is supported... */
+static PyObject * py_cleanup_cb = NULL;
+static void call_the_python_cleanup_callback(session_state * state, char * sid) {
+	PyObject *result;
+	if (!py_cleanup_cb)
+		return;
+	
+	/* Call the function */
+	result = PyEval_CallFunction(py_cleanup_cb, "(Os)", state, sid);
+	
+	Py_XDECREF(result);
+	return;
+}
+%}
+
+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");
+		return NULL;
+	}
+	session_handler(PyObject * PyCleanupCb) {
+		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;
+		}
+		if (!PyCallable_Check(PyCleanupCb)) {
+			PyErr_SetString(PyExc_TypeError, "Need a callable object!");
+			return NULL;
+		}
+		py_cleanup_cb = PyCleanupCb;
+		Py_XINCREF(py_cleanup_cb);
+		
+		ret = fd_sess_handler_create_internal ( &hdl, call_the_python_cleanup_callback );
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
 			PyErr_SetString(PyExc_MemoryError,"Not enough memory");
+			return NULL;
+		}
+		return hdl;
+	}
+	~session_handler() {
+		if (self) {
+			struct session_handler * hdl = self;
+			int ret = fd_sess_handler_destroy(&hdl);
+			if (ret != 0) {
+				fd_log_debug("Error: %s\n", strerror(ret));
+			}
 			return;
 		}
-		memcpy($self->os.data, STRING, LENGTH);
-		$self->os.len = LENGTH;
+	}
+	void dump() {
+		if ($self) {
+			fd_sess_dump_hdl(0, $self);
+		}
+	}
+}
+
+struct session {
+};
+
+%extend session {
+	/* The first two versions create a new session string. The third one allow to use an existing string. */
+	session() {
+		int ret;
+		struct session * s = NULL;
+		ret = fd_sess_new(&s, fd_g_config->cnf_diamid, "dbg_interactive", sizeof("dbg_interactive"));
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
+			PyErr_SetString(PyExc_MemoryError,"Not enough memory");
+			return NULL;
+		}
+		return s;
 	}
-	void os_set(avp_value_os * os) {
-		free($self->os.data);
-		$self->os.data = malloc(os->len);
-		if (!$self->os.data) {
-			fd_log_debug("Out of memory!\n");
+	session(char * diamid, char * STRING, size_t LENGTH) {
+		int ret;
+		struct session * s = NULL;
+		ret = fd_sess_new(&s, diamid, STRING, LENGTH);
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
+			PyErr_SetString(PyExc_MemoryError,"Not enough memory");
+			return NULL;
+		}
+		return s;
+	}
+	session(char * STRING, size_t LENGTH) {
+		int ret, n;
+		struct session * s = NULL;
+		ret = fd_sess_fromsid(STRING, LENGTH, &s, &n);
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
 			PyErr_SetString(PyExc_MemoryError,"Not enough memory");
+			return NULL;
+		}
+		/* When defining n as OUTPUT parameter, we get something strange... Use fd_sess_fromsid if you need it */
+		if (n) {
+			fd_log_debug("A new session has been created\n");
+		} else {
+			fd_log_debug("A session with same id already existed\n");
+		}
+		return s;
+	}
+	~session() {
+		if (self) {
+			struct session * s = self;
+			int ret = fd_sess_reclaim(&s);
+			if (ret != 0) {
+				fd_log_debug("Error: %s\n", strerror(ret));
+			}
 			return;
 		}
-		memcpy($self->os.data, os->data, os->len);
-		$self->os.len = os->len;
+	}
+	char * getsid() {
+		int ret;
+		char * sid = NULL;
+		if (!$self)
+			return NULL;
+		ret = fd_sess_getsid( $self, &sid);
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
+			PyErr_SetString(PyExc_MemoryError,"Problem...");
+			return NULL;
+		}
+		return sid;
+	}
+	void settimeout(long seconds) {
+		struct timespec timeout;
+		int ret;
+		clock_gettime(CLOCK_REALTIME, &timeout);
+		timeout.tv_sec += seconds;
+		ret = fd_sess_settimeout( $self, &timeout );
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
+			PyErr_SetString(PyExc_MemoryError,"Problem...");
+		}
+	}
+	void dump() {
+		if ($self) {
+			fd_sess_dump(0, $self);
+		}
 	}
-};
+	void store(struct session_handler * handler, PyObject * state) {
+		int ret;
+		void * store = state;
+		Py_INCREF(state);
+		ret = fd_sess_state_store_internal(handler, $self, (void *) &store);
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
+			PyErr_SetString(PyExc_MemoryError,"Problem...");
+		}
+	}
+	PyObject *  retrieve(struct session_handler * handler) {
+		int ret;
+		PyObject * state = NULL;
+		ret = fd_sess_state_retrieve_internal(handler, $self, (void *) &state);
+		if (ret != 0) {
+			fd_log_debug("Error: %s\n", strerror(ret));
+			PyErr_SetString(PyExc_MemoryError,"Problem...");
+		}
+		if (state == NULL) {
+			return Py_None;
+		}
+		Py_DECREF(state);
+		return state;
+	}
+}	
+
+
+
+/****** MESSAGES *********/
+
 
 %cstring_output_allocate_size(char ** swig_buffer, size_t * swig_len, free(*$1))
 %inline %{
"Welcome to our mercurial repository"