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

📄 event.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	       inet_ntop(request->proxy->dst_ipaddr.af,			 &request->proxy->dst_ipaddr.ipaddr,			 buffer, sizeof(buffer)),	       request->proxy->dst_port);	wait_for_proxy_id_to_expire(request);}static void received_response_to_ping(REQUEST *request){	home_server *home = request->home_server;	char buffer[128];	home->num_received_pings++;	DEBUG2("Received response to status check %d (%d in current sequence)",	       request->number, home->num_received_pings);	if (home->num_received_pings < home->num_pings_to_alive) {		wait_for_proxy_id_to_expire(request);		return;	}	DEBUG2("Marking home server %s port %d alive",	       inet_ntop(request->proxy->dst_ipaddr.af,			 &request->proxy->dst_ipaddr.ipaddr,			 buffer, sizeof(buffer)),	       request->proxy->dst_port);	if (!fr_event_delete(el, &home->ev)) {		DEBUG2("Hmm... no event for home server, WTF?");	}	if (!fr_event_delete(el, &request->ev)) {		DEBUG2("Hmm... no event for request, WTF?");	}	wait_for_proxy_id_to_expire(request);	home->state = HOME_STATE_ALIVE;	home->currently_outstanding = 0;}static void ping_home_server(void *ctx){	uint32_t jitter;	home_server *home = ctx;	REQUEST *request;	VALUE_PAIR *vp;	if (home->state == HOME_STATE_ALIVE) {		radlog(L_INFO, "Suspicious proxy state... continuing");		return;	}	request = request_alloc();	request->number = request_num_counter++;	request->proxy = rad_alloc(1);	rad_assert(request->proxy != NULL);	fr_event_now(el, &request->when);	home->when = request->when;	if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {		request->proxy->code = PW_STATUS_SERVER;		radius_pairmake(request, &request->proxy->vps,				"Message-Authenticator", "0x00", T_OP_SET);	} else if (home->type == HOME_TYPE_AUTH) {		request->proxy->code = PW_AUTHENTICATION_REQUEST;		radius_pairmake(request, &request->proxy->vps,				"User-Name", home->ping_user_name, T_OP_SET);		radius_pairmake(request, &request->proxy->vps,				"User-Password", home->ping_user_password, T_OP_SET);		radius_pairmake(request, &request->proxy->vps,				"Service-Type", "Authenticate-Only", T_OP_SET);		radius_pairmake(request, &request->proxy->vps,				"Message-Authenticator", "0x00", T_OP_SET);	} else {		request->proxy->code = PW_ACCOUNTING_REQUEST;				radius_pairmake(request, &request->proxy->vps,				"User-Name", home->ping_user_name, T_OP_SET);		radius_pairmake(request, &request->proxy->vps,				"Acct-Status-Type", "Stop", T_OP_SET);		radius_pairmake(request, &request->proxy->vps,				"Acct-Session-Id", "00000000", T_OP_SET);		vp = radius_pairmake(request, &request->proxy->vps,				     "Event-Timestamp", "0", T_OP_SET);		vp->vp_date = now.tv_sec;	}	radius_pairmake(request, &request->proxy->vps,			"NAS-Identifier", "Status Check. Are you alive?",			T_OP_SET);	request->proxy->dst_ipaddr = home->ipaddr;	request->proxy->dst_port = home->port;	request->home_server = home;	rad_assert(request->proxy_listener == NULL);	if (!insert_into_proxy_hash(request)) {		DEBUG2("ERROR: Failed inserting status check %d into proxy hash.  Discarding it.",		       request->number);		request_free(&request);		return;	}	rad_assert(request->proxy_listener != NULL);	request->proxy_listener->send(request->proxy_listener,				      request);	request->next_callback = NULL;	request->child_state = REQUEST_PROXIED;	request->when.tv_sec += home->ping_timeout;;	INSERT_EVENT(no_response_to_ping, request);	/*	 *	Add +/- 2s of jitter, as suggested in RFC 3539	 *	and in the Issues and Fixes draft.	 */	home->when.tv_sec += home->ping_interval - 2;	jitter = fr_rand();	jitter ^= (jitter >> 10);	jitter &= ((1 << 23) - 1); /* 22 bits of 1 */	tv_add(&home->when, jitter);	INSERT_EVENT(ping_home_server, home);}static void check_for_zombie_home_server(REQUEST *request){	home_server *home;	struct timeval when;	char buffer[128];	home = request->home_server;	if (home->state != HOME_STATE_ZOMBIE) return;	when = home->zombie_period_start;	when.tv_sec += home->zombie_period;	fr_event_now(el, &now);	if (timercmp(&now, &when, <)) {		return;	}	/*	 *	It's been a zombie for too long, mark it as	 *	dead.	 */	DEBUG2("FAILURE: Marking home server %s port %d as dead.",	       inet_ntop(request->proxy->dst_ipaddr.af,			 &request->proxy->dst_ipaddr.ipaddr,			 buffer, sizeof(buffer)),	       request->proxy->dst_port);	home->state = HOME_STATE_IS_DEAD;	home->num_received_pings = 0;	home->when = request->when;	if (home->ping_check != HOME_PING_CHECK_NONE) {		rad_assert((home->ping_check == HOME_PING_CHECK_STATUS_SERVER) ||			   (home->ping_user_name != NULL));		home->when.tv_sec += home->ping_interval;		INSERT_EVENT(ping_home_server, home);	} else {		home->when.tv_sec += home->revive_interval;		INSERT_EVENT(revive_home_server, home);	}}static int setup_post_proxy_fail(REQUEST *request){	DICT_VALUE *dval = NULL;	VALUE_PAIR *vp;	if (request->packet->code == PW_AUTHENTICATION_REQUEST) {		dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Authentication");	} else if (request->packet->code == PW_ACCOUNTING_REQUEST) {		dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Accounting");	} else {		return 0;	}	if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail");	if (!dval) {		pairdelete(&request->config_items, PW_POST_PROXY_TYPE);		return 0;	}	vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);	if (!vp) vp = radius_paircreate(request, &request->config_items,					PW_POST_PROXY_TYPE, PW_TYPE_INTEGER);	vp->vp_integer = dval->value;	rad_assert(request->proxy_reply == NULL);	return 1;}static int null_handler(UNUSED REQUEST *request){	return 0;}static void post_proxy_fail_handler(REQUEST *request){	/*	 *	A proper time is required for wait_a_bit.	 */	request->delay = USEC / 10;	gettimeofday(&now, NULL);	/*	 *	Not set up to run Post-Proxy-Type = Fail.	 *	 *	Mark the request as still running, and figure out what	 *	to do next.	 */	if (!setup_post_proxy_fail(request)) {		request->child_state = REQUEST_RUNNING;		request_post_handler(request);	} else {		/*		 *	Re-queue the request.		 */		request->child_state = REQUEST_QUEUED;		/*		 *	There is a post-proxy-type of fail.  We run		 *	the request through the pre/post proxy		 *	handlers, just like it was a real proxied		 *	request.  However, we set the per-request		 *	handler to NULL, as we don't want to do		 *	anything else.		 *		 *	Note that when we're not threaded, this will		 *	process the request even if it's greater than		 *	max_request_time.  That's not fatal.		 */		request->priority = 0;		rad_assert(request->proxy != NULL);		thread_pool_addrequest(request, null_handler);	}	/*	 *	MAY free the request if we're over max_request_time,	 *	AND we're not in threaded mode!	 *	 *	Note that we call this ONLY if we're threaded, as	 *	if we're NOT threaded, request_post_handler() calls	 *	wait_a_bit(), which means that "request" may not	 *	exist any more...	 */	if (have_children) wait_a_bit(request);}/* maybe check this against wait_for_proxy_id_to_expire? */static void no_response_to_proxied_request(void *ctx){	REQUEST *request = ctx;	home_server *home;	char buffer[128];	rad_assert(request->magic == REQUEST_MAGIC);	rad_assert(request->child_state == REQUEST_PROXIED);	radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",	       request->number,	       inet_ntop(request->proxy->dst_ipaddr.af,			 &request->proxy->dst_ipaddr.ipaddr,			 buffer, sizeof(buffer)),	       request->proxy->dst_port);	check_for_zombie_home_server(request);	home = request->home_server;	post_proxy_fail_handler(request);	/*	 *	Don't touch request due to race conditions	 */	if (home->state == HOME_STATE_IS_DEAD) {		rad_assert(home->ev != NULL); /* or it will never wake up */		return;	}	/*	 *	Enable the zombie period when we notice that the home	 *	server hasn't responded.  We also back-date the start	 *	of the zombie period to when the proxied request was	 *	sent.	 */	if (home->state == HOME_STATE_ALIVE) {		DEBUG2("WARNING: Marking home server %s port %d as zombie (it looks like it is dead).",		       inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,				 buffer, sizeof(buffer)),		       home->port);		home->state = HOME_STATE_ZOMBIE;		home->zombie_period_start = now;		home->zombie_period_start.tv_sec -= home->response_window;		return;	}}static void wait_a_bit(void *ctx){	struct timeval when;	REQUEST *request = ctx;	fr_event_callback_t callback = NULL;	rad_assert(request->magic == REQUEST_MAGIC);	switch (request->child_state) {	case REQUEST_QUEUED:	case REQUEST_RUNNING:		when = request->received;		when.tv_sec += request->root->max_request_time;		/*		 *	Normally called from the event loop with the		 *	proper event loop time.  Otherwise, called from		 *	post proxy fail handler, which sets "now", and		 *	this call won't re-set it, because we're not		 *	in the event loop.		 */		fr_event_now(el, &now);		/*		 *	Request still has more time.  Continue		 *	waiting.		 */		if (timercmp(&now, &when, <) ||		    ((request->listener->type == RAD_LISTEN_DETAIL) &&		     (request->child_state == REQUEST_QUEUED))) {			if (request->delay < (USEC / 10)) {				request->delay = USEC / 10;			}			request->delay += request->delay >> 1;			/*			 *	Cap wait at some sane value for detail			 *	files.			 */			if ((request->listener->type == RAD_LISTEN_DETAIL) &&			    (request->delay > (request->root->max_request_time * USEC))) {				request->delay = request->root->max_request_time * USEC;			}			request->when = now;			tv_add(&request->when, request->delay);			callback = wait_a_bit;			break;		}		/*		 *	A child thread MAY still be running on the		 *	request.  Ask the thread to stop working on		 *	the request.		 */		if (have_children) {			/* FIXME: kill unresponsive children? */			/*			 *	Print this error message ONLY if			 *	there's a child currently processing			 *	the request.  As we don't have thread			 *	locks here, there may be race			 *	conditions on this check.  But it's			 *	just an error message, so that's OK.			 */			if (request->child_pid != NO_SUCH_CHILD_PID) {				radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d, in module %s component %s",			       (unsigned long)request->child_pid, request->number,				       request->module ? request->module : "<server core>",				       request->component ? request->component : "<server core>");			}			request->master_state = REQUEST_STOP_PROCESSING;						request->delay = USEC / 4;			tv_add(&request->when, request->delay);			callback = wait_for_child_to_die;			break;		}		/*		 *	Else there are no child threads.  We probably		 *	should have just marked the request as 'done'		 *	elsewhere, like in the post-proxy-fail		 *	handler.  But doing that would involve		 *	checking for max_request_time in multiple		 *	places, so this may be simplest.		 */		request->child_state = REQUEST_DONE;		/* FALL-THROUGH */		/*		 *	Mark the request as no longer running,		 *	and clean it up.		 */	case REQUEST_DONE:		request->child_pid = NO_SUCH_CHILD_PID;		snmp_inc_counters(request);		cleanup_delay(request);		return;	case REQUEST_REJECT_DELAY:	case REQUEST_CLEANUP_DELAY:		request->child_pid = NO_SUCH_CHILD_PID;		snmp_inc_counters(request);	case REQUEST_PROXIED:		rad_assert(request->next_callback != NULL);		rad_assert(request->next_callback != wait_a_bit);		request->when = request->next_when;		callback = request->next_callback;		request->next_callback = NULL;		break;	default:		rad_panic("Internal sanity check failure");		return;	}	/*	 *	Something major went wrong.  Discard the request, and	 *	keep running.	 *	 *	FIXME: No idea why this happens or how to fix it...	 *	It seems to happen *only* when requests are proxied,	 *	and where the home server doesn't respond.  So it looks	 *	like a race condition above, but it happens in debug	 *	mode, with no threads...	 */	if (!callback) {		DEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number);		fr_event_delete(el, &request->ev);		remove_from_proxy_hash(request);		remove_from_request_hash(request);		request_free(&request);		return;	}	INSERT_EVENT(callback, request);}static int request_pre_handler(REQUEST *request){	int rcode;	rad_assert(request->magic == REQUEST_MAGIC);	rad_assert(request->packet != NULL);	request->child_state = REQUEST_RUNNING;	/*	 *	Don't decode the packet if it's an internal "fake"	 *	request.  Instead, just return so that the caller can	 *	process it.	 */	if (request->packet->dst_port == 0) {		request->username = pairfind(request->packet->vps,					     PW_USER_NAME);		request->password = pairfind(request->packet->vps,					     PW_USER_PASSWORD);		return 1;	}	/*	 *	Put the decoded packet into it's proper place.	 */	if (request->proxy_reply != NULL) {		rcode = request->proxy_listener->decode(request->proxy_listener,							request);	} else if (request->packet->vps == NULL) {		rcode = request->listener->decode(request->listener, request);	} else {		rcode = 0;	}	if (rcode < 0) {		radlog(L_ERR, "%s Dropping packet without response.", librad_errstr);		request->child_state = REQUEST_DONE;		return 0;	}	if (!request->proxy) {		request->username = pairfind(request->packet->vps,					     PW_USER_NAME);	} else {		int post_proxy_type = 0;		VALUE_PAIR *vp;		/*

⌨️ 快捷键说明

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