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

📄 detail.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * detail.c	Process the detail file * * Version:	$Id: detail.c,v 1.14 2008/04/26 15:07:43 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: detail.c,v 1.14 2008/04/26 15:07:43 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/modules.h>#include <freeradius-devel/detail.h>#include <freeradius-devel/rad_assert.h>#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#ifdef HAVE_GLOB_H#include <glob.h>#endif#include <fcntl.h>#define USEC (1000000)typedef struct listen_detail_t {	int		delay_time; /* should be first entry */	char		*filename;	char		*filename_work;	VALUE_PAIR	*vps;	FILE		*fp;	int		state;	time_t		timestamp;	fr_ipaddr_t	client_ip;	int		load_factor; /* 1..100 */	int		signal;	int		has_rtt;	int		srtt;	int		rttvar;	struct timeval  last_packet;	RADCLIENT	detail_client;} listen_detail_t;#define STATE_UNOPENED	(0)#define STATE_UNLOCKED	(1)#define STATE_HEADER	(2)#define STATE_READING	(3)#define STATE_QUEUED	(4)#define STATE_RUNNING	(5)#define STATE_NO_REPLY	(6)#define STATE_REPLIED	(7)/* *	If we're limiting outstanding packets, then mark the response *	as being sent. */int detail_send(rad_listen_t *listener, REQUEST *request){	int rtt;	struct timeval now;	listen_detail_t *data = listener->data;	rad_assert(request->listener == listener);	rad_assert(listener->send == detail_send);	/*	 *	This request timed out.  Remember that, and tell the	 *	caller it's OK to read more "detail" file stuff.	 */	if (request->reply->code == 0) {		data->delay_time = USEC;		data->signal = 1;		data->state = STATE_NO_REPLY;		radius_signal_self(RADIUS_SIGNAL_SELF_DETAIL);		return 0;	}	/*	 *	We call gettimeofday a lot.  But here it should be OK,	 *	because there's nothing else to do.	 */	gettimeofday(&now, NULL);	/*	 *	If we haven't sent a packet in the last second, reset	 *	the RTT.	 */	now.tv_sec -= 1;	if (timercmp(&data->last_packet, &now, <)) {		data->has_rtt = FALSE;	}	now.tv_sec += 1;	/*	 *	Only one detail packet may be outstanding at a time,	 *	so it's safe to update some entries in the detail	 *	structure.	 *	 *	We keep smoothed round trip time (SRTT), but not round	 *	trip timeout (RTO).  We use SRTT to calculate a rough	 *	load factor.	 */	rtt = now.tv_sec - request->received.tv_sec;	rtt *= USEC;	rtt += now.tv_usec;	rtt -= request->received.tv_usec;	/*	 *	If we're proxying, the RTT is our processing time,	 *	plus the network delay there and back, plus the time	 *	on the other end to process the packet.  Ideally, we	 *	should remove the network delays from the RTT, but we	 *	don't know what they are.	 *	 *	So, to be safe, we over-estimate the total cost of	 *	processing the packet.	 */	if (!data->has_rtt) {		data->has_rtt = TRUE;		data->srtt = rtt;		data->rttvar = rtt / 2;	} else {		data->rttvar -= data->rttvar >> 2;		data->rttvar += (data->srtt - rtt);		data->srtt -= data->srtt >> 3;		data->srtt += rtt >> 3;	}	/*	 *	Calculate the time we wait before sending the next	 *	packet.	 *	 *	rtt / (rtt + delay) = load_factor / 100	 */	data->delay_time = (data->srtt * (100 - data->load_factor)) / (data->load_factor);	if (data->delay_time == 0) data->delay_time = USEC / 10;	/*	 *	Cap delay at 4 packets/s.  If the end system can't	 *	handle this, then it's very broken.	 */	if (data->delay_time > (USEC / 4)) data->delay_time= USEC / 4;#if 0	DEBUG2("RTT %d\tdelay %d", data->srtt, data->delay_time);#endif	data->last_packet = now;	data->signal = 1;	data->state = STATE_REPLIED;	radius_signal_self(RADIUS_SIGNAL_SELF_DETAIL);	return 0;}int detail_delay(rad_listen_t *listener){	listen_detail_t *data = listener->data;	if (!data->signal) return 0;	data->signal = 0;	return data->delay_time;}/* *	Open the detail file, if we can. * *	FIXME: create it, if it's not already there, so that the main *	server select() will wake us up if there's anything to read. */static int detail_open(rad_listen_t *this){	struct stat st;	listen_detail_t *data = this->data;	char *filename = data->filename;	rad_assert(data->state == STATE_UNOPENED);	data->delay_time = USEC;	/*	 *	Open detail.work first, so we don't lose	 *	accounting packets.  It's probably better to	 *	duplicate them than to lose them.	 *	 *	Note that we're not writing to the file, but	 *	we've got to open it for writing in order to	 *	establish the lock, to prevent rlm_detail from	 *	writing to it.	 */	this->fd = open(data->filename_work, O_RDWR);	if (this->fd < 0) {		DEBUG2("Polling for detail file %s", filename);		/*		 *	Try reading the detail file.  If it		 *	doesn't exist, we can't do anything.		 *		 *	Doing the stat will tell us if the file		 *	exists, even if we don't have permissions		 *	to read it.		 */		if (stat(filename, &st) < 0) {#ifdef HAVE_GLOB_H			int i, found;			time_t ctime;			glob_t files;			memset(&files, 0, sizeof(files));			if (glob(filename, 0, NULL, &files) != 0) {				return 0;			}			ctime = 0;			found = -1;			for (i = 0; i < files.gl_pathc; i++) {				if (stat(files.gl_pathv[i], &st) < 0) continue;				if ((i == 0) ||				    (st.st_ctime < ctime)) {					ctime = st.st_ctime;					found = i;				}			}			if (found < 0) {				globfree(&files);				return 0;			}			filename = strdup(files.gl_pathv[found]);			globfree(&files);#else			return 0;#endif		}		/*		 *	Open it BEFORE we rename it, just to		 *	be safe...		 */		this->fd = open(filename, O_RDWR);		if (this->fd < 0) {			radlog(L_ERR, "Failed to open %s: %s",			       filename, strerror(errno));			if (filename != data->filename) free(filename);			return 0;		}		/*		 *	Rename detail to detail.work		 */		DEBUG("detail_recv: Renaming %s -> %s", filename, data->filename_work);		if (rename(filename, data->filename_work) < 0) {			if (filename != data->filename) free(filename);			close(this->fd);			this->fd = -1;			return 0;		}		if (filename != data->filename) free(filename);	} /* else detail.work existed, and we opened it */	rad_assert(data->vps == NULL);	rad_assert(data->fp == NULL);	data->state = STATE_UNLOCKED;	data->client_ip.af = AF_UNSPEC;	data->timestamp = 0;	return 1;}/* *	FIXME: add a configuration "exit when done" so that the detail *	file reader can be used as a one-off tool to update stuff. * *	The time sequence for reading from the detail file is: * *	t_0		signalled that the server is idle, and we *			can read from the detail file. * *	t_rtt		the packet has been processed successfully, *			wait for t_delay to enforce load factor. *			 *	t_rtt + t_delay wait for signal that the server is idle. *	 */int detail_recv(rad_listen_t *listener,		RAD_REQUEST_FUNP *pfun, REQUEST **prequest){	char		key[256], value[1024];	VALUE_PAIR	*vp, **tail;	RADIUS_PACKET	*packet;	char		buffer[2048];	listen_detail_t *data = listener->data;	switch (data->state) {		case STATE_UNOPENED:	open_file:			rad_assert(listener->fd < 0);						if (!detail_open(listener)) return 0;			rad_assert(data->state == STATE_UNLOCKED);			rad_assert(listener->fd >= 0);			/* FALL-THROUGH */			/*			 *	Try to lock fd.  If we can't, return.			 *	If we can, continue.  This means that			 *	the server doesn't block while waiting			 *	for the lock to open...			 */		case STATE_UNLOCKED:			/*			 *	Note that we do NOT block waiting for			 *	the lock.  We've re-named the file			 *	above, so we've already guaranteed			 *	that any *new* detail writer will not			 *	be opening this file.  The only			 *	purpose of the lock is to catch a race			 *	condition where the execution			 *	"ping-pongs" between radiusd &			 *	radrelay.			 */			if (rad_lockfd_nonblock(listener->fd, 0) < 0) {				/*				 *	Close the FD.  The main loop				 *	will wake up in a second and				 *	try again.				 */				close(listener->fd);				listener->fd = -1;				data->state = STATE_UNOPENED;				return 0;			}			data->fp = fdopen(listener->fd, "r");			if (!data->fp) {				radlog(L_ERR, "FATAL: Failed to re-open detail file %s: %s",				       data->filename, strerror(errno));				exit(1);			}			/*			 *	Look for the header			 */			data->state = STATE_HEADER;			data->vps = NULL;			/* FALL-THROUGH */		case STATE_HEADER:		do_header:			if (!data->fp) {				data->state = STATE_UNOPENED;				goto open_file;			}			{				struct stat buf;								fstat(listener->fd, &buf);				if (((off_t) ftell(data->fp)) == buf.st_size) {					goto cleanup;				}			}			/*			 *	End of file.  Delete it, and re-set			 *	everything.			 */			if (feof(data->fp)) {			cleanup:				unlink(data->filename_work);				if (data->fp) fclose(data->fp);

⌨️ 快捷键说明

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