view extensions/rt_default/rt_default.c @ 400:22f29007b931

Detect when extensions are loaded several times (not allowed)
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 02 Jun 2009 14:49:37 +0900
parents 316bb3f38d04
children
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2009, 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.								 *
*********************************************************************************************************/

/* 
 * Basic routing of the messages based on their Destination-Realm, Destination-Host, and configuration file.
 */

#define DECLARE_API_POINTERS
#include "rt_default.h"

static dict_object_t * dict_avp_DH  = NULL; /* Destination-Host */
static dict_object_t * dict_avp_DR  = NULL; /* Destination-Realm */

int rt_default_verbosity = 0;

/* Analyze a message content to find Destination-Realm and Destination-Host */
static int find_avps(msg_t * msg, avp_value_t ** dr, avp_value_t ** dh)
{
	int ret = 0;
	msg_avp_t * avp = NULL;
	msg_avp_data_t * avpdata;

	/* Destination-Host */
	ret = msg_search_avp( msg, dict_avp_DH, &avp );
	if (ret != 0) {
		TRACE_DEBUG(INFO, "Error in msg_search_avp: %s", strerror(ret));
		return ret;
	}
	
	if (avp != NULL) {
		ret = msg_avp_data( avp, &avpdata );
		if (ret != 0) {
			TRACE_DEBUG(INFO, "Error in msg_avp_data: %s", strerror(ret));
			return ret;
		}
		*dh = avpdata->avp_data;
	}
		
	/* Destination-Realm */
	ret = msg_search_avp( msg, dict_avp_DR, &avp );
	if (ret != 0) {
		TRACE_DEBUG(INFO, "Error in msg_search_avp: %s", strerror(ret));
		return ret;
	}
	
	if (avp != NULL) {
		ret = msg_avp_data( avp, &avpdata );
		if (ret != 0) {
			TRACE_DEBUG(INFO, "Error in msg_avp_data: %s", strerror(ret));
			return ret;
		}
		*dr = avpdata->avp_data;
	}
	
	return 0;
}

/* The callback doing all the work */
static int cb_def_out(void * data, msg_t * msg, rt_dpl_t * list )
{
	int ret = 0;
	avp_value_t * dr = NULL;
	avp_value_t * dh = NULL;
	rt_dpl_t * candidate = list;
	
	TRACE_ENTRY("%p %p", msg, list);
	
	/* First find Destination Realm and Destination Host AVPs in msg */
	ret = find_avps(msg, &dr, &dh);
	if (ret != 0) {
		TRACE_DEBUG(INFO, "Failed to analyze the message: %s", strerror(ret));
		return ret;
	}
	
	/* Then for each candidate peer for routing */
	while (candidate != NULL) {
		char * candname = NULL; /* name of this candidate peer */
		int tablescore = 0;
		
		ret = peer_get(candidate->peer, PEER_DIAMETER_ID, (void *)&candname);
		if (ret != 0) {
			TRACE_DEBUG(INFO, "Unable to retrieve peer name: %s", strerror(ret));
			return ret;
		}
		
		/* Is destination host ? */
		if ((rtd_conf->do_dest_host) && (dh != NULL)) {
			if ((dh->os.len == strlen(candname)) &&
				(strncasecmp(candname, (char *)dh->os.data, dh->os.len) == 0)) {
				TRACE_DEBUG(FULL, "Peer '%s' is Destination-Host, adding appropriate score", candname);
				candidate->score += rtd_conf->sc_dest_host;
			}
		}
	
		/* Is matching destination realm ? */
		if ((rtd_conf->do_dest_realm) && (dr != NULL)) {
			char * candrealm = NULL; /* realm of this candidate peer */
			
			ret = peer_get(candidate->peer, PEER_REALM, (void *)&candrealm);
			if (ret != 0) {
				TRACE_DEBUG(INFO, "Unable to retrieve peer realm: %s", strerror(ret));
				return ret;
			}
			
			if ((dr->os.len == strlen(candrealm)) &&
				(strncasecmp(candrealm, (char *)dr->os.data, dr->os.len) == 0)) {
				TRACE_DEBUG(FULL, "Peer '%s' has matching Destination-Realm, adding appropriate score", candname);
				candidate->score += rtd_conf->sc_dest_realm;
			}
		}
	
		/* Is defined in configuration as a default route ? */
		ret = rtd_search( dr ? dr->os.data : NULL, dr ? dr->os.len : 0, candname, &tablescore);
		if (ret != 0) {
			TRACE_DEBUG(INFO, "Internal extension error, search failed: %s", strerror(ret));
			return ret;
		}
		candidate->score += tablescore;
		
		/* Move to next candidate */
		candidate = candidate->next;
	}
	
	return 0;
}

/* Initialize the configuration */
rtd_conf_t * rtd_conf = NULL;
static rtd_conf_t _conf;

static int conf_init(void)
{
	rtd_conf = &_conf;
	memset(rtd_conf, 0, sizeof(rtd_conf_t));
	
	/* Set the default values */
	rtd_conf->do_dest_host = 1;
	rtd_conf->do_dest_realm = 1;
	
	rtd_conf->sc_dest_host = PEER_SCORE_FINALDEST;
	rtd_conf->sc_dest_realm = PEER_SCORE_DEFAULT_REALM;
	
	rtd_conf->sc_no_info = 0;
	rtd_conf->sc_all = PEER_SCORE_DEFAULT;
	rtd_conf->sc_all_pref = PEER_SCORE_DEFAULT + PEER_SCORE_LOAD_BALANCE;
	rtd_conf->sc_rlm = PEER_SCORE_DEFAULT_REALM;
	rtd_conf->sc_rlm_pref = PEER_SCORE_DEFAULT_REALM + PEER_SCORE_LOAD_BALANCE;
	
	return 0;
}

static void conf_dump(void)
{
	TRACE_DEBUG(FULL, "rt_default configuration dump:\n"
			  " Verbosity...........: %d\n"
			  " Handle Dest Host....: %d\n"
			  " Handle Dest Realm...: %d\n"
			  " Score Dest Host.....: %d\n"
			  " Score Dest Realm....: %d\n"
			  " Score no info.......: %d\n"
			  " Score default route.: %d\n"
			  " Score default pref..: %d\n"
			  " Score realm.........: %d\n"
			  " Score realm pref....: %d",
			  		  rt_default_verbosity,
					  rtd_conf->do_dest_host,
					  rtd_conf->do_dest_realm,
					  rtd_conf->sc_dest_host,
					  rtd_conf->sc_dest_realm,
					  rtd_conf->sc_no_info,
					  rtd_conf->sc_all,
					  rtd_conf->sc_all_pref,
					  rtd_conf->sc_rlm,
					  rtd_conf->sc_rlm_pref);
}

/* handler */
static rt_out_hdl_t * rt_def_hdl = NULL;

/* entry point */
static int entry(char * conffile)
{
	int ret = 0;
	
	TRACE_ENTRY("%p", conffile);
	
	ret = dict_search( DICT_AVP, AVP_BY_NAME, "Destination-Host",  &dict_avp_DH, ENOENT  );
	if (ret != 0) {
		log_error("Error initializing extension's dictionary objects: %s\n", strerror(ret));
		return ret;
	}
	
	ret = dict_search( DICT_AVP, AVP_BY_NAME, "Destination-Realm", &dict_avp_DR, ENOENT  );
	if (ret != 0) {
		log_error("Error initializing extension's dictionary objects: %s\n", strerror(ret));
		return ret;
	}
	
	ret = conf_init();
	if (ret != 0) {
		log_error("Error initializing extension: %s\n", strerror(ret));
		return ret;
	}
	
	ret = rtd_init();
	if (ret != 0) {
		log_error("Error initializing extension: %s\n", strerror(ret));
		return ret;
	}
	
	if (conffile != NULL) {
		ret = rtd_conf_handle(conffile);
		if (ret != 0) {
			log_error("Error parsing extension configuration: %s\n", strerror(ret));
			return ret;
		}
		TRACE_DEBUG(INFO, "Extension RT/Default initialized with configuration: '%s'", conffile);
		conf_dump();
		rtd_dump();
	} else {
		TRACE_DEBUG(INFO, "Extension RT/Default initialized with default configuration");
	}
		
	return rt_out_register( cb_def_out, NULL, RT_OUT_NORMAL, &rt_def_hdl );
}

/* Unload */
void waaad_ext_fini(void)
{
	rt_out_unregister ( rt_def_hdl );
	rtd_fini();
}

EXTENSION_API_INIT( API_MODULE_ALL, entry, "rt_default", 1);
"Welcome to our mercurial repository"