Index: doc/dbg_interactive.py.sample
===================================================================
--- doc/dbg_interactive.py.sample	(revision 639)
+++ doc/dbg_interactive.py.sample	(revision 640)
@@ -90,5 +90,5 @@
 l1.concat(l3)        # l1 -> l2 -> l5 -> l4
 
-elements = l1.enum_as()  # default: enumerates as fd_list. Warning: this a copy, changing the python list has no effect on the underlying list.
+elements = l1.enum_as()  # default: enumerates as fd_list. Warning: this a copy, changing the python list has no effect on the underlying fd_list.
 for li in elements:
   li.dump()
@@ -224,7 +224,4 @@
 del r
 
-d.dump()
-del d
-
 r2 = dict_rule_data(my_avp_int, RULE_REQUIRED) # min & max are optional parameters, default to -1
 r3 = dict_rule_data(my_avp_int, RULE_REQUIRED, 2, 3) # min is 2, max is 3
@@ -234,4 +231,7 @@
 del r4
 
+d.dump()
+del d
+
 ####### Now play with the "real" dictionary
 
@@ -273,5 +273,5 @@
 s1.getsid()
 s2 = session("this.is.a.full.session.id")
-r,s3,isnew = fd_sess_fromsid("this.is.a.full.session.id")
+r,s3,isnew = fd_sess_fromsid("this.is.a.full.session.id")  # use this call if "isnew" is really needed...
 s4 = session("host.id", "optional.part")
 s4.settimeout(30) # the python wrapper takes a number of seconds as parameter for simplicity
@@ -304,4 +304,29 @@
   print "%s (%s): %s" % (c.diamid, c.realm, c.score)
 
+del rd
+
+
+# A rt_fwd callback has the following prototype:
+def my_rtfwd_cb(msg):
+    print "Forwarding the following message:"
+    msg.dump()
+    return [ 0, msg ]  # return None instead of msg to stop forwarding.
+
+fwdhdl = fd_rt_fwd_hdl( my_rtfwd_cb, RT_FWD_REQ )
+
+
+# A rt_out cb has the following prototype:
+def my_rtout_cb(msg, list):
+    print "Sending out the following message:"
+    msg.dump()
+    print "The possible candidates are:"
+    for c in list.enum_as("struct rtd_candidate *"):
+       print "%s (%s): %s" % (c.diamid, c.realm, c.score)
+    return 0   # returns an error code (standard errno values)
+
+outhdl = fd_rt_out_hdl( my_rtout_cb )  # a priority can be specified as 2nd parameter, default is 0.
+
+
+
 
 
@@ -322,5 +347,5 @@
 val = avp_value()
 val.u32 = 123
-vi.setval(None)  # this cleans a previous value (not needed)
+vi.setval(None)  # this cleans a previous value (usually not needed)
 vi.setval(val)
 val.os = "my.origin.host"
@@ -379,5 +404,5 @@
 dwr.children()
 # example use:
-for a in dwr.children()
+for a in dwr.children():
   a.dump(0)  # 0 means: dump only this object, do not walk the tree
 
@@ -436,4 +461,5 @@
 
 # Send a message:
+mydwr = msg(buf)
 mydwr.send()
 
@@ -447,8 +473,10 @@
     return None
 
+mydwr = msg(buf)
 mydwr.send(send_callback, some_object)
 
 
 # Set a result code in an answer message.
+mydwr = msg(buf)
 dwa = mydwr.create_answer()
 dwa.rescode_set()   # This adds the DIAMETER_SUCCESS result code
@@ -598,4 +626,19 @@
 myqueue.length()
 
+
+## Variants:
+# All the previous calls are suitable to queue Python objects.
+# In order to interact with objects queued / poped by C counterpart,
+# a second parameter must be passed to specify the object type,
+# as follow:
+ev = fd_event()
+ev.code = FDEV_DUMP_EXT
+cvar.fd_g_config.cnf_main_ev.post(ev, "struct fd_event *")
+
+# Similarly, for *get, we can specify the structure that was queued:
+myqueue.get("struct fd_event *")
+myqueue.tryget("struct fd_event *")
+myqueue.timedget(3, "struct fd_event *")
+
 del myqueue
 
@@ -614,7 +657,5 @@
 np = peer_info()
 np.pi_diamid = "nas.localdomain"
-np.config.pic_flags.pro4 = 1   # 1 for TCP, for some reason PI_P4_TCP is not defined
-
-
+np.config.pic_flags.pro4 = PI_P4_TCP
 
 
@@ -634,6 +675,54 @@
         print "The peer has been destroyed before it completed the connection."
 
-# Then add the peer simply like this:
+# Then add the peer like this:
 np.add(add_cb)
 
 
+# Search a peer by its diameter id (returns a peer_hdr object if found) -- similar to fd_peer_getbyid
+p = peer_search("nas.domain.aaa")
+
+
+## Validation callback (see fd_peer_validate_register documentation)
+
+# cb2 prototype:
+def my_validate_cb2(pinfo):
+    print "Cb2 callback trigged for peer %s" % (pinfo.pi_diamid)
+    # Usually, this would be used only to check some TLS properties, 
+    # which is not really possible yet through the python interpreter...
+    return 0   # return an error code if the peer is not validated
+
+# cb prototype:
+def my_validate_cb(pinfo):
+    print "Validate callback trigged for peer %s" % (pinfo.pi_diamid)
+    # If the peer is not allowed to connect:
+    #return -1
+    # If the peer is authorized:
+    #return 1
+    # In addition, if IPsec is allowed,
+    #pinfo.config.pic_flags.sec = PI_SEC_NONE
+    # If no decision has been made:
+    #return 0
+    # If the peer is temporarily authorized but a second callback must be called after TLS negociation:
+    return my_validate_cb2
+
+# Register the callback, it will be called on new incoming connections.
+peer_validate_register(my_validate_cb)
+
+
+
+############# ENDPOINTS ############
+
+ep = fd_endpoint("129.168.168.192")
+
+# with port:
+ep = fd_endpoint("129.168.168.192", 3868)
+
+# With different flags:
+ep = fd_endpoint("129.168.168.192", 3868, EP_FL_PRIMARY)
+
+# Add IP information for the peer
+np = peer_info()
+ep.add_merge(np.pi_endpoints)
+fd_ep_dump(0, np.pi_endpoints)
+
+
Index: extensions/dbg_interactive/CMakeLists.txt
===================================================================
--- extensions/dbg_interactive/CMakeLists.txt	(revision 637)
+++ extensions/dbg_interactive/CMakeLists.txt	(revision 640)
@@ -26,4 +26,6 @@
 	queues.i
 	peers.i
+	events.i
+	endpoints.i
 	)
 SET_SOURCE_FILES_PROPERTIES(dbg_interactive.i PROPERTIES SWIG_MODULE_NAME fDpy)
Index: extensions/dbg_interactive/dbg_interactive.i
===================================================================
--- extensions/dbg_interactive/dbg_interactive.i	(revision 638)
+++ extensions/dbg_interactive/dbg_interactive.i	(revision 640)
@@ -68,5 +68,5 @@
 static int wrapper_errno;
 static PyObject* wrapper_errno_py;
-static char * wrapper_error_txt; /* if NULL, use strerror(errno) */
+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\n", __PRETTY_FUNCTION__, str ? str : strerror(code)); \
@@ -88,5 +88,5 @@
 	/* Now, test for error */
 	if (wrapper_errno) {
-		char * str = wrapper_error_txt ? wrapper_error_txt : strerror(wrapper_errno);
+		const char * str = wrapper_error_txt ? wrapper_error_txt : strerror(wrapper_errno);
 		PyObject * exc = wrapper_errno_py;
 		if (!exc) {
@@ -109,5 +109,5 @@
  ***********************************/
 
-%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) }; /* fd_hash */
+%apply (char *STRING, size_t LENGTH) { ( char * string, size_t len ) };
 
 /* Generic typemap for functions that create something */
@@ -119,18 +119,39 @@
 }
 
+/* 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 (!PyCallable_Check($input)) {
-		PyErr_SetString(PyExc_TypeError, "Need a callable object!");
-		SWIG_fail;
+	if (!$input || ($input == Py_None)) {
+		$1 = NULL;
+	} else {
+		if (!PyCallable_Check($input)) {
+			PyErr_SetString(PyExc_TypeError, "Need a callable object!");
+			SWIG_fail;
+		}
+		$1 = $input;
 	}
-	$1 = $input;
 }
 
-
+%{
 /* Forward declaration for the peers module */
-%{
 static void fd_add_cb(struct peer_info *peer, void *data);
 %}
+
+/* Overwrite declaration to apply typemaps */
+int fd_sess_fromsid ( char * STRING, size_t LENGTH, struct session ** OUTPUT, int * BOOL_OUT);
+
 
 /*********************************************************
@@ -155,2 +176,4 @@
 
 %include "peers.i"
+%include "events.i"
+%include "endpoints.i"
Index: extensions/dbg_interactive/endpoints.i
===================================================================
--- extensions/dbg_interactive/endpoints.i	(revision 640)
+++ extensions/dbg_interactive/endpoints.i	(revision 640)
@@ -0,0 +1,130 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2010, 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() {
+		fd_ep_dump_one( "", $self, "\n" );
+	}
+}
Index: extensions/dbg_interactive/events.i
===================================================================
--- extensions/dbg_interactive/events.i	(revision 640)
+++ extensions/dbg_interactive/events.i	(revision 640)
@@ -0,0 +1,52 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2010, 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 = STRING; /* Should maybe malloc it ? */
+		fd->size = LENGTH;
+		return fd;
+	}
+}	
Index: extensions/dbg_interactive/lists.i
===================================================================
--- extensions/dbg_interactive/lists.i	(revision 637)
+++ extensions/dbg_interactive/lists.i	(revision 640)
@@ -71,6 +71,12 @@
 	}
 	/* Test for emptyness */
-	int isempty() {
-		return FD_IS_LIST_EMPTY($self);
+	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 */
Index: extensions/dbg_interactive/messages.i
===================================================================
--- extensions/dbg_interactive/messages.i	(revision 638)
+++ extensions/dbg_interactive/messages.i	(revision 640)
@@ -293,6 +293,12 @@
 	
 	/* Is routable? */
-	int is_routable() {
-		return fd_msg_is_routable($self);
+	PyObject * is_routable() {
+		PyObject * r;
+		if (fd_msg_is_routable($self))
+			r = Py_True;
+		else
+			r = Py_False;
+		Py_XINCREF(r);
+		return r;
 	}
 	
Index: extensions/dbg_interactive/peers.i
===================================================================
--- extensions/dbg_interactive/peers.i	(revision 638)
+++ extensions/dbg_interactive/peers.i	(revision 640)
@@ -67,5 +67,18 @@
 
 %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;
@@ -81,9 +94,134 @@
 		}
 	}
-
-	/* Add an endpoint */
-	void add_endpoint(char * endpoint) {
-		fd_log_debug("What is the best way in python to pass an endpoint? (ip + port)");
-	}
-
-}
+}
+
+%inline %{
+static struct peer_hdr * peer_search(char *diamid) {
+	struct peer_hdr *r = NULL;
+	int ret = fd_peer_getbyid( diamid, &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!\n");
+		return ENOTSUP;
+	}
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyInfo  = SWIG_NewPointerObj((void *)info,     SWIGTYPE_p_peer_info,     0 );
+	
+	/* Call the function */
+	result = PyEval_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.\n");
+		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!\n");
+		return ENOTSUP;
+	}
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyInfo  = SWIG_NewPointerObj((void *)info,     SWIGTYPE_p_peer_info,     0 );
+	
+	/* Call the function */
+	result = PyEval_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.\n");
+		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\n");
+				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.\n");
+			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);
+	}
+}
+%}
Index: extensions/dbg_interactive/queues.i
===================================================================
--- extensions/dbg_interactive/queues.i	(revision 638)
+++ extensions/dbg_interactive/queues.i	(revision 640)
@@ -77,10 +77,26 @@
 	
 	/* Post an item */
-	void post(PyObject * item) {
-		int ret;
-		PyObject * i = item;
-		
-		Py_XINCREF(i);
-		ret = fd_fifo_post($self, &i);
+	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);
@@ -89,22 +105,45 @@
 	
 	/* Get (blocking) */
-	PyObject * get() {
+	PyObject * get(char * type = NULL) {
 		int ret;
 		PyObject * i = NULL;
-		
-		ret = fd_fifo_get($self, &i);
-		if (ret != 0) {
-			DI_ERROR(ret, NULL, NULL);
-		}
-		
-		return i;
+		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() {
+	PyObject * tryget(char * type = NULL) {
 		int ret;
 		PyObject * i = NULL;
-		
-		ret = fd_fifo_tryget($self, &i);
+		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_XINCREF(Py_None);
@@ -115,17 +154,31 @@
 		}
 		
-		return i;
+		if (type) {
+			return SWIG_NewPointerObj(obj, desttype, 0 );
+		} else {
+			i = obj;
+			return i;
+		}
 	}
 	
 	/* TimedGet (blocking for a while) */
-	PyObject * timedget(long seconds) {
+	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, &i, &ts);
+		ret = fd_fifo_timedget($self, &obj, &ts);
 		if (ret == ETIMEDOUT) {
 			Py_XINCREF(Py_None);
@@ -136,5 +189,10 @@
 		}
 		
-		return i;
+		if (type) {
+			return SWIG_NewPointerObj(obj, desttype, 0 );
+		} else {
+			i = obj;
+			return i;
+		}
 	}
 	
Index: extensions/dbg_interactive/routing.i
===================================================================
--- extensions/dbg_interactive/routing.i	(revision 637)
+++ extensions/dbg_interactive/routing.i	(revision 640)
@@ -77,4 +77,6 @@
 }
 
+
+
 %extend rtd_candidate {
 	void dump() {
@@ -86,2 +88,160 @@
 }
 
+
+%{
+/* 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!\n");
+		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 = PyEval_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 ].\n");
+		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.\n");
+		ret = EINVAL;
+		goto out;
+	}
+	if (ret) {
+		TRACE_DEBUG(INFO, "The Python callback returned the error code %d (%s)\n", 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.\n");
+		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!\n");
+		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 = PyEval_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.\n");
+		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.\n");
+		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;
+	}
+}
+
Index: freeDiameter/endpoints.c
===================================================================
--- freeDiameter/endpoints.c	(revision 559)
+++ freeDiameter/endpoints.c	(revision 640)
@@ -53,4 +53,9 @@
 	CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) );
 	
+	if (list->next == NULL) {
+		/* the list is not initialized yet, do it */
+		fd_list_init(list, NULL);
+	}
+	
 	if (TRACE_BOOL(ANNOYING + 1)) {
 		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Current list:");
Index: include/freeDiameter/freeDiameter.h
===================================================================
--- include/freeDiameter/freeDiameter.h	(revision 628)
+++ include/freeDiameter/freeDiameter.h	(revision 640)
@@ -70,7 +70,7 @@
 
 /* Structure to hold the configuration of the freeDiameter daemon */
+#define	EYEC_CONFIG	0xC011F16
 struct fd_config {
 	int		 cnf_eyec;	/* Eye catcher: EYEC_CONFIG */
-			#define	EYEC_CONFIG	0xC011F16
 	
 	char		*cnf_file;	/* Configuration file to parse, default is DEFAULT_CONF_FILE */
@@ -178,4 +178,27 @@
 	(((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
 
+/* Constants for the peer_info structure bellow */
+#define PI_P3_DEFAULT	0	/* Use any available protocol */
+#define PI_P3_IP	1	/* Use only IP to connect to this peer */
+#define PI_P3_IPv6	2	/* resp, IPv6 */
+
+#define PI_P4_DEFAULT	0	/* Attempt any available protocol */
+#define PI_P4_TCP	1	/* Only use TCP */
+#define PI_P4_SCTP	2	/* Only use SCTP */
+
+#define PI_ALGPREF_SCTP	0	/* SCTP is  attempted first (default) */
+#define PI_ALGPREF_TCP	1	/* TCP is attempted first */
+
+#define PI_SEC_DEFAULT	0	/* New TLS security (handshake after connection, protecting also CER/CEA) */
+#define PI_SEC_NONE	1	/* Transparent security with this peer (IPsec) */
+#define PI_SEC_TLS_OLD	2	/* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */
+				/* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */
+
+#define PI_EXP_NONE	0	/* the peer entry does not expire */
+#define PI_EXP_INACTIVE	1	/* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
+
+#define PI_PRST_NONE	0	/* the peer entry is deleted after disconnection / error */
+#define PI_PRST_ALWAYS	1	/* the peer entry is persistant (will be kept as ZOMBIE in case of error) */
+			
 /* Information about a remote peer */
 struct peer_info {
@@ -185,30 +208,10 @@
 	struct {
 		struct {
-			#define PI_P3_DEFAULT	0	/* Use any available protocol */
-			#define PI_P3_IP	1	/* Use only IP to connect to this peer */
-			#define PI_P3_IPv6	2	/* resp, IPv6 */
-			unsigned	pro3 :2;
-
-			#define PI_P4_DEFAULT	0	/* Attempt any available protocol */
-			#define PI_P4_TCP	1	/* Only use TCP */
-			#define PI_P4_SCTP	2	/* Only use SCTP */
-			unsigned	pro4 :2;
-
-			#define PI_ALGPREF_SCTP	0	/* SCTP is  attempted first (default) */
-			#define PI_ALGPREF_TCP	1	/* TCP is attempted first */
-			unsigned	alg :1;
-
-			#define PI_SEC_DEFAULT	0	/* New TLS security (handshake after connection, protecting also CER/CEA) */
-			#define PI_SEC_NONE	1	/* Transparent security with this peer (IPsec) */
-			#define PI_SEC_TLS_OLD	2	/* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */
-			unsigned	sec :2;		/* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */
-
-			#define PI_EXP_NONE	0	/* the peer entry does not expire */
-			#define PI_EXP_INACTIVE	1	/* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
-			unsigned	exp :1;
-
-			#define PI_PRST_NONE	0	/* the peer entry is deleted after disconnection / error */
-			#define PI_PRST_ALWAYS	1	/* the peer entry is persistant (will be kept as ZOMBIE in case of error) */
-			unsigned	persist :1;
+			unsigned	pro3 :2;	/* PI_P3_* */
+			unsigned	pro4 :2;	/* PI_P4_* */
+			unsigned	alg :1;		/* PI_ALGPREF_* */
+			unsigned	sec :2;		/* PI_SEC_* */
+			unsigned	exp :1;		/* PI_EXP_* */
+			unsigned	persist :1;	/* PI_PRST_* */
 			
 		}		pic_flags;	/* Flags influencing the connection to the remote peer */
