# HG changeset patch # User Sebastien Decugis # Date 1259746108 -32400 # Node ID c662d3eb6ff611c6f4e06cece5233963d5029c8b # Parent b6344f1d521a3db9d6fc3f21fb4030a571ac3ebb Started support for routing module diff -r b6344f1d521a -r c662d3eb6ff6 freeDiameter/fD.h --- 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; diff -r b6344f1d521a -r c662d3eb6ff6 include/freeDiameter/freeDiameter.h --- 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 */ diff -r b6344f1d521a -r c662d3eb6ff6 include/freeDiameter/libfreeDiameter.h --- 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 diff -r b6344f1d521a -r c662d3eb6ff6 libfreeDiameter/CMakeLists.txt --- 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 ) diff -r b6344f1d521a -r c662d3eb6ff6 libfreeDiameter/lists.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 */ diff -r b6344f1d521a -r c662d3eb6ff6 libfreeDiameter/messages.c --- 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; }