changeset 356:555dc5a58aef

Added server code for radius extension
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 19 May 2009 17:21:54 +0900
parents b811859f9963
children 6c2198aa037c
files extensions/radius_gw/CMakeLists.txt extensions/radius_gw/radius_gw.c extensions/radius_gw/radius_gw.h extensions/radius_gw/radius_gw.y extensions/radius_gw/radius_gw_internal.h extensions/radius_gw/rg_utils.c extensions/radius_gw/rgw_clients.c extensions/radius_gw/rgw_extensions.c extensions/radius_gw/rgw_msg.c extensions/radius_gw/rgw_servers.c extensions/radius_gw/rgw_utils.c extensions/radius_gw/rgw_work.c
diffstat 12 files changed, 693 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- a/extensions/radius_gw/CMakeLists.txt	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/CMakeLists.txt	Tue May 19 17:21:54 2009 +0900
@@ -1,6 +1,16 @@
 # The rt_default extension
 PROJECT("RADIUS/Diameter extensible gateway extension for waaad" C)
 
+
+########### Utility library #############
+# utilities libray for both the main extension and the sub extensions
+SET(RG_COMMON_SRC
+	rg_utils.c
+)
+ADD_LIBRARY(rg_common STATIC ${RG_COMMON_SRC})
+# Note : we should remove the STATIC here to avoid duplicating the code; but it is not tested yet.
+
+########### Main radius_gw extension #############
 # Parser files
 BISON_FILE(radius_gw.y)
 FLEX_FILE(radius_gw.l)
@@ -12,11 +22,11 @@
 	lex.radius_gw.c
 	radius_gw.tab.c
 	radius_gw.tab.h
-	rgw_utils.c
 	rgw_clients.c
 	rgw_extensions.c
+	rgw_servers.c
 	rgw_msg.c
-	rgw_servers.c
+	rgw_work.c
 )
 
 SET( RGW_DEFAULT_HEADER
@@ -25,7 +35,10 @@
 
 # Compile these files as a module
 ADD_LIBRARY(radius_gw MODULE ${RGW_DEFAULT_SRC} ${RGW_DEFAULT_HEADER})
+TARGET_LINK_LIBRARIES(radius_gw rg_common)
 
+
+########### Sub extensions #############
 # Example of support extension:
 # OPTION(BUILD_RADIUS_GW_2865 "Build support for RFC2865? (RADIUS base Authentication support)" ON)
 # 	IF (BUILD_RADIUS_GW_2865)
@@ -37,9 +50,11 @@
 # 		lex.2865.c
 # 		2865.tab.c
 # 		2865.tab.h)
+#          TARGET_LINK_LIBRARIES(2865 rg_common)
 # 	ENDIF (BUILD_RADIUS_GW_2865)
 
 OPTION(BUILD_RADIUS_GW_SAMPLE "Build sample sub-extension? (for debug only)" ON)
  	IF (BUILD_RADIUS_GW_SAMPLE)
  	   ADD_LIBRARY(sub_sample MODULE ${RGW_DEFAULT_HEADER} sub_sample.c)
+	   TARGET_LINK_LIBRARIES(sub_sample rg_common)
  	ENDIF (BUILD_RADIUS_GW_SAMPLE)
--- a/extensions/radius_gw/radius_gw.c	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/radius_gw.c	Tue May 19 17:21:54 2009 +0900
@@ -67,7 +67,10 @@
 	
 	/* Start making extension list accelerators */
 	rgw_extensions_start_cache();
-		
+	
+	/* Start the worker threads */
+	CHECK_FCT( rgw_work_start() );
+	
 	/* Start the servers */
 	CHECK_FCT( rgw_servers_start() );
 	
@@ -78,6 +81,7 @@
 void waaad_ext_fini(void)
 {
 	rgw_servers_fini();
+	rgw_work_fini();
 	rgw_extensions_fini();
 	rgw_clients_fini();
 }
--- a/extensions/radius_gw/radius_gw.h	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/radius_gw.h	Tue May 19 17:21:54 2009 +0900
@@ -40,11 +40,14 @@
 #ifndef _RADIUS_GW_H
 #define _RADIUS_GW_H
 
+#include <stdint.h>	/* uint8_t, etc... */
+#include <waaad/waaad.h> /* session_t, etc... */
+
 /* This type is used for all lists in this extension */
-struct rgw_list {
-	struct rgw_list *next;
-	struct rgw_list *prev;
-	struct rgw_list *head;
+struct rg_list {
+	struct rg_list *next;
+	struct rg_list *prev;
+	struct rg_list *head;
 };
 
 /**************************************************************/
@@ -57,7 +60,7 @@
 /* This type describes a RADIUS attribute */
 struct rad_attr {
 	/* Meta data */
-	struct rgw_list	chain;	/* link this attribute in a message */
+	struct rg_list	chain;	/* link this attribute in a message */
 	int		handled; /* Has this attribute already been converted to Diameter? */
 	
 	/* Data */
@@ -88,12 +91,11 @@
 /* The following type represents a complete RADIUS message (internal representation) with parsing information */
 typedef struct _rad_t {
 	/* Metadata */
-	struct rgw_list	attributes;	/* The list of attributes */
+	struct rg_list	attributes;	/* The list of attributes */
 		
 	/* Data */
 	uint8_t		code;
 	uint8_t		identifier;
-	uint16_t	length;		/* always stored in host byte-order */
 	uint8_t		authenticator[16];
 } rad_t;
 
@@ -119,25 +121,31 @@
 
 
 /**************************************************************/
-/*      Functions exported by the radius_gw extension         */
+/*      Functions exported by the common library extension    */
 /**************************************************************/
 
 /* List management */
 
-void rgw_list_init(struct rgw_list * plist);
-int rgw_list_is_empty(struct rgw_list * plist);
-void rgw_list_insert_after(struct rgw_list * ref, struct rgw_list * item);
-void rgw_list_insert_before(struct rgw_list * ref, struct rgw_list * item);
-void rgw_list_unlink(struct rgw_list * plist);
+void rg_list_init(struct rg_list * plist);
+int  rg_list_is_empty(struct rg_list * plist);
+void rg_list_insert_after(struct rg_list * ref, struct rg_list * item);
+void rg_list_insert_before(struct rg_list * ref, struct rg_list * item);
+void rg_list_unlink(struct rg_list * plist);
 
 
+/* Radius message */
+void rg_msg_free(rad_t * msg);
+
 
 /****************************************/
 /*      Debug and related stuff         */
 /****************************************/
 
-/* Verbosity level for debug */
-extern int radius_gw_verbosity;
+#include <assert.h>
+#ifndef ASSERT
+#define ASSERT(x) assert(x)
+#endif /* ASSERT */
+
 
 /* CHECK_* macro from the daemon */
 /* Helper for tracing the CHECK_* macros bellow */
--- a/extensions/radius_gw/radius_gw.y	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/radius_gw.y	Tue May 19 17:21:54 2009 +0900
@@ -334,7 +334,7 @@
 			}
 			| AUTH_IP4 '=' DISABLED ';'
 			{
-				rgw_servers.auth_serv.ipv4_disabled = 1;
+				rgw_servers.auth_serv.ip_disabled = 1;
 			}
 			| AUTH_IP4 '=' IP ';'
 			{
@@ -342,13 +342,13 @@
 					yyerror (&yylloc, conffile, "Invalid address specification !");
 					YYERROR;
 				}
-				memcpy( & rgw_servers.auth_serv.ipv4_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) );
+				memcpy( & rgw_servers.auth_serv.ip_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) );
 				free($3);
-				rgw_servers.auth_serv.ipv4_disabled = 0;
+				rgw_servers.auth_serv.ip_disabled = 0;
 			}
 			| AUTH_IP6 '=' DISABLED ';'
 			{
-				rgw_servers.auth_serv.ipv6_disabled = 1;
+				rgw_servers.auth_serv.ip6_disabled = 1;
 			}
 			| AUTH_IP6 '=' IP ';'
 			{
@@ -356,9 +356,9 @@
 					yyerror (&yylloc, conffile, "Invalid address specification !");
 					YYERROR;
 				}
-				memcpy( & rgw_servers.auth_serv.ipv6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) );
+				memcpy( & rgw_servers.auth_serv.ip6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) );
 				free($3);
-				rgw_servers.auth_serv.ipv6_disabled = 0;
+				rgw_servers.auth_serv.ip6_disabled = 0;
 			}
 			;
 
@@ -383,7 +383,7 @@
 			}
 			| ACCT_IP4 '=' DISABLED ';'
 			{
-				rgw_servers.acct_serv.ipv4_disabled = 1;
+				rgw_servers.acct_serv.ip_disabled = 1;
 			}
 			| ACCT_IP4 '=' IP ';'
 			{
@@ -391,13 +391,13 @@
 					yyerror (&yylloc, conffile, "Invalid address specification !");
 					YYERROR;
 				}
-				memcpy( & rgw_servers.auth_serv.ipv4_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) );
+				memcpy( & rgw_servers.auth_serv.ip_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) );
 				free($3);
-				rgw_servers.acct_serv.ipv4_disabled = 0;
+				rgw_servers.acct_serv.ip_disabled = 0;
 			}
 			| ACCT_IP6 '=' DISABLED ';'
 			{
-				rgw_servers.acct_serv.ipv6_disabled = 1;
+				rgw_servers.acct_serv.ip6_disabled = 1;
 			}
 			| ACCT_IP6 '=' IP ';'
 			{
@@ -405,8 +405,8 @@
 					yyerror (&yylloc, conffile, "Invalid address specification !");
 					YYERROR;
 				}
-				memcpy( & rgw_servers.auth_serv.ipv6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) );
+				memcpy( & rgw_servers.auth_serv.ip6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) );
 				free($3);
-				rgw_servers.acct_serv.ipv6_disabled = 0;
+				rgw_servers.acct_serv.ip6_disabled = 0;
 			}
 			;
--- a/extensions/radius_gw/radius_gw_internal.h	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/radius_gw_internal.h	Tue May 19 17:21:54 2009 +0900
@@ -32,6 +32,7 @@
 * 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.								 *
 *********************************************************************************************************/
+
 /* This file contains the definitions needed by the radius_gw extension alone, not exported to sub-extensions. */
   
 #ifndef _RADIUS_GW_INTERNAL_H
@@ -50,25 +51,20 @@
 #include <stdlib.h>
 #include <errno.h>
 
-#include <assert.h>
-#ifndef ASSERT
-#define ASSERT(x) assert(x)
-#endif /* ASSERT */
-
 /* API definition of waaad */
 extern waaad_api_t * waaad_api;
     
 /* The RADIUS server(s) interface */
 struct rgw_serv {
 	unsigned	disabled	:1;
-	unsigned	ipv4_disabled	:1;
-	unsigned	ipv6_disabled	:1;
+	unsigned	ip_disabled	:1;
+	unsigned	ip6_disabled	:1;
 	unsigned	:13; /* padding */
 	
 	uint16_t	port;	/* stored in network byte order */
 	
-	struct in_addr	ipv4_endpoint;
-	struct in6_addr	ipv6_endpoint;
+	struct in_addr	ip_endpoint;
+	struct in6_addr	ip6_endpoint;
 };
 
 extern struct rgw_servs {
@@ -89,6 +85,11 @@
 void rgw_clients_fini(void);
 
 
+/* Functions related to RADIUS messages buffers on the network */
+int rgw_msg_parse(unsigned char *buf, size_t len, rad_t **msg);
+int rgw_msg_gen(rad_t *msg, unsigned char **buf, size_t *len);
+
+
 /* The sub-extensions that provide functions to support RADIUS messages and attributes (see also radius_gw.h) */
 #define RGW_EXT_PORT_AUTH	1
 #define RGW_EXT_PORT_ACCT	2
@@ -102,5 +103,44 @@
 int rgw_conf_handle(char * conffile);
 
 
+/* Worker module that handle incoming RADIUS messages */
+int rgw_work_start(void);
+int rgw_work_add(rad_t * msg, void * client);
+void rgw_work_fini(void);
+
+
+/* Verbosity level for debug */
+extern int radius_gw_verbosity;
+
+
+/* Terminate a thread */
+static __inline__ int _thread_term(pthread_t * th)
+{
+	int ret = 0;
+	void * th_ret = NULL;
+	
+	CHECK_PARAMS(th);
+	
+	/* Test if it was already terminated */
+	if (*th == (pthread_t)NULL)
+		return 0;
+	
+	/* Cancel the thread if it is still running - ignore error if it was already terminated */
+	(void) pthread_cancel(*th);
+	
+	/* Then join the thread */
+	CHECK_POSIX_DO( ret = pthread_join(*th, &th_ret), /* continue */ );
+	
+	if (th_ret != NULL) {
+		TRACE_DEBUG(FULL, "The thread returned the following value: %p (ignored)", th_ret);
+	}
+	
+	/* Clean the location */
+	*th = (pthread_t)NULL;
+	
+	return ret;
+}
+
+
 #endif /* _RADIUS_GW_INTERNAL_H */
   
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rg_utils.c	Tue May 19 17:21:54 2009 +0900
@@ -0,0 +1,101 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, 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.								 *
+*********************************************************************************************************/
+
+/* Some useful functions */
+
+#include "radius_gw.h"
+
+#include <stdlib.h>
+
+void rg_list_init(struct rg_list * plist)
+{
+	ASSERT(plist != NULL);
+	plist->next = plist;
+	plist->prev = plist;
+	plist->head = plist;
+}
+
+int rg_list_is_empty(struct rg_list * plist)
+{
+	ASSERT(plist != NULL);
+	return plist == plist->next;
+}
+
+void rg_list_insert_after(struct rg_list * ref, struct rg_list * item)
+{
+	ASSERT(ref != NULL);
+	ASSERT(item != NULL);
+	ASSERT(rg_list_is_empty(item));
+	item->next = ref->next;
+	item->prev = ref;
+	item->head = ref->head;
+	ref->next->prev = item;
+	ref->next = item;
+}
+
+void rg_list_insert_before(struct rg_list * ref, struct rg_list * item)
+{
+	ASSERT(ref != NULL);
+	ASSERT(item != NULL);
+	ASSERT(rg_list_is_empty(item));
+	item->prev = ref->prev;
+	item->next = ref;
+	item->head = ref->head;
+	ref->prev->next = item;
+	ref->prev = item;
+}
+
+void rg_list_unlink(struct rg_list * plist)
+{
+	ASSERT(plist != NULL);
+	if (plist->head == plist)
+		return;
+	plist->next->prev = plist->prev;
+	plist->prev->next = plist->next;
+	plist->next = plist;
+	plist->prev = plist;
+	plist->head = plist;
+}
+
+
+void rg_msg_free(rad_t * msg)
+{
+	while ( ! rg_list_is_empty( &msg->attributes ) ) {
+		struct rg_list * item = msg->attributes.next;
+		rg_list_unlink(item);
+		free(item);
+	}
+	free(msg);	
+}
--- a/extensions/radius_gw/rgw_clients.c	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/rgw_clients.c	Tue May 19 17:21:54 2009 +0900
@@ -41,14 +41,14 @@
    For same addresses, the port is compared.
    A given address cannot be added with a 0-port and another port value.
  */
-static struct rgw_list cli_ip, cli_ip6;
+static struct rg_list cli_ip, cli_ip6;
 
 /* Mutex to protect the previous lists */
 static pthread_mutex_t cli_mtx = PTHREAD_MUTEX_INITIALIZER;
 
 /* Structure describing one client */
 struct cli_info {
-	struct rgw_list		chain;
+	struct rg_list		chain;
 	union {
 		struct sockaddr_in	*sin;
 		struct sockaddr_in6	*sin6;
@@ -70,7 +70,7 @@
 	memset(tmp, 0, sizeof(struct cli_info));
 	
 	/* Initialize the chain */
-	rgw_list_init(&tmp->chain);
+	rg_list_init(&tmp->chain);
 	
 	/* move the sa info reference */
 	if ((*ip_port)->sa_family == AF_INET)
@@ -91,13 +91,13 @@
 
 
 /* Decrease refcount on a client; the lock must be held when this function is called. */
-void rgw_clients_unlink(struct cli_info * client)
+static void cli_info_unlink(struct cli_info * client)
 {
 	client->refcount -= 1;
 	
 	if (client->refcount <= 0) {
 		/* to be sure */
-		ASSERT( rgw_list_is_empty(&client->chain) );
+		ASSERT( rg_list_is_empty(&client->chain) );
 		
 		/* Free the data */
 		free(client->sin);
@@ -106,12 +106,6 @@
 	}
 }
 
-/* Increase refcount on a client; the lock must be held when this function is called. */
-void rgw_clients_link(struct cli_info * client)
-{
-	client->refcount += 1;
-}
-
 
 /* Function to look for an existing cli_info, or the previous element. 
    The cli_mtx must be held when calling this func. 
@@ -122,7 +116,7 @@
 {
 	int ret = 0;
 	int cmp;
-	struct rgw_list *ref = NULL;
+	struct rg_list *ref = NULL;
 	
 	CHECK_PARAMS(res && ip_port);
 	
@@ -223,12 +217,45 @@
 	}
 }
 
+int rgw_clients_search(struct sockaddr * ip_port, void ** ref)
+{
+	int ret = 0;
+	struct cli_info * cli;
+	
+	TRACE_ENTRY("%p %p", ip_port, ref);
+	
+	CHECK_PARAMS(ip_port && ref);
+	*ref = NULL;
+	
+	CHECK_POSIX( pthread_mutex_lock(&cli_mtx) );
+	ret = cli_info_search(&cli, ip_port);
+	
+	if (ret == EEXIST) {
+		cli->refcount ++;
+		ret = 0;
+		*ref = cli;
+	}
+	
+	CHECK_POSIX( pthread_mutex_unlock(&cli_mtx) );
+	
+	return ret;
+}
 
+void rgw_clients_dispose(void ** ref)
+{
+	TRACE_ENTRY("%p", ref);
+	CHECK_PARAMS_DO(ref, return);
+	
+	CHECK_POSIX_DO( pthread_mutex_lock(&cli_mtx),  );
+	cli_info_unlink(*(struct cli_info **)ref);
+	*ref = NULL;
+	CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), );
+}
 
 int rgw_clients_init(void)
 {
-	rgw_list_init(&cli_ip);
-	rgw_list_init(&cli_ip6);
+	rg_list_init(&cli_ip);
+	rg_list_init(&cli_ip6);
 	return 0;
 }
 
@@ -269,9 +296,9 @@
 	if (ret == ENOENT) {
 		CHECK_FCT_DO( ret = cli_info_create( &new, &ip_port, key, keylen ), goto end );
 		
-		rgw_list_insert_after(&prev->chain, &new->chain);
+		rg_list_insert_after(&prev->chain, &new->chain);
 		
-		rgw_clients_link(new);
+		new->refcount++;
 		
 		ret = 0;
 		goto end;
@@ -325,7 +352,7 @@
 void rgw_clients_dump(void)
 {
 	struct cli_info * client = NULL;
-	struct rgw_list *ref = NULL;
+	struct rg_list *ref = NULL;
 	char ipstr[INET6_ADDRSTRLEN];
 	char keydump[60];
 	uint16_t port;
@@ -366,22 +393,22 @@
 
 void rgw_clients_fini(void)
 {
-	struct rgw_list * client;
+	struct rg_list * client;
 	
 	TRACE_ENTRY();
 	
 	CHECK_POSIX_DO( pthread_mutex_lock(&cli_mtx), /* ignore error */ );
 	
 	/* empty the lists */
-	while ( ! rgw_list_is_empty(&cli_ip) ) {
+	while ( ! rg_list_is_empty(&cli_ip) ) {
 		client = cli_ip.next;
-		rgw_list_unlink(client);
-		rgw_clients_unlink((struct cli_info *)client);
+		rg_list_unlink(client);
+		cli_info_unlink((struct cli_info *)client);
 	}
-	while (! rgw_list_is_empty(&cli_ip6)) {
+	while (! rg_list_is_empty(&cli_ip6)) {
 		client = cli_ip6.next;
-		rgw_list_unlink(client);
-		rgw_clients_unlink((struct cli_info *)client);
+		rg_list_unlink(client);
+		cli_info_unlink((struct cli_info *)client);
 	}
 	
 	CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), /* ignore error */ );
--- a/extensions/radius_gw/rgw_extensions.c	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/rgw_extensions.c	Tue May 19 17:21:54 2009 +0900
@@ -40,11 +40,11 @@
 #include <libgen.h>
 
 /* List of extensions, in the order they are written in the configuration file. */
-static struct rgw_list ext_list;
+static struct rg_list ext_list;
 
 /* Description of an extension entry */
 struct ext_descr {
-	struct rgw_list		chain; 	/* chaining in the ext_list list */
+	struct rg_list		chain; 	/* chaining in the ext_list list */
 	
 	void * 			dlo;	/* object returned by dlopen of the extension, to use with dlclose later */
 	struct radius_gw_api	api;	/* the callbacks registered by rga_register */
@@ -59,18 +59,18 @@
 };
 
 /* Accelerators for each command code (one for each port). These accelerators are built on-demand, as a cache, after start_cache function has been called.  */
-static struct rgw_list ext_accel_auth, ext_accel_acct;
+static struct rg_list ext_accel_auth, ext_accel_acct;
 
 /* accelerator list, one per command code */
 struct ext_accel {
-	struct rgw_list		chain;	/* link in the ext_accel_* list */
+	struct rg_list		chain;	/* link in the ext_accel_* list */
 	unsigned char		ccode;	/* the command code of this accelerator. The previous list is ordered according to this value. We don't handle extended CC yet */
-	struct rgw_list		extensions; /* head for the list of extensions to be called for this command code. List of ext_accel_item items */
+	struct rg_list		extensions; /* head for the list of extensions to be called for this command code. List of ext_accel_item items */
 };
 
 /* accelerator item, references to extensions */
 struct ext_accel_item {
-	struct rgw_list		chain; 	/* link in the ext_accel "extensions" list */
+	struct rg_list		chain; 	/* link in the ext_accel "extensions" list */
 	struct ext_descr *	ext;	/* pointer to the extension data */
 };
 
@@ -82,9 +82,9 @@
 
 
 /* The lock must be held before calling this function */
-static int get_accelerator(struct rgw_list ** list, unsigned char ccode, int port)
+static int get_accelerator(struct rg_list ** list, unsigned char ccode, int port)
 {
-	struct rgw_list *refer, *search;
+	struct rg_list *refer, *search;
 	struct ext_accel * accel = NULL;
 	struct ext_accel_item * item = NULL;
 	
@@ -116,8 +116,8 @@
 	
 	CHECK_MALLOC( accel = malloc(sizeof(struct ext_accel)) );
 	memset(accel, 0, sizeof(struct ext_accel) );
-	rgw_list_init(&accel->chain);
-	rgw_list_init(&accel->extensions);
+	rg_list_init(&accel->chain);
+	rg_list_init(&accel->extensions);
 	accel->ccode = ccode;
 	
 	/* Check if each extension from the global list is enabled for this port and ccode */
@@ -146,14 +146,14 @@
 		/* Ok, this extension is called for this port / ccode, add to the accelerator */
 		CHECK_MALLOC( item = malloc(sizeof(struct ext_accel_item)) );
 		memset(item, 0, sizeof(struct ext_accel_item));
-		rgw_list_init(&item->chain);
+		rg_list_init(&item->chain);
 		item->ext = loc;
 		/* Add as last element of the accelerator */
-		rgw_list_insert_before(&accel->extensions, &item->chain);
+		rg_list_insert_before(&accel->extensions, &item->chain);
 	}
 	
 	/* Now, save this accelerator entry in the global list */
-	rgw_list_insert_before(search, &accel->chain);
+	rg_list_insert_before(search, &accel->chain);
 	
 	return 0;
 }
@@ -164,9 +164,9 @@
 	TRACE_ENTRY();
 	
 	cache_started = 0;
-	rgw_list_init(&ext_list);
-	rgw_list_init(&ext_accel_auth);
-	rgw_list_init(&ext_accel_acct);
+	rg_list_init(&ext_list);
+	rg_list_init(&ext_accel_auth);
+	rg_list_init(&ext_accel_acct);
 	
 	return 0;
 }
@@ -187,7 +187,7 @@
 	CHECK_MALLOC( new = malloc(sizeof(struct ext_descr)) );
 	memset(new, 0, sizeof(struct ext_descr));
 	
-	rgw_list_init(&new->chain);
+	rg_list_init(&new->chain);
 	
 	/* Copy some names to be freed when object is destroyed */
 	CHECK_MALLOC( new->extname = strdup(basename(myextfile)) );
@@ -255,7 +255,7 @@
 	
 	/* And save this new extension in the list */
 	CHECK_POSIX( pthread_mutex_lock(&ext_mtx) );
-	rgw_list_insert_before(&ext_list, &new->chain);
+	rg_list_insert_before(&ext_list, &new->chain);
 	CHECK_POSIX( pthread_mutex_unlock(&ext_mtx) );
 	
 	return 0;
@@ -272,13 +272,13 @@
 void rgw_extensions_dump(void)
 {
 	struct ext_descr * ext;
-	struct rgw_list * ptr, *ptraccel;
+	struct rg_list * ptr, *ptraccel;
 	
 	if ( ! TRACE_BOOL(FULL) )
 		return;
 	
 	CHECK_POSIX_DO( pthread_mutex_lock(&ext_mtx), );
-	if ( ! rgw_list_is_empty( &ext_list ) )
+	if ( ! rg_list_is_empty( &ext_list ) )
 		log_debug(" RADIUS gateway registered sub-extensions:\n");
 	
 	for (ptr = ext_list.next; ptr != &ext_list; ptr = ptr->next) {
@@ -316,7 +316,7 @@
 		return;
 	
 	CHECK_POSIX_DO( pthread_mutex_lock(&ext_mtx), );
-	if ( !rgw_list_is_empty( &ext_accel_auth ) || !rgw_list_is_empty( &ext_accel_acct ))
+	if ( !rg_list_is_empty( &ext_accel_auth ) || !rg_list_is_empty( &ext_accel_acct ))
 		log_debug(" RADIUS gateway sub-extensions accelerators:\n");
 	
 	for (ptraccel = ext_accel_auth.next; ptraccel != &ext_accel_auth; ptraccel = ptraccel->next) {
@@ -349,7 +349,7 @@
 	
 	/* tmp: for debug purpose
 	{
-		struct rgw_list *mylist = NULL;
+		struct rg_list *mylist = NULL;
 		CHECK_FCT_DO( get_accelerator(&mylist, 4, RGW_EXT_PORT_AUTH),  );
 		CHECK_FCT_DO( get_accelerator(&mylist, 4, RGW_EXT_PORT_ACCT),  );
 		CHECK_FCT_DO( get_accelerator(&mylist, 8, RGW_EXT_PORT_AUTH),  );
@@ -363,34 +363,34 @@
 
 void rgw_extensions_fini(void)
 {
-	struct rgw_list * item, *subitem;
+	struct rg_list * item, *subitem;
 	
 	TRACE_ENTRY();
 	
 	CHECK_POSIX_DO( pthread_mutex_lock(&ext_mtx), );
 	
 	/* Remove all elements from all accelerators */
-	while ( ! rgw_list_is_empty(&ext_accel_auth) ) {
+	while ( ! rg_list_is_empty(&ext_accel_auth) ) {
 		item = ext_accel_auth.next;
-		rgw_list_unlink(item);
+		rg_list_unlink(item);
 		{
 			struct ext_accel * accel = (struct ext_accel *)item;
-			while ( ! rgw_list_is_empty(&accel->extensions) ) {
+			while ( ! rg_list_is_empty(&accel->extensions) ) {
 				subitem = accel->extensions.next;
-				rgw_list_unlink(subitem);
+				rg_list_unlink(subitem);
 				free(subitem);
 			}
 		}
 		free(item);
 	}
-	while ( ! rgw_list_is_empty(&ext_accel_acct) ) {
+	while ( ! rg_list_is_empty(&ext_accel_acct) ) {
 		item = ext_accel_acct.next;
-		rgw_list_unlink(item);
+		rg_list_unlink(item);
 		{
 			struct ext_accel * accel = (struct ext_accel *)item;
-			while ( ! rgw_list_is_empty(&accel->extensions) ) {
+			while ( ! rg_list_is_empty(&accel->extensions) ) {
 				subitem = accel->extensions.next;
-				rgw_list_unlink(subitem);
+				rg_list_unlink(subitem);
 				free(subitem);
 			}
 		}
@@ -398,9 +398,9 @@
 	}
 	
 	/* Now destroy all extensions */
-	while ( ! rgw_list_is_empty(&ext_list) ) {
+	while ( ! rg_list_is_empty(&ext_list) ) {
 		struct ext_descr * ext = (struct ext_descr *) ext_list.next;
-		rgw_list_unlink(&ext->chain);
+		rg_list_unlink(&ext->chain);
 		free(ext->conffile);
 		free(ext->extname);
 		free(ext->cc);
--- a/extensions/radius_gw/rgw_msg.c	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/rgw_msg.c	Tue May 19 17:21:54 2009 +0900
@@ -63,20 +63,126 @@
 	/* followed by length-2 octets of attribute value */
 } STRUCT_PACKED;
 
-struct radius_attr_vendor {
-	uint8_t vendor_type;
-	uint8_t vendor_length;
-} STRUCT_PACKED;
-
 #ifdef _MSC_VER
 #pragma pack(pop)
 #endif /* _MSC_VER */
 
-/* Default size to be allocated for new RADIUS messages */
-#define RADIUS_DEFAULT_MSG_SIZE 1024
+int rgw_msg_parse(unsigned char *buf, size_t len, rad_t **msg)
+{
+	struct radius_hdr * hdr = (struct radius_hdr *)buf;
+	rad_t * new = NULL;
+	size_t remaining = 0;
+	struct radius_attr_hdr *next;
+	
+	TRACE_ENTRY("%p %g %p", buf, len, msg);
+	
+	CHECK_PARAMS(buf && msg);
+	
+	if (len < sizeof(struct radius_hdr) ) {
+		TRACE_DEBUG(FULL, "Message too short received (%g bytes), discard.\n", len);
+		return EINVAL;
+	}
+	
+	remaining = ntohs(hdr->length);
+	if (len < remaining) {
+		TRACE_DEBUG(FULL, "Truncated message received (%g / %g bytes), discard.\n", len, remaining);
+		return EINVAL;
+	}
+	
+	if (len > remaining) {
+		TRACE_DEBUG(FULL, "Ignore extra bytes at the end of RADIUS message (%g / %g bytes).\n", len, remaining);
+	}
+	
+	/* Ok, we can try and parse the buffer */
+	CHECK_MALLOC( new = malloc(sizeof(rad_t)) );
+	memset(new, 0, sizeof(rad_t));
+	rg_list_init(&new->attributes);
+	
+	/* Copy header data */
+	new->code = hdr->code;
+	new->identifier = hdr->identifier;
+	memcpy(&new->authenticator[0], &hdr->authenticator[0], 16);
+	
+	/* Parse the attributes */
+	next = (struct radius_attr_hdr *)(hdr + 1);
+	remaining -= sizeof(struct radius_hdr);
+	
+	while (remaining > sizeof(struct radius_attr_hdr)) {
+		struct rad_attr * newattr = NULL;
+		struct radius_attr_hdr *cur = next;
+		
+		if ((cur->length > remaining) || (cur->length < sizeof(struct radius_attr_hdr)))
+			break;
 
-/* Default size to be allocated for attribute array */
-#define RADIUS_DEFAULT_ATTR_COUNT 16
+		next = (struct radius_attr_hdr *)(((unsigned char *)cur) + cur->length);
+		remaining -= cur->length;
+		
+		CHECK_MALLOC( newattr = malloc(sizeof(struct rad_attr)) );
+		memset(newattr, 0, sizeof(struct rad_attr));
+		rg_list_init(&newattr->chain);
+		
+		newattr->type = cur->type;
+		newattr->length = cur->length;
+		
+		if ( cur->length > sizeof(struct radius_attr_hdr) )
+			memcpy(&newattr->data.buf[0], cur+1, cur->length - sizeof(struct radius_attr_hdr));
+		
+		rg_list_insert_before(&new->attributes, &newattr->chain);
+	}
+	
+	/* Done! */
+	*msg = new;
+	return 0;
+}
+
+int rgw_msg_gen(rad_t *msg, unsigned char **buf, size_t *len)
+{
+	size_t mylen;
+	struct rg_list * li;
+	unsigned char * mybuf = NULL;
+	struct radius_hdr * hdr;
+	struct radius_attr_hdr *attr;
+	
+	TRACE_ENTRY("%p %p %p", msg, buf, len);
+	
+	CHECK_PARAMS(msg && buf && len);
+	
+	/* Compute the size of the final message */
+	mylen = sizeof(struct radius_hdr);
+	
+	for (li = msg->attributes.next; li != &msg->attributes; li = li->next)
+		mylen += ((struct rad_attr *)li)->length;
+	
+	CHECK_PARAMS( mylen < (1<<16) );
+	
+	CHECK_MALLOC( mybuf = malloc(mylen) );
+	memset(mybuf, 0, mylen);
+	
+	/* Now write the header */
+	hdr = (struct radius_hdr *)mybuf;
+	hdr->code = msg->code;
+	hdr->identifier = msg->identifier;
+	hdr->length = htons( (unsigned short)mylen );
+	memcpy(&hdr->authenticator[0], &msg->authenticator[0], 16);
+	
+	attr = (struct radius_attr_hdr *)(hdr+1);
+	for (li = msg->attributes.next; li != &msg->attributes; li = li->next) {
+		struct rad_attr * attrmem = (struct rad_attr *)li;
+		
+		attr->type = attrmem->type;
+		attr->length = attrmem->length;
+		
+		if (attr->length > sizeof(struct radius_attr_hdr)) {
+			memcpy(attr+1, &attrmem->data.buf[0], attr->length - sizeof(struct radius_attr_hdr));
+		}
+		
+		attr = (struct radius_attr_hdr *)(((unsigned char *)attr) + attrmem->length);
+	}
+	
+	/* Done */
+	*buf = mybuf;
+	*len = mylen;
+	return 0;
+}
 
 
-
--- a/extensions/radius_gw/rgw_servers.c	Tue May 19 13:34:51 2009 +0900
+++ b/extensions/radius_gw/rgw_servers.c	Tue May 19 17:21:54 2009 +0900
@@ -37,24 +37,12 @@
 
 #include "radius_gw_internal.h"
 
+#define RADIUS_MAX_MSG_LEN 3000
+
+
 /* Declare the rgw_servers */
 struct rgw_servs rgw_servers;
 
-int rgw_servers_init(void)
-{
-	memset(&rgw_servers, 0, sizeof(rgw_servers));
-
-	rgw_servers.auth_serv.port = htons(1812);
-	rgw_servers.auth_serv.ipv4_endpoint.s_addr = INADDR_ANY;
-	memcpy(&rgw_servers.auth_serv.ipv6_endpoint, &in6addr_any, sizeof(struct in6_addr));
-	
-	rgw_servers.acct_serv.port = htons(1813);
-	rgw_servers.acct_serv.ipv4_endpoint.s_addr = INADDR_ANY;
-	memcpy(&rgw_servers.acct_serv.ipv6_endpoint, &in6addr_any, sizeof(struct in6_addr));
-	
-	return 0;
-}
-
 void rgw_servers_dump(void)
 {
 	char ipstr[INET6_ADDRSTRLEN];
@@ -64,33 +52,182 @@
 	
 	log_debug(" auth server:\n");
 	log_debug("    disabled..... : %s\n", rgw_servers.auth_serv.disabled ? "TRUE":"false");
-	log_debug("    IP disabled.. : %s\n", rgw_servers.auth_serv.ipv4_disabled ? "TRUE":"false");
-	log_debug("    IPv6 disabled : %s\n", rgw_servers.auth_serv.ipv6_disabled ? "TRUE":"false");
+	log_debug("    IP disabled.. : %s\n", rgw_servers.auth_serv.ip_disabled ? "TRUE":"false");
+	log_debug("    IPv6 disabled : %s\n", rgw_servers.auth_serv.ip6_disabled ? "TRUE":"false");
 	log_debug("    port......... : %hu\n", ntohs(rgw_servers.auth_serv.port));
-	inet_ntop(AF_INET, &rgw_servers.auth_serv.ipv4_endpoint,ipstr,sizeof(ipstr));
+	inet_ntop(AF_INET, &rgw_servers.auth_serv.ip_endpoint,ipstr,sizeof(ipstr));
 	log_debug("    IP bind...... : %s\n", ipstr);
-	inet_ntop(AF_INET6, &rgw_servers.auth_serv.ipv6_endpoint,ipstr,sizeof(ipstr));
+	inet_ntop(AF_INET6, &rgw_servers.auth_serv.ip6_endpoint,ipstr,sizeof(ipstr));
 	log_debug("    IPv6 bind.... : %s\n", ipstr);
 
 	log_debug(" acct server:\n");
 	log_debug("    disabled..... : %s\n", rgw_servers.acct_serv.disabled ? "TRUE":"false");
-	log_debug("    IP disabled.. : %s\n", rgw_servers.acct_serv.ipv4_disabled ? "TRUE":"false");
-	log_debug("    IPv6 disabled : %s\n", rgw_servers.acct_serv.ipv6_disabled ? "TRUE":"false");
+	log_debug("    IP disabled.. : %s\n", rgw_servers.acct_serv.ip_disabled ? "TRUE":"false");
+	log_debug("    IPv6 disabled : %s\n", rgw_servers.acct_serv.ip6_disabled ? "TRUE":"false");
 	log_debug("    port......... : %hu\n", ntohs(rgw_servers.acct_serv.port));
-	inet_ntop(AF_INET, &rgw_servers.acct_serv.ipv4_endpoint,ipstr,sizeof(ipstr));
+	inet_ntop(AF_INET, &rgw_servers.acct_serv.ip_endpoint,ipstr,sizeof(ipstr));
 	log_debug("    IP bind...... : %s\n", ipstr);
-	inet_ntop(AF_INET6, &rgw_servers.acct_serv.ipv6_endpoint,ipstr,sizeof(ipstr));
+	inet_ntop(AF_INET6, &rgw_servers.acct_serv.ip6_endpoint,ipstr,sizeof(ipstr));
 	log_debug("    IPv6 bind.... : %s\n", ipstr);
 
 }
 
+static struct servers_data {
+	int	port; /* auth or acct */
+	int	sock; /* the socket number */
+	pthread_t th; /* the running server thread, or NULL */
+	char    name[10];
+} SERVERS[4];
+
+int rgw_servers_init(void)
+{
+	memset(&rgw_servers, 0, sizeof(rgw_servers));
+	memset(&SERVERS[0], 0, sizeof(SERVERS));
+
+	rgw_servers.auth_serv.port = htons(1812);
+	rgw_servers.auth_serv.ip_endpoint.s_addr = INADDR_ANY;
+	memcpy(&rgw_servers.auth_serv.ip6_endpoint, &in6addr_any, sizeof(struct in6_addr));
+	
+	rgw_servers.acct_serv.port = htons(1813);
+	rgw_servers.acct_serv.ip_endpoint.s_addr = INADDR_ANY;
+	memcpy(&rgw_servers.acct_serv.ip6_endpoint, &in6addr_any, sizeof(struct in6_addr));
+	
+	
+	return 0;
+}
+
+static void * server_thread(void * param)
+{
+	struct servers_data * me = (struct servers_data *)param;
+	
+	TRACE_ENTRY("%p", param);
+	
+	CHECK_PARAMS_DO(param, return NULL);
+	
+	log_set_thread_name( me->name, "rgw server" );
+	
+	/* Now loop on this socket, parse and queue each message received, until thread is cancelled. */
+	while (1) {
+		struct sockaddr_storage from;
+		unsigned char * buf = NULL;
+		socklen_t fromlen = sizeof(from);
+		int len;
+		rad_t * msg = NULL;
+		void * nas_info = NULL;
+		
+		pthread_testcancel();
+		
+		CHECK_MALLOC_DO( buf = malloc(RADIUS_MAX_MSG_LEN), break );
+		memset(buf, 0, RADIUS_MAX_MSG_LEN);
+		
+		/* read the next message */
+		CHECK_SYS_DO( len = recvfrom( me->sock, buf, RADIUS_MAX_MSG_LEN, 0, (struct sockaddr *) &from, &fromlen),  break );
+		TRACE_DEBUG(FULL, "Received %d bytes", len);
+		
+		/* parse the message or loop if message is bad */
+		CHECK_FCT_DO( rgw_msg_parse(buf, len, &msg), 
+			{ 
+				TRACE_DEBUG(INFO, "Discarding invalid RADIUS message");
+				free(buf); 
+				continue; 
+			} );
+		
+		/* Free the buffer, we don't need it anymore */
+		free(buf);
+		
+		/* Search the associated client definition, if any */
+		CHECK_FCT_DO( rgw_clients_search((struct sockaddr *) &from, &nas_info),
+			{
+				TRACE_DEBUG(INFO, "Discarding message from unknown RADIUS client");
+				rg_msg_free(msg);
+				continue;
+			} );
+				
+		
+		/* queue the message for a worker thread */
+		CHECK_FCT_DO( rgw_work_add(msg, nas_info), break );
+		
+		/* Then wait for next incoming message */
+	}
+	
+	return NULL;
+	
+}
+
+/* Set the socket options for UDP sockets, before bind is called */
+static int _udp_setsockopt(int family, int sk)
+{
+	int ret = 0;
+	int opt;
+	
+	/* In case of v6 address, force the v6only option, we use a different socket for v4 */
+	#ifdef IPV6_V6ONLY
+	if (family == AF_INET6) {
+		opt = 1;
+		ret = setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
+		if (ret != 0) {
+			ret = errno;
+			TRACE_DEBUG(INFO, "Unable to set the socket IPV6_V6ONLY option: %s", strerror(ret));
+			return ret;
+		}
+	}
+	#endif /* IPV6_V6ONLY */
+	
+	return 0;
+}
+
+#define UDPSERV( type, portval, family ) {										\
+	if ( (! rgw_servers. type ## _serv.disabled) 								\
+		&& ( ! rgw_servers.auth_serv.ip ## family ## _disabled ) ) {					\
+			struct sockaddr_in ## family sin ## family;						\
+			CHECK_SYS( SERVERS[idx].sock = socket(AF_INET ## family, SOCK_DGRAM, 0) );		\
+			memset(& sin ## family, 0, sizeof(struct sockaddr_in ## family));			\
+			sin ## family . sin ## family ## _family = AF_INET ## family;				\
+			sin ## family . sin ## family ## _port = rgw_servers. type ## _serv . port;		\
+			memcpy( &sin ## family.sin ## family ## _addr, 						\
+					&rgw_servers. type ## _serv . ip ## family ## _endpoint,		\
+					sizeof(struct in ## family ## _addr) );					\
+			TRACE_DEBUG(FULL, "Setting socket options...");						\
+			CHECK_FCT( _udp_setsockopt(AF_INET ## family, SERVERS[idx].sock) );			\
+			TRACE_DEBUG(FULL, "Binding " #type " ip" #family " server...");				\
+			CHECK_SYS( bind( SERVERS[idx].sock,							\
+					(struct sockaddr *)&sin ## family,					\
+					sizeof(struct sockaddr_in ## family) ) );				\
+			SERVERS[idx].port = portval;								\
+			snprintf(&SERVERS[idx].name[0], sizeof(SERVERS[idx].name), # type " ip" #family);	\
+			CHECK_POSIX( pthread_create(&SERVERS[idx].th, NULL, server_thread, &SERVERS[idx]) );	\
+			idx++;											\
+	}													\
+}
+	
+
 int rgw_servers_start(void)
 {
-	return ENOTSUP;
+	int idx = 0;
+	
+	TRACE_ENTRY();
+	
+	UDPSERV( auth, RGW_EXT_PORT_AUTH,  );
+	UDPSERV( auth, RGW_EXT_PORT_AUTH, 6 );
+	UDPSERV( acct, RGW_EXT_PORT_ACCT,  );
+	UDPSERV( acct, RGW_EXT_PORT_ACCT, 6 );
+	
+	TRACE_DEBUG(FULL, "%d UDP servers started succesfully.", idx);
+	return 0;
 }
 
 void rgw_servers_fini(void)
 {
+	int idx = 0;
+	
+	for (idx = 0; idx < sizeof(SERVERS) / sizeof(SERVERS[0]); idx++) {
+		if (SERVERS[idx].sock == 0)
+			break;
+		
+		CHECK_FCT_DO( _thread_term(&SERVERS[idx].th), /* continue */ );
+		close(SERVERS[idx].sock);
+		SERVERS[idx].sock = 0;
+	}
 	
 }
 
--- a/extensions/radius_gw/rgw_utils.c	Tue May 19 13:34:51 2009 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*********************************************************************************************************
-* Software License Agreement (BSD License)                                                               *
-* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
-*													 *
-* Copyright (c) 2008, 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.								 *
-*********************************************************************************************************/
-
-/* Some useful functions */
-
-#include "radius_gw_internal.h"
-
-void rgw_list_init(struct rgw_list * plist)
-{
-	ASSERT(plist != NULL);
-	plist->next = plist;
-	plist->prev = plist;
-	plist->head = plist;
-}
-
-int rgw_list_is_empty(struct rgw_list * plist)
-{
-	ASSERT(plist != NULL);
-	return plist == plist->next;
-}
-
-void rgw_list_insert_after(struct rgw_list * ref, struct rgw_list * item)
-{
-	ASSERT(ref != NULL);
-	ASSERT(item != NULL);
-	ASSERT(rgw_list_is_empty(item));
-	item->next = ref->next;
-	item->prev = ref;
-	item->head = ref->head;
-	ref->next->prev = item;
-	ref->next = item;
-}
-
-void rgw_list_insert_before(struct rgw_list * ref, struct rgw_list * item)
-{
-	ASSERT(ref != NULL);
-	ASSERT(item != NULL);
-	ASSERT(rgw_list_is_empty(item));
-	item->prev = ref->prev;
-	item->next = ref;
-	item->head = ref->head;
-	ref->prev->next = item;
-	ref->prev = item;
-}
-
-void rgw_list_unlink(struct rgw_list * plist)
-{
-	ASSERT(plist != NULL);
-	if (plist->head == plist)
-		return;
-	plist->next->prev = plist->prev;
-	plist->prev->next = plist->next;
-	plist->next = plist;
-	plist->prev = plist;
-	plist->head = plist;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rgw_work.c	Tue May 19 17:21:54 2009 +0900
@@ -0,0 +1,125 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, 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.								 *
+*********************************************************************************************************/
+
+/* Manage incoming RADIUS message. */
+
+#include "radius_gw_internal.h"
+
+/* How many threads to work on messages ? */
+#define NB_WORKERS	2
+
+
+static pthread_mutex_t work_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t work_cond = PTHREAD_COND_INITIALIZER;
+
+static struct rg_list work_data;
+struct work_item {
+	struct rg_list chain;
+	rad_t * msg;
+	void * cli;
+};
+
+static pthread_t workers[NB_WORKERS];
+
+static void * work_th(void * arg)
+{
+	TRACE_ENTRY("%p", arg);
+	
+	THREAD_NAME("worker");
+	
+	CHECK_POSIX_DO( pthread_mutex_lock(&work_mtx), return NULL );
+	
+in:
+	/* wait for new work data */
+	if (rg_list_is_empty(&work_data)) {
+		CHECK_POSIX_DO( pthread_cond_wait( &work_cond, &work_mtx ), goto out );
+		goto in;
+	}
+	
+	
+	
+	/* process the data */
+	
+	
+
+out:
+	CHECK_POSIX_DO( pthread_mutex_unlock(&work_mtx), );
+	return NULL;
+}
+
+
+int rgw_work_start(void)
+{
+	int i;
+	TRACE_ENTRY();
+	
+	memset(workers, 0, sizeof(workers));
+	rg_list_init(&work_data);
+	
+	/* Create the worker thread(s) */
+	for (i = 0; i < NB_WORKERS; i++) {
+		CHECK_POSIX( pthread_create(&workers[i], NULL, work_th, NULL) );
+	}
+	
+	return 0;
+}
+
+int rgw_work_add(rad_t * msg, void * client)
+{
+	struct work_item * new;
+	
+	CHECK_MALLOC( new = malloc(sizeof(struct work_item)) );
+	memset(new, 0, sizeof(struct work_item));
+	rg_list_init(&new->chain);
+	
+	new->msg = msg;
+	new->cli = client;
+	
+	CHECK_POSIX( pthread_mutex_lock(&work_mtx) );
+	rg_list_insert_before(&work_data, &new->chain);
+	CHECK_POSIX( pthread_cond_signal(&work_cond) );
+	CHECK_POSIX( pthread_mutex_unlock(&work_mtx) );
+	
+	return 0;
+}
+
+void rgw_work_fini(void)
+{
+	TRACE_ENTRY();
+	
+	/* kill all threads */
+	
+	return;
+}
"Welcome to our mercurial repository"