Index: doc/rt_default.conf.sample
===================================================================
--- doc/rt_default.conf.sample	(revision 1197)
+++ doc/rt_default.conf.sample	(revision 1336)
@@ -2,4 +2,8 @@
 #
 # This extension provides configurable routing properties for freeDiameter.
+
+# This extension supports configuration reload at runtime. Send
+# signal SIGUSR1 to the process to cause the process to reload its
+# config.
 
 # Lines starting with a # are comments and ignored.
Index: extensions/rt_default/rt_default.c
===================================================================
--- extensions/rt_default/rt_default.c	(revision 1235)
+++ extensions/rt_default/rt_default.c	(revision 1336)
@@ -38,5 +38,15 @@
  */
 
+#include <signal.h>
+
 #include "rt_default.h"
+
+#define MODULE_NAME "rt_default"
+
+#include <pthread.h>
+
+static pthread_rwlock_t rtd_lock;
+
+static char *rtd_config_file;
 
 /* The callback called on new messages */
@@ -45,13 +55,23 @@
 	struct msg * msg = *pmsg;
 	TRACE_ENTRY("%p %p %p", cbdata, msg, candidates);
+	int ret;
 	
 	CHECK_PARAMS(msg && candidates);
-	
+
+	if (pthread_rwlock_rdlock(&rtd_lock) != 0) {
+		fd_log_notice("%s: read-lock failed, skipping handler", MODULE_NAME);
+		return 0;
+	}
 	/* Simply pass it to the appropriate function */
 	if (FD_IS_LIST_EMPTY(candidates)) {
-		return 0;
+		ret = 0;
 	} else {
-		return rtd_process( msg, candidates );
+		ret = rtd_process( msg, candidates );
 	}
+	if (pthread_rwlock_unlock(&rtd_lock) != 0) {
+		fd_log_notice("%s: read-unlock failed after rtd_out, exiting", MODULE_NAME);
+		exit(1);
+	}
+	return ret;
 }
 
@@ -59,9 +79,44 @@
 static struct fd_rt_out_hdl * rtd_hdl = NULL;
 
+static volatile int in_signal_handler = 0;
+
+/* signal handler */
+static void sig_hdlr(void)
+{
+	if (in_signal_handler) {
+		fd_log_error("%s: already handling a signal, ignoring new one", MODULE_NAME);
+		return;
+	}
+	in_signal_handler = 1;
+
+	if (pthread_rwlock_wrlock(&rtd_lock) != 0) {
+		fd_log_error("%s: locking failed, aborting config reload", MODULE_NAME);
+		return;
+	}
+	rtd_conf_reload(rtd_config_file);
+	if (pthread_rwlock_unlock(&rtd_lock) != 0) {
+		fd_log_error("%s: unlocking failed after config reload, exiting", MODULE_NAME);
+		exit(1);
+	}		
+
+	fd_log_notice("%s: reloaded configuration", MODULE_NAME);
+
+	in_signal_handler = 0;
+}
+
+
 /* entry point */
 static int rtd_entry(char * conffile)
 {
 	TRACE_ENTRY("%p", conffile);
-	
+
+	rtd_config_file = conffile;
+	pthread_rwlock_init(&rtd_lock, NULL);
+
+	if (pthread_rwlock_wrlock(&rtd_lock) != 0) {
+		fd_log_notice("%s: write-lock failed, aborting", MODULE_NAME);
+		return EDEADLK;
+	}
+
 	/* Initialize the repo */
 	CHECK_FCT( rtd_init() );
@@ -69,5 +124,13 @@
 	/* Parse the configuration file */
 	CHECK_FCT( rtd_conf_handle(conffile) );
-	
+
+	if (pthread_rwlock_unlock(&rtd_lock) != 0) {
+		fd_log_notice("%s: write-unlock failed, aborting", MODULE_NAME);
+		return EDEADLK;
+	}
+
+	/* Register reload callback */
+	CHECK_FCT(fd_event_trig_regcb(SIGUSR1, MODULE_NAME, sig_hdlr));
+
 #if 0
 	/* Dump the rules */
@@ -92,8 +155,10 @@
 	/* Destroy the data */
 	rtd_fini();
-	
+
+	pthread_rwlock_destroy(&rtd_lock);
+
 	/* Done */
 	return ;
 }
 
-EXTENSION_ENTRY("rt_default", rtd_entry);
+EXTENSION_ENTRY(MODULE_NAME, rtd_entry);
Index: extensions/rt_default/rt_default.h
===================================================================
--- extensions/rt_default/rt_default.h	(revision 741)
+++ extensions/rt_default/rt_default.h	(revision 1336)
@@ -83,4 +83,7 @@
 int rtd_process( struct msg * msg, struct fd_list * candidates );
 
+/* Reload the config file */
+void rtd_conf_reload(char *config_file);
+
 /* For debug: dump the rule repository */
 void rtd_dump(void);
Index: extensions/rt_default/rtd_conf.y
===================================================================
--- extensions/rt_default/rtd_conf.y	(revision 1127)
+++ extensions/rt_default/rtd_conf.y	(revision 1336)
@@ -55,4 +55,5 @@
 /* Forward declaration */
 int yyparse(char * conffile);
+void rtd_confrestart(FILE *input_file);
 
 static int rules_added = 0;
@@ -66,14 +67,16 @@
 	TRACE_ENTRY("%p", conffile);
 	
-	TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile);
-	
+	TRACE_DEBUG (FULL, "rt_default: Parsing configuration file: %s...", conffile);
+
+	rules_added = 0;
 	rtd_confin = fopen(conffile, "r");
 	if (rtd_confin == NULL) {
 		ret = errno;
 		fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret));
-		TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file.");
+		TRACE_DEBUG (INFO, "rt_default: Error occurred, message logged -- configuration file.");
 		return ret;
 	}
 
+	rtd_confrestart(rtd_confin);
 	ret = yyparse(conffile);
 
@@ -81,8 +84,8 @@
 
 	if (ret != 0) {
-		TRACE_DEBUG (INFO, "Unable to parse the configuration file.");
+		TRACE_DEBUG (INFO, "rt_default: Unable to parse the configuration file.");
 		return EINVAL;
 	} else {
-		TRACE_DEBUG(FULL, "Added %d RULES routing entries successfully.", rules_added);
+		TRACE_DEBUG(INFO, "rt_default: Added %d RULES routing entries successfully.", rules_added);
 	}
 	
@@ -96,5 +99,5 @@
 void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
 {
-	TRACE_DEBUG(INFO, "Error in configuration parsing");
+	TRACE_DEBUG(INFO, "rt_default: Error in configuration parsing");
 	
 	if (ploc->first_line != ploc->last_line)
Index: extensions/rt_default/rtd_rules.c
===================================================================
--- extensions/rt_default/rtd_rules.c	(revision 1179)
+++ extensions/rt_default/rtd_rules.c	(revision 1336)
@@ -47,5 +47,5 @@
  *  Under each TARGET element, we have the list of RULES that are defined for this target, ordered by CRITERIA type, then is_regex, then string value.
  *
- * Note: Except during configuration parsing and module termination, the lists are only ever accessed read-only, so we do not need a lock.
+ * Note: Access these only when holding rtd_lock; config reload may change the underlying data.
  */
 
@@ -390,10 +390,7 @@
 }
 
-/* Destroy the module's data */
-void rtd_fini(void)
+static void free_targets(void)
 {
 	int i;
-	
-	TRACE_ENTRY();
 
 	for (i = 0; i < RTD_TAR_MAX; i++) {
@@ -402,5 +399,12 @@
 		}
 	}
-	
+}
+
+/* Destroy the module's data */
+void rtd_fini(void)
+{
+	TRACE_ENTRY();
+
+	free_targets();
 }
 
@@ -493,4 +497,38 @@
 	
 	return 0;
+}
+
+void rtd_conf_reload(char *config_file)
+{
+	/* save old config in case reload goes wrong */
+	struct fd_list old_config[RTD_TAR_MAX];
+	int i;
+
+	for (i = 0; i < RTD_TAR_MAX; i++) {
+		old_config[i] = TARGETS[i];
+	}
+	memset(TARGETS, 0, sizeof(*TARGETS) * RTD_TAR_MAX);
+	for (i = 0; i < RTD_TAR_MAX; i++) {
+		fd_list_init(&TARGETS[i], NULL);
+	}
+
+	if (rtd_conf_handle(config_file) != 0) {
+		fd_log_notice("rt_default: error reloading configuration, restoring previous configuration");
+		free_targets();
+		for (i = 0; i < RTD_TAR_MAX; i++) {
+			TARGETS[i] = old_config[i];
+		}
+	} else {
+		/* this has to be done in this weird way because the items contain back pointers referencing TARGETS */
+		struct fd_list save_config[RTD_TAR_MAX];
+		for (i = 0; i < RTD_TAR_MAX; i++) {
+			save_config[i] = TARGETS[i];
+			TARGETS[i] = old_config[i];
+		}
+		free_targets();
+		for (i = 0; i < RTD_TAR_MAX; i++) {
+			TARGETS[i] = save_config[i];
+		}
+	}
 }
 
