2 * stats.c Internal statistics handling.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008 Alan DeKok <aland@deployingradius.com>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
32 #define USEC (1000000)
33 #define PREC (USEC * EMA_SCALE)
35 #define F_EMA_SCALE (1000000)
37 struct timeval radius_start_time;
38 struct timeval radius_hup_time;
40 fr_stats_t radius_auth_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
41 #ifdef WITH_ACCOUNTING
42 fr_stats_t radius_acct_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
46 fr_stats_t proxy_auth_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
47 #ifdef WITH_ACCOUNTING
48 fr_stats_t proxy_acct_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
52 void request_stats_final(REQUEST *request)
54 if (request->master_state == REQUEST_COUNTED) return;
56 if ((request->listener->type != RAD_LISTEN_NONE) &&
57 (request->listener->type != RAD_LISTEN_AUTH) &&
58 (request->listener->type != RAD_LISTEN_ACCT)) return;
61 #define INC_AUTH(_x) radius_auth_stats._x++;request->listener->stats._x++;if (request->client && request->client->auth) request->client->auth->_x++;
65 #define INC_ACCT(_x) radius_acct_stats._x++;request->listener->stats._x++;if (request->client && request->client->acct) request->client->acct->_x++
68 * Update the statistics.
70 * Note that we do NOT do this in a child thread.
71 * Instead, we update the stats when a request is
72 * deleted, because only the main server thread calls
73 * this function, which makes it thread-safe.
75 if (request->reply) switch (request->reply->code) {
76 case PW_AUTHENTICATION_ACK:
77 INC_AUTH(total_responses);
78 INC_AUTH(total_access_accepts);
81 case PW_AUTHENTICATION_REJECT:
82 INC_AUTH(total_responses);
83 INC_AUTH(total_access_rejects);
86 case PW_ACCESS_CHALLENGE:
87 INC_AUTH(total_responses);
88 INC_AUTH(total_access_challenges);
91 #ifdef WITH_ACCOUNTING
92 case PW_ACCOUNTING_RESPONSE:
93 INC_ACCT(total_responses);
98 * No response, it must have been a bad
102 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
103 if (request->reply->offset == -2) {
104 INC_AUTH(total_bad_authenticators);
106 INC_AUTH(total_packets_dropped);
108 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
109 if (request->reply->offset == -2) {
110 INC_ACCT(total_bad_authenticators);
112 INC_ACCT(total_packets_dropped);
122 if (!request->proxy || !request->proxy_listener) goto done; /* simplifies formatting */
124 switch (request->proxy->code) {
125 case PW_AUTHENTICATION_REQUEST:
126 proxy_auth_stats.total_requests += request->num_proxied_requests;
127 request->proxy_listener->stats.total_requests += request->num_proxied_requests;
128 request->home_server->stats.total_requests += request->num_proxied_requests;
131 #ifdef WITH_ACCOUNTING
132 case PW_ACCOUNTING_REQUEST:
133 proxy_acct_stats.total_requests++;
134 request->proxy_listener->stats.total_requests += request->num_proxied_requests;
135 request->home_server->stats.total_requests += request->num_proxied_requests;
143 if (!request->proxy_reply) goto done; /* simplifies formatting */
146 #define INC(_x) proxy_auth_stats._x += request->num_proxied_responses; request->proxy_listener->stats._x += request->num_proxied_responses; request->home_server->stats._x += request->num_proxied_responses;
148 switch (request->proxy_reply->code) {
149 case PW_AUTHENTICATION_ACK:
150 INC(total_responses);
151 INC(total_access_accepts);
154 case PW_AUTHENTICATION_REJECT:
155 INC(total_responses);
156 INC(total_access_rejects);
159 case PW_ACCESS_CHALLENGE:
160 INC(total_responses);
161 INC(total_access_challenges);
164 #ifdef WITH_ACCOUNTING
165 case PW_ACCOUNTING_RESPONSE:
166 radius_acct_stats.total_responses++;
167 request->proxy_listener->stats.total_responses++;
168 request->home_server->stats.total_responses++;
173 proxy_auth_stats.total_unknown_types++;
174 request->proxy_listener->stats.total_unknown_types++;
175 request->home_server->stats.total_unknown_types++;
180 #endif /* WITH_PROXY */
182 request->master_state = REQUEST_COUNTED;
185 void radius_stats_init(int flag)
188 gettimeofday(&radius_start_time, NULL);
189 radius_hup_time = radius_start_time; /* it's just nicer this way */
191 gettimeofday(&radius_hup_time, NULL);
195 void radius_stats_ema(fr_stats_ema_t *ema,
196 struct timeval *start, struct timeval *end)
200 #ifdef WITH_STATS_DEBUG
203 if (ema->window == 0) return;
205 rad_assert(start->tv_sec >= end->tv_sec);
211 if (ema->window > 10000) ema->window = 10000;
213 ema->f1 = (2 * F_EMA_SCALE) / (ema->window + 1);
214 ema->f10 = (2 * F_EMA_SCALE) / ((10 * ema->window) + 1);
218 tdiff = start->tv_sec;
219 tdiff -= end->tv_sec;
222 if (micro > 40) micro = 40; /* don't overflow 32-bit ints */
224 micro += start->tv_usec;
225 micro -= end->tv_usec;
229 if (ema->ema1 == 0) {
235 diff = ema->f1 * (micro - ema->ema1);
236 ema->ema1 += (diff / 1000000);
238 diff = ema->f10 * (micro - ema->ema10);
239 ema->ema10 += (diff / 1000000);
243 #ifdef WITH_STATS_DEBUG
244 DEBUG("time %d %d.%06d\t%d.%06d\t%d.%06d\n",
245 n, micro / PREC, (micro / EMA_SCALE) % USEC,
246 ema->ema1 / PREC, (ema->ema1 / EMA_SCALE) % USEC,
247 ema->ema10 / PREC, (ema->ema10 / EMA_SCALE) % USEC);
252 #endif /* WITH_STATS */