Mercurial > hg > waaad
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; +}