Initial commit

Change-Id: I6a4444e3c193dae437cd7929f4c39aba7b749efa
diff --git a/extensions/dbg_interactive/CMakeLists.txt b/extensions/dbg_interactive/CMakeLists.txt
new file mode 100644
index 0000000..4bb3eb0
--- /dev/null
+++ b/extensions/dbg_interactive/CMakeLists.txt
@@ -0,0 +1,77 @@
+# The dbg_interactive extension
+PROJECT("Interactive debug facility based on SWIG" C)
+
+
+# This module is using Python
+SET(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
+FIND_PACKAGE(PythonLibs)
+INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
+
+##### 
+# Wrapper to fD in python
+FIND_PACKAGE(SWIG REQUIRED)
+INCLUDE(${SWIG_USE_FILE})
+SET(CMAKE_SWIG_FLAGS -castmode -threads)
+
+# Add the dependencies for re-swig-ing the file
+SET(SWIG_MODULE_fDpy_EXTRA_DEPS 
+	${CMAKE_BINARY_DIR}/include/freeDiameter/freeDiameter-host.h 
+	${CMAKE_SOURCE_DIR}/include/freeDiameter/libfdcore.h 
+	${CMAKE_SOURCE_DIR}/include/freeDiameter/libfdproto.h 
+	lists.i
+	dictionary.i
+	sessions.i
+	routing.i
+	messages.i
+	dispatch.i
+	queues.i
+	peers.i
+	events.i
+	endpoints.i
+	posix.i
+	hooks.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
+SWIG_MODULE_INITIALIZE(fDpy python)
+SWIG_ADD_SOURCE_TO_MODULE(fDpy swig_generated_sources "dbg_interactive.i")
+	
+# In order to avoid shipping the python file that contains the shadow class definitions, 
+# we transform this file in a C-style string and compile it within our software.
+# We use for this purpose xxd tool provided with vim package.
+FIND_PROGRAM(XXD_EXECUTABLE xxd)
+# To avoid the dependency, simply compile it if not provided
+if (NOT XXD_EXECUTABLE) 
+   SET_SOURCE_FILES_PROPERTIES(helper/xxd.c PROPERTIES COMPILE_DEFINITIONS UNIX)
+   ADD_EXECUTABLE(xxd helper/xxd.c)
+   SET(XXD_EXECUTABLE xxd)
+endif (NOT XXD_EXECUTABLE) 
+# And now the magic command
+ADD_CUSTOM_COMMAND(
+    OUTPUT "fDpy-inc.c"
+    COMMAND "${XXD_EXECUTABLE}"
+    ARGS "-i"
+    "fDpy.py"
+    "fDpy-inc.c"
+    MAIN_DEPENDENCY "${swig_extra_generated_files}"
+    COMMENT "Shadow definitions") 
+
+# Ensure that the generated source files are removed
+GET_DIRECTORY_PROPERTY(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
+SET_DIRECTORY_PROPERTIES(PROPERTIES
+        ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources};fDpy-inc.c")
+
+
+#####
+# Extension that embeds the python interpreter
+FD_ADD_EXTENSION(dbg_interactive dbg_interactive.c ${swig_generated_sources} fDpy-inc.c)
+TARGET_LINK_LIBRARIES(dbg_interactive ${PYTHON_LIBRARIES})
+
+
+####
+## INSTALL section ##
+
+INSTALL(TARGETS dbg_interactive
+	LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX}
+	COMPONENT freeDiameter-debug-tools)
diff --git a/extensions/dbg_interactive/dbg_interactive.c b/extensions/dbg_interactive/dbg_interactive.c
new file mode 100644
index 0000000..d1347a2
--- /dev/null
+++ b/extensions/dbg_interactive/dbg_interactive.c
@@ -0,0 +1,140 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+#include <Python.h>
+#include <freeDiameter/extension.h>
+#include <unistd.h>
+
+/* wrapper generated by SWIG */
+#if PY_VERSION_HEX >= 0x03000000
+	extern void PyInit__fDpy(void);
+	#define WRAPPER_INIT	PyInit__fDpy()
+#else /* PY_VERSION_HEX */
+	extern void init_fDpy(void);
+	#define WRAPPER_INIT	init_fDpy()
+#endif /* PY_VERSION_HEX */
+	
+/* The string created in the shadow proxy C string file */
+extern unsigned char fDpy_py[];
+extern unsigned int fDpy_py_len;
+
+/* Run an interactive interpreter in a separate thread */
+static pthread_t pyinterp = (pthread_t)NULL;
+static void * myinterp (void * arg)
+{
+	char * dum[3] = { "<dbg_interactive>", arg, NULL };
+
+	TRACE_ENTRY("%p", arg);
+	
+	fd_log_threadname ( "fDpy" );
+	
+	CHECK_FCT_DO(fd_core_waitstartcomplete(), goto end);
+	
+	if (arg) {
+		fd_log_debug("Starting python interpreter with a script file [experimental].");
+		Py_Main(2, dum);
+	} else {
+		if (!isatty(fileno(stdin)) || !isatty(fileno(stdout))) {
+			TRACE_ERROR("[dbg_interactive]: this extension requires freeDiameter to be run from a console terminal!");
+			goto end;
+		}
+		printf("Starting interactive python interpreter [experimental].\n");
+		printf("Please use Ctrl-D to exit.\n");
+		printf("Example syntax:\n");
+		printf("   >>> print cvar.fd_g_config.cnf_diamid\n");
+		printf("   '%s'\n", fd_g_config->cnf_diamid);
+		Py_Main(1, dum);
+		printf("Python interpreter has exited...\n");
+	}
+	
+end:	
+	/* Upon exit, issue the order of terminating to fD, if the interpreter was started without a file */
+	if (!arg) {
+		(void)fd_core_shutdown();
+	}
+
+	return NULL;
+}
+
+/* Register the callbacks to the daemon */
+static int di_main(char * conffile)
+{
+	char * shadow_hlp = NULL;
+	int mustfree = 0;
+	TRACE_ENTRY("%p", conffile);
+	
+	Py_InitializeEx(0);
+	
+	WRAPPER_INIT;
+	
+	/* Small hack to avoid duplicating the string, we replace the last char by a \0.
+	  It works if the python file is terminated with several \n */
+	if (   (fDpy_py[fDpy_py_len - 2] == '\n')
+	    && (fDpy_py[fDpy_py_len - 1] == '\n')) {
+		fDpy_py[fDpy_py_len - 1] = '\0';
+		shadow_hlp = (char *)&fDpy_py[0];
+	} else {
+		CHECK_MALLOC(shadow_hlp = malloc(fDpy_py_len + 1));
+		memcpy(shadow_hlp, fDpy_py, fDpy_py_len);
+		shadow_hlp[fDpy_py_len] = '\0';
+		mustfree=1;
+	}
+	
+	PyRun_SimpleString("__file__ = \"\"\n");
+	PyRun_SimpleString(shadow_hlp);
+	
+	if (mustfree)
+		free(shadow_hlp);
+		
+	CHECK_POSIX( pthread_create(&pyinterp, NULL, myinterp, conffile) );
+ 
+	return 0;
+}
+
+/* Terminate the extension */
+void fd_ext_fini(void)
+{
+	TRACE_ENTRY();
+	void * ret;
+	
+	/* Cleanup the python interpreter */
+	Py_Finalize();
+	pthread_join(pyinterp, &ret);
+	
+	return ;
+}
+
+/* Define the entry point function */
+EXTENSION_ENTRY("dbg_interactive", di_main);
diff --git a/extensions/dbg_interactive/dbg_interactive.i b/extensions/dbg_interactive/dbg_interactive.i
new file mode 100644
index 0000000..044584f
--- /dev/null
+++ b/extensions/dbg_interactive/dbg_interactive.i
@@ -0,0 +1,209 @@
+/* This interface file is processed by SWIG to create a python wrapper interface to freeDiameter framework. */
+%module fDpy
+%begin %{
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+%}
+
+%{
+/* This text is included in the generated wrapper verbatim */
+#define SWIG
+#include <freeDiameter/extension.h>
+%}
+
+
+/* Include standard types & functions used in freeDiameter headers */
+%include <stdint.i>
+//%include <cdata.i>
+%include <cstring.i>
+%include <typemaps.i>
+
+
+/* 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;
+
+#pragma SWIG nowarn=451
+
+/*****************
+ *  Exceptions  *
+*****************/
+%{
+/* This is not thread-safe etc. but it should work /most of the time/. */
+static int wrapper_errno;
+static PyObject* wrapper_errno_py;
+static const char * wrapper_error_txt; /* if NULL, use strerror(errno) */
+#define DI_ERROR(code, pycode, str) {	\
+	fd_log_debug("[dbg_interactive] ERROR: %s: %s", __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) {
+		const 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 
+ ***********************************/
+
+%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) };
+%apply (char *STRING, size_t LENGTH) { ( uint8_t * string, size_t len ) };
+
+/* Generic typemap for functions that create something */
+%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));
+}
+
+/* Case of the fd_*_dump functions */
+%typemap(in,noblock=1,numinputs=0) (char ** buf, size_t *len, size_t *offset) ($*1_ltype temp = NULL, $*2_ltype tempn = 0) {
+	$1 = &temp; $2 = &tempn; $3 = NULL;
+}
+%typemap(freearg,match="in") (char ** buf, size_t *len, size_t *offset) "";
+%typemap(argout,noblock=1,fragment="SWIG_FromCharPtr")(char ** buf, size_t *len, size_t *offset) { 
+  if (*$1) {
+    %append_output(SWIG_FromCharPtr(*$1));
+    free(*$1);					  	     
+  }					  	     
+}							     
+
+/* Typemap to return a boolean value as output parameter */
+%typemap(in, numinputs=0,noblock=1) int * BOOL_OUT (int temp) {
+	$1 = &temp;
+}
+%typemap(argout,noblock=1) int * BOOL_OUT {
+	PyObject * r;
+	if (*$1)
+		r = Py_True;
+	else
+		r = Py_False;
+	Py_XINCREF(r);
+	%append_output(r);
+}
+
+/* To allow passing callback functions defined in python */
+%typemap(in) PyObject *PyCb {
+	if (!$input || ($input == Py_None)) {
+		$1 = NULL;
+	} else {
+		if (!PyCallable_Check($input)) {
+			PyErr_SetString(PyExc_TypeError, "Need a callable object!");
+			SWIG_fail;
+		}
+		$1 = $input;
+	}
+}
+
+%{
+/* Forward declaration for the peers module */
+static void fd_add_cb(struct peer_info *peer, void *data);
+
+/* This one gives problems when included from the header file */
+void fd_log_va( int, const char *, va_list);
+void fd_log_deprecated( int level, const char *format, ... ) MARK_DEPRECATED
+{ 
+	va_list ap;
+	va_start(ap, format);
+	fd_log_va(level, format, ap);
+	va_end(ap);
+}
+
+%}
+
+/* Overwrite declaration to apply typemaps */
+int fd_sess_fromsid ( uint8_t * string, size_t len, struct session ** OUTPUT, int * BOOL_OUT);
+
+
+
+/*********************************************************
+ Now, create wrappers for (almost) all objects from fD API 
+ *********************************************************/
+%include "freeDiameter/freeDiameter-host.h"
+%include "freeDiameter/libfdproto.h"
+%include "freeDiameter/libfdcore.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"
+
+%include "peers.i"
+%include "events.i"
+%include "endpoints.i"
+%include "hooks.i"
+
+%include "posix.i"
diff --git a/extensions/dbg_interactive/dictionary.i b/extensions/dbg_interactive/dictionary.i
new file mode 100644
index 0000000..41c9be8
--- /dev/null
+++ b/extensions/dbg_interactive/dictionary.i
@@ -0,0 +1,417 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** 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() {
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_dict_dump(&buf, &len, NULL, $self));
+		free(buf);
+	}
+	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;
+	}
+}
+
+%nodefaultctor dict_object;
+struct dict_object {
+};
+
+%extend dict_object {
+	void dump() {
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_dict_dump_object(&buf, &len, NULL, $self));
+		free(buf);
+	}
+	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 below, 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, $self->data, n == LEN_MAX ? "..." : "");
+	}
+	%cstring_output_allocate_size(char ** outbuffer, size_t * outlen, free(*$1));
+	void as_str ( char ** outbuffer, size_t * outlen ) {
+		char * b;
+		if (!$self->len) {
+			*outlen = 0;
+			*outbuffer = NULL;
+			return;
+		}
+		b = malloc($self->len);
+		if (!b) {
+			DI_ERROR_MALLOC;
+			return;
+		}
+		memcpy(b, $self->data, $self->len);
+		*outlen = $self->len;
+		*outbuffer = b;
+	}
+}
+
+
+/* Allow constructors with parameters for the dict_*_data */
+%extend dict_vendor_data {
+	dict_vendor_data(uint32_t id = 0, char * name = NULL) {
+		struct dict_vendor_data * d = (struct dict_vendor_data *)calloc(1, sizeof(struct dict_vendor_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->vendor_id = id;
+		if (name) {
+			d->vendor_name = strdup(name);
+			if (!d->vendor_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		return d;
+	}
+}
+
+%extend dict_application_data {
+	dict_application_data(uint32_t id = 0, char * name = NULL) {
+		struct dict_application_data * d = (struct dict_application_data *)calloc(1, sizeof(struct dict_application_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->application_id = id;
+		if (name) {
+			d->application_name = strdup(name);
+			if (!d->application_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		return d;
+	}
+}
+
+%extend dict_type_data {
+	dict_type_data(enum dict_avp_basetype base = 0, char * name = NULL) {
+		struct dict_type_data * d = (struct dict_type_data *)calloc(1, sizeof(struct dict_type_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->type_base = base;
+		if (name) {
+			d->type_name = strdup(name);
+			if (!d->type_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		return d;
+	}
+}
+
+%extend dict_enumval_data {
+	dict_enumval_data(char * name = NULL, uint32_t v = 0) {
+		struct dict_enumval_data * d = (struct dict_enumval_data *)calloc(1, sizeof(struct dict_enumval_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		if (name) {
+			d->enum_name = strdup(name);
+			if (!d->enum_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		d->enum_value.u32 = v;
+		return d;
+	}
+}
+
+%extend dict_avp_data {
+	dict_avp_data(uint32_t code = 0, char * name = NULL, enum dict_avp_basetype basetype = 0, uint32_t vendor = 0, int mandatory=0) {
+		struct dict_avp_data * d = (struct dict_avp_data *)calloc(1, sizeof(struct dict_avp_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		if (name) {
+			d->avp_name = strdup(name);
+			if (!d->avp_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		d->avp_code = code;
+		d->avp_basetype = basetype;
+		d->avp_vendor = vendor;
+		if (vendor) {
+			d->avp_flag_val |= AVP_FLAG_VENDOR;
+			d->avp_flag_mask |= AVP_FLAG_VENDOR;
+		}
+		d->avp_flag_mask |= AVP_FLAG_MANDATORY;
+		if (mandatory)
+			d->avp_flag_val |= AVP_FLAG_MANDATORY;
+		return d;
+	}
+}
+
+%extend dict_cmd_data {
+	dict_cmd_data(uint32_t code = 0, char * name = NULL, int request = 1) {
+		struct dict_cmd_data * d = (struct dict_cmd_data *)calloc(1, sizeof(struct dict_cmd_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		if (name) {
+			d->cmd_name = strdup(name);
+			if (!d->cmd_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		d->cmd_code = code;
+		d->cmd_flag_mask = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE;
+		d->cmd_flag_val = CMD_FLAG_PROXIABLE | ( request ? CMD_FLAG_REQUEST : 0 );
+		return d;
+	}
+}
+
+%extend dict_rule_data {
+	dict_rule_data(struct dict_object *avp = NULL, enum rule_position pos = 0, int min = -1, int max = -1 ) {
+		struct dict_rule_data * d = (struct dict_rule_data *)calloc(1, sizeof(struct dict_rule_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->rule_avp = avp;
+		d->rule_position = pos;
+		d->rule_order = 1;
+		d->rule_min = min;
+		d->rule_max = max;
+		return d;
+	}
+}
+
diff --git a/extensions/dbg_interactive/dispatch.i b/extensions/dbg_interactive/dispatch.i
new file mode 100644
index 0000000..bc39251
--- /dev/null
+++ b/extensions/dbg_interactive/dispatch.i
@@ -0,0 +1,146 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** DISPATCH *********/
+
+
+%{
+/* call it (will be called from a different thread than the interpreter, when message arrives) */
+static int call_the_python_dispatch_callback(struct msg **msg, struct avp *avp, struct session *session, void * pycb, enum disp_action *action) {
+	PyObject *PyMsg, *PyAvp, *PySess;
+	PyObject *cb, *result = NULL;
+	int ret = 0;
+	
+	if (!pycb) {
+		fd_log_debug("Internal error: missing the callback!");
+		return ENOTSUP;
+	}
+	cb = pycb;
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyMsg  = SWIG_NewPointerObj((void *)*msg,     SWIGTYPE_p_msg,     0 );
+	PyAvp  = SWIG_NewPointerObj((void *) avp,     SWIGTYPE_p_avp,     0 );
+	PySess = SWIG_NewPointerObj((void *) session, SWIGTYPE_p_session, 0 );
+	
+	/* Call the function */
+	result = PyObject_CallFunction(cb, "(OOO)", PyMsg, PyAvp, PySess);
+	
+	/* The result is supposedly composed of: [ ret, *msg, *action ] */
+	if ((result == NULL) || (!PyList_Check(result)) || (PyList_Size(result) != 3)) {
+		fd_log_debug("Error: The Python callback did not return [ ret, msg, action ].");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	/* Convert the return values */
+	if (!SWIG_IsOK(SWIG_AsVal_int(PyList_GetItem(result, 0), &ret))) {
+		fd_log_debug("Error: Cannot convert the first return value to integer.");
+		ret = EINVAL;
+		goto out;
+	}
+	if (ret) {
+		TRACE_DEBUG(INFO, "The Python callback returned the error code %d (%s)", ret, strerror(ret));
+		goto out;
+	}
+	
+	if (!SWIG_IsOK(SWIG_ConvertPtr(PyList_GetItem(result, 1), (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
+		fd_log_debug("Error: Cannot convert the second return value to message.");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	if (!SWIG_IsOK(SWIG_AsVal_int(PyList_GetItem(result, 2), (int *)action))) {
+		fd_log_debug("Error: Cannot convert the third return value to integer.");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	TRACE_DEBUG(FULL, "Python callback return: *action = %d", *action);
+out:	
+	Py_XDECREF(result);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return ret;
+}
+%}
+
+struct disp_hdl {
+};
+
+%nodefaultctor disp_hdl;
+%extend disp_hdl {
+	disp_hdl(PyObject * PyCb, enum disp_how how, struct disp_when * when) {
+		struct disp_hdl * hdl = NULL;
+		int ret;
+		
+		Py_XINCREF(PyCb);
+		
+		ret = fd_disp_register ( call_the_python_dispatch_callback, how, when, PyCb, &hdl );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return hdl;
+	}
+	~disp_hdl() {
+		struct disp_hdl * hdl = self;
+		PyObject * cb = NULL;
+		int ret = fd_disp_unregister(&hdl, (void *)&cb);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		Py_XDECREF(cb);
+		return;
+	}
+}
+
+
+%extend disp_when {
+	disp_when(struct dict_object * app = NULL, struct dict_object * command = NULL, struct dict_object * avp = NULL, struct dict_object * value = NULL) {
+      		struct disp_when * w = (struct disp_when *)calloc(1, sizeof(struct disp_when));
+		if (!w) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		w->app = app;
+		w->command = command;
+		w->avp = avp;
+		w->value = value;
+		return w;
+	}
+}
diff --git a/extensions/dbg_interactive/endpoints.i b/extensions/dbg_interactive/endpoints.i
new file mode 100644
index 0000000..329f379
--- /dev/null
+++ b/extensions/dbg_interactive/endpoints.i
@@ -0,0 +1,133 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** ENDPOINTS *********/
+
+%{
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+%}
+
+%extend fd_endpoint {
+	fd_endpoint() {
+		struct fd_endpoint *np = (struct fd_endpoint *)calloc(1, sizeof(struct fd_endpoint));
+		if (!np) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		fd_list_init(&np->chain, np);
+		return np;
+	}
+	
+	fd_endpoint(const char * endpoint, uint16_t port = 0, uint32_t flags = EP_FL_CONF) {
+		struct addrinfo hints;
+		struct addrinfo *ai = NULL;
+		int ret;
+		
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family= AF_UNSPEC;
+		hints.ai_flags = AI_NUMERICHOST;
+		
+		ret = getaddrinfo(endpoint, NULL, &hints, &ai);
+		if (ret) {
+			DI_ERROR(ret, PyExc_ValueError, gai_strerror(ret));
+			return NULL;
+		}
+		
+		if (port) {
+			switch (ai->ai_family) {
+				case AF_INET:
+					((sSA4 *)ai->ai_addr)->sin_port = htons(port);
+					break;
+				case AF_INET6:
+					((sSA6 *)ai->ai_addr)->sin6_port = htons(port);
+					break;
+				default:
+					DI_ERROR(EINVAL, PyExc_RuntimeError, "Unknown family returned by getaddrinfo");
+					return NULL;
+			}
+		}
+		
+		struct fd_endpoint *np = (struct fd_endpoint *)calloc(1, sizeof(struct fd_endpoint));
+		if (!np) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		fd_list_init(&np->chain, np);
+		
+		memcpy(&np->s.sa, ai->ai_addr, ai->ai_addrlen);
+		
+		freeaddrinfo(ai);
+		
+		np->flags = flags;
+		
+		return np;
+	}
+	
+	~fd_endpoint() {
+		fd_list_unlink(&$self->chain);
+		free($self);
+	}
+	
+	/* Merge to a list */
+	%delobject add_merge;
+	void add_merge(struct fd_list * eplist) {
+		int ret;
+		
+		if (!eplist) {
+			DI_ERROR(EINVAL, NULL, NULL);
+			return;
+		}
+		
+		ret = fd_ep_add_merge( eplist, &$self->s.sa, sSAlen(&$self->s.sa), $self->flags );
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		
+		return;
+	}
+	
+	void dump() {
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_ep_dump_one(&buf, &len, NULL, 1, $self));
+		free(buf);
+	}
+}
diff --git a/extensions/dbg_interactive/events.i b/extensions/dbg_interactive/events.i
new file mode 100644
index 0000000..a70c89e
--- /dev/null
+++ b/extensions/dbg_interactive/events.i
@@ -0,0 +1,73 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2011, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** EVENTS *********/
+
+%extend fd_event {
+	fd_event(int code, char *STRING, size_t LENGTH) {
+		struct fd_event * fd = calloc(1, sizeof(struct fd_event));
+		if (!fd) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		fd->code = code;
+		fd->data = os0dup(STRING, LENGTH);
+		if (!fd->data) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		};
+		fd->size = LENGTH;
+		return fd;
+	}
+	
+	fd_event(int code, int value) {
+		struct fd_event * fd = calloc(1, sizeof(struct fd_event));
+		if (!fd) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		fd->code = code;
+		fd->data = malloc(sizeof(int));
+		if (!fd->data) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		};
+		*((int *)fd->data) = value;
+		fd->size = sizeof(int);
+		return fd;
+	}
+}	
diff --git a/extensions/dbg_interactive/helper/xxd.c b/extensions/dbg_interactive/helper/xxd.c
new file mode 100644
index 0000000..490f571
--- /dev/null
+++ b/extensions/dbg_interactive/helper/xxd.c
@@ -0,0 +1,787 @@
+/* fD note: This source file comes from the VIM source package. All credits go to the original authors */
+
+/* xxd: my hexdump facility. jw
+ *
+ *  2.10.90 changed to word output
+ *  3.03.93 new indent style, dumb bug inserted and fixed.
+ *	    -c option, mls
+ * 26.04.94 better option parser, -ps, -l, -s added.
+ *  1.07.94 -r badly needs - as input file.  Per default autoskip over
+ *	       consecutive lines of zeroes, as unix od does.
+ *	    -a shows them too.
+ *	    -i dump as c-style #include "file.h"
+ *  1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
+ *	    array is written in correct c-syntax.
+ *	    -s improved, now defaults to absolute seek, relative requires a '+'.
+ *	    -r improved, now -r -s -0x... is supported.
+ *	       change/suppress leading '\0' bytes.
+ *	    -l n improved: stops exactly after n bytes.
+ *	    -r improved, better handling of partial lines with trailing garbage.
+ *	    -r improved, now -r -p works again!
+ *	    -r improved, less flushing, much faster now! (that was silly)
+ *  3.04.96 Per repeated request of a single person: autoskip defaults to off.
+ * 15.05.96 -v added. They want to know the version.
+ *	    -a fixed, to show last line inf file ends in all zeros.
+ *	    -u added: Print upper case hex-letters, as preferred by unix bc.
+ *	    -h added to usage message. Usage message extended.
+ *	    Now using outfile if specified even in normal mode, aehem.
+ *	    No longer mixing of ints and longs. May help doze people.
+ *	    Added binify ioctl for same reason. (Enough Doze stress for 1996!)
+ * 16.05.96 -p improved, removed occasional superfluous linefeed.
+ * 20.05.96 -l 0 fixed. tried to read anyway.
+ * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
+ *	    compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
+ *	    support --gnuish-longhorn-options
+ * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
+ *	    which is included by MacHeaders (Axel Kielhorn). Renamed to
+ *	    xxdline().
+ *  7.06.96 -i printed 'int' instead of 'char'. *blush*
+ *	    added Bram's OS2 ifdefs...
+ * 18.07.96 gcc -Wall @ SunOS4 is now slient.
+ *	    Added osver for MSDOS/DJGPP/WIN32.
+ * 29.08.96 Added size_t to strncmp() for Amiga.
+ * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
+ * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
+ *	    (azc10@yahoo.com)
+ * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
+ * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
+ *	    missing or wrong.
+ * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
+ * 27.10.98 Fixed: -g option parser required blank.
+ *	    option -b added: 01000101 binary output in normal format.
+ * 16.05.00 Added VAXC changes by Stephen P. Wall
+ * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
+ *
+ * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de)
+ *
+ * Small changes made afterwards by Bram Moolenaar et al.
+ *
+ * Distribute freely and credit me,
+ * make money and share with me,
+ * lose money and don't ask me.
+ */
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
+# define CYGWIN
+#endif
+
+#include <stdio.h>
+#ifdef VAXC
+# include <file.h>
+#else
+# include <fcntl.h>
+#endif
+#ifdef __TSC__
+# define MSDOS
+#endif
+#if !defined(OS2) && defined(__EMX__)
+# define OS2
+#endif
+#if defined(MSDOS) || defined(WIN32) || defined(OS2) || defined(__BORLANDC__) \
+  || defined(CYGWIN)
+# include <io.h>	/* for setmode() */
+#else
+# ifdef UNIX
+#  include <unistd.h>
+# endif
+#endif
+#include <stdlib.h>
+#include <string.h>	/* for strncmp() */
+#include <ctype.h>	/* for isalnum() */
+#if __MWERKS__ && !defined(BEBOX)
+# include <unix.h>	/* for fdopen() on MAC */
+#endif
+
+#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
+/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
+# define fileno(f)       ((f)->fd)
+FILE   _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
+#endif
+
+
+/*  This corrects the problem of missing prototypes for certain functions
+ *  in some GNU installations (e.g. SunOS 4.1.x).
+ *  Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
+ */
+#if defined(__GNUC__) && defined(__STDC__)
+# ifndef __USE_FIXED_PROTOTYPES__
+#  define __USE_FIXED_PROTOTYPES__
+# endif
+#endif
+
+#ifndef __USE_FIXED_PROTOTYPES__
+/*
+ * This is historic and works only if the compiler really has no prototypes:
+ *
+ * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
+ * FILE is defined on OS 4.x, not on 5.x (Solaris).
+ * if __SVR4 is defined (some Solaris versions), don't include this.
+ */
+#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
+#  define __P(a) a
+/* excerpt from my sun_stdlib.h */
+extern int fprintf __P((FILE *, char *, ...));
+extern int fputs   __P((char *, FILE *));
+extern int _flsbuf __P((unsigned char, FILE *));
+extern int _filbuf __P((FILE *));
+extern int fflush  __P((FILE *));
+extern int fclose  __P((FILE *));
+extern int fseek   __P((FILE *, long, int));
+extern int rewind  __P((FILE *));
+
+extern void perror __P((char *));
+# endif
+#endif
+
+extern long int strtol();
+extern long int ftell();
+
+char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
+#ifdef WIN32
+char osver[] = " (Win32)";
+#else
+# ifdef DJGPP
+char osver[] = " (dos 32 bit)";
+# else
+#  ifdef MSDOS
+char osver[] = " (dos 16 bit)";
+#  else
+char osver[] = "";
+#  endif
+# endif
+#endif
+
+#if defined(MSDOS) || defined(WIN32) || defined(OS2)
+# define BIN_READ(yes)  ((yes) ? "rb" : "rt")
+# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
+# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
+# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
+# define PATH_SEP '\\'
+#elif defined(CYGWIN)
+# define BIN_READ(yes)  ((yes) ? "rb" : "rt")
+# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
+# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
+# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
+# define PATH_SEP '/'
+#else
+# ifdef VMS
+#  define BIN_READ(dummy)  "r"
+#  define BIN_WRITE(dummy) "w"
+#  define BIN_CREAT(dummy) O_CREAT
+#  define BIN_ASSIGN(fp, dummy) fp
+#  define PATH_SEP ']'
+#  define FILE_SEP '.'
+# else
+#  define BIN_READ(dummy)  "r"
+#  define BIN_WRITE(dummy) "w"
+#  define BIN_CREAT(dummy) O_CREAT
+#  define BIN_ASSIGN(fp, dummy) fp
+#  define PATH_SEP '/'
+# endif
+#endif
+
+/* open has only to arguments on the Mac */
+#if __MWERKS__
+# define OPEN(name, mode, umask) open(name, mode)
+#else
+# define OPEN(name, mode, umask) open(name, mode, umask)
+#endif
+
+#ifdef AMIGA
+# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
+#else
+# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
+#endif
+
+#ifndef __P
+# if defined(__STDC__) || defined(MSDOS) || defined(WIN32) || defined(OS2) \
+		|| defined(__BORLANDC__)
+#  define __P(a) a
+# else
+#  define __P(a) ()
+# endif
+#endif
+
+/* Let's collect some prototypes */
+/* CodeWarrior is really picky about missing prototypes */
+static void exit_with_usage __P((char *));
+static int huntype __P((FILE *, FILE *, FILE *, char *, int, int, long));
+static void xxdline __P((FILE *, char *, int));
+
+#define TRY_SEEK	/* attempt to use lseek, or skip forward by reading */
+#define COLS 256	/* change here, if you ever need more columns */
+#define LLEN (11 + (9*COLS-1)/1 + COLS + 2)
+
+char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
+
+/* the different hextypes known by this program: */
+#define HEX_NORMAL 0
+#define HEX_POSTSCRIPT 1
+#define HEX_CINCLUDE 2
+#define HEX_BITS 3		/* not hex a dump, but bits: 01111001 */
+
+static void
+exit_with_usage(pname)
+char *pname;
+{
+  fprintf(stderr, "Usage:\n       %s [options] [infile [outfile]]\n", pname);
+  fprintf(stderr, "    or\n       %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
+  fprintf(stderr, "Options:\n");
+  fprintf(stderr, "    -a          toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
+  fprintf(stderr, "    -b          binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
+  fprintf(stderr, "    -c cols     format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
+  fprintf(stderr, "    -E          show characters in EBCDIC. Default ASCII.\n");
+  fprintf(stderr, "    -g          number of octets per group in normal output. Default 2.\n");
+  fprintf(stderr, "    -h          print this summary.\n");
+  fprintf(stderr, "    -i          output in C include file style.\n");
+  fprintf(stderr, "    -l len      stop after <len> octets.\n");
+  fprintf(stderr, "    -ps         output in postscript plain hexdump style.\n");
+  fprintf(stderr, "    -r          reverse operation: convert (or patch) hexdump into binary.\n");
+  fprintf(stderr, "    -r -s off   revert with <off> added to file positions found in hexdump.\n");
+  fprintf(stderr, "    -s %sseek  start at <seek> bytes abs. %sinfile offset.\n",
+#ifdef TRY_SEEK
+	  "[+][-]", "(or +: rel.) ");
+#else
+	  "", "");
+#endif
+  fprintf(stderr, "    -u          use upper case hex letters.\n");
+  fprintf(stderr, "    -v          show version: \"%s%s\".\n", version, osver);
+  exit(1);
+}
+
+/*
+ * Max. cols binary characters are decoded from the input stream per line.
+ * Two adjacent garbage characters after evaluated data delimit valid data.
+ * Everything up to the next newline is discarded.
+ *
+ * The name is historic and came from 'undo type opt h'.
+ */
+static int
+huntype(fpi, fpo, fperr, pname, cols, hextype, base_off)
+FILE *fpi, *fpo, *fperr;
+char *pname;
+int cols, hextype;
+long base_off;
+{
+  int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
+  long have_off = 0, want_off = 0;
+
+  rewind(fpi);
+
+  while ((c = getc(fpi)) != EOF)
+    {
+      if (c == '\r')	/* Doze style input file? */
+	continue;
+
+      /* Allow multiple spaces.  This doesn't work when there is normal text
+       * after the hex codes in the last line that looks like hex, thus only
+       * use it for PostScript format. */
+      if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
+	continue;
+
+      n3 = n2;
+      n2 = n1;
+
+      if (c >= '0' && c <= '9')
+	n1 = c - '0';
+      else if (c >= 'a' && c <= 'f')
+	n1 = c - 'a' + 10;
+      else if (c >= 'A' && c <= 'F')
+	n1 = c - 'A' + 10;
+      else
+	{
+	  n1 = -1;
+	  if (ign_garb)
+	    continue;
+	}
+
+      ign_garb = 0;
+
+      if (p >= cols)
+	{
+	  if (!hextype)
+	    {
+	      if (n1 < 0)
+		{
+		  p = 0;
+		  continue;
+		}
+	      want_off = (want_off << 4) | n1;
+	      continue;
+	    }
+	  else
+	    p = 0;
+	}
+
+      if (base_off + want_off != have_off)
+	{
+	  fflush(fpo);
+#ifdef TRY_SEEK
+	  c = fseek(fpo, base_off + want_off - have_off, 1);
+	  if (c >= 0)
+	    have_off = base_off + want_off;
+#endif
+	  if (base_off + want_off < have_off)
+	    {
+	      fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
+	      return 5;
+	    }
+	  for (; have_off < base_off + want_off; have_off++)
+	    putc(0, fpo);
+	}
+
+      if (n2 >= 0 && n1 >= 0)
+	{
+	  putc((n2 << 4) | n1, fpo);
+	  have_off++;
+	  want_off++;
+	  n1 = -1;
+	  if ((++p >= cols) && !hextype)
+	    {
+	      /* skip rest of line as garbage */
+	      want_off = 0;
+	      while ((c = getc(fpi)) != '\n' && c != EOF)
+		;
+	      ign_garb = 1;
+	    }
+	}
+      else if (n1 < 0 && n2 < 0 && n3 < 0)
+	{
+	  /* already stumbled into garbage, skip line, wait and see */
+	  if (!hextype)
+	    want_off = 0;
+	  while ((c = getc(fpi)) != '\n' && c != EOF)
+	    ;
+	  ign_garb = 1;
+	}
+    }
+  fflush(fpo);
+#ifdef TRY_SEEK
+  fseek(fpo, 0L, 2);
+#endif
+  fclose(fpo);
+  fclose(fpi);
+  return 0;
+}
+
+/*
+ * Print line l. If nz is false, xxdline regards the line a line of
+ * zeroes. If there are three or more consecutive lines of zeroes,
+ * they are replaced by a single '*' character.
+ *
+ * If the output ends with more than two lines of zeroes, you
+ * should call xxdline again with l being the last line and nz
+ * negative. This ensures that the last line is shown even when
+ * it is all zeroes.
+ *
+ * If nz is always positive, lines are never suppressed.
+ */
+static void
+xxdline(fp, l, nz)
+FILE *fp;
+char *l;
+int nz;
+{
+  static char z[LLEN+1];
+  static int zero_seen = 0;
+
+  if (!nz && zero_seen == 1)
+    strcpy(z, l);
+
+  if (nz || !zero_seen++)
+    {
+      if (nz)
+	{
+	  if (nz < 0)
+	    zero_seen--;
+	  if (zero_seen == 2)
+	    fputs(z, fp);
+	  if (zero_seen > 2)
+	    fputs("*\n", fp);
+	}
+      if (nz >= 0 || zero_seen > 0)
+	fputs(l, fp);
+      if (nz)
+	zero_seen = 0;
+    }
+}
+
+/* This is an EBCDIC to ASCII conversion table */
+/* from a proposed BTL standard April 16, 1979 */
+static unsigned char etoa64[] =
+{
+    0040,0240,0241,0242,0243,0244,0245,0246,
+    0247,0250,0325,0056,0074,0050,0053,0174,
+    0046,0251,0252,0253,0254,0255,0256,0257,
+    0260,0261,0041,0044,0052,0051,0073,0176,
+    0055,0057,0262,0263,0264,0265,0266,0267,
+    0270,0271,0313,0054,0045,0137,0076,0077,
+    0272,0273,0274,0275,0276,0277,0300,0301,
+    0302,0140,0072,0043,0100,0047,0075,0042,
+    0303,0141,0142,0143,0144,0145,0146,0147,
+    0150,0151,0304,0305,0306,0307,0310,0311,
+    0312,0152,0153,0154,0155,0156,0157,0160,
+    0161,0162,0136,0314,0315,0316,0317,0320,
+    0321,0345,0163,0164,0165,0166,0167,0170,
+    0171,0172,0322,0323,0324,0133,0326,0327,
+    0330,0331,0332,0333,0334,0335,0336,0337,
+    0340,0341,0342,0343,0344,0135,0346,0347,
+    0173,0101,0102,0103,0104,0105,0106,0107,
+    0110,0111,0350,0351,0352,0353,0354,0355,
+    0175,0112,0113,0114,0115,0116,0117,0120,
+    0121,0122,0356,0357,0360,0361,0362,0363,
+    0134,0237,0123,0124,0125,0126,0127,0130,
+    0131,0132,0364,0365,0366,0367,0370,0371,
+    0060,0061,0062,0063,0064,0065,0066,0067,
+    0070,0071,0372,0373,0374,0375,0376,0377
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+  FILE *fp, *fpo;
+  int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
+  int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
+  int ebcdic = 0;
+  int octspergrp = -1;	/* number of octets grouped in output */
+  int grplen;		/* total chars per octet group */
+  long length = -1, n = 0, seekoff = 0;
+  char l[LLEN+1];
+  char *pname, *pp;
+
+#ifdef AMIGA
+  /* This program doesn't work when started from the Workbench */
+  if (argc == 0)
+    exit(1);
+#endif
+
+  pname = argv[0];
+  for (pp = pname; *pp; )
+    if (*pp++ == PATH_SEP)
+      pname = pp;
+#ifdef FILE_SEP
+  for (pp = pname; *pp; pp++)
+    if (*pp == FILE_SEP)
+      {
+	*pp = '\0';
+	break;
+      }
+#endif
+
+  while (argc >= 2)
+    {
+      pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
+	   if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
+      else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
+      else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
+      else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
+      else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
+      else if (!STRNCMP(pp, "-r", 2)) revert++;
+      else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
+      else if (!STRNCMP(pp, "-v", 2))
+	{
+	  fprintf(stderr, "%s%s\n", version, osver);
+	  exit(0);
+	}
+      else if (!STRNCMP(pp, "-c", 2))
+	{
+	  if (pp[2] && STRNCMP("ols", pp + 2, 3))
+	    cols = (int)strtol(pp + 2, NULL, 0);
+	  else
+	    {
+	      if (!argv[2])
+		exit_with_usage(pname);
+	      cols = (int)strtol(argv[2], NULL, 0);
+	      argv++;
+	      argc--;
+	    }
+	}
+      else if (!STRNCMP(pp, "-g", 2))
+	{
+	  if (pp[2] && STRNCMP("group", pp + 2, 5))
+	    octspergrp = (int)strtol(pp + 2, NULL, 0);
+	  else
+	    {
+	      if (!argv[2])
+		exit_with_usage(pname);
+	      octspergrp = (int)strtol(argv[2], NULL, 0);
+	      argv++;
+	      argc--;
+	    }
+	}
+      else if (!STRNCMP(pp, "-s", 2))
+	{
+	  relseek = 0;
+	  negseek = 0;
+	  if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
+	    {
+#ifdef TRY_SEEK
+	      if (pp[2] == '+')
+		relseek++;
+	      if (pp[2+relseek] == '-')
+		negseek++;
+#endif
+	      seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
+	    }
+	  else
+	    {
+	      if (!argv[2])
+		exit_with_usage(pname);
+#ifdef TRY_SEEK
+	      if (argv[2][0] == '+')
+		relseek++;
+	      if (argv[2][relseek] == '-')
+		negseek++;
+#endif
+	      seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
+	      argv++;
+	      argc--;
+	    }
+	}
+      else if (!STRNCMP(pp, "-l", 2))
+	{
+	  if (pp[2] && STRNCMP("en", pp + 2, 2))
+	    length = strtol(pp + 2, (char **)NULL, 0);
+	  else
+	    {
+	      if (!argv[2])
+		exit_with_usage(pname);
+	      length = strtol(argv[2], (char **)NULL, 0);
+	      argv++;
+	      argc--;
+	    }
+	}
+      else if (!strcmp(pp, "--"))	/* end of options */
+	{
+	  argv++;
+	  argc--;
+	  break;
+	}
+      else if (pp[0] == '-' && pp[1])	/* unknown option */
+	exit_with_usage(pname);
+      else
+	break;				/* not an option */
+
+      argv++;				/* advance to next argument */
+      argc--;
+    }
+
+  if (!cols)
+    switch (hextype)
+      {
+      case HEX_POSTSCRIPT:	cols = 30; break;
+      case HEX_CINCLUDE:	cols = 12; break;
+      case HEX_BITS:		cols = 6; break;
+      case HEX_NORMAL:
+      default:			cols = 16; break;
+      }
+
+  if (octspergrp < 0)
+    switch (hextype)
+      {
+      case HEX_BITS:		octspergrp = 1; break;
+      case HEX_NORMAL:		octspergrp = 2; break;
+      case HEX_POSTSCRIPT:
+      case HEX_CINCLUDE:
+      default:			octspergrp = 0; break;
+      }
+
+  if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS)
+							    && (cols > COLS)))
+    {
+      fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
+      exit(1);
+    }
+
+  if (octspergrp < 1)
+    octspergrp = cols;
+
+  if (argc > 3)
+    exit_with_usage(pname);
+
+  if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
+    BIN_ASSIGN(fp = stdin, !revert);
+  else
+    {
+      if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
+	{
+	  fprintf(stderr,"%s: ", pname);
+	  perror(argv[1]);
+	  return 2;
+	}
+    }
+
+  if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
+    BIN_ASSIGN(fpo = stdout, revert);
+  else
+    {
+      int fd;
+      int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
+
+      if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
+	  (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
+	{
+	  fprintf(stderr, "%s: ", pname);
+	  perror(argv[2]);
+	  return 3;
+	}
+      rewind(fpo);
+    }
+
+  if (revert)
+    {
+      if (hextype && (hextype != HEX_POSTSCRIPT))
+	{
+	  fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
+	  return -1;
+	}
+      return huntype(fp, fpo, stderr, pname, cols, hextype,
+		negseek ? -seekoff : seekoff);
+    }
+
+  if (seekoff || negseek || !relseek)
+    {
+#ifdef TRY_SEEK
+      if (relseek)
+	e = fseek(fp, negseek ? -seekoff : seekoff, 1);
+      else
+	e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
+      if (e < 0 && negseek)
+	{
+	  fprintf(stderr, "%s: sorry cannot seek.\n", pname);
+	  return 4;
+	}
+      if (e >= 0)
+	seekoff = ftell(fp);
+      else
+#endif
+	{
+	  long s = seekoff;
+
+	  while (s--)
+	    (void)getc(fp);
+	}
+    }
+
+  if (hextype == HEX_CINCLUDE)
+    {
+      if (fp != stdin)
+	{
+	  fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "");
+	  for (e = 0; (c = argv[1][e]) != 0; e++)
+	    putc(isalnum(c) ? c : '_', fpo);
+	  fputs("[] = {\n", fpo);
+	}
+
+      p = 0;
+      while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
+	{
+	  fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
+	    (p % cols) ? ", " : ",\n  "+2*!p,  c);
+	  p++;
+	}
+
+      if (p)
+	fputs("\n};\n"+3*(fp == stdin), fpo);
+
+      if (fp != stdin)
+	{
+	  fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "");
+	  for (e = 0; (c = argv[1][e]) != 0; e++)
+	    putc(isalnum(c) ? c : '_', fpo);
+	  fprintf(fpo, "_len = %d;\n", p);
+	}
+
+      fclose(fp);
+      fclose(fpo);
+      return 0;
+    }
+
+  if (hextype == HEX_POSTSCRIPT)
+    {
+      p = cols;
+      while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
+	{
+	  putchar(hexx[(e >> 4) & 0xf]);
+	  putchar(hexx[(e     ) & 0xf]);
+	  n++;
+	  if (!--p)
+	    {
+	      putchar('\n');
+	      p = cols;
+	    }
+	}
+      if (p < cols)
+	putchar('\n');
+      fclose(fp);
+      fclose(fpo);
+      return 0;
+    }
+
+  /* hextype: HEX_NORMAL or HEX_BITS */
+
+  if (hextype == HEX_NORMAL)
+    grplen = octspergrp + octspergrp + 1;	/* chars per octet group */
+  else	/* hextype == HEX_BITS */
+    grplen = 8 * octspergrp + 1;
+
+  while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
+    {
+      if (p == 0)
+	{
+	  sprintf(l, "%07lx: ", n + seekoff);
+	  for (c = 9; c < LLEN; l[c++] = ' ');
+	}
+      if (hextype == HEX_NORMAL)
+	{
+	  l[c = (9 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
+	  l[++c]			       = hexx[ e       & 0xf];
+	}
+      else /* hextype == HEX_BITS */
+	{
+	  int i;
+
+	  c = (9 + (grplen * p) / octspergrp) - 1;
+	  for (i = 7; i >= 0; i--)
+	    l[++c] = (e & (1 << i)) ? '1' : '0';
+	}
+      if (ebcdic)
+	e = (e < 64) ? '.' : etoa64[e-64];
+      /* When changing this update definition of LLEN above. */
+      l[11 + (grplen * cols - 1)/octspergrp + p] =
+#ifdef __MVS__
+	  (e >= 64)
+#else
+	  (e > 31 && e < 127)
+#endif
+	  ? e : '.';
+      if (e)
+	nonzero++;
+      n++;
+      if (++p == cols)
+	{
+	  l[c = (11 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
+	  xxdline(fpo, l, autoskip ? nonzero : 1);
+	  nonzero = 0;
+	  p = 0;
+	}
+    }
+  if (p)
+    {
+      l[c = (11 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
+      xxdline(fpo, l, 1);
+    }
+  else if (autoskip)
+    xxdline(fpo, l, -1);	/* last chance to flush out suppressed lines */
+
+  fclose(fp);
+  fclose(fpo);
+  return 0;
+}
diff --git a/extensions/dbg_interactive/hooks.i b/extensions/dbg_interactive/hooks.i
new file mode 100644
index 0000000..98cbc58
--- /dev/null
+++ b/extensions/dbg_interactive/hooks.i
@@ -0,0 +1,190 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** HOOKS *********/
+
+
+/* Functions to handle the PMD */
+%{
+
+struct fd_hook_permsgdata {
+	PyObject *PyPML;
+};
+
+static void init_permsgdata (struct fd_hook_permsgdata * pmd) {
+	/* The PMD is None by default */
+	Py_INCREF(Py_None);
+	pmd->PyPML = Py_None;
+}
+
+static void fini_permsgdata (struct fd_hook_permsgdata * pmd) {
+	Py_DECREF(pmd->PyPML);
+}
+
+%}
+
+struct fd_hook_data_hdl {
+};
+
+%nodefaultctor fd_hook_data_hdl;
+%extend fd_hook_data_hdl {
+	fd_hook_data_hdl() {
+		struct fd_hook_data_hdl * hdl = NULL;
+		int ret;
+		
+		ret = fd_hook_data_register ( sizeof(struct fd_hook_permsgdata), init_permsgdata, fini_permsgdata, &hdl );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return hdl;
+	}
+}
+
+
+/* Now the hook itself */
+%{
+static void call_the_python_hook_callback(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata) {
+	PyObject *cb, *result = NULL;
+	PyObject *PyType, *PyMsg, *PyPeer, *PyOther, *PyOldPmd;
+	
+	if (!regdata) {
+		LOG_E("Internal error: missing the callback!");
+		return;
+	}
+	cb = regdata;
+
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyType = PyLong_FromLong(type);
+	Py_INCREF(PyType);
+	
+	PyMsg  = SWIG_NewPointerObj((void *) msg,     SWIGTYPE_p_msg,     0 );
+	
+	PyPeer = SWIG_NewPointerObj((void *) peer,    SWIGTYPE_p_peer_hdr,     0 );
+	if (other == NULL) {
+		PyOther=Py_None;
+		Py_INCREF(Py_None);
+	} else {
+		switch (type) {
+		case HOOK_DATA_RECEIVED:
+			PyOther= SWIG_NewPointerObj( other, SWIGTYPE_p_fd_cnx_rcvdata, 0 );
+			break;
+			
+		case HOOK_MESSAGE_RECEIVED:
+		case HOOK_MESSAGE_ROUTING_ERROR:
+		case HOOK_MESSAGE_DROPPED:
+		case HOOK_PEER_CONNECT_FAILED:
+			PyOther= SWIG_NewPointerObj( other, SWIGTYPE_p_char, 0 );
+			break;
+			
+		case HOOK_MESSAGE_PARSING_ERROR:
+			if (msg) {
+				PyOther= SWIG_NewPointerObj( other, SWIGTYPE_p_char, 0 );
+			} else {
+				PyOther= SWIG_NewPointerObj( other, SWIGTYPE_p_fd_cnx_rcvdata, 0 );
+			}
+			break;
+		default:
+			/* In other cases, other should be NULL */
+			LOG_E("Internal error: got a value of *other");
+		}
+		
+	}
+	
+	if (pmd == NULL) {
+		Py_INCREF(Py_None);
+		PyOldPmd=Py_None;
+	} else {
+		PyOldPmd=pmd->PyPML;
+	}
+	
+	/* Call the function */
+	result = PyObject_CallFunction(cb, "(OOOOO)", PyType, PyMsg, PyPeer, PyOther, PyOldPmd);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	if (pmd == NULL)
+		return;
+	
+	Py_DECREF(pmd->PyPML);
+	Py_INCREF(result);
+	pmd->PyPML = result;
+}
+%}
+
+
+
+struct fd_hook_hdl {
+};
+
+%nodefaultctor fd_hook_hdl;
+%extend fd_hook_hdl {
+	fd_hook_hdl(uint32_t type_mask, PyObject * PyCb) {
+		struct fd_hook_hdl *hdl;
+		int ret;
+		
+		Py_XINCREF(PyCb);
+		
+		ret = fd_hook_register ( type_mask, call_the_python_hook_callback, PyCb, NULL, &hdl );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return hdl;
+	}
+	fd_hook_hdl(uint32_t type_mask, PyObject * PyCb, struct fd_hook_data_hdl *datahdl) {
+		struct fd_hook_hdl *hdl;
+		int ret;
+		
+		Py_XINCREF(PyCb);
+		
+		ret = fd_hook_register ( type_mask, call_the_python_hook_callback, PyCb, datahdl, &hdl );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return hdl;
+	}
+	~fd_hook_hdl() {
+		struct fd_hook_hdl * hdl = self;
+		int ret = fd_hook_unregister(hdl);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return;
+	}
+}
diff --git a/extensions/dbg_interactive/lists.i b/extensions/dbg_interactive/lists.i
new file mode 100644
index 0000000..6ac26f2
--- /dev/null
+++ b/extensions/dbg_interactive/lists.i
@@ -0,0 +1,132 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** 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", $self);
+		fd_log_debug("  - next: %p", $self->next);
+		fd_log_debug("  - prev: %p", $self->prev);
+		fd_log_debug("  - head: %p", $self->head);
+		fd_log_debug("  - o   : %p", $self->o);
+	}
+	/* Insert before/after wrapper */
+	void insert_prev(struct fd_list * li) {
+		fd_list_insert_before($self, li);
+	}
+	void insert_next(struct fd_list * li) {
+		fd_list_insert_after($self, li);
+	}
+	/* Test for emptyness */
+	PyObject * isempty() {
+		PyObject * ret;
+		if (FD_IS_LIST_EMPTY($self))
+			ret = Py_True;
+		else
+			ret = Py_False;
+		Py_XINCREF(ret);
+		return ret;
+	}
+	/* Concatenate two lists */
+	void concat(struct fd_list * li) {
+		fd_list_move_end($self, li);
+	}
+	/* Unlink without freeing */
+	void detach() {
+		fd_list_unlink($self);
+	}
+	
+	/* Return the list as python list of elements */
+	PyObject * enum_as(char * type = NULL, int dont_use_o = 0) {
+		struct fd_list *li;
+		swig_type_info * desttype = NULL;
+		PyObject * rl;
+		
+		if ($self->head != $self) {
+			DI_ERROR(EINVAL, NULL, "This method can only be called on the list sentinel.");
+			return NULL;
+		}
+		
+		if (type) {
+			desttype = SWIG_TypeQuery(type);
+			if (!desttype) {
+				DI_ERROR(EINVAL, NULL, "Unable to resolve this type. Please check the form: 'struct blahbla *'");
+				return NULL;
+			}
+		}
+		if (desttype == NULL) {
+			/* fallback to fd_list */
+			desttype = SWIGTYPE_p_fd_list;
+			/* in this case, don't follow the 'o' link */
+			dont_use_o = 1;
+		}
+		
+		rl = PyList_New(0);
+		SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+		for (li = $self->next; li != $self; li = li->next) {
+			void * obj = NULL;
+			if (dont_use_o || li->o == NULL)
+				obj = li;
+			else
+				obj = li->o;
+			PyList_Append(rl, SWIG_NewPointerObj(obj, desttype, 0 ));
+		}
+		Py_XINCREF(rl);
+		SWIG_PYTHON_THREAD_END_BLOCK;
+		
+		return rl;
+	}
+};
+
diff --git a/extensions/dbg_interactive/messages.i b/extensions/dbg_interactive/messages.i
new file mode 100644
index 0000000..3d13e5d
--- /dev/null
+++ b/extensions/dbg_interactive/messages.i
@@ -0,0 +1,615 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** MESSAGES *********/
+
+%{
+struct anscb_py_layer {
+	PyObject * cb;
+	PyObject * expcb;
+	PyObject * data;
+};
+
+/* If a python callback was provided, it is received in cbdata */
+static void anscb_python(void *cbdata, struct msg ** msg) {
+	/* The python callback is received in cbdata */
+	PyObject * result, *PyMsg;
+	struct anscb_py_layer * l = cbdata;
+	
+	if (!l) {
+		fd_log_debug("Internal error! Python callback disappeared...");
+		return;
+	}
+	
+	if (l->cb) {
+	
+		SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+
+		if (!msg || !*msg) {
+			PyMsg = Py_None;
+		} else {
+			PyMsg = SWIG_NewPointerObj((void *)*msg,     SWIGTYPE_p_msg,     0 );
+		}
+
+		result = PyObject_CallFunction(l->cb, "(OO)", PyMsg, l->data);
+		Py_XDECREF(l->cb);
+		Py_XDECREF(l->expcb);
+		Py_XDECREF(l->data);
+		free(l);
+
+		/* The callback is supposed to return a message or NULL */
+		if (!SWIG_IsOK(SWIG_ConvertPtr(result, (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
+			fd_log_debug("Error: Cannot convert the return value to message.");
+			*msg = NULL;
+		}
+
+		Py_XDECREF(result);
+
+		SWIG_PYTHON_THREAD_END_BLOCK;
+		
+	}
+	/* else */
+		/* Only the timeout was specified, without a callback */
+		/* in this case, just delete the message */
+		/* it actually happens automatically when we do nothing. */
+}
+
+static void expcb_python(void *cbdata, DiamId_t sentto, size_t senttolen, struct msg ** msg) {
+	/* The python callback is received in cbdata */
+	PyObject * result, *PyMsg;
+	struct anscb_py_layer * l = cbdata;
+	
+	if (!l) {
+		fd_log_debug("Internal error! Python callback disappeared...");
+		return;
+	}
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+
+	if (!msg || !*msg) {
+		PyMsg = Py_None;
+	} else {
+		PyMsg = SWIG_NewPointerObj((void *)*msg,     SWIGTYPE_p_msg,     0 );
+	}
+
+	result = PyObject_CallFunction(l->expcb, "(Os#O)", PyMsg, sentto, senttolen, l->data);
+	Py_XDECREF(l->cb);
+	Py_XDECREF(l->expcb);
+	Py_XDECREF(l->data);
+	free(l);
+
+	/* The callback is supposed to return a message or NULL */
+	if (!SWIG_IsOK(SWIG_ConvertPtr(result, (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
+		fd_log_debug("Error: Cannot convert the return value to message.");
+		*msg = NULL;
+	}
+
+	Py_XDECREF(result);
+
+	SWIG_PYTHON_THREAD_END_BLOCK;
+		
+}
+
+
+
+%}
+
+struct msg {
+};
+
+%extend msg {
+	msg(struct dict_object * model=NULL, int flags = MSGFL_ALLOC_ETEID) {
+		struct msg * m = NULL;
+		int ret = fd_msg_new( model, flags, &m);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return m;
+	}
+	/* construct also from a binary buffer */
+	msg(char * STRING, size_t LENGTH) {
+		int ret;
+		struct msg * m = NULL;
+		/* First, copy the string */
+		unsigned char * buf = malloc(LENGTH);
+		if (buf == NULL) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		memcpy(buf, STRING, LENGTH);
+		ret = fd_msg_parse_buffer(&buf, LENGTH, &m);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			free(buf);
+			return NULL;
+		}
+		return m;
+	}
+	~msg() {
+		int ret = fd_msg_free($self);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* SEND THE MESSAGE */
+	%delobject send; /* when this has been called, the msg must not be freed anymore */
+	void send(PyObject * PyCb = NULL, PyObject * data = NULL, PyObject * PyExpCb = NULL, unsigned int timeout = 0) {
+		int ret;
+		struct msg * m = $self;
+		struct anscb_py_layer * l = NULL;
+		
+		if (PyCb || timeout) {
+			l = malloc(sizeof(struct anscb_py_layer));
+			if (!l) {
+				DI_ERROR_MALLOC;
+				return;
+			}
+
+			Py_XINCREF(PyCb);
+			Py_XINCREF(data);
+			Py_XINCREF(PyExpCb);
+			l->expcb = PyExpCb;
+			l->cb = PyCb;
+			l->data = data;
+		}
+		
+		if (timeout) {
+			struct timespec ts;
+			(void) clock_gettime(CLOCK_REALTIME, &ts);
+			ts.tv_sec += timeout;
+			ret = fd_msg_send_timeout(&m, anscb_python, l, expcb_python, &ts);
+		} else {
+			ret = fd_msg_send(&m, PyCb ? anscb_python : NULL, l);
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Create an answer */
+	%delobject create_answer; /* when this has been called, the original msg should not be freed anymore */
+	struct msg * create_answer(struct dictionary * dict = NULL, int flags = 0) {
+		/* if dict is not provided, attempt to get it from the request model */
+		struct dictionary * d = dict;
+		struct msg * m = $self;
+		int ret;
+		if (!d) {
+			struct dict_object * mo = NULL;
+			ret = fd_msg_model($self, &mo);
+			if (ret != 0) {
+				DI_ERROR(ret, NULL, "Error retrieving query model.");
+				return NULL;
+			}
+			if (mo == NULL) {
+				/* use the fD dictionary by default */
+				d = fd_g_config->cnf_dict;
+			} else {
+				ret = fd_dict_getdict ( mo, &d );
+				if (ret != 0) {
+					DI_ERROR(ret, NULL, "Error retrieving query's dictionary.");
+					return NULL;
+				}
+			}
+		}
+		ret = fd_msg_new_answer_from_req(d, &m, flags);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, "Cannot guess the dictionary to use, please provide it as parameter.");
+			return NULL;
+		}
+		
+		return m;
+	}
+	/* Return the first child AVP if any */
+	struct avp * first_child() {
+		struct avp * a = NULL;
+		int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return a;
+	}
+	
+	/* Enumerable list of children AVP */
+	%newobject children;
+	PyObject * children() {
+		struct avp * a = NULL;
+		PyObject * rl;
+		int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+		rl = PyList_New(0);
+		while (a) {
+			PyList_Append(rl, SWIG_NewPointerObj((void *)a, SWIGTYPE_p_avp, 0 /* do not own the AVPs */ ));
+			ret = fd_msg_browse(a, MSG_BRW_NEXT, &a, NULL);
+			if (ret != 0) {
+				DI_ERROR(ret, NULL, NULL);
+				return NULL;
+			}
+		}
+		Py_XINCREF(rl);
+		SWIG_PYTHON_THREAD_END_BLOCK;
+		return rl;
+	}
+	
+	/* Add a new AVP */
+	void add_child(struct avp *DISOWN, int begin = 0) {
+		int ret = fd_msg_avp_add ( $self, begin ? MSG_BRW_FIRST_CHILD : MSG_BRW_LAST_CHILD, DISOWN);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Search an AVP */
+	struct avp * search(struct dict_object * what) {
+		struct avp * a = NULL;
+		int ret = fd_msg_search_avp($self, what, &a);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return a;
+	}
+	
+	/* Dump */
+	void dump (int tree = 1) {
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_msg_dump_treeview(&buf, &len, NULL, $self, NULL, 0, tree));
+		free(buf);
+	}
+	
+	/* Model */
+	struct dict_object * model() {
+		struct dict_object * m = NULL;
+		int ret = fd_msg_model($self, &m);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return m;
+	}
+	
+	/* Header */
+	struct msg_hdr * header() {
+		struct msg_hdr * h = NULL;
+		int ret = fd_msg_hdr($self, &h);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return h;
+	}
+	
+	/* Get query if message is an answer */
+	struct msg * get_query() {
+		struct msg * q = NULL;
+		int ret = fd_msg_answ_getq($self, &q);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return q;
+	}
+	
+	/* Get / Set routing data */
+	struct rt_data * get_rtd() {
+		struct rt_data * r = NULL;
+		int ret = fd_msg_rt_get($self, &r);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return r;
+	}
+	void set_rtd(struct rt_data *DISOWN) {
+		struct rt_data * r = DISOWN;
+		int ret = fd_msg_rt_associate($self, r);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return;
+	}
+	
+	/* Is routable? */
+	PyObject * is_routable() {
+		PyObject * r;
+		if (fd_msg_is_routable($self))
+			r = Py_True;
+		else
+			r = Py_False;
+		Py_XINCREF(r);
+		return r;
+	}
+	
+	/* Is request? (shortcut) */
+	PyObject * is_request() {
+		PyObject * r;
+		int ret;
+		struct msg_hdr * h;
+		
+		ret = fd_msg_hdr($self, &h);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		if (h->msg_flags & CMD_FLAG_REQUEST) 
+			r = Py_True;
+		else
+			r = Py_False;
+		Py_XINCREF(r);
+		return r;
+	}
+	
+	/* Get the source */
+	%cstring_output_allocate_size(char ** outid, size_t * outlen, /* do not free */);
+	void source(char ** outid, size_t * outlen) {
+		int ret = fd_msg_source_get($self, outid, outlen);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		return;
+	}
+	
+	/* Get the session */
+	%newobject get_session; /* it may be created or not, it is harmless because we only reclaim in ~session */
+	struct session *get_session(struct dictionary * dict = NULL) {
+		struct session *s = NULL;
+		struct dictionary * d = dict;
+		int ret = 0;
+		if (d == NULL)
+			d = fd_g_config->cnf_dict; /* default: use daemon's */
+		ret = fd_msg_sess_get(d, $self, &s, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return s;
+	}
+	
+	/* Bufferize */
+	%cstring_output_allocate_size(char ** outbuffer, size_t * outlen, free(*$1));
+	void bufferize ( char ** outbuffer, size_t * outlen ) {
+		int ret = fd_msg_bufferize ( $self, (void *)outbuffer, outlen );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Dictionary parsing */
+	%newobject parse_dict;
+	struct fd_pei * parse_dict(struct dictionary * dict=NULL) {
+		int ret;
+		struct fd_pei pei, *e = NULL;
+		struct dictionary * d = dict;
+		memset(&pei, 0, sizeof(struct fd_pei));
+		if (d == NULL)
+			d = fd_g_config->cnf_dict; /* default: use daemon's */
+		
+		ret = fd_msg_parse_dict ( $self, d, &pei );
+		if (ret != 0) {
+			e = malloc(sizeof(struct fd_pei));
+			if (!e) {
+				DI_ERROR_MALLOC;
+				return NULL;
+			}
+			memcpy(e, &pei, sizeof(struct fd_pei));
+		}
+		return e; /* returns NULL when everything went OK */
+	}
+	
+	/* Rules parsing */
+	%newobject parse_rules;
+	struct fd_pei * parse_rules(struct dictionary * dict=NULL) {
+		int ret;
+		struct fd_pei pei, *e = NULL;
+		struct dictionary * d = dict;
+		memset(&pei, 0, sizeof(struct fd_pei));
+		if (d == NULL)
+			d = fd_g_config->cnf_dict; /* default: use daemon's */
+		
+		ret = fd_msg_parse_rules ( $self, d, &pei );
+		if (ret != 0) {
+			e = malloc(sizeof(struct fd_pei));
+			if (!e) {
+				DI_ERROR_MALLOC;
+				return NULL;
+			}
+			memcpy(e, &pei, sizeof(struct fd_pei));
+		}
+		return e; /* returns NULL when everything went OK */
+	}
+	
+	/* Update the length info in header */
+	void update_length() {
+		int ret = fd_msg_update_length ( $self );
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Set the result code */
+	void rescode_set(char * rescode = "DIAMETER_SUCCESS", char * errormsg = NULL, struct avp * optavp = NULL, int type_id = 0) {
+		int ret = fd_msg_rescode_set( $self, rescode, errormsg, optavp, type_id );
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Add the origin */
+	void add_origin(int osi = 0) {
+		int ret = fd_msg_add_origin( $self, osi );
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+}
+
+struct avp {
+};
+
+%extend avp {
+	avp(struct dict_object * model = NULL, int flags = 0) {
+		struct avp * a = NULL;
+		int ret = fd_msg_avp_new( model, flags, &a);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return a;
+	}
+	~avp() {
+		int ret = fd_msg_free($self);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Return the first child AVP if any */
+	struct avp * first_child() {
+		struct avp * a = NULL;
+		int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return a;
+	}
+	
+	/* Enumerable list of children AVP */
+	%newobject children;
+	PyObject * children() {
+		struct avp * a = NULL;
+		PyObject * rl;
+		int ret = fd_msg_browse($self, MSG_BRW_FIRST_CHILD, &a, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+		rl = PyList_New(0);
+		while (a) {
+			PyList_Append(rl, SWIG_NewPointerObj((void *)a, SWIGTYPE_p_avp, 0 /* the AVPs are not owned */ ));
+			ret = fd_msg_browse(a, MSG_BRW_NEXT, &a, NULL);
+			if (ret != 0) {
+				DI_ERROR(ret, NULL, NULL);
+				return NULL;
+			}
+		}
+		Py_XINCREF(rl);
+		SWIG_PYTHON_THREAD_END_BLOCK;
+		return rl;
+	}
+	
+	/* Add a new AVP */
+	void add_next(struct avp *avp) {
+		int ret = fd_msg_avp_add ( $self, MSG_BRW_NEXT, avp);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void add_prev(struct avp *avp) {
+		int ret = fd_msg_avp_add ( $self, MSG_BRW_PREV, avp);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void add_child(struct avp *DISOWN, int begin = 0) {
+		int ret = fd_msg_avp_add ( $self, begin ? MSG_BRW_FIRST_CHILD : MSG_BRW_LAST_CHILD, DISOWN);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Get the next AVP at the same level */
+	struct avp * get_next() {
+		struct avp * a = NULL;
+		int ret = fd_msg_browse($self, MSG_BRW_NEXT, &a, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return a;
+	}
+	
+	/* Dump */
+	void dump (int tree = 1) {
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_msg_dump_treeview(&buf, &len, NULL, $self, NULL, 0, tree));
+		free(buf);
+	}
+	
+	/* Model */
+	struct dict_object * model() {
+		struct dict_object * m = NULL;
+		int ret = fd_msg_model($self, &m);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return m;
+	}
+	
+	/* Header */
+	struct avp_hdr * header() {
+		struct avp_hdr * h = NULL;
+		int ret = fd_msg_avp_hdr($self, &h);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return h;
+	}
+	
+	/* set value */
+	void setval(union avp_value * val) {
+		int ret = fd_msg_avp_setvalue ( $self, val );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Update the length info in header */
+	void update_length() {
+		int ret = fd_msg_update_length ( $self );
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+}
diff --git a/extensions/dbg_interactive/peers.i b/extensions/dbg_interactive/peers.i
new file mode 100644
index 0000000..a256cf7
--- /dev/null
+++ b/extensions/dbg_interactive/peers.i
@@ -0,0 +1,227 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** PEERS *********/
+
+%{
+static void fd_add_cb(struct peer_info *peer, void *data) {
+	/* Callback called when the peer connection completes (or fails) */
+	PyObject *PyPeer, *PyFunc;
+	PyObject *result = NULL;
+	
+	if (!data) {
+		TRACE_DEBUG(INFO, "Internal error: missing callback");
+		return;
+	}
+	PyFunc = data;
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	
+	/* Convert the argument */
+	PyPeer  = SWIG_NewPointerObj((void *)peer,     SWIGTYPE_p_peer_info,     0 );
+	
+	/* Call the function */
+	result = PyObject_CallFunction(PyFunc, "(O)", PyPeer);
+	
+	Py_XDECREF(result);
+	Py_XDECREF(PyFunc);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return;
+}
+%}
+
+%extend peer_info {
+	peer_info () {
+		struct peer_info *np = (struct peer_info *)calloc(1, sizeof(struct peer_info));
+		if (!np) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		
+		fd_list_init(&np->pi_endpoints, NULL);
+		
+		return np;
+	}
+
+	/* Wrapper around fd_peer_add to allow calling the python callback */
+	%delobject add;
+	void add(PyObject * PyCb=NULL) {
+		int ret;
+		
+		if (PyCb) {
+			Py_XINCREF(PyCb);
+			ret = fd_peer_add ( $self, "dbg_interactive", fd_add_cb, PyCb );
+		} else {
+			ret = fd_peer_add ( $self, "dbg_interactive", NULL, NULL );
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+}
+
+%inline %{
+static struct peer_hdr * peer_search(char *STRING, size_t LENGTH) {
+	struct peer_hdr *r = NULL;
+	int ret = fd_peer_getbyid( STRING, LENGTH, 0, &r );
+	if (ret) {
+		DI_ERROR(ret, NULL, NULL);
+		return NULL;
+	}
+	return r;
+}
+%}
+
+%{
+static PyObject * validate_cb_py = NULL;
+static PyObject * validate_cb2_py = NULL;
+
+/* C wrapper that calls validate_cb2_py */
+int call_the_python_validate_callback2(struct peer_info * info) {
+	PyObject *PyInfo;
+	PyObject *result = NULL;
+	int ret = 0;
+	
+	if (!validate_cb2_py) {
+		fd_log_debug("Internal error: missing the callback2!");
+		return ENOTSUP;
+	}
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyInfo  = SWIG_NewPointerObj((void *)info,     SWIGTYPE_p_peer_info,     0 );
+	
+	/* Call the function */
+	result = PyObject_CallFunction(validate_cb2_py, "(O)", PyInfo);
+	
+	/* The result is an integer */
+	if ((result == NULL) || !SWIG_IsOK(SWIG_AsVal_int(result, &ret))) {
+		fd_log_debug("Error: The Python callback did not return an integer.");
+		ret = EINVAL;
+		goto out;
+	}
+	
+out:	
+	Py_XDECREF(result);
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return ret;
+}
+
+/* C wrapper that calls validate_cb_py */
+int call_the_python_validate_callback(struct peer_info * info, int * auth, int (**cb2)(struct peer_info *)) {
+	PyObject *PyInfo;
+	PyObject *result = NULL;
+	int ret = 0;
+	
+	if (!validate_cb_py) {
+		fd_log_debug("Internal error: missing the callback!");
+		return ENOTSUP;
+	}
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyInfo  = SWIG_NewPointerObj((void *)info,     SWIGTYPE_p_peer_info,     0 );
+	
+	/* Call the function */
+	result = PyObject_CallFunction(validate_cb_py, "(O)", PyInfo);
+	
+	/* The result is supposedly -1, 1, or a cb2 */
+	if (result == NULL) {
+		fd_log_debug("Error: The Python callback did not return a value.");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	if (PyCallable_Check(result)) {
+		if (cb2) {
+			if (validate_cb2_py && (validate_cb2_py != result)) {
+				fd_log_debug("Only 1 register callback2 is supported currently");
+				ret = ENOTSUP;
+				goto out;
+			}
+			validate_cb2_py = result;
+			*cb2 = call_the_python_validate_callback2;
+			*auth = 1;
+			goto out_nodec;
+		} else {
+			*auth = 1;
+			goto out; /* ignore the callback since it won't be used */
+		}
+	} else { /* In this case, the return value must be -1, 0, or 1 */
+		if (!SWIG_IsOK(SWIG_AsVal_int(result, auth))) {
+			fd_log_debug("Error: Cannot convert the return value to integer.");
+			ret = EINVAL;
+			goto out;
+		}
+	}
+	
+out:	
+	Py_XDECREF(result);
+out_nodec:	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	TRACE_DEBUG(FULL, "ret=%d, *auth=%d, cb2=%p, *cb2=%p", ret, *auth, cb2, cb2 ? *cb2 : NULL);
+	return ret;
+}
+
+%}
+
+%inline %{
+static void peer_validate_register(PyObject * PyCb) {
+	int ret ;
+	
+	if (!PyCb) {
+		DI_ERROR(EINVAL, NULL, "The callback must be provided");
+		return;
+	}
+	
+	if (validate_cb_py) {
+		if (PyCb != validate_cb_py) {
+			DI_ERROR(ENOTSUP, PyExc_RuntimeError, "Only 1 register callback is supported currently");
+			return;
+		}
+	} else {
+		validate_cb_py = PyCb;
+		Py_XINCREF(PyCb);
+	}
+	
+	ret = fd_peer_validate_register ( call_the_python_validate_callback );
+	if (ret) {
+		DI_ERROR(ret, NULL, NULL);
+	}
+}
+%}
diff --git a/extensions/dbg_interactive/posix.i b/extensions/dbg_interactive/posix.i
new file mode 100644
index 0000000..ceafeb6
--- /dev/null
+++ b/extensions/dbg_interactive/posix.i
@@ -0,0 +1,194 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2012, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** POSIX wrappers around useful functions for fD *********/
+
+/**** MUTEX ****/
+typedef struct {
+} pthread_mutex_t;
+
+%extend pthread_mutex_t {
+	pthread_mutex_t() {
+		int ret = 0;
+		pthread_mutex_t * r = calloc(1, sizeof(pthread_mutex_t));
+		if (!r) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		ret = pthread_mutex_init(r, NULL);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+			free(r);
+			return NULL;
+		}
+		return r;
+	}
+	~pthread_mutex_t() {
+		int ret = 0;
+		ret = pthread_mutex_destroy($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		free($self);
+		return;
+	}
+	void lock() {
+		int ret = pthread_mutex_lock($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void unlock() {
+		int ret = pthread_mutex_unlock($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+}
+
+/**** CONDVAR ****/
+typedef struct {
+} pthread_cond_t;
+
+%extend pthread_cond_t {
+	pthread_cond_t() {
+		int ret = 0;
+		pthread_cond_t * r = calloc(1, sizeof(pthread_cond_t));
+		if (!r) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		ret = pthread_cond_init(r, NULL);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+			free(r);
+			return NULL;
+		}
+		return r;
+	}
+	~pthread_cond_t() {
+		int ret = 0;
+		ret = pthread_cond_destroy($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		free($self);
+		return;
+	}
+	void signal() {
+		int ret = pthread_cond_signal($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void broadcast() {
+		int ret = pthread_cond_broadcast($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void wait(pthread_mutex_t * mutex) {
+		int ret = pthread_cond_wait($self, mutex);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void timedwait(pthread_mutex_t * mutex, long seconds) {
+		struct timespec ts;
+		int ret;
+		
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += seconds;
+		
+		ret = pthread_cond_timedwait($self, mutex, &ts);
+		if (ret && (ret != ETIMEDOUT)) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+}
+
+/**** RWLOCK ****/
+typedef struct {
+} pthread_rwlock_t;
+
+%extend pthread_rwlock_t {
+	pthread_rwlock_t() {
+		int ret = 0;
+		pthread_rwlock_t * r = calloc(1, sizeof(pthread_rwlock_t));
+		if (!r) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		ret = pthread_rwlock_init(r, NULL);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+			free(r);
+			return NULL;
+		}
+		return r;
+	}
+	~pthread_rwlock_t() {
+		int ret = 0;
+		ret = pthread_rwlock_destroy($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		free($self);
+		return;
+	}
+	void rdlock() {
+		int ret = pthread_rwlock_rdlock($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void wrlock() {
+		int ret = pthread_rwlock_wrlock($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void unlock() {
+		int ret = pthread_rwlock_unlock($self);
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+}
diff --git a/extensions/dbg_interactive/queues.i b/extensions/dbg_interactive/queues.i
new file mode 100644
index 0000000..ff1728d
--- /dev/null
+++ b/extensions/dbg_interactive/queues.i
@@ -0,0 +1,198 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** FIFO QUEUES *********/
+
+struct fifo {
+};
+
+%extend fifo {
+	fifo(int max = 0) {
+		struct fifo * q = NULL;
+		int ret = fd_fifo_new(&q, max);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return q;
+	}
+	~fifo() {
+		struct fifo *q = self;
+		fd_fifo_del(&q);
+	}
+	
+	/* Move all elements to another queue */
+	void move(struct fifo * to) {
+		int ret = fd_fifo_move($self, to, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Get the length of the queue (nb elements) */
+	int length() {
+		return fd_fifo_length ( $self ) ;
+	}
+
+	/* Is the threashold function useful here? TODO... */
+	
+	/* Post an item */
+	void post(PyObject * item, char * type = NULL) {
+		int ret;
+		if (type) {
+			void * real_obj = NULL;
+			swig_type_info * desttype = NULL;
+			desttype = SWIG_TypeQuery(type);
+			if (!desttype) {
+				DI_ERROR(EINVAL, NULL, "Unable to resolve this type. Please check the form: 'struct blahbla *'");
+				return;
+			}
+			/* Now, get the "real" value under the shadow umbrella */
+			ret = SWIG_ConvertPtr(item, &real_obj, desttype, SWIG_POINTER_DISOWN );
+			if (!SWIG_IsOK(ret)) {
+				DI_ERROR(EINVAL, SWIG_ErrorType(ret), "Unable to convert the item to given type");
+				return;
+			}
+			ret = fd_fifo_post($self, &real_obj);
+		} else {
+			PyObject * i = item;
+			Py_XINCREF(i);
+			ret = fd_fifo_post($self, &i);
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Get (blocking) */
+	PyObject * get(char * type = NULL) {
+		int ret;
+		PyObject * i = NULL;
+		void * obj = NULL;
+		swig_type_info * desttype = NULL;
+		if (type) {
+			desttype = SWIG_TypeQuery(type);
+			if (!desttype) {
+				DI_ERROR(EINVAL, NULL, "Unable to resolve this type. Please check the form: 'struct blahbla *'");
+				return NULL;
+			}
+		}
+		
+		ret = fd_fifo_get($self, &obj);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		
+		if (type) {
+			return SWIG_NewPointerObj(obj, desttype, 0 );
+		} else {
+			i = obj;
+			return i;
+		}
+	}
+	
+	/* TryGet (non-blocking, returns None on empty queue) */
+	PyObject * tryget(char * type = NULL) {
+		int ret;
+		PyObject * i = NULL;
+		void * obj = NULL;
+		swig_type_info * desttype = NULL;
+		if (type) {
+			desttype = SWIG_TypeQuery(type);
+			if (!desttype) {
+				DI_ERROR(EINVAL, NULL, "Unable to resolve this type. Please check the form: 'struct blahbla *'");
+				return NULL;
+			}
+		}
+		
+		ret = fd_fifo_tryget($self, &obj);
+		if (ret == EWOULDBLOCK) {
+			Py_INCREF(Py_None);
+			return Py_None;
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		
+		if (type) {
+			return SWIG_NewPointerObj(obj, desttype, 0 );
+		} else {
+			i = obj;
+			return i;
+		}
+	}
+	
+	/* TimedGet (blocking for a while) */
+	PyObject * timedget(long seconds, char * type = NULL) {
+		int ret;
+		PyObject * i = NULL;
+		struct timespec ts;
+		void * obj = NULL;
+		swig_type_info * desttype = NULL;
+		if (type) {
+			desttype = SWIG_TypeQuery(type);
+			if (!desttype) {
+				DI_ERROR(EINVAL, NULL, "Unable to resolve this type. Please check the form: 'struct blahbla *'");
+				return NULL;
+			}
+		}
+		
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += seconds;
+		
+		ret = fd_fifo_timedget($self, &obj, &ts);
+		if (ret == ETIMEDOUT) {
+			Py_INCREF(Py_None);
+			return Py_None;
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		
+		if (type) {
+			return SWIG_NewPointerObj(obj, desttype, 0 );
+		} else {
+			i = obj;
+			return i;
+		}
+	}
+	
+}		
+	
+	
+	
+	
diff --git a/extensions/dbg_interactive/routing.i b/extensions/dbg_interactive/routing.i
new file mode 100644
index 0000000..324674f
--- /dev/null
+++ b/extensions/dbg_interactive/routing.i
@@ -0,0 +1,251 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** ROUTING *********/
+
+struct rt_data {
+};
+
+%extend rt_data {
+	rt_data() {
+		struct rt_data * r = NULL;
+		int ret = fd_rtd_init(&r);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return r;
+	}
+	~rt_data() {
+		struct rt_data *r = self;
+		fd_rtd_free(&r);
+	}
+	%apply (char *STRING, int LENGTH) { (char * peerid, size_t peeridlen) };
+	%apply (char *STRING, int LENGTH) { (char * realm, size_t realmlen) };
+	void add(char * peerid, size_t peeridlen, char * realm, size_t realmlen) {
+		int ret = fd_rtd_candidate_add($self, peerid, peeridlen, realm, realmlen);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void remove(char * STRING, size_t LENGTH) {
+		fd_rtd_candidate_del($self, (os0_t)STRING, LENGTH);
+	}
+	int error(char * peerid, size_t peeridlen, char * STRING, size_t LENGTH, uint32_t rcode) {
+		int n;
+		int ret =  fd_rtd_error_add($self, peerid, peeridlen, (os0_t)STRING, LENGTH, rcode, NULL, &n);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return n;
+	}
+	struct fd_list * extract(int score = 0) {
+		struct fd_list * li = NULL;
+		fd_rtd_candidate_extract($self, &li, score);
+		return li;
+	}
+}
+
+
+
+%extend rtd_candidate {
+	void dump() {
+		fd_log_debug("candidate %p", $self);
+		fd_log_debug("  id : %s",  $self->diamid);
+		fd_log_debug("  rlm: %s", $self->realm);
+		fd_log_debug("  sc : %d", $self->score);
+	}
+}
+
+
+%{
+/* call it (will be called from a different thread than the interpreter, when message arrives) */
+static int call_the_python_rt_fwd_callback(void * pycb, struct msg **msg) {
+	PyObject *PyMsg;
+	PyObject *cb, *result = NULL;
+	int ret = 0;
+	
+	if (!pycb) {
+		fd_log_debug("Internal error: missing the callback!");
+		return ENOTSUP;
+	}
+	cb = pycb;
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyMsg  = SWIG_NewPointerObj((void *)*msg,     SWIGTYPE_p_msg,     0 );
+	
+	/* Call the function */
+	result = PyObject_CallFunction(cb, "(O)", PyMsg);
+	
+	/* The result is supposedly composed of: [ ret, *msg ] */
+	if ((result == NULL) || (!PyList_Check(result)) || (PyList_Size(result) != 2)) {
+		fd_log_debug("Error: The Python callback did not return [ ret, msg ].");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	/* Convert the return values */
+	if (!SWIG_IsOK(SWIG_AsVal_int(PyList_GetItem(result, 0), &ret))) {
+		fd_log_debug("Error: Cannot convert the first return value to integer.");
+		ret = EINVAL;
+		goto out;
+	}
+	if (ret) {
+		TRACE_DEBUG(INFO, "The Python callback returned the error code %d (%s)", ret, strerror(ret));
+		goto out;
+	}
+	
+	if (!SWIG_IsOK(SWIG_ConvertPtr(PyList_GetItem(result, 1), (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
+		fd_log_debug("Error: Cannot convert the second return value to message.");
+		ret = EINVAL;
+		goto out;
+	}
+	
+out:	
+	Py_XDECREF(result);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return ret;
+}
+%}
+
+
+struct fd_rt_fwd_hdl {
+};
+
+%extend fd_rt_fwd_hdl{
+	fd_rt_fwd_hdl(PyObject * PyCb, enum fd_rt_fwd_dir dir) {
+		struct fd_rt_fwd_hdl * r = NULL;
+		int ret;
+		
+		Py_XINCREF(PyCb);
+
+		ret = fd_rt_fwd_register( call_the_python_rt_fwd_callback, PyCb, dir, &r );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return r;
+	}
+	
+	~fd_rt_fwd_hdl() {
+		PyObject * func;
+		int ret = fd_rt_fwd_unregister ( $self, (void *) &func );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		Py_XDECREF(func);
+		return;
+	}
+}
+
+
+%{
+/* call it (will be called from a different thread than the interpreter, when message arrives) */
+static int call_the_python_rt_out_callback(void * pycb, struct msg **msg, struct fd_list * candidates) {
+	PyObject *PyMsg, *PyCands;
+	PyObject *cb, *result = NULL;
+	int ret = 0;
+	
+	if (!pycb) {
+		fd_log_debug("Internal error: missing the callback!");
+		return ENOTSUP;
+	}
+	cb = pycb;
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyMsg   = SWIG_NewPointerObj((void *)*msg,       SWIGTYPE_p_msg,     0 );
+	PyCands = SWIG_NewPointerObj((void *)candidates, SWIGTYPE_p_fd_list, 0 );
+	
+	/* Call the function */
+	result = PyObject_CallFunction(cb, "(OO)", PyMsg, PyCands);
+	
+	/* The result is supposedly composed of: [ ret, *msg ] */
+	if (result == NULL){
+		fd_log_debug("Error: The Python callback raised an exception.");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	/* Convert the return values */
+	if (!SWIG_IsOK(SWIG_AsVal_int(result, &ret))) {
+		fd_log_debug("Error: Cannot convert the return value to integer.");
+		ret = EINVAL;
+		goto out;
+	}
+out:	
+	Py_XDECREF(result);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return ret;
+}
+%}
+
+
+struct fd_rt_out_hdl {
+};
+
+%extend fd_rt_out_hdl{
+	fd_rt_out_hdl(PyObject * PyCb, int priority = 0) {
+		struct fd_rt_out_hdl * r = NULL;
+		int ret;
+		
+		Py_XINCREF(PyCb);
+
+		ret = fd_rt_out_register( call_the_python_rt_out_callback, PyCb, priority, &r );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return r;
+	}
+	
+	~fd_rt_out_hdl() {
+		PyObject * func;
+		int ret = fd_rt_out_unregister ( $self, (void *) &func );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		Py_XDECREF(func);
+		return;
+	}
+}
+
diff --git a/extensions/dbg_interactive/sessions.i b/extensions/dbg_interactive/sessions.i
new file mode 100644
index 0000000..180a150
--- /dev/null
+++ b/extensions/dbg_interactive/sessions.i
@@ -0,0 +1,210 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Do not include this directly, use dbg_interactive.i instead */
+
+/****** SESSIONS *********/
+
+%{
+struct sess_state {
+	PyObject * pystate;
+};
+
+/* call it (might be called from a different thread than the interpreter, when session times out) */
+static void call_the_python_cleanup_callback(struct sess_state * state, os0_t sid, void * cb) {
+	PyObject *result;
+	if (!cb) {
+		fd_log_debug("Internal error: missing callback object!");
+		return;
+	}
+	
+	/* Call the function */
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	result = PyObject_CallFunction((PyObject *)cb, "(Os)", state, sid);
+	Py_XDECREF(result);
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return;
+}
+%}
+
+struct session_handler {
+};
+
+%nodefaultctor session_handler;
+%extend session_handler {
+	session_handler(PyObject * PyCb) {
+		struct session_handler * hdl = NULL;
+		int ret;
+		
+		Py_XINCREF(PyCb);
+		
+		ret = fd_sess_handler_create ( &hdl, call_the_python_cleanup_callback, NULL, PyCb );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return hdl;
+	}
+	~session_handler() {
+		struct session_handler * hdl = self;
+		PyObject * cb = NULL;
+		
+		int ret = fd_sess_handler_destroy(&hdl, (void *)&cb);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		/* Now free the callback */
+		Py_XDECREF(cb);
+		return;
+	}
+	void dump() {
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_sess_dump_hdl(&buf, &len, NULL, $self));
+		free(buf);
+	}
+}
+
+
+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, fd_g_config->cnf_diamid_len, (os0_t)"dbg_interactive", CONSTSTRLEN("dbg_interactive"));
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return s;
+	}
+	session(char * diamid, char * STRING, size_t LENGTH) {
+		int ret;
+		struct session * s = NULL;
+		ret = fd_sess_new(&s, diamid, 0, (os0_t)STRING, LENGTH);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return s;
+	}
+	session(char * STRING, size_t LENGTH) {
+		int ret, n;
+		struct session * s = NULL;
+		ret = fd_sess_fromsid((os0_t)STRING, LENGTH, &s, &n);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		/* When defining n as OUTPUT parameter, we get something strange... Use fd_sess_fromsid if you need it */
+		#if 0
+		if (n) {
+			fd_log_debug("A new session has been created");
+		} else {
+			fd_log_debug("A session with same id already existed");
+		}
+		#endif /* 0 */
+		
+		return s;
+	}
+	~session() {
+		struct session * s = self;
+		int ret = fd_sess_reclaim(&s);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return;
+	}
+	
+	%cstring_output_allocate_size(char ** outsid, size_t * sidlen, /* do not free */);
+	void getsid(char ** outsid, size_t * sidlen) {
+		int ret;
+		ret = fd_sess_getsid( $self, (void *)outsid, sidlen);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return;
+		}
+		return;
+	}
+	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) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	void dump() {
+		char * buf = NULL;
+		size_t len = 0;
+		printf("%s", fd_sess_dump(&buf, &len, NULL, $self, 1) );
+		free(buf);
+	}
+	void store(struct session_handler * handler, PyObject * DISOWN) {
+		int ret;
+		struct sess_state * st = NULL;
+		st = malloc(sizeof(struct sess_state));
+		st->pystate = DISOWN;
+		Py_XINCREF(DISOWN);
+		ret = fd_sess_state_store(handler, $self, (void *) &st);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	%newobject retrieve;
+	PyObject * retrieve(struct session_handler * handler) {
+		int ret;
+		struct sess_state * st = NULL;
+		PyObject * state = NULL;
+		ret = fd_sess_state_retrieve(handler, $self, (void *) &st);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		if (st == NULL) {
+			Py_INCREF(Py_None);
+			return Py_None;
+		}
+		state = st->pystate;
+		free(st);
+		return state;
+	}
+}	
+