changeset 83:c662d3eb6ff6

Started support for routing module
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 02 Dec 2009 18:28:28 +0900
parents b6344f1d521a
children 03740d31e56e
files freeDiameter/fD.h include/freeDiameter/freeDiameter.h include/freeDiameter/libfreeDiameter.h libfreeDiameter/CMakeLists.txt libfreeDiameter/lists.c libfreeDiameter/messages.c
diffstat 6 files changed, 104 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/freeDiameter/fD.h	Wed Dec 02 14:20:38 2009 +0900
+++ b/freeDiameter/fD.h	Wed Dec 02 18:28:28 2009 +0900
@@ -166,7 +166,6 @@
 		pthread_t	p_ini_thr;	/* Initiator thread for establishing a connection */
 		struct fd_list  p_connparams;	/* The list of connection attempts, see p_cnx.c */
 	};
-		
 	
 	/* connection context: socket and related information */
 	struct cnxctx	*p_cnxctx;
--- a/include/freeDiameter/freeDiameter.h	Wed Dec 02 14:20:38 2009 +0900
+++ b/include/freeDiameter/freeDiameter.h	Wed Dec 02 18:28:28 2009 +0900
@@ -426,17 +426,66 @@
 
 
 /***************************************/
+/*          Routing module             */
+/***************************************/
+
+/* This file contains the definitions of types and functions involved in the routing decisions in freeDiameter,
+ * and that can be called by extensions. 
+ *
+ * Three different type of messages must be distinguished:
+ *  - Messages received, and the peer is final recipient (IN messages)
+ *  - Messages received, and the peer is not final recipient (FWD messages)
+ *  - Message is locally generated (OUT messages)
+ *
+ * There are three global message queues (in queues.c) and also peers-specific queues (in struct fd_peer).
+ *
+ * (*) IN messages processing details:
+ *   - the message is received from the remote peer, a FDEVP_CNX_MSG_RECV event is generated for the peer.
+ *   - the PSM thread parses the buffer, does some verifications, handles non routable messages (fd_msg_is_routable)
+ *   - routable messages are queued in the fd_g_incoming global queue.
+ *   - a thread (routing-in) picks the message and takes the decision if it is handled locally or forwarded, 
+ *       based on local capabilities (registered by extensions).
+ *   - If the message is handled locally, it is queued in fd_g_local.
+ *   - Another thread (dispatch.c) will handle this message and pass it to registered callbacks (see fd_disp_register in libfreeDiameter.h).
+ *
+ * (*) FWD messages details:
+ *   - The process is the same as for IN messages, until the routing-in threads makes its decision that the message is not handled locally.
+ *   - All callbacks registered with fd_rt_fwd_register are called for the message (see bellow).
+ *     - these callbacks will typically do proxying work. Note that adding the route-record is handled by the daemon.
+ *   - Once all callbacks have been called, the message is queued in the global fd_g_outgoing queue.
+ *   - The remaining processing is the same as for OUT messages, as described bellow.
+ *
+ * (*) OUT messages details:
+ *   - The message are picked from fd_g_outgoing, as result of forwarding process or call to fd_msg_send.
+ *   - The (routing-out) thread builds a list of possible destinations for the message.
+ *     The logic to build this list is as follow:
+ *      - create a list of all known peers in the "OPEN" state.
+ *      - remove from that list all peers that are in a Route-Record AVP of the message, to avoid routing loops.
+ *      - remove also all peers that have previously replied an error message for this message.
+ *   - If the list is empty, create an error UNABLE_TO_DELIVER (note: should we trig dynamic discovery here???) and reply this.
+ *   - Otherwise, call all callbacks registered by function fd_rt_out_register, with the list of peers and the message.
+ *   - Order the resulting list of peers by score (see bellow), and sent the message to the peer with highest (positive) score.
+ *    - in case the peer is no longer in the "OPEN" state, send the message to the second peer in the list.
+ *      - if no peer is in OPEN state anymore, restart the process of creating the list.
+ *   - The peer thread will handle the creation of the Hop-by-hop ID and sending the message.
+ *
+ * This part of the API (routing-api.h) provides the definitions of the rt_out_cb_t and rt_fwd_cb_t callbacks, and the
+ * functions to register and deregister these callbacks.
+ */
+
+
+
+/***************************************/
 /*   Events helpers                    */
 /***************************************/
 
-/* Events */
 struct fd_event {
 	int	 code; /* codespace depends on the queue */
 	size_t 	 size;
 	void    *data;
 };
 
-/* Daemon's codespace: 1000->1999 */
+/* Daemon's codespace: 1000->1999 (1500->1999 defined in fD.h) */
 enum {
 	 FDEV_TERMINATE	= 1000	/* request to terminate */
 	,FDEV_DUMP_DICT		/* Dump the content of the dictionary */
--- a/include/freeDiameter/libfreeDiameter.h	Wed Dec 02 14:20:38 2009 +0900
+++ b/include/freeDiameter/libfreeDiameter.h	Wed Dec 02 18:28:28 2009 +0900
@@ -1612,6 +1612,43 @@
 
 
 /*============================================================*/
+/*                         ROUTING                            */
+/*============================================================*/
+
+/* The following functions are helpers for the routing module. 
+  The routing data is stored in the message it-self. */
+
+/* Structure that contains the routing data for a message */
+struct rt_data;
+
+/* Following functions are helpers to create the routing data of a message */
+int  fd_rtd_init(struct rt_data ** rtd);
+void fd_rtd_free(struct rt_data ** rtd);
+
+/* Add a peer to the candidates list */
+int  fd_rtd_candidate_add(struct rt_data * rtd, char * peerid);
+
+/* Remove a peer from the candidates (if it is found) */
+void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */);
+
+/* If a peer returned a protocol error for this message, save it so that we don't try to send it there again */
+int  fd_rtd_error_add(struct rt_data * rtd, char * sentto, uint8_t * origin, size_t originsz, uint32_t rcode);
+
+/* Extract the list of valid candidates, and initialize their scores to 0 */
+void fd_rtd_candidate_extract(struct rt_data * rtd, struct fd_list ** candidates);
+
+/* The extracted list items have the following structure: */
+struct rtd_candidate {
+	struct fd_list	chain;	/* link in the list returned by the previous fct */
+	char *		diamid;	/* the diameter Id of the peer */
+	int		score;	/* the current routing score for this peer, see fd_rt_out_register definition for details */
+};
+
+/* Reorder the list of peers */
+int  fd_rtd_candidate_reorder(struct fd_list * candidates);
+
+
+/*============================================================*/
 /*                         MESSAGES                           */
 /*============================================================*/
 
@@ -1958,8 +1995,8 @@
  *  0 	  : ok
  *  EINVAL: a parameter is invalid
  */
-int fd_msg_rt_associate( struct msg * msg, struct fd_list ** list );
-int fd_msg_rt_get      ( struct msg * msg, struct fd_list ** list );
+int fd_msg_rt_associate( struct msg * msg, struct rt_data ** rtd );
+int fd_msg_rt_get      ( struct msg * msg, struct rt_data ** rtd );
 
 /*
  * FUNCTION:	fd_msg_is_routable
--- a/libfreeDiameter/CMakeLists.txt	Wed Dec 02 14:20:38 2009 +0900
+++ b/libfreeDiameter/CMakeLists.txt	Wed Dec 02 18:28:28 2009 +0900
@@ -11,6 +11,7 @@
 	lists.c
 	log.c
 	messages.c
+	rt_data.c
 	sessions.c
 	)
 
--- a/libfreeDiameter/lists.c	Wed Dec 02 14:20:38 2009 +0900
+++ b/libfreeDiameter/lists.c	Wed Dec 02 18:28:28 2009 +0900
@@ -86,7 +86,6 @@
 	ref->prev         = senti->prev;
 	senti->prev = senti;
 	senti->next = senti;
-	
 }
 
 /* insert before a reference, checks done */
--- a/libfreeDiameter/messages.c	Wed Dec 02 14:20:38 2009 +0900
+++ b/libfreeDiameter/messages.c	Wed Dec 02 18:28:28 2009 +0900
@@ -117,7 +117,7 @@
 	uint8_t			*msg_rawbuffer;		/* data buffer that was received, saved during fd_msg_parse_buffer and freed in fd_msg_parse_dict */
 	int			 msg_routable;		/* Is this a routable message? (0: undef, 1: routable, 2: non routable) */
 	struct msg		*msg_query;		/* the associated query if the message is a received answer */
-	struct fd_list		*msg_rtlist;		/* Routing list for the query */
+	struct rt_data		*msg_rtdata;		/* Routing list for the query */
 	struct {
 			void (*fct)(void *, struct msg **);
 			void * data;
@@ -568,14 +568,8 @@
 		free(_M(obj)->msg_src_id);
 	}
 	
-	if ((obj->type == MSG_MSG) && (_M(obj)->msg_rtlist != NULL)) {
-		while (! FD_IS_LIST_EMPTY(_M(obj)->msg_rtlist) ) {
-			struct fd_list * li = _M(obj)->msg_rtlist->next;
-			fd_list_unlink(li);
-			free(li);
-		}
-
-		free(_M(obj)->msg_rtlist);
+	if ((obj->type == MSG_MSG) && (_M(obj)->msg_rtdata != NULL)) {
+		fd_rtd_free(&_M(obj)->msg_rtdata);
 	}
 	
 	/* free the object */
@@ -1030,26 +1024,26 @@
 }	
 
 /* Associate routing lists */
-int fd_msg_rt_associate( struct msg * msg, struct fd_list ** list )
+int fd_msg_rt_associate( struct msg * msg, struct rt_data ** rtd )
 {
-	TRACE_ENTRY( "%p %p", msg, list );
+	TRACE_ENTRY( "%p %p", msg, rtd );
 	
-	CHECK_PARAMS(  CHECK_MSG(msg) && list  );
+	CHECK_PARAMS(  CHECK_MSG(msg) && rtd  );
 	
-	msg->msg_rtlist = *list;
-	*list = NULL;
+	msg->msg_rtdata = *rtd;
+	*rtd = NULL;
 	
 	return 0;
 }
 
-int fd_msg_rt_get( struct msg * msg, struct fd_list ** list )
+int fd_msg_rt_get( struct msg * msg, struct rt_data ** rtd )
 {
-	TRACE_ENTRY( "%p %p", msg, list );
+	TRACE_ENTRY( "%p %p", msg, rtd );
 	
-	CHECK_PARAMS(  CHECK_MSG(msg) && list  );
+	CHECK_PARAMS(  CHECK_MSG(msg) && rtd  );
 	
-	*list = msg->msg_rtlist;
-	msg->msg_rtlist = NULL;
+	*rtd = msg->msg_rtdata;
+	msg->msg_rtdata = NULL;
 	
 	return 0;
 }	
"Welcome to our mercurial repository"