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

📄 event.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * event.c	Server event handling * * Version:	$Id: event.c,v 1.100 2008/04/20 15:00:06 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2007  The FreeRADIUS server project * Copyright 2007  Alan DeKok <aland@deployingradius.com> */#include <freeradius-devel/ident.h>RCSID("$Id: event.c,v 1.100 2008/04/20 15:00:06 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/modules.h>#include <freeradius-devel/event.h>#include <freeradius-devel/detail.h>#include <freeradius-devel/radius_snmp.h>#include <freeradius-devel/rad_assert.h>#include <signal.h>#include <fcntl.h>#ifdef HAVE_SYS_WAIT_H#	include <sys/wait.h>#endif#define USEC (1000000)extern pid_t radius_pid;extern int dont_fork;extern int check_config;extern void force_log_reopen(void);/* *	Ridiculous amounts of local state. */static fr_event_list_t	*el = NULL;static fr_packet_list_t	*pl = NULL;static int			request_num_counter = 0;static struct timeval		now;static time_t			start_time;static int			have_children;static int			has_detail_listener = FALSE;static int			just_started = FALSE;#ifndef __MINGW32__static int self_pipe[2];#endif#ifdef HAVE_PTHREAD_Hstatic pthread_mutex_t	proxy_mutex;#define PTHREAD_MUTEX_LOCK if (have_children) pthread_mutex_lock#define PTHREAD_MUTEX_UNLOCK if (have_children) pthread_mutex_unlock#else/* *	This is easier than ifdef's throughout the code. */#define PTHREAD_MUTEX_LOCK(_x)#define PTHREAD_MUTEX_UNLOCK(_x)#endif#define INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }static fr_packet_list_t *proxy_list = NULL;/* *	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];static rad_listen_t	*proxy_listeners[32];static void request_post_handler(REQUEST *request);static void wait_a_bit(void *ctx);static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd, void *ctx);static void NEVER_RETURNS _rad_panic(const char *file, unsigned int line,				    const char *msg){	radlog(L_ERR, "[%s:%d] %s", file, line, msg);	_exit(1);}#define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)static void tv_add(struct timeval *tv, int usec_delay){	if (usec_delay > USEC) {		tv->tv_sec += usec_delay / USEC;		usec_delay %= USEC;	}	tv->tv_usec += usec_delay;	if (tv->tv_usec > USEC) {		tv->tv_usec -= USEC;		tv->tv_sec++;	}}#ifdef WITH_SNMPstatic void snmp_inc_counters(REQUEST *request){	if (!request->root->do_snmp) return;	if (request->master_state == REQUEST_COUNTED) return;	if ((request->listener->type != RAD_LISTEN_AUTH) &&	    (request->listener->type != RAD_LISTEN_ACCT)) return;	/*	 *	Update the SNMP statistics.	 *	 *	Note that we do NOT do this in a child thread.	 *	Instead, we update the stats when a request is	 *	deleted, because only the main server thread calls	 *	this function, which makes it thread-safe.	 */	switch (request->reply->code) {	case PW_AUTHENTICATION_ACK:		rad_snmp.auth.total_responses++;		rad_snmp.auth.total_access_accepts++;		if (request->client && request->client->auth) {			request->client->auth->accepts++;		}		break;	case PW_AUTHENTICATION_REJECT:		rad_snmp.auth.total_responses++;		rad_snmp.auth.total_access_rejects++;		if (request->client && request->client->auth) {			request->client->auth->rejects++;		}		break;	case PW_ACCESS_CHALLENGE:		rad_snmp.auth.total_responses++;		rad_snmp.auth.total_access_challenges++;		if (request->client && request->client->auth) {			request->client->auth->challenges++;		}		break;	case PW_ACCOUNTING_RESPONSE:		rad_snmp.acct.total_responses++;		if (request->client && request->client->acct) {			request->client->acct->responses++;		}		break;		/*		 *	No response, it must have been a bad		 *	authenticator.		 */	case 0:		if (request->packet->code == PW_AUTHENTICATION_REQUEST) {			rad_snmp.auth.total_bad_authenticators++;			if (request->client && request->client->auth) {				request->client->auth->bad_authenticators++;			}		}		break;	default:		break;	}	request->master_state = REQUEST_COUNTED;}#else#define snmp_inc_counters(_x)#endifstatic void remove_from_request_hash(REQUEST *request){	if (!request->in_request_hash) return;	fr_packet_list_yank(pl, request->packet);	request->in_request_hash = FALSE;	snmp_inc_counters(request);}static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply){	RADIUS_PACKET **proxy_p;	REQUEST *request;	PTHREAD_MUTEX_LOCK(&proxy_mutex);	proxy_p = fr_packet_list_find_byreply(proxy_list, reply);	if (!proxy_p) {		PTHREAD_MUTEX_UNLOCK(&proxy_mutex);		return NULL;	}	request = fr_packet2myptr(REQUEST, proxy, proxy_p);	if (!request) {		PTHREAD_MUTEX_UNLOCK(&proxy_mutex);		return NULL;	}	request->num_proxied_responses++;	/*	 *	Catch the most common case of everything working	 *	correctly.	 */	if (request->num_proxied_requests == request->num_proxied_responses) {		fr_packet_list_yank(proxy_list, request->proxy);		fr_packet_list_id_free(proxy_list, request->proxy);		request->in_proxy_hash = FALSE;	}	/*	 *	On the FIRST reply, decrement the count of outstanding	 *	requests.  Note that this is NOT the count of sent	 *	packets, but whether or not the home server has	 *	responded at all.	 */	if (!request->proxy_reply &&	    request->home_server->currently_outstanding) {		request->home_server->currently_outstanding--;	}	PTHREAD_MUTEX_UNLOCK(&proxy_mutex);	return request;}static void remove_from_proxy_hash(REQUEST *request){	if (!request->in_proxy_hash) return;	PTHREAD_MUTEX_LOCK(&proxy_mutex);	fr_packet_list_yank(proxy_list, request->proxy);	fr_packet_list_id_free(proxy_list, request->proxy);	/*	 *	The home server hasn't replied, but we've given up on	 *	this request.  Don't count this request against the	 *	home server.	 */	if (!request->proxy_reply &&	    request->home_server->currently_outstanding) {		request->home_server->currently_outstanding--;	}  	PTHREAD_MUTEX_UNLOCK(&proxy_mutex);	request->in_proxy_hash = FALSE;}static int insert_into_proxy_hash(REQUEST *request){	int i, proxy;	char buf[128];	rad_assert(request->proxy != NULL);	rad_assert(proxy_list != NULL);	request->proxy->sockfd = -1;	PTHREAD_MUTEX_LOCK(&proxy_mutex);	request->home_server->currently_outstanding++;	request->home_server->total_requests_sent++;	/*	 *	On overflow, back up to ~0.	 */	if (!request->home_server->total_requests_sent) {		request->home_server->total_requests_sent--;	}	if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {		int found;		rad_listen_t *proxy_listener;		/*		 *	Allocate a new proxy fd.  This function adds		 *	it to the tail of the list of listeners.  With		 *	some care, this can be thread-safe.		 */		proxy_listener = proxy_new_listener();		if (!proxy_listener) {			PTHREAD_MUTEX_UNLOCK(&proxy_mutex);			DEBUG2("ERROR: Failed to create a new socket for proxying requests.");			return 0;		}		/*		 *	Cache it locally.		 */		found = -1;		proxy = proxy_listener->fd;		for (i = 0; i < 32; i++) {			/*			 *	Found a free entry.  Save the socket,			 *	and remember where we saved it.			 */			if (proxy_fds[(proxy + i) & 0x1f] == -1) {				found = (proxy + i) & 0x1f;				proxy_fds[found] = proxy;				proxy_listeners[found] = proxy_listener;				break;			}		}		rad_assert(found >= 0);		if (!fr_packet_list_socket_add(proxy_list, proxy_listener->fd)) {			PTHREAD_MUTEX_UNLOCK(&proxy_mutex);			DEBUG2("ERROR: Failed to create a new socket for proxying requests.");			return 0;		}		if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {			PTHREAD_MUTEX_UNLOCK(&proxy_mutex);			DEBUG2("ERROR: Failed to create a new socket for proxying requests.");			return 0;		}		/*		 *	Signal the main thread to add the new FD to the list		 *	of listening FD's.		 */		radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);	}	rad_assert(request->proxy->sockfd >= 0);	/*	 *	FIXME: Hack until we get rid of rad_listen_t, and put	 *	the information into the packet_list.	 */	proxy = -1;	for (i = 0; i < 32; i++) {		if (proxy_fds[i] == request->proxy->sockfd) {			proxy = i;			break;		}	}	if (proxy < 0) {		PTHREAD_MUTEX_UNLOCK(&proxy_mutex);		DEBUG2("ERROR: All sockets are full.");		return 0;	}	rad_assert(proxy_fds[proxy] != -1);	rad_assert(proxy_listeners[proxy] != NULL);	request->proxy_listener = proxy_listeners[proxy];	if (!fr_packet_list_insert(proxy_list, &request->proxy)) {		fr_packet_list_id_free(proxy_list, request->proxy);		PTHREAD_MUTEX_UNLOCK(&proxy_mutex);		DEBUG2("ERROR: Failed to insert entry into proxy list");		return 0;	}	PTHREAD_MUTEX_UNLOCK(&proxy_mutex);	DEBUG3(" proxy: allocating destination %s port %d - Id %d",	       inet_ntop(request->proxy->dst_ipaddr.af,			 &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),	       request->proxy->dst_port,	       request->proxy->id);	request->in_proxy_hash = TRUE;	return 1;}/* *	Called as BOTH an event, and in-line from other functions. */static void wait_for_proxy_id_to_expire(void *ctx){	REQUEST *request = ctx;	home_server *home = request->home_server;	rad_assert(request->magic == REQUEST_MAGIC);	rad_assert(request->proxy != NULL);	if (!fr_event_now(el, &now)) gettimeofday(&now, NULL);	request->when = request->proxy_when;	request->when.tv_sec += home->response_window;	if ((request->num_proxied_requests == request->num_proxied_responses) ||	    timercmp(&now, &request->when, >)) {		if (request->packet) {			DEBUG2("Cleaning up request %d ID %d with timestamp +%d",			       request->number, request->packet->id,			       (unsigned int) (request->timestamp - start_time));		} else {			DEBUG2("Cleaning up request %d with timestamp +%d",			       request->number,			       (unsigned int) (request->timestamp - start_time));		}		fr_event_delete(el, &request->ev);		remove_from_proxy_hash(request);		remove_from_request_hash(request);		request_free(&request);		return;	}	INSERT_EVENT(wait_for_proxy_id_to_expire, request);}static void wait_for_child_to_die(void *ctx){	REQUEST *request = ctx;	rad_assert(request->magic == REQUEST_MAGIC);	if ((request->child_state == REQUEST_QUEUED) |	    (request->child_state == REQUEST_RUNNING)) {		request->delay += (request->delay >> 1);		tv_add(&request->when, request->delay);		DEBUG2("Child is still stuck for request %d", request->number);		INSERT_EVENT(wait_for_child_to_die, request);		return;	}	DEBUG2("Child is finally responsive for request %d", request->number);	remove_from_request_hash(request);	if (request->proxy) {		wait_for_proxy_id_to_expire(request);		return;	}	request_free(&request);}static void cleanup_delay(void *ctx){	REQUEST *request = ctx;	rad_assert(request->magic == REQUEST_MAGIC);	rad_assert((request->child_state == REQUEST_CLEANUP_DELAY) ||		   (request->child_state == REQUEST_DONE));	remove_from_request_hash(request);	if (request->proxy && request->in_proxy_hash) {		wait_for_proxy_id_to_expire(request);		return;	}	DEBUG2("Cleaning up request %d ID %d with timestamp +%d",	       request->number, request->packet->id,	       (unsigned int) (request->timestamp - start_time));	fr_event_delete(el, &request->ev);	request_free(&request);}static void reject_delay(void *ctx){	REQUEST *request = ctx;	rad_assert(request->magic == REQUEST_MAGIC);	rad_assert(request->child_state == REQUEST_REJECT_DELAY);	DEBUG2("Sending delayed reject for request %d", request->number);	request->listener->send(request->listener, request);	request->when.tv_sec += request->root->cleanup_delay;	request->child_state = REQUEST_CLEANUP_DELAY;	INSERT_EVENT(cleanup_delay, request);}static void revive_home_server(void *ctx){	home_server *home = ctx;	home->state = HOME_STATE_ALIVE;	DEBUG2("Marking home server alive again... we have no idea if it really is alive or not.");	home->currently_outstanding = 0;}static void no_response_to_ping(void *ctx){	REQUEST *request = ctx;	home_server *home = request->home_server;	char buffer[128];	home->num_received_pings = 0;	DEBUG2("No response to status check %d from home server %s port %d",	       request->number,

⌨️ 快捷键说明

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