Index: doc/freediameter.conf.sample
===================================================================
--- doc/freediameter.conf.sample	(revision 1326)
+++ doc/freediameter.conf.sample	(revision 1396)
@@ -88,4 +88,17 @@
 # Default: 5 unidentified clients in paralel.
 #ThreadsPerServer = 5;
+
+# If this host is used as relay or proxy, it can be useful to limit
+# connections from "outside" until enough processing nodes are available.
+# This parameter defines a regex pattern for recognizing such nodes;
+# Default: NO DEFAULT
+#ProcessingPeersPattern = "worker[0-9]*.example.com";
+
+# This next parameter defines how many of these processing peers
+# must be connected before CERs from other hosts are accepted.
+# If this is set, ProcessingPeersPattern must also be defined.
+# If unset or less than 1, ProcessingPeersPattern and this variable do nothing.
+# Default: 0
+#ProcessingPeersMinimum = 0;
 
 ##############################################################
Index: include/freeDiameter/libfdcore.h
===================================================================
--- include/freeDiameter/libfdcore.h	(revision 1329)
+++ include/freeDiameter/libfdcore.h	(revision 1396)
@@ -45,4 +45,5 @@
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
+#include <regex.h>
 
 /* GNUTLS version */
@@ -133,4 +134,6 @@
 	struct fd_list	 cnf_endpoints;	/* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all). After servers are started, this is the actual list of endpoints including port information. */
 	int		 cnf_thr_srv;	/* Number of threads per servers handling the connection state machines */
+	int		 cnf_processing_peers_minimum;	/* Number of processing peers that must be connected before other peers may connect */
+	regex_t		 cnf_processing_peers_pattern_regex;	/* Regex pattern for identifying processing peers */
 	struct fd_list	 cnf_apps;	/* Applications locally supported (except relay, see flags). Use fd_disp_app_support to add one. list of struct fd_app. */
 	uint16_t	 cnf_dispthr;	/* Number of dispatch threads to create */
Index: libfdcore/config.c
===================================================================
--- libfdcore/config.c	(revision 1326)
+++ libfdcore/config.c	(revision 1396)
@@ -60,4 +60,5 @@
 	fd_g_config->cnf_sctp_str = 30;
 	fd_g_config->cnf_thr_srv  = 5;
+	fd_g_config->cnf_processing_peers_minimum = 0;
 	fd_g_config->cnf_dispthr  = 4;
 	fd_list_init(&fd_g_config->cnf_endpoints, NULL);
@@ -102,4 +103,5 @@
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of clients thr .. : %d\n", fd_g_config->cnf_thr_srv), return NULL);
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of app threads .. : %hu\n", fd_g_config->cnf_dispthr), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Minimal processing peers : %hu\n", fd_g_config->cnf_processing_peers_minimum), return NULL);
 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : Default (use all available)\n"), return NULL);
Index: libfdcore/fdd.l
===================================================================
--- libfdcore/fdd.l	(revision 1394)
+++ libfdcore/fdd.l	(revision 1396)
@@ -257,4 +257,6 @@
 (?i:"ListenOn")		{ return LISTENON; }
 (?i:"ThreadsPerServer")	{ return THRPERSRV; }
+(?i:"ProcessingPeersPattern")	{ return PROCESSINGPEERSPATTERN; }
+(?i:"ProcessingPeersMinimum")	{ return PROCESSINGPEERSMINIMUM; }
 (?i:"TcTimer")		{ return TCTIMER; }
 (?i:"TwTimer")		{ return TWTIMER; }
Index: libfdcore/fdd.y
===================================================================
--- libfdcore/fdd.y	(revision 1326)
+++ libfdcore/fdd.y	(revision 1396)
@@ -110,4 +110,6 @@
 %token		LISTENON
 %token		THRPERSRV
+%token		PROCESSINGPEERSPATTERN
+%token		PROCESSINGPEERSMINIMUM
 %token		TCTIMER
 %token		TWTIMER
@@ -142,4 +144,6 @@
 			| conffile listenon
 			| conffile thrpersrv
+			| conffile processingpeerspattern
+			| conffile processingpeersminimum
 			| conffile norelay
 			| conffile appservthreads
@@ -250,4 +254,43 @@
 					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
 				conf->cnf_thr_srv = $3;
+			}
+			;
+
+processingpeerspattern:		PROCESSINGPEERSPATTERN '=' QSTRING ';'
+			{
+				char *pattern = $3;
+				int err;
+				CHECK_FCT_DO( err=regcomp(&conf->cnf_processing_peers_pattern_regex, pattern, REG_EXTENDED | REG_NOSUB),
+					{
+						char * buf;
+						size_t bl;
+
+						/* Error while compiling the regex */
+						TRACE_DEBUG(INFO, "error while compiling the regular expression '%s':", pattern);
+
+						/* Get the error message size */
+						bl = regerror(err, &conf->cnf_processing_peers_pattern_regex, NULL, 0);
+
+						/* Alloc the buffer for error message */
+						CHECK_MALLOC( buf = malloc(bl) );
+
+						/* Get the error message content */
+						regerror(err, &conf->cnf_processing_peers_pattern_regex, buf, bl);
+						TRACE_DEBUG(INFO, "\t%s", buf);
+
+						/* Free the buffer, return the error */
+						free(buf);
+
+						yyerror (&yylloc, conf, "Invalid regular expression in ProcessingPeersPattern");
+						YYERROR;
+					} );
+			}
+			;
+
+processingpeersminimum:		PROCESSINGPEERSMINIMUM '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 >= 0),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_processing_peers_minimum = $3;
 			}
 			;
Index: libfdcore/p_ce.c
===================================================================
--- libfdcore/p_ce.c	(revision 1281)
+++ libfdcore/p_ce.c	(revision 1396)
@@ -834,4 +834,24 @@
 }
 
+/* Check if enough processing peers are connected to allow connections by other peers */
+static int sufficient_processing_peers(void) {
+	int processing_peers_count = 0;
+	struct fd_list * li;
+
+	CHECK_FCT( pthread_rwlock_rdlock(&fd_g_activ_peers_rw) );
+	for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
+		struct fd_peer * p = (struct fd_peer *)li->o;
+
+		TRACE_DEBUG(FULL, "comparing '%s' against processing peers pattern", p->p_hdr.info.pi_diamid);
+		if (regexec(&fd_g_config->cnf_processing_peers_pattern_regex, p->p_hdr.info.pi_diamid, 0, NULL, 0) == 0) {
+			processing_peers_count++;
+		}
+	}
+	CHECK_FCT( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
+
+	TRACE_DEBUG(FULL, "%d processing peers found", processing_peers_count);
+	return (processing_peers_count >= fd_g_config->cnf_processing_peers_minimum);
+}
+
 /* Handle the receiver side to go to OPEN or OPEN_NEW state (any election is resolved) */
 int fd_p_ce_process_receiver(struct fd_peer * peer)
@@ -884,4 +904,24 @@
 	}
 	
+	/* Check peer type and if enough processing peers are already connected */
+	if (fd_g_config->cnf_processing_peers_minimum > 0) {
+		if (regexec(&fd_g_config->cnf_processing_peers_pattern_regex, peer->p_hdr.info.pi_diamid, 0, NULL, 0) != 0) {
+			/* peer is not a processing peer */
+			if (!sufficient_processing_peers()) {
+				pei.pei_errcode = "DIAMETER_TOO_BUSY";
+				goto error_abort;
+			}
+		}
+	}
+
+	if (peer->p_flags.pf_responder) {
+		int res = fd_peer_validate( peer );
+		if (res < 0) {
+			TRACE_DEBUG(INFO, "Rejected CER from peer '%s', validation failed (returning DIAMETER_UNKNOWN_PEER).", peer->p_hdr.info.pi_diamid);
+			pei.pei_errcode = "DIAMETER_UNKNOWN_PEER";
+			goto error_abort;
+		}
+		CHECK_FCT( res );
+	}
 	/* Check if we have common applications */
 	if ( fd_g_config->cnf_flags.no_fwd && (! peer->p_hdr.info.runtime.pir_relay) ) {
