summaryrefslogtreecommitdiff
path: root/accel-pppd/radius/acct.c
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2014-09-20 12:18:49 +0400
committerDmitry Kozlov <xeb@mail.ru>2014-09-20 12:18:49 +0400
commit62e89248160d3592c2d754fcaa15e37586a5b091 (patch)
treea6513cfd1e8ef6c6079ea2436e8573b122cc1ec6 /accel-pppd/radius/acct.c
parent0a58c20b44136c1fba996becea18696b3f67a1f9 (diff)
downloadaccel-ppp-62e89248160d3592c2d754fcaa15e37586a5b091.tar.gz
accel-ppp-62e89248160d3592c2d754fcaa15e37586a5b091.zip
rewrite of authentication/accounting procedures
This patch gets rid of synchronuos style of authentication/accounting. Synchronous style of authentication/accounting produced sleeping threads which becomes a problem when lots of sessions started/stopped and all they want authorization/accounting.
Diffstat (limited to 'accel-pppd/radius/acct.c')
-rw-r--r--accel-pppd/radius/acct.c654
1 files changed, 315 insertions, 339 deletions
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index 9a5e549e..f9919453 100644
--- a/accel-pppd/radius/acct.c
+++ b/accel-pppd/radius/acct.c
@@ -18,7 +18,6 @@
#include "memdebug.h"
-#define STAT_UPDATE_INTERVAL (10 * 60 * 1000)
#define INTERIM_SAFE_TIME 10
static int req_set_RA(struct rad_req_t *req, const char *secret)
@@ -40,13 +39,13 @@ static int req_set_stat(struct rad_req_t *req, struct ap_session *ses)
{
struct rtnl_link_stats stats;
struct radius_pd_t *rpd = req->rpd;
- time_t stop_time;
+ struct timespec ts;
int ret = 0;
if (ses->stop_time)
- stop_time = ses->stop_time;
+ ts.tv_sec = ses->stop_time;
else
- time(&stop_time);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
if (ap_session_read_stats(ses, &stats) == 0) {
rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", stats.rx_bytes);
@@ -58,99 +57,56 @@ static int req_set_stat(struct rad_req_t *req, struct ap_session *ses)
} else
ret = -1;
- rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", stop_time - ses->start_time);
+ rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", ts.tv_sec - ses->start_time);
return ret;
}
-static int rad_acct_read(struct triton_md_handler_t *h)
+static void rad_acct_sent(struct rad_req_t *req, int res)
{
- struct rad_req_t *req = container_of(h, typeof(*req), hnd);
- struct rad_packet_t *pack;
- int r;
- unsigned int dt;
-
- if (req->reply) {
- rad_packet_free(req->reply);
- req->reply = NULL;
+ if (res) {
+ if (conf_acct_timeout)
+ ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0);
+ else
+ triton_timer_del(&req->timeout);
+ return;
}
-
- while (1) {
- r = rad_packet_recv(h->fd, &pack, NULL);
-
- if (pack) {
- rad_server_reply(req->serv);
- if (req->reply)
- rad_packet_free(req->reply);
- req->reply = pack;
- if (conf_interim_verbose) {
- log_ppp_info2("recv ");
- rad_packet_print(req->reply, req->serv, log_ppp_info2);
- }
- }
-
- if (r)
- break;
+
+ __sync_add_and_fetch(&req->serv->stat_interim_sent, 1);
+
+ if (!req->hnd.tpd) {
+ triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd);
+ triton_md_enable_handler(&req->hnd, MD_MODE_READ);
}
- if (!req->reply)
- return 0;
-
- if (req->reply->id != req->pack->id)
- return 0;
-
- rad_server_req_exit(req);
+ if (req->timeout.tpd)
+ triton_timer_mod(&req->timeout, 0);
+ else
+ triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0);
+}
- dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 +
+static void rad_acct_recv(struct rad_req_t *req)
+{
+ int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 +
(req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000;
stat_accm_add(req->serv->stat_interim_query_1m, dt);
stat_accm_add(req->serv->stat_interim_query_5m, dt);
- if (req->reply->code != CODE_ACCOUNTING_RESPONSE || req->reply->id != req->pack->id) {
- rad_packet_free(req->reply);
- req->reply = NULL;
- } else {
- if (req->timeout.tpd)
- triton_timer_del(&req->timeout);
- }
-
- triton_md_unregister_handler(h, 1);
-
- return 1;
-}
-
-static int __rad_req_send(struct rad_req_t *req)
-{
- while (1) {
- if (rad_server_req_enter(req)) {
- if (rad_server_realloc(req))
- return -1;
- continue;
- }
-
- if (rad_req_send(req, conf_interim_verbose ? log_ppp_info2 : NULL)) {
- rad_server_req_exit(req);
- rad_server_fail(req->serv);
- continue;
- }
-
- if (!req->hnd.tpd) {
- triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd);
- triton_md_enable_handler(&req->hnd, MD_MODE_READ);
- }
+ triton_timer_del(&req->timeout);
- break;
- }
-
- return 0;
+ triton_md_unregister_handler(&req->hnd, 1);
+
+ rad_packet_free(req->reply);
+ req->reply = NULL;
}
static void rad_acct_timeout(struct triton_timer_t *t)
{
struct rad_req_t *req = container_of(t, typeof(*req), timeout);
- time_t ts, dt;
-
+ time_t dt;
+ struct timespec ts;
+
rad_server_req_exit(req);
rad_server_timeout(req->serv);
@@ -164,9 +120,9 @@ static void rad_acct_timeout(struct triton_timer_t *t)
return;
}
- time(&ts);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
- dt = ts - req->rpd->acct_timestamp;
+ dt = ts.tv_sec - req->ts;
if (dt > conf_acct_timeout) {
rad_server_fail(req->serv);
@@ -176,42 +132,30 @@ static void rad_acct_timeout(struct triton_timer_t *t)
ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0);
return;
}
- time(&req->rpd->acct_timestamp);
}
- if (dt > conf_acct_timeout / 2) {
- req->timeout.period += 1000;
- triton_timer_mod(&req->timeout, 0);
- } else if (dt > conf_acct_timeout / 3) {
- if (req->timeout.period != conf_timeout * 2000) {
- req->timeout.period = conf_timeout * 2000;
- triton_timer_mod(&req->timeout, 0);
- }
+ if (dt > conf_acct_timeout / 2)
+ req->timeout.expire_tv.tv_sec++;
+ else if (dt > conf_acct_timeout / 4) {
+ if (req->timeout.expire_tv.tv_sec < conf_timeout * 2)
+ req->timeout.expire_tv.tv_sec = conf_timeout * 2;
}
- if (conf_acct_delay_time) {
+ if (conf_acct_delay_time)
req->pack->id++;
- rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", dt);
- req_set_RA(req, req->serv->secret);
- }
-
- if (__rad_req_send(req)) {
- triton_timer_del(t);
-
- if (conf_acct_timeout) {
- log_ppp_warn("radius:acct: no servers available, terminating session...\n");
- ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0);
- }
+
+ req->try = 0;
- return;
+ if (rad_req_send(req) && conf_acct_timeout) {
+ log_ppp_warn("radius:acct: no servers available, terminating session...\n");
+ ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0);
}
-
- __sync_add_and_fetch(&req->serv->stat_interim_sent, 1);
}
static void rad_acct_interim_update(struct triton_timer_t *t)
{
struct radius_pd_t *rpd = container_of(t, typeof(*rpd), acct_interim_timer);
+ struct timespec ts;
if (rpd->acct_req->timeout.tpd)
return;
@@ -228,281 +172,313 @@ static void rad_acct_interim_update(struct triton_timer_t *t)
if (!rpd->acct_interim_interval)
return;
- time(&rpd->acct_timestamp);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ rpd->acct_req->ts = ts.tv_sec;
rpd->acct_req->pack->id++;
- rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Interim-Update");
- if (conf_acct_delay_time)
- rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", 0);
- req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret);
+ if (!rpd->acct_req->before_send)
+ req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret);
+
+ rpd->acct_req->timeout.expire_tv.tv_sec = conf_timeout;
+ rpd->acct_req->try = 0;
- if (__rad_req_send(rpd->acct_req))
- return;
+ if (rad_req_send(rpd->acct_req) && conf_acct_timeout) {
+ log_ppp_warn("radius:acct: no servers available, terminating session...\n");
+ ap_session_terminate(rpd->ses, TERM_NAS_ERROR, 0);
+ }
+}
- /* The above call may set rpd->acct_req to NULL in the following chain of events:
- 1. __rad_req_send fails (on rad_server_realloc) and calls ppp_terminate;
- 2. As a result, an EV_PPP_FINISHING event is fired;
- 3. ppp_finishing calls rad_acct_stop that cleans up the request. */
- if (!rpd->acct_req)
- return;
+static int rad_acct_before_send(struct rad_req_t *req)
+{
+ struct timespec ts;
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_interim_sent, 1);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", ts.tv_sec - req->ts);
+ req_set_RA(req, req->serv->secret);
- rpd->acct_req->timeout.period = conf_timeout * 1000;
- triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_req->timeout, 0);
+ return 0;
}
-int rad_acct_start(struct radius_pd_t *rpd)
+static void rad_acct_start_sent(struct rad_req_t *req, int res)
{
- int i;
- time_t ts;
- unsigned int dt;
+ if (res) {
+ ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0);
+ return;
+ }
- if (!conf_accounting)
- return 0;
+ __sync_add_and_fetch(&req->serv->stat_acct_sent, 1);
- if (!rpd->acct_req)
- rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
+ if (!req->hnd.tpd) {
+ triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd);
+ triton_md_enable_handler(&req->hnd, MD_MODE_READ);
+ }
- if (!rpd->acct_req)
- return -1;
+ if (req->timeout.tpd)
+ triton_timer_mod(&req->timeout, 0);
+ else
+ triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0);
+}
- if (rad_req_acct_fill(rpd->acct_req)) {
- log_ppp_error("radius:acct: failed to fill accounting attributes\n");
- goto out_err;
- }
+static void rad_acct_start_recv(struct rad_req_t *req)
+{
+ struct radius_pd_t *rpd = req->rpd;
+ int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 +
+ (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000;
+
+ stat_accm_add(req->serv->stat_acct_query_1m, dt);
+ stat_accm_add(req->serv->stat_acct_query_5m, dt);
- //if (rad_req_add_val(rpd->acct_req, "Acct-Status-Type", "Start", 4))
- // goto out_err;
- //if (rad_req_add_str(rpd->acct_req, "Acct-Session-Id", rpd->ses->ionid, PPP_SESSIONID_LEN, 1))
- // goto out_err;
+ triton_timer_del(&req->timeout);
- if (rpd->acct_req->reply) {
- rad_packet_free(rpd->acct_req->reply);
- rpd->acct_req->reply = NULL;
+ triton_md_unregister_handler(&req->hnd, 1);
+
+ if (rpd->acct_interim_interval) {
+ rad_packet_free(req->reply);
+ req->reply = NULL;
+
+ rad_packet_change_val(req->pack, NULL, "Acct-Status-Type", "Interim-Update");
+ rpd->acct_interim_timer.expire = rad_acct_interim_update;
+ rpd->acct_interim_timer.period = rpd->acct_interim_interval * 1000;
+ triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_interim_timer, 0);
+
+ req->timeout.expire = rad_acct_timeout;
+ req->recv = rad_acct_recv;
+ req->sent = rad_acct_sent;
+ req->log = conf_interim_verbose ? log_ppp_info2 : NULL;
+ } else {
+ rad_req_free(rpd->acct_req);
+ rpd->acct_req = NULL;
}
- time(&rpd->acct_timestamp);
+ rpd->acct_started = 1;
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- goto out_err;
+ ap_session_accounting_started(rpd->ses);
+}
-#ifdef USE_BACKUP
- if (rpd->ses->state != AP_STATE_RESTORE || !rpd->ses->backup->internal) {
-#endif
- while (1) {
-
- if (rad_server_req_enter(rpd->acct_req)) {
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_start: no servers available\n");
- goto out_err;
- }
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- goto out_err;
- continue;
- }
-
- for (i = 0; i < conf_max_try; i++) {
- if (conf_acct_delay_time) {
- time(&ts);
- rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret)) {
- rad_server_req_exit(rpd->acct_req);
- goto out_err;
- }
- }
-
- if (rad_req_send(rpd->acct_req, conf_verbose ? log_ppp_info1 : NULL))
- goto out;
-
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1);
-
- rad_req_wait(rpd->acct_req, conf_timeout);
-
- if (!rpd->acct_req->reply) {
- if (conf_acct_delay_time)
- rpd->acct_req->pack->id++;
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- continue;
- }
-
- dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
- (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000;
- stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
- stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt);
-
- if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
- rad_packet_free(rpd->acct_req->reply);
- rpd->acct_req->reply = NULL;
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- } else
- break;
- }
-
-out:
- rad_server_req_exit(rpd->acct_req);
-
- if (rpd->acct_req->reply)
- break;
-
- rad_server_fail(rpd->acct_req->serv);
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_start: no servers available\n");
- goto out_err;
- }
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- goto out_err;
- }
-#ifdef USE_BACKUP
+static void rad_acct_start_timeout(struct triton_timer_t *t)
+{
+ struct rad_req_t *req = container_of(t, typeof(*req), timeout);
+
+ __sync_add_and_fetch(&req->serv->stat_acct_lost, 1);
+ stat_accm_add(req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(req->serv->stat_acct_lost_5m, 1);
+
+ if (req->before_send)
+ req->pack->id++;
+
+ if (rad_req_send(req))
+ ap_session_terminate(req->rpd->ses, TERM_NAS_ERROR, 0);
+}
+
+int rad_acct_start(struct radius_pd_t *rpd)
+{
+ struct rad_req_t *req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
+
+ if (!req)
+ return -1;
+
+ if (rad_req_acct_fill(req)) {
+ log_ppp_error("radius:acct: failed to fill accounting attributes\n");
+ goto out_err;
}
-#endif
- close(rpd->acct_req->hnd.fd);
- rpd->acct_req->hnd.fd = -1;
- rpd->acct_req->hnd.read = rad_acct_read;
+ if (conf_acct_delay_time)
+ req->before_send = rad_acct_before_send;
+ else if (req_set_RA(req, req->serv->secret))
+ goto out_err;
+
+ req->recv = rad_acct_start_recv;
+ req->timeout.expire = rad_acct_start_timeout;
+ req->timeout.expire_tv.tv_sec = conf_timeout;
+ req->sent = rad_acct_start_sent;
+ req->log = conf_verbose ? log_ppp_info1 : NULL;
- rpd->acct_req->timeout.expire = rad_acct_timeout;
- rpd->acct_req->timeout.period = conf_timeout * 1000;
+ if (rad_req_send(req))
+ goto out_err;
+
+ rpd->acct_req = req;
- rpd->acct_interim_timer.expire = rad_acct_interim_update;
- rpd->acct_interim_timer.period = rpd->acct_interim_interval ? rpd->acct_interim_interval * 1000 : STAT_UPDATE_INTERVAL;
- if (rpd->acct_interim_interval)
- triton_timer_add(rpd->ses->ctrl->ctx, &rpd->acct_interim_timer, 0);
return 0;
out_err:
- rad_req_free(rpd->acct_req);
- rpd->acct_req = NULL;
+ rad_req_free(req);
return -1;
}
-void rad_acct_stop(struct radius_pd_t *rpd)
+static void rad_acct_stop_sent(struct rad_req_t *req, int res)
{
- int i;
- time_t ts;
- unsigned int dt;
-
- if (!rpd->acct_req || !rpd->acct_req->serv)
+ if (res) {
+ if (req->rpd)
+ rad_acct_stop_defer(req->rpd);
+ else {
+ if (ap_shutdown)
+ rad_req_free(req);
+ else
+ req->try = 0;
+ }
+
return;
+ }
+
+ __sync_add_and_fetch(&req->serv->stat_acct_sent, 1);
+
+ if (!req->hnd.tpd) {
+ triton_md_register_handler(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->hnd);
+ triton_md_enable_handler(&req->hnd, MD_MODE_READ);
+ }
- if (rpd->acct_interim_timer.tpd)
- triton_timer_del(&rpd->acct_interim_timer);
+ if (req->timeout.tpd)
+ triton_timer_mod(&req->timeout, 0);
+ else
+ triton_timer_add(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->timeout, 0);
+}
- if (rpd->acct_req->timeout.tpd)
- rad_server_req_exit(rpd->acct_req);
+static void rad_acct_stop_recv(struct rad_req_t *req)
+{
+ struct radius_pd_t *rpd = req->rpd;
+ int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 +
+ (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000;
+
+ stat_accm_add(req->serv->stat_acct_query_1m, dt);
+ stat_accm_add(req->serv->stat_acct_query_5m, dt);
+
+ rad_req_free(req);
- if (rpd->acct_req->hnd.tpd)
- triton_md_unregister_handler(&rpd->acct_req->hnd, 0);
+ if (rpd)
+ rpd->acct_req = NULL;
+}
+
+static void rad_acct_stop_timeout(struct triton_timer_t *t)
+{
+ struct rad_req_t *req = container_of(t, typeof(*req), timeout);
+
+ if (req->active) {
+ rad_server_req_exit(req);
+ rad_server_timeout(req->serv);
+
+ __sync_add_and_fetch(&req->serv->stat_acct_lost, 1);
+ stat_accm_add(req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(req->serv->stat_acct_lost_5m, 1);
- if (rpd->acct_req->timeout.tpd)
- triton_timer_del(&rpd->acct_req->timeout);
-
- switch (rpd->ses->terminate_cause) {
- case TERM_USER_REQUEST:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Request");
- break;
- case TERM_SESSION_TIMEOUT:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Session-Timeout");
- break;
- case TERM_ADMIN_RESET:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Admin-Reset");
- break;
- case TERM_USER_ERROR:
- case TERM_AUTH_ERROR:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "User-Error");
- break;
- case TERM_NAS_ERROR:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Error");
- break;
- case TERM_NAS_REQUEST:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Request");
- break;
- case TERM_NAS_REBOOT:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "NAS-Reboot");
- break;
- case TERM_LOST_CARRIER:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Lost-Carrier");
- break;
- case TERM_IDLE_TIMEOUT:
- rad_packet_add_val(rpd->acct_req->pack, NULL, "Acct-Terminate-Cause", "Idle-Timeout");
- break;
+ if (req->before_send)
+ req->pack->id++;
+ }
+
+ if (req->try == conf_max_try) {
+ rad_req_free(req);
+ return;
+ }
+
+ if (rad_req_send(req)) {
+ if (ap_shutdown) {
+ rad_req_free(req);
+ return;
}
- rad_packet_change_val(rpd->acct_req->pack, NULL, "Acct-Status-Type", "Stop");
- req_set_stat(rpd->acct_req, rpd->ses);
- req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret);
- /// !!! rad_req_add_val(rpd->acct_req, "Acct-Terminate-Cause", "");
+ req->try = 0;
+ }
+}
+
+static void start_deferred(struct rad_req_t *req)
+{
+ if (req->hnd.fd != -1) {
+ triton_md_register_handler(NULL, &req->hnd);
+ triton_md_enable_handler(&req->hnd, MD_MODE_READ);
+ if (rad_req_read(&req->hnd))
+ return;
+ }
+
+ triton_timer_add(NULL, &req->timeout, 0);
+}
+
+void rad_acct_stop_defer(struct radius_pd_t *rpd)
+{
+ struct rad_req_t *req = rpd->acct_req;
+ rad_server_req_cancel(req);
+ if (req->hnd.tpd)
+ triton_md_unregister_handler(&req->hnd, 0);
+ rpd->acct_req = NULL;
+
+ req->rpd = NULL;
+ req->log = conf_verbose ? log_info1 : NULL;
+ req->timeout.expire = rad_acct_stop_timeout;
+
+ triton_context_call(NULL, (triton_event_func)start_deferred, req);
+}
+
+int rad_acct_stop(struct radius_pd_t *rpd)
+{
+ struct rad_req_t *req = rpd->acct_req;
+ struct timespec ts;
+
+ if (req) {
+ triton_timer_del(&rpd->acct_interim_timer);
- if (rpd->acct_req->reply) {
- rad_packet_free(rpd->acct_req->reply);
- rpd->acct_req->reply = NULL;
- }
+ rad_server_req_cancel(req);
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ req->ts = ts.tv_sec;
+ req->try = 0;
+ } else {
+ req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
+ if (!req)
+ return -1;
- time(&rpd->acct_timestamp);
-
- while (1) {
-
- if (rad_server_req_enter(rpd->acct_req)) {
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_stop: no servers available\n");
- break;
- }
- req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret);
- continue;
- }
-
- for(i = 0; i < conf_max_try; i++) {
- if (conf_acct_delay_time) {
- time(&ts);
- rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
- rpd->acct_req->pack->id++;
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- break;
- }
- if (rad_req_send(rpd->acct_req, conf_verbose ? log_ppp_info1 : NULL))
- goto out;
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1);
- rad_req_wait(rpd->acct_req, conf_timeout);
- if (!rpd->acct_req->reply) {
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- continue;
- }
-
- dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
- (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000;
- stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
- stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt);
-
- if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
- rad_packet_free(rpd->acct_req->reply);
- rpd->acct_req->reply = NULL;
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- } else
- break;
- }
-
-out:
- rad_server_req_exit(rpd->acct_req);
-
- if (rpd->acct_req->reply)
- break;
-
- rad_server_fail(rpd->acct_req->serv);
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_stop: no servers available\n");
- break;
- }
- req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret);
+ if (rad_req_acct_fill(req)) {
+ log_ppp_error("radius:acct: failed to fill accounting attributes\n");
+ rad_req_free(req);
+ return -1;
}
- rad_req_free(rpd->acct_req);
- rpd->acct_req = NULL;
+ rpd->acct_req = req;
+ }
+
+ switch (rpd->ses->terminate_cause) {
+ case TERM_USER_REQUEST:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "User-Request");
+ break;
+ case TERM_SESSION_TIMEOUT:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Session-Timeout");
+ break;
+ case TERM_ADMIN_RESET:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Admin-Reset");
+ break;
+ case TERM_USER_ERROR:
+ case TERM_AUTH_ERROR:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "User-Error");
+ break;
+ case TERM_NAS_ERROR:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Error");
+ break;
+ case TERM_NAS_REQUEST:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Request");
+ break;
+ case TERM_NAS_REBOOT:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "NAS-Reboot");
+ break;
+ case TERM_LOST_CARRIER:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Lost-Carrier");
+ break;
+ case TERM_IDLE_TIMEOUT:
+ rad_packet_add_val(req->pack, NULL, "Acct-Terminate-Cause", "Idle-Timeout");
+ break;
+ }
+
+ rad_packet_change_val(req->pack, NULL, "Acct-Status-Type", "Stop");
+ req_set_stat(req, rpd->ses);
+ req_set_RA(req, req->serv->secret);
+
+ req->recv = rad_acct_stop_recv;
+ req->timeout.expire = rad_acct_start_timeout;
+ req->timeout.expire_tv.tv_sec = conf_timeout;
+ req->sent = rad_acct_stop_sent;
+ req->log = conf_verbose ? log_ppp_info1 : NULL;
+
+ if (rad_req_send(req)) {
+ rad_acct_stop_defer(rpd);
+ return -1;
+ }
+
+ return 0;
}