⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 request_list.c

📁 radius server在linux下的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * request_list.c	Hide the handling of the REQUEST list from *			the main server. * * Version:	$Id: request_list.c,v 1.40.2.2 2004/06/01 14:35:55 aland Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Copyright 2003-2004  The FreeRADIUS server project */static const char rcsid[] = "$Id: request_list.c,v 1.40.2.2 2004/06/01 14:35:55 aland Exp $";#include "autoconf.h"#include "libradius.h"#include <stdlib.h>#include <string.h>#include "radiusd.h"#include "rad_assert.h"#include "request_list.h"#include "radius_snmp.h"/* *	We keep the incoming requests in an array, indexed by ID. * *	Each array element contains a linked list of containers of *	active requests, a count of the number of requests, and a time *	at which the first request in the list must be serviced. * *	Note that we ALSO keep a tree view of the same data, below. *	Both views are needed for the server to work optimally. */typedef struct REQNODE {	struct REQNODE *prev, *next;	REQUEST *req;} REQNODE;typedef struct REQUESTINFO {	REQNODE *first_request;	REQNODE *last_request;	int request_count;	time_t last_cleaned_list;} REQUESTINFO;static REQUESTINFO	request_list[256];/* *	Remember the next request at which we start walking *	the list. */static REQUEST *last_request = NULL;/* *	It MAY make more sense here to key off of the packet ID, just *	like the request_list.  Then again, saving another 8 lookups *	(on average) isn't much of a problem. * *	The "request_cmp" function keys off of the packet ID first, *	so the first 8 layers of the tree will be the fanned-out *	tree for packet ID's. */static rbtree_t		*request_tree;#ifdef HAVE_PTHREAD_Hstatic pthread_mutex_t	proxy_mutex;#else/* *	This is easier than ifdef's throughout the code. */#define pthread_mutex_lock(_x)#define pthread_mutex_unlock(_x)#endif/* *	We keep track of packets we're proxying, keyed by *	source socket, and destination ip/port, and Id. */static rbtree_t		*proxy_tree;/* *	We keep track of free/used Id's, by destination ip/port. * *	We need a different tree than above, because this one is NOT *	keyed by Id.  Instead, we use this one to allocate Id's. */static rbtree_t		*proxy_id_tree;/* *	We keep the proxy FD's here.  The RADIUS Id's are marked *	"allocated" per Id, via a bit per proxy FD. */static int		proxy_fds[32];/* *	We can use 256 RADIUS Id's per dst ipaddr/port, per server *	socket.  So, to allocate them, we key off of dst ipaddr/port, *	and then search the RADIUS Id's, looking for an unused socket. * *	We do NOT key off of socket fd's, here, either.  Instead, *	we look for a free Id from a sockfd, any sockfd. */typedef struct proxy_id_t {	uint32_t	dst_ipaddr;	int		dst_port;	/*	 *	FIXME: Allocate more proxy sockets when this gets full.	 */	int		index;	uint32_t	mask;	/* of FD's we know about. */	uint32_t	id[1];	/* really id[256] */} proxy_id_t;/* *	Find a matching entry in the proxy ID tree. */static int proxy_id_cmp(const void *one, const void *two){	const proxy_id_t *a = one;	const proxy_id_t *b = two;	/*	 *	The following comparisons look weird, but it's	 *	the only way to make the comparisons work.	 */	if (a->dst_ipaddr < b->dst_ipaddr) return -1;	if (a->dst_ipaddr > b->dst_ipaddr) return +1;	if (a->dst_port < b->dst_port) return -1;	if (a->dst_port > b->dst_port) return +1;		/*	 *	Everything's equal.  Say so.	 */	return 0;}/* *	Compare two REQUEST data structures, based on a number *	of criteria. */static int request_cmp(const void *one, const void *two){	const REQUEST *a = one;	const REQUEST *b = two;	/*	 *	The following comparisons look weird, but it's	 *	the only way to make the comparisons work.	 */	/*	 *	If the packets didn't arrive on the same socket,	 *	they're not identical, no matter what their src/dst	 *	ip/ports say.	 */	if (a->packet->sockfd < b->packet->sockfd) return -1;	if (a->packet->sockfd > b->packet->sockfd) return +1;	if (a->packet->id < b->packet->id) return -1;	if (a->packet->id > b->packet->id) return +1;	if (a->packet->code < b->packet->code) return -1;	if (a->packet->code > b->packet->code) return +1;	if (a->packet->src_ipaddr < b->packet->src_ipaddr) return -1;	if (a->packet->src_ipaddr > b->packet->src_ipaddr) return +1;	if (a->packet->src_port < b->packet->src_port) return -1;	if (a->packet->src_port > b->packet->src_port) return +1;	/*	 *	Hmm... we may be listening on IPADDR_ANY, in which case	 *	the destination IP is important, too.	 */	if (a->packet->dst_ipaddr < b->packet->dst_ipaddr) return -1;	if (a->packet->dst_ipaddr > b->packet->dst_ipaddr) return +1;	if (a->packet->dst_port < b->packet->dst_port) return -1;	if (a->packet->dst_port > b->packet->dst_port) return +1;	/*	 *	Everything's equal.  Say so.	 */	return 0;}/* *	Compare two REQUEST data structures, based on a number *	of criteria, for proxied packets. */static int proxy_cmp(const void *one, const void *two){	const REQUEST *a = one;	const REQUEST *b = two;	rad_assert(a->magic == REQUEST_MAGIC);	rad_assert(b->magic == REQUEST_MAGIC);	rad_assert(a->proxy != NULL);	rad_assert(b->proxy != NULL);	/*	 *	The following code looks unreasonable, but it's	 *	the only way to make the comparisons work.	 */	if (a->proxy->sockfd < b->proxy->sockfd) return -1;	if (a->proxy->sockfd > b->proxy->sockfd) return +1;	if (a->proxy->id < b->proxy->id) return -1;	if (a->proxy->id > b->proxy->id) return +1;	/*	 *	We've got to check packet codes, too.  But	 *	this should be done later, by someone else...	 */	if (a->proxy->dst_ipaddr < b->proxy->dst_ipaddr) return -1;	if (a->proxy->dst_ipaddr > b->proxy->dst_ipaddr) return +1;	if (a->proxy->dst_port < b->proxy->dst_port) return -1;	if (a->proxy->dst_port > b->proxy->dst_port) return +1;	/*	 *	FIXME: Check the Proxy-State attribute, too.	 *	This will help cut down on duplicates.	 */	/*	 *	Everything's equal.  Say so.	 */	return 0;}/* *	Initialize the request list. */int rl_init(void){	/*	 *	Initialize the request_list[] array.	 */	memset(request_list, 0, sizeof(request_list));	request_tree = rbtree_create(request_cmp, NULL, 0);	if (!request_tree) {		rad_assert("FAIL" == NULL);	}	/*	 *	Create the tree for managing proxied requests and	 *	responses.	 */	proxy_tree = rbtree_create(proxy_cmp, NULL, 1);	if (!proxy_tree) {		rad_assert("FAIL" == NULL);	}	/*	 *	Create the tree for allocating proxy ID's.	 */	proxy_id_tree = rbtree_create(proxy_id_cmp, NULL, 0);	if (!proxy_id_tree) {		rad_assert("FAIL" == NULL);	}#ifdef HAVE_PTHREAD_H	/*	 *	For now, always create the mutex.	 *	 *	Later, we can only create it if there are multiple threads.	 */	if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {		radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",		       strerror(errno));		exit(1);	}#endif	/*	 *	The Id allocation table is done by bits, so we have	 *	32 bits per Id.  These bits indicate which entry	 *	in the proxy_fds array is used for that Id.	 *	 *	This design allows 256*32 = 8k requests to be	 *	outstanding to a home server, before something goes	 *	wrong.	 */	{		int i;		rad_listen_t *listener;		/*		 *	Mark the Fd's as unused.		 */		for (i = 0; i < 32; i++) proxy_fds[i] = -1;		for (listener = mainconfig.listen;		     listener != NULL;		     listener = listener->next) {			if (listener->type == RAD_LISTEN_PROXY) {				proxy_fds[listener->fd & 0x1f] = listener->fd;				break;			}		}	}	return 1;}/* *	Delete a request from the proxy trees. */static void rl_delete_proxy(REQUEST *request, rbnode_t *node){	proxy_id_t	myid, *entry;	rad_assert(node != NULL);	rbtree_delete(proxy_tree, node);		myid.dst_ipaddr = request->proxy->dst_ipaddr;	myid.dst_port = request->proxy->dst_port;	/*	 *	Find the Id in the array of allocated Id's,	 *	and delete it.	 */	entry = rbtree_finddata(proxy_id_tree, &myid);	if (entry) {		int i;		DEBUG3(" proxy: de-allocating %08x:%d %d",		       entry->dst_ipaddr,		       entry->dst_port,		       request->proxy->id);		/*		 *	Find the proxy socket associated with this		 *	Id.  We loop over all 32 proxy fd's, but we		 *	partially index by proxy fd's, which means		 *	that we almost always break out of the loop		 *	quickly.		 */		for (i = 0; i < 32; i++) {			int offset;			offset = (request->proxy->sockfd + i) & 0x1f;		  			if (proxy_fds[offset] == request->proxy->sockfd) {								entry->id[request->proxy->id] &= ~(1 << offset);				break;			}		} /* else die horribly? */	} else {		/*		 *	Hmm... not sure what to do here.		 */		DEBUG3(" proxy: FAILED TO FIND %08x:%d %d",		       myid.dst_ipaddr,		       myid.dst_port,		       request->proxy->id);	}}/* *	Delete a particular request. */void rl_delete(REQUEST *request){	int id;	REQNODE *prev, *next;	prev = ((REQNODE *) request->container)->prev;	next = ((REQNODE *) request->container)->next;	id = request->packet->id;	/*	 *	Update the last request we touched.	 *	 *	This is so the periodic "walk & clean list"	 *	function, below, doesn't walk over all requests	 *	all of the time.  Rather, it tries to amortize	 *	the cost...	 */	if (last_request == request) {		last_request = rl_next(last_request);	}	if (prev == NULL) {		request_list[id].first_request = next;	} else {		prev->next = next;	}	if (next == NULL) {		request_list[id].last_request = prev;	} else {		next->prev = prev;	}	free(request->container);#ifdef WITH_SNMP	/*	 *	Update the SNMP statistics.	 *	 *	Note that we do NOT do this in rad_respond(),	 *	as that function is called from child threads.	 *	Instead, we update the stats when a request is	 *	deleted, because only the main server thread calls	 *	this function...	 */	if (mainconfig.do_snmp) {		switch (request->reply->code) {		case PW_AUTHENTICATION_ACK:		  rad_snmp.auth.total_responses++;		  rad_snmp.auth.total_access_accepts++;		  break;		case PW_AUTHENTICATION_REJECT:		  rad_snmp.auth.total_responses++;		  rad_snmp.auth.total_access_rejects++;		  break;		case PW_ACCESS_CHALLENGE:		  rad_snmp.auth.total_responses++;		  rad_snmp.auth.total_access_challenges++;		  break;		case PW_ACCOUNTING_RESPONSE:		  rad_snmp.acct.total_responses++;		  break;		default:			break;		}	}#endif	/*	 *	Delete the request from the tree.	 */	{		rbnode_t *node;		node = rbtree_find(request_tree, request);		rad_assert(node != NULL);		rbtree_delete(request_tree, node);		/*		 *	If there's a proxied packet, and we're still		 *	waiting for a reply, then delete the packet		 *	from the list of outstanding proxied requests.		 */		if (request->proxy &&		    (request->proxy_outstanding > 0)) {			pthread_mutex_lock(&proxy_mutex);			node = rbtree_find(proxy_tree, request);			rl_delete_proxy(request, node);			pthread_mutex_unlock(&proxy_mutex);		}	}	request_free(&request);	request_list[id].request_count--;}/* *	Add a request to the request list. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -