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

📄 request_list.c

📁 radius server在linux下的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
 *  When walking over the request list, all of the per-request *  magic is done here. */static int refresh_request(REQUEST *request, void *data){	rl_walk_t *info = (rl_walk_t *) data;	time_t difference;	child_pid_t child_pid;	rad_assert(request->magic == REQUEST_MAGIC);	/*	 *  If the request is marked as a delayed reject, AND it's	 *  time to send the reject, then do so now.	 */	if (request->finished &&	    ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) != 0)) {		rad_assert(request->child_pid == NO_SUCH_CHILD_PID);		difference = info->now - request->timestamp;		if (difference >= (time_t) mainconfig.reject_delay) {			/*			 *  Clear the 'delayed reject' bit, so that we			 *  don't do this again.			 */			request->options &= ~RAD_REQUEST_OPTION_DELAYED_REJECT;			rad_send(request->reply, request->packet,				 request->secret);		}	}	/*	 *  If the request has finished processing, AND it's child has	 *  been cleaned up, AND it's time to clean up the request,	 *  OR, it's an accounting request.  THEN, go delete it.	 *	 *  If this is a request which had the "don't cache" option	 *  set, then delete it immediately, as it CANNOT have a	 *  duplicate.	 */	if (request->finished &&	    ((request->timestamp + mainconfig.cleanup_delay <= info->now) ||	     ((request->options & RAD_REQUEST_OPTION_DONT_CACHE) != 0))) {		rad_assert(request->child_pid == NO_SUCH_CHILD_PID);		/*		 *  Request completed, delete it, and unlink it		 *  from the currently 'alive' list of requests.		 */		DEBUG2("Cleaning up request %d ID %d with timestamp %08lx",				request->number, request->packet->id,				(unsigned long) request->timestamp);		/*		 *  Delete the request.		 */		rl_delete(request);		return RL_WALK_CONTINUE;	}	/*	 *  Maybe the child process handling the request has hung:	 *  kill it, and continue.	 */	if ((request->timestamp + mainconfig.max_request_time) <= info->now) {		int number;		child_pid = request->child_pid;		number = request->number;		/*		 *	There MUST be a RAD_PACKET reply.		 */		rad_assert(request->reply != NULL);		/*		 *	If we've tried to proxy the request, and		 *	the proxy server hasn't responded, then		 *	we send a REJECT back to the caller.		 *		 *	For safety, we assert that there is no child		 *	handling the request.  If the assertion fails,		 *	it means that we've sent a proxied request to		 *	the home server, and the child thread is still		 *	sitting on the request!		 */		if (request->proxy && !request->proxy_reply) {			rad_assert(request->child_pid == NO_SUCH_CHILD_PID);			radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s:%d",			       request->number,			       client_name(request->packet->src_ipaddr),			       request->packet->src_port);			request_reject(request);			request->finished = TRUE;			return RL_WALK_CONTINUE;		}		if (mainconfig.kill_unresponsive_children) {			if (child_pid != NO_SUCH_CHILD_PID) {				/*				 *  This request seems to have hung				 *   - kill it				 */#ifdef HAVE_PTHREAD_H				radlog(L_ERR, "Killing unresponsive thread for request %d",				       request->number);				pthread_cancel(child_pid);#endif			} /* else no proxy reply, quietly fail */			/*			 *	Maybe we haven't killed it.  In that			 *	case, print a warning.			 */		} else if ((child_pid != NO_SUCH_CHILD_PID) &&			   ((request->options & RAD_REQUEST_OPTION_LOGGED_CHILD) == 0)) {			radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d",			       (unsigned long)child_pid, number);			/*			 *  Set the option that we've sent a log message,			 *  so that we don't send more than one message			 *  per request.			 */			request->options |= RAD_REQUEST_OPTION_LOGGED_CHILD;		}		/*		 *  Send a reject message for the request, mark it		 *  finished, and forget about the child.		 */		request_reject(request);		request->child_pid = NO_SUCH_CHILD_PID;		if (mainconfig.kill_unresponsive_children)			request->finished = TRUE;		return RL_WALK_CONTINUE;	} /* the request has been in the queue for too long */	/*	 *  If the request is still being processed, then due to the	 *  above check, it's still within it's time limit.  In that	 *  case, don't do anything.	 */	if (request->child_pid != NO_SUCH_CHILD_PID) {		return RL_WALK_CONTINUE;	}	/*	 *  The request is finished.	 */	if (request->finished) goto setup_timeout;	/*	 *  We're not proxying requests at all.	 */	if (!mainconfig.proxy_requests) goto setup_timeout;	/*	 *  We're proxying synchronously, so we don't retry it here.	 *  Some other code takes care of retrying the proxy requests.	 */	if (mainconfig.proxy_synchronous) goto setup_timeout;	/*	 *  The proxy retry delay is zero, meaning don't retry.	 */	if (mainconfig.proxy_retry_delay == 0) goto setup_timeout;	/*	 *  There is no proxied request for this packet, so there's	 *  no proxy retries.	 */	if (!request->proxy) goto setup_timeout;	/*	 *  We've already seen the proxy reply, so we don't need	 *  to send another proxy request.	 */	if (request->proxy_reply) goto setup_timeout;	/*	 *  It's not yet time to re-send this proxied request.	 */	if (request->proxy_next_try > info->now) goto setup_timeout;	/*	 *  If the proxy retry count is zero, then	 *  we've sent the last try, and have NOT received	 *  a reply from the end server.  In that case,	 *  we don't bother trying again, but just mark	 *  the request as finished, and go to the next one.	 */	if (request->proxy_try_count == 0) {		rad_assert(request->child_pid == NO_SUCH_CHILD_PID);		request_reject(request);		realm_disable(request->proxy->dst_ipaddr,request->proxy->dst_port);		request->finished = TRUE;		goto setup_timeout;	}	/*	 *  We're trying one more time, so count down	 *  the tries, and set the next try time.	 */	request->proxy_try_count--;	request->proxy_next_try = info->now + mainconfig.proxy_retry_delay;	/* Fix up Acct-Delay-Time */	if (request->proxy->code == PW_ACCOUNTING_REQUEST) {		VALUE_PAIR *delaypair;		delaypair = pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME);		if (!delaypair) {			delaypair = paircreate(PW_ACCT_DELAY_TIME, PW_TYPE_INTEGER);			if (!delaypair) {				radlog(L_ERR|L_CONS, "no memory");				exit(1);			}			pairadd(&request->proxy->vps, delaypair);		}		delaypair->lvalue = info->now - request->proxy->timestamp;		/* Must recompile the valuepairs to wire format */		free(request->proxy->data);		request->proxy->data = NULL;	} /* proxy accounting request */	/*	 *  Assert that we have NOT seen the proxy reply yet.	 *	 *  If we HAVE seen it, then we SHOULD NOT be bugging the	 *  home server!	 */	rad_assert(request->proxy_reply == NULL);	/*	 *  Send the proxy packet.	 */	request->proxy_outstanding++;	rad_send(request->proxy, NULL, request->proxysecret);setup_timeout:	/*	 *  Don't do more long-term checks, if we've got to wake	 *  up now.	 */	if (info->smallest == 0) {		return RL_WALK_CONTINUE;	}	/*	 *  The request is finished.  Wake up when it's time to	 *  clean it up.	 */	if (request->finished) {		difference = (request->timestamp + mainconfig.cleanup_delay) - info->now;		/*		 *  If the request is marked up to be rejected later,		 *  then wake up later.		 */		if ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) != 0) {			if (difference >= (time_t) mainconfig.reject_delay) {				difference = (time_t) mainconfig.reject_delay;			}		}	} else if (request->proxy && !request->proxy_reply) {		/*		 *  The request is NOT finished, but there is an		 *  outstanding proxy request, with no matching		 *  proxy reply.		 *		 *  Wake up when it's time to re-send		 *  the proxy request.		 *		 *  But in synchronous proxy, we don't retry but we update		 *  the next retry time as NAS has not resent the request		 *  in the given retry window.		 */		if (mainconfig.proxy_synchronous) {			/*			 *	If the retry_delay * count has passed,			 *	then mark the realm dead.			 */			if (info->now > (request->timestamp + (mainconfig.proxy_retry_delay * mainconfig.proxy_retry_count))) {				rad_assert(request->child_pid == NO_SUCH_CHILD_PID);				request_reject(request);								realm_disable(request->proxy->dst_ipaddr,					      request->proxy->dst_port);				request->finished = TRUE;				goto setup_timeout;			}			request->proxy_next_try = info->now + mainconfig.proxy_retry_delay;		}		difference = request->proxy_next_try - info->now;	} else {		/*		 *  The request is NOT finished.		 *		 *  Wake up when it's time to kill the errant		 *  thread/process.		 */		difference = (request->timestamp + mainconfig.max_request_time) - info->now;	}	/*	 *  If the server is CPU starved, then we CAN miss a time	 *  for servicing requests.  In which case the 'difference'	 *  value will be negative.  select() doesn't like that,	 *  so we fix it.	 */	if (difference < 0) {		difference = 0;	}	/*	 *  Update the 'smallest' time.	 */	if ((info->smallest < 0) ||		(difference < info->smallest)) {		info->smallest = difference;	}	return RL_WALK_CONTINUE;}/* *  Clean up the request list, every so often. * *  This is done by walking through ALL of the list, and *  - marking any requests which are finished, and expired *  - killing any processes which are NOT finished after a delay *  - deleting any marked requests. */struct timeval *rl_clean_list(time_t now){	/*	 *  Static variables, so that we don't do all of this work	 *  more than once per second.	 *	 *  Note that we have 'tv' and 'last_tv'.  'last_tv' is	 *  pointed to by 'last_tv_ptr', and depending on the	 *  system implementation of select(), it MAY be modified.	 *	 *  In that was, we want to use the ORIGINAL value, from	 *  'tv', and wipe out the (possibly modified) last_tv.	 */	static time_t last_cleaned_list = 0;	static struct timeval tv, *last_tv_ptr = NULL;	static struct timeval last_tv;	rl_walk_t info;	info.now = now;	info.smallest = -1;	/*	 *  If we've already set up the timeout or cleaned the	 *  request list this second, then don't do it again.  We	 *  simply return the sleep delay from last time.	 *	 *  Note that if we returned NULL last time, there was nothing	 *  to do.  BUT we've been woken up since then, which can only	 *  happen if we received a packet.  And if we've received a	 *  packet, then there's some work to do in the future.	 *	 *  FIXME: We can probably use gettimeofday() for finer clock	 *  resolution, as the current method will cause it to sleep	 *  too long...	 */	if ((last_tv_ptr != NULL) &&	    (last_cleaned_list == now) &&	    (tv.tv_sec != 0)) {		int i;		/*		 *  If we're NOT walking the entire request list,		 *  then we want to iteratively check the request		 *  list.		 *		 *  If there is NO previous request, go look for one.		 */		if (!last_request)			last_request = rl_next(last_request);		/*		 *  On average, there will be one request per		 *  'cleanup_delay' requests, which needs to be		 *  serviced.		 *		 *  And only do this servicing, if we have a request		 *  to service.		 */		if (last_request)			for (i = 0; i < mainconfig.cleanup_delay; i++) {				REQUEST *next;				/*				 *  This function call MAY delete the				 *  request pointed to by 'last_request'.				 */				next = rl_next(last_request);				refresh_request(last_request, &info);				last_request = next;				/*				 *  Nothing to do any more, exit.				 */				if (!last_request)					break;			}		last_tv = tv;		DEBUG2("Waking up in %d seconds...",				(int) last_tv_ptr->tv_sec);		return last_tv_ptr;	}	last_cleaned_list = now;	last_request = NULL;	DEBUG2("--- Walking the entire request list ---");	/*	 *  Hmmm... this is Big Magic.  We make it seem like	 *  there's an additional second to wait, for a whole	 *  host of reasons which I can't explain adequately,	 *  but which cause the code to Just Work Right.	 */	info.now--;	rl_walk(refresh_request, &info);	/*	 *  We haven't found a time at which we need to wake up.	 *  Return NULL, so that the select() call will sleep forever.	 */	if (info.smallest < 0) {		/*		 *  If we're not proxying, then there really isn't anything		 *  to do.		 *		 *  If we ARE proxying, then we can safely sleep		 *  forever if we're told to NEVER send proxy retries		 *  ourselves, until the NAS kicks us again.		 *		 *  Otherwise, there are no outstanding requests, then		 *  we can sleep forever.  This happens when we get		 *  woken up with a bad packet.  It's discarded, so if		 *  there are no live requests, we can safely sleep		 *  forever.		 */		if ((!mainconfig.proxy_requests) ||		    mainconfig.proxy_synchronous ||		    (rl_num_requests() == 0)) {			DEBUG2("Nothing to do.  Sleeping until we see a request.");			last_tv_ptr = NULL;			return NULL;		}		/*		 *  We ARE proxying.  In that case, we avoid a race condition		 *  where a child thread handling a request proxies the		 *  packet, and sets the retry delay.  In that case, we're		 *  supposed to wake up in N seconds, but we can't, as		 *  we're sleeping forever.		 *		 *  Instead, we prevent the problem by waking up anyhow		 *  at the 'proxy_retry_delay' time, even if there's		 *  nothing to do.  In the worst case, this will cause		 *  the server to wake up every N seconds, to do a small		 *  amount of unnecessary work.		 */		info.smallest = mainconfig.proxy_retry_delay;	}	/*	 *  Set the time (in seconds) for how long we're	 *  supposed to sleep.	 */	tv.tv_sec = info.smallest;	tv.tv_usec = 0;	DEBUG2("Waking up in %d seconds...", (int) info.smallest);	/*	 *  Remember how long we should sleep for.	 */	last_tv = tv;	last_tv_ptr = &last_tv;	return last_tv_ptr;}

⌨️ 快捷键说明

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