summaryrefslogtreecommitdiff
path: root/accel-pppd/radius
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
parent0a58c20b44136c1fba996becea18696b3f67a1f9 (diff)
downloadaccel-ppp-xebd-62e89248160d3592c2d754fcaa15e37586a5b091.tar.gz
accel-ppp-xebd-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')
-rw-r--r--accel-pppd/radius/acct.c654
-rw-r--r--accel-pppd/radius/auth.c492
-rw-r--r--accel-pppd/radius/packet.c11
-rw-r--r--accel-pppd/radius/radius.c70
-rw-r--r--accel-pppd/radius/radius_p.h47
-rw-r--r--accel-pppd/radius/req.c173
-rw-r--r--accel-pppd/radius/serv.c205
7 files changed, 860 insertions, 792 deletions
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index 9a5e549..f991945 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;
}
diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c
index f4efe3b..b73f259 100644
--- a/accel-pppd/radius/auth.c
+++ b/accel-pppd/radius/auth.c
@@ -4,6 +4,7 @@
#include "crypto.h"
#include "triton.h"
+#include "mempool.h"
#include "events.h"
#include "log.h"
#include "pwdb.h"
@@ -142,193 +143,179 @@ static uint8_t* encrypt_password(const char *passwd, const char *secret, const u
return epasswd;
}
-static int rad_auth_send(struct rad_req_t *req)
+static void rad_auth_finalize(struct radius_pd_t *rpd, int r)
{
- int i;
- struct timespec tv, tv2;
+ hold_pd(rpd);
+
+ rpd->auth_ctx->cb(rpd->auth_ctx->cb_arg, r);
+
+ if (rpd->auth_ctx) {
+ rad_req_free(rpd->auth_ctx->req);
+ mempool_free(rpd->auth_ctx);
+ rpd->auth_ctx = NULL;
+ }
+
+ release_pd(rpd);
+}
+
+static void rad_auth_recv(struct rad_req_t *req)
+{
+ struct rad_packet_t *pack = req->reply;
unsigned int dt;
- int timeout;
- while (1) {
- if (rad_server_req_enter(req)) {
- if (rad_server_realloc(req)) {
- log_ppp_warn("radius: no available servers\n");
- break;
- }
- continue;
+ triton_timer_del(&req->timeout);
+
+ 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_auth_query_1m, dt);
+ stat_accm_add(req->serv->stat_auth_query_5m, dt);
+
+ if (pack->code == CODE_ACCESS_ACCEPT) {
+ if (rad_proc_attrs(req)) {
+ rad_auth_finalize(req->rpd, PWDB_DENIED);
+ return;
}
+
+ struct ev_radius_t ev = {
+ .ses = req->rpd->ses,
+ .request = req->pack,
+ .reply = pack,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ }
+
+ if (req->rpd->auth_ctx->recv && req->rpd->auth_ctx->recv(req)) {
+ rad_auth_finalize(req->rpd, PWDB_DENIED);
+ return;
+ }
+
+ req->rpd->authenticated = 1;
+
+ rad_auth_finalize(req->rpd, PWDB_SUCCESS);
+}
- for(i = 0; i < conf_max_try; i++) {
- __sync_add_and_fetch(&req->serv->stat_auth_sent, 1);
- clock_gettime(CLOCK_MONOTONIC, &tv);
- if (rad_req_send(req, conf_verbose ? log_ppp_info1 : NULL))
- goto out;
+static void rad_auth_timeout(struct triton_timer_t *t)
+{
+ struct rad_req_t *req = container_of(t, typeof(*req), timeout);
+
+ __sync_add_and_fetch(&req->serv->stat_auth_lost, 1);
+ stat_accm_add(req->serv->stat_auth_lost_1m, 1);
+ stat_accm_add(req->serv->stat_auth_lost_5m, 1);
- timeout = conf_timeout;
+ if (rad_req_send(req))
+ rad_auth_finalize(req->rpd, PWDB_DENIED);
+}
- while (timeout > 0) {
+static void rad_auth_sent(struct rad_req_t *req, int res)
+{
+ if (res) {
+ rad_auth_finalize(req->rpd, PWDB_DENIED);
+ return;
+ }
+
+ __sync_add_and_fetch(&req->serv->stat_auth_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->timeout.tpd)
+ triton_timer_mod(&req->timeout, 0);
+ else
+ triton_timer_add(req->rpd->ses->ctrl->ctx, &req->timeout, 0);
+}
+
+static struct rad_req_t *rad_auth_req_alloc(struct radius_pd_t *rpd, const char *username, int (*recv)(struct rad_req_t *))
+{
+ struct rad_req_t *req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+
+ if (!req)
+ return NULL;
+
+ if (conf_sid_in_auth) {
+ if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid))
+ goto out;
+ }
- rad_req_wait(req, timeout);
+ if (rpd->attr_state) {
+ if (rad_packet_add_octets(req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
+ goto out;
+ }
- if (req->reply) {
- if (req->reply->id != req->pack->id) {
- rad_packet_free(req->reply);
- req->reply = NULL;
- clock_gettime(CLOCK_MONOTONIC, &tv2);
- timeout = conf_timeout - ((tv2.tv_sec - tv.tv_sec) * 1000 + (tv2.tv_nsec - tv.tv_nsec) / 1000000);
- } else
- break;
- } else
- break;
- }
+ req->hnd.read = rad_req_read;
+ req->timeout.expire = rad_auth_timeout;
+ req->timeout.expire_tv.tv_sec = conf_timeout;
+ req->recv = rad_auth_recv;
+ req->sent = rad_auth_sent;
+ if (conf_verbose)
+ req->log = log_ppp_info1;
- if (req->reply) {
- dt = (req->reply->tv.tv_sec - tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - tv.tv_nsec) / 1000000;
- stat_accm_add(req->serv->stat_auth_query_1m, dt);
- stat_accm_add(req->serv->stat_auth_query_5m, dt);
- break;
- } else {
- __sync_add_and_fetch(&req->serv->stat_auth_lost, 1);
- stat_accm_add(req->serv->stat_auth_lost_1m, 1);
- stat_accm_add(req->serv->stat_auth_lost_5m, 1);
- }
- }
-out:
- rad_server_req_exit(req);
+ rpd->auth_ctx->recv = recv;
+ rpd->auth_ctx->req = req;
- if (!req->reply) {
- rad_server_fail(req->serv);
- if (rad_server_realloc(req)) {
- log_ppp_warn("radius: no available servers\n");
- break;
- }
- } else {
- if (req->reply->code == CODE_ACCESS_ACCEPT) {
- if (rad_proc_attrs(req))
- return PWDB_DENIED;
- return PWDB_SUCCESS;
- } else
- break;
- }
- }
+ return req;
- return PWDB_DENIED;
+out:
+ rad_req_free(req);
+ return NULL;
}
int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args)
{
- struct rad_req_t *req;
- int r = PWDB_DENIED;
- //int id = va_arg(args, int);
+ struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL);
+ int r;
const char *passwd = va_arg(args, const char *);
uint8_t *epasswd;
int epasswd_len;
- req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
if (!req)
return PWDB_DENIED;
epasswd = encrypt_password(passwd, req->serv->secret, req->RA, &epasswd_len);
if (!epasswd)
- goto out;
-
- if (rad_packet_add_octets(req->pack, NULL, "User-Password", epasswd, epasswd_len)) {
- if (epasswd_len)
- _free(epasswd);
- goto out;
- }
+ return PWDB_DENIED;
+ r = rad_packet_add_octets(req->pack, NULL, "User-Password", epasswd, epasswd_len);
if (epasswd_len)
_free(epasswd);
+
+ if (r)
+ return PWDB_DENIED;
- if (conf_sid_in_auth)
- if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid))
- return -1;
-
- r = rad_auth_send(req);
- if (r == PWDB_SUCCESS) {
- struct ev_radius_t ev = {
- .ses = rpd->ses,
- .request = req->pack,
- .reply = req->reply,
- };
- triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
- }
-
-out:
- rad_req_free(req);
+ if (rad_req_send(req))
+ return PWDB_DENIED;
- return r;
+ return PWDB_WAIT;
}
int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args)
{
- int r = PWDB_DENIED;
+ struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL);
uint8_t chap_password[17];
-
int id = va_arg(args, int);
uint8_t *challenge = va_arg(args, uint8_t *);
int challenge_len = va_arg(args, int);
uint8_t *response = va_arg(args, uint8_t *);
+
+ if (!req)
+ return PWDB_DENIED;
chap_password[0] = id;
memcpy(chap_password + 1, response, 16);
- if (!rpd->auth_req) {
- rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
- if (!rpd->auth_req)
- return PWDB_DENIED;
-
- if (challenge_len == 16)
- memcpy(rpd->auth_req->RA, challenge, 16);
- if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len))
- goto out;
+ if (challenge_len == 16)
+ memcpy(req->RA, challenge, 16);
- if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17))
- goto out;
- } else {
- if (challenge_len == 16)
- memcpy(rpd->auth_req->RA, challenge, 16);
- if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Challenge", challenge, challenge_len))
- goto out;
+ if (rad_packet_add_octets(req->pack, NULL, "CHAP-Challenge", challenge, challenge_len))
+ return PWDB_DENIED;
- if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "CHAP-Password", chap_password, 17))
- goto out;
-
- if (rpd->attr_state) {
- if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) {
- if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
- goto out;
- } else {
- if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
- goto out;
- }
- }
-
- if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA))
- return -1;
- }
+ if (rad_packet_add_octets(req->pack, NULL, "CHAP-Password", chap_password, 17))
+ return PWDB_DENIED;
- if (conf_sid_in_auth)
- if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid))
- goto out;
-
- r = rad_auth_send(rpd->auth_req);
- if (r == PWDB_SUCCESS) {
- struct ev_radius_t ev = {
- .ses = rpd->ses,
- .request = rpd->auth_req->pack,
- .reply = rpd->auth_req->reply,
- };
- triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
- rpd->auth_req->pack->id++;
- }
-
-out:
- rad_req_free(rpd->auth_req);
- rpd->auth_req = NULL;
+ if (rad_req_send(req))
+ return PWDB_DENIED;
- return r;
+ return PWDB_WAIT;
}
static void setup_mppe(struct rad_req_t *req, const uint8_t *challenge)
@@ -376,11 +363,26 @@ static void setup_mppe(struct rad_req_t *req, const uint8_t *challenge)
triton_event_fire(EV_MPPE_KEYS, &ev_mppe);
}
+static int rad_auth_mschap_v1_recv(struct rad_req_t *req)
+{
+ if (req->reply->code == CODE_ACCESS_ACCEPT)
+ setup_mppe(req, req->rpd->auth_ctx->challenge);
+ else {
+ struct rad_attr_t *ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP-Error");
+ if (ra) {
+ char **mschap_error = req->rpd->auth_ctx->mschap_error;
+ *mschap_error = _malloc(ra->len + 1);
+ memcpy(*mschap_error, ra->val.string, ra->len);
+ (*mschap_error)[ra->len] = 0;
+ }
+ }
+
+ return 0;
+}
+
int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args)
{
- int r = PWDB_DENIED;
uint8_t response[50];
- struct rad_attr_t *ra;
int id = va_arg(args, int);
const uint8_t *challenge = va_arg(args, const uint8_t *);
@@ -388,80 +390,70 @@ int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list ar
const uint8_t *lm_response = va_arg(args, const uint8_t *);
const uint8_t *nt_response = va_arg(args, const uint8_t *);
int flags = va_arg(args, int);
- char **mschap_error = va_arg(args, char **);
+ rpd->auth_ctx->mschap_error = va_arg(args, char **);
+ struct rad_req_t *req = rad_auth_req_alloc(rpd, username, rad_auth_mschap_v1_recv);
+
+ if (!req)
+ return PWDB_DENIED;
+
+ rpd->auth_ctx->challenge = challenge;
response[0] = id;
response[1] = flags;
memcpy(response + 2, lm_response, 24);
memcpy(response + 2 + 24, nt_response, 24);
- if (!rpd->auth_req) {
- rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
- if (!rpd->auth_req)
- return PWDB_DENIED;
-
- if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len))
- goto out;
-
- if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response)))
- goto out;
- } else {
- if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len))
- goto out;
-
- if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response)))
- goto out;
+ if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, challenge_len))
+ return PWDB_DENIED;
+
+ if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Response", response, sizeof(response)))
+ return PWDB_DENIED;
+
+ if (rad_req_send(req))
+ return PWDB_DENIED;
- if (rpd->attr_state) {
- if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) {
- if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
- goto out;
- } else {
- if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
- goto out;
- }
- }
-
- if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA))
- return -1;
- }
+ return PWDB_WAIT;
+}
- if (conf_sid_in_auth)
- if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid))
- goto out;
+static int rad_auth_mschap_v2_recv(struct rad_req_t *req)
+{
+ struct radius_pd_t *rpd = req->rpd;
+ struct rad_attr_t *ra;
+ if (req->reply->code == CODE_ACCESS_ACCEPT) {
+ ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP2-Success");
+ if (!ra) {
+ log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n");
+ return -1;
+ } else
+ memcpy(rpd->auth_ctx->authenticator, ra->val.octets + 3, 40);
- r = rad_auth_send(rpd->auth_req);
- if (r == PWDB_SUCCESS) {
- struct ev_radius_t ev = {
- .ses = rpd->ses,
- .request = rpd->auth_req->pack,
- .reply = rpd->auth_req->reply,
- };
- triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
- setup_mppe(rpd->auth_req, challenge);
- rpd->auth_req->pack->id++;
- } else if (rpd->auth_req->reply) {
- ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP-Error");
+ setup_mppe(rpd->auth_ctx->req, NULL);
+ } else {
+ ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP-Error");
if (ra) {
+ char **mschap_error = req->rpd->auth_ctx->mschap_error;
*mschap_error = _malloc(ra->len + 1);
memcpy(*mschap_error, ra->val.string, ra->len);
(*mschap_error)[ra->len] = 0;
}
- }
-out:
- rad_req_free(rpd->auth_req);
- rpd->auth_req = NULL;
+ ra = rad_packet_find_attr(req->reply, NULL, "Reply-Message");
+ if (ra) {
+ char **reply_msg = req->rpd->auth_ctx->reply_msg;
+ *reply_msg = _malloc(ra->len + 1);
+ memcpy(*reply_msg, ra->val.string, ra->len);
+ (*reply_msg)[ra->len] = 0;
+ }
+ }
- return r;
+ return 0;
}
int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args)
{
- int r = PWDB_DENIED;
- struct rad_attr_t *ra;
uint8_t mschap_response[50];
+ struct rad_req_t *req = rad_auth_req_alloc(rpd, username, rad_auth_mschap_v2_recv);
int id = va_arg(args, int);
const uint8_t *challenge = va_arg(args, const uint8_t *);
@@ -469,9 +461,12 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar
const uint8_t *reserved = va_arg(args, const uint8_t *);
const uint8_t *response = va_arg(args, const uint8_t *);
int flags = va_arg(args, int);
- uint8_t *authenticator = va_arg(args, uint8_t *);
- char **mschap_error = va_arg(args, char **);
- char **reply_msg = va_arg(args, char **);
+ rpd->auth_ctx->authenticator = va_arg(args, uint8_t *);
+ rpd->auth_ctx->mschap_error = va_arg(args, char **);
+ rpd->auth_ctx->reply_msg = va_arg(args, char **);
+
+ if (!req)
+ return PWDB_DENIED;
mschap_response[0] = id;
mschap_response[1] = flags;
@@ -479,107 +474,28 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar
memcpy(mschap_response + 2 + 16, reserved, 8);
memcpy(mschap_response + 2 + 16 + 8, response, 24);
- if (!rpd->auth_req) {
- rpd->auth_req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
- if (!rpd->auth_req)
- return PWDB_DENIED;
-
- if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16))
- goto out;
-
- if (rad_packet_add_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response)))
- goto out;
- } else {
- if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16))
- goto out;
+ if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP-Challenge", challenge, 16))
+ return PWDB_DENIED;
- if (rad_packet_change_octets(rpd->auth_req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response)))
- goto out;
-
- if (rpd->attr_state) {
- if (rad_packet_find_attr(rpd->auth_req->pack, NULL, "State")) {
- if (rad_packet_change_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
- goto out;
- } else {
- if (rad_packet_add_octets(rpd->auth_req->pack, NULL, "State", rpd->attr_state, rpd->attr_state_len))
- goto out;
- }
- }
+ if (rad_packet_add_octets(req->pack, "Microsoft", "MS-CHAP2-Response", mschap_response, sizeof(mschap_response)))
+ return PWDB_DENIED;
- if (rad_packet_build(rpd->auth_req->pack, rpd->auth_req->RA))
- return -1;
- }
-
- if (conf_sid_in_auth)
- if (rad_packet_add_str(rpd->auth_req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid))
- goto out;
-
- r = rad_auth_send(rpd->auth_req);
- if (r == PWDB_SUCCESS) {
- ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP2-Success");
- if (!ra) {
- log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n");
- r = PWDB_DENIED;
- } else
- memcpy(authenticator, ra->val.octets + 3, 40);
- }
- if (r == PWDB_SUCCESS) {
- struct ev_radius_t ev = {
- .ses = rpd->ses,
- .request = rpd->auth_req->pack,
- .reply = rpd->auth_req->reply,
- };
- triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
- setup_mppe(rpd->auth_req, NULL);
- rpd->auth_req->pack->id++;
- } else if (rpd->auth_req->reply) {
- ra = rad_packet_find_attr(rpd->auth_req->reply, "Microsoft", "MS-CHAP-Error");
- if (ra) {
- *mschap_error = _malloc(ra->len + 1);
- memcpy(*mschap_error, ra->val.string, ra->len);
- (*mschap_error)[ra->len] = 0;
- }
- ra = rad_packet_find_attr(rpd->auth_req->reply, NULL, "Reply-Message");
- if (ra) {
- *reply_msg = _malloc(ra->len + 1);
- memcpy(*reply_msg, ra->val.string, ra->len);
- (*reply_msg)[ra->len] = 0;
- }
- }
-
-out:
- rad_req_free(rpd->auth_req);
- rpd->auth_req = NULL;
+ if (rad_req_send(req))
+ return PWDB_DENIED;
- return r;
+ return PWDB_WAIT;
}
-
int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args)
{
- struct rad_req_t *req;
- int r = PWDB_DENIED;
-
- req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+ struct rad_req_t *req = rad_auth_req_alloc(rpd, username, NULL);
+
if (!req)
return PWDB_DENIED;
-
- if (conf_sid_in_auth)
- if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid))
- return -1;
- r = rad_auth_send(req);
- if (r == PWDB_SUCCESS) {
- struct ev_radius_t ev = {
- .ses = rpd->ses,
- .request = req->pack,
- .reply = req->reply,
- };
- triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
- }
-
- rad_req_free(req);
+ if (rad_req_send(req))
+ return PWDB_DENIED;
- return r;
+ return PWDB_WAIT;
}
diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c
index 5bff60a..87c337f 100644
--- a/accel-pppd/radius/packet.c
+++ b/accel-pppd/radius/packet.c
@@ -143,13 +143,14 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
else
n = read(fd, pack->buf, REQ_LENGTH_MAX);
if (n < 0) {
- if (errno == EAGAIN) {
- rad_packet_free(pack);
- return -1;
- }
+ rad_packet_free(pack);
+ if (errno == EAGAIN)
+ return 1;
+
if (errno != ECONNREFUSED)
log_ppp_error("radius:packet:read: %s\n", strerror(errno));
- goto out_err;
+
+ return -1;
}
break;
}
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index a3b211e..ec7d911 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -54,6 +54,7 @@ static void *pd_key;
static struct ipdb_t ipdb;
static mempool_t rpd_pool;
+static mempool_t auth_ctx_pool;
int rad_proc_attrs(struct rad_req_t *req)
{
@@ -159,7 +160,7 @@ int rad_proc_attrs(struct rad_req_t *req)
return res;
}
-static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const char *username, int type, va_list _args)
+static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, pwdb_callback cb, void *cb_arg, const char *username, int type, va_list _args)
{
int r = PWDB_NO_IMPL;
va_list args;
@@ -180,6 +181,12 @@ static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const cha
username1[len + 1 + conf_default_realm_len] = 0;
username = username1;
}
+
+ rpd->auth_ctx = mempool_alloc(auth_ctx_pool);
+ memset(rpd->auth_ctx, 0, sizeof(rpd->auth_ctx));
+
+ rpd->auth_ctx->cb = cb;
+ rpd->auth_ctx->cb_arg = cb_arg;
va_copy(args, _args);
@@ -208,8 +215,12 @@ static int rad_pwdb_check(struct pwdb_t *pwdb, struct ap_session *ses, const cha
va_end(args);
- if (r == PWDB_SUCCESS)
- rpd->authenticated = 1;
+ if (r == PWDB_DENIED) {
+ if (rpd->auth_ctx->req)
+ rad_req_free(rpd->auth_ctx->req);
+ mempool_free(rpd->auth_ctx);
+ rpd->auth_ctx = NULL;
+ }
return r;
}
@@ -247,8 +258,6 @@ static struct ipv6db_prefix_t *get_ipv6_prefix(struct ap_session *ses)
return NULL;
}
-
-
static void session_timeout(struct triton_timer_t *t)
{
struct radius_pd_t *rpd = container_of(t, typeof(*rpd), session_timeout);
@@ -290,6 +299,7 @@ static void ses_starting(struct ap_session *ses)
memset(rpd, 0, sizeof(*rpd));
rpd->pd.key = &pd_key;
rpd->ses = ses;
+ rpd->refs = 1;
pthread_mutex_init(&rpd->lock, NULL);
INIT_LIST_HEAD(&rpd->plugin_list);
INIT_LIST_HEAD(&rpd->ipv6_addr.addr_list);
@@ -315,6 +325,9 @@ static void ses_acct_start(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
+ if (!conf_accounting)
+ return;
+
if (!rpd->authenticated)
return;
@@ -322,26 +335,35 @@ static void ses_acct_start(struct ap_session *ses)
ap_session_terminate(rpd->ses, TERM_NAS_ERROR, 0);
return;
}
-
+
+ ses->acct_start++;
+}
+
+static void ses_started(struct ap_session *ses)
+{
+ struct radius_pd_t *rpd = find_pd(ses);
+
if (rpd->session_timeout.expire_tv.tv_sec) {
rpd->session_timeout.expire = session_timeout;
triton_timer_add(ses->ctrl->ctx, &rpd->session_timeout, 0);
}
-
+
if (rpd->idle_timeout.period) {
rpd->idle_timeout.expire = idle_timeout;
triton_timer_add(ses->ctrl->ctx, &rpd->idle_timeout, 0);
}
}
+
static void ses_finishing(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
- if (!rpd->authenticated)
+ if (!rpd->acct_started)
return;
rad_acct_stop(rpd);
}
+
static void ses_finished(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
@@ -353,11 +375,19 @@ static void ses_finished(struct ap_session *ses)
pthread_mutex_unlock(&rpd->lock);
pthread_rwlock_unlock(&sessions_lock);
- if (rpd->auth_req)
- rad_req_free(rpd->auth_req);
+ if (rpd->auth_ctx) {
+ rad_server_req_cancel(rpd->auth_ctx->req);
+ rad_req_free(rpd->auth_ctx->req);
+ mempool_free(rpd->auth_ctx);
+ rpd->auth_ctx = NULL;
+ }
- if (rpd->acct_req)
- rad_req_free(rpd->acct_req);
+ if (rpd->acct_req) {
+ if (rpd->acct_started)
+ rad_acct_stop_defer(rpd);
+ else
+ rad_req_free(rpd->acct_req);
+ }
if (rpd->dm_coa_req)
dm_coa_cancel(rpd);
@@ -373,7 +403,7 @@ static void ses_finished(struct ap_session *ses)
if (rpd->attr_state)
_free(rpd->attr_state);
-
+
while (!list_empty(&rpd->ipv6_addr.addr_list)) {
a = list_entry(rpd->ipv6_addr.addr_list.next, typeof(*a), entry);
list_del(&a->entry);
@@ -388,7 +418,7 @@ static void ses_finished(struct ap_session *ses)
list_del(&rpd->pd.entry);
- mempool_free(rpd);
+ release_pd(rpd);
}
struct radius_pd_t *find_pd(struct ap_session *ses)
@@ -406,6 +436,16 @@ struct radius_pd_t *find_pd(struct ap_session *ses)
abort();
}
+void hold_pd(struct radius_pd_t *rpd)
+{
+ rpd->refs++;
+}
+
+void release_pd(struct radius_pd_t *rpd)
+{
+ if (--rpd->refs == 0)
+ mempool_free(rpd);
+}
struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, const char *port_id, int port, in_addr_t ipaddr, const char *csid)
{
@@ -650,6 +690,7 @@ static void radius_init(void)
struct conf_option_t *opt1;
rpd_pool = mempool_create(sizeof(struct radius_pd_t));
+ auth_ctx_pool = mempool_create(sizeof(struct radius_auth_ctx));
if (load_config())
_exit(EXIT_FAILURE);
@@ -670,6 +711,7 @@ static void radius_init(void)
ipdb_register(&ipdb);
triton_event_register_handler(EV_SES_STARTING, (triton_event_func)ses_starting);
+ triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ses_started);
triton_event_register_handler(EV_SES_ACCT_START, (triton_event_func)ses_acct_start);
triton_event_register_handler(EV_SES_FINISHING, (triton_event_func)ses_finishing);
triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ses_finished);
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index 8ad69da..cfb92cd 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -9,18 +9,32 @@
#include "radius.h"
#include "ppp.h"
#include "ipdb.h"
+#include "pwdb.h"
struct rad_server_t;
+struct radius_auth_ctx {
+ struct rad_req_t *req;
+ pwdb_callback cb;
+ void *cb_arg;
+ int (*recv)(struct rad_req_t *);
+
+ const uint8_t *challenge;
+ uint8_t *authenticator;
+ char **mschap_error;
+ char **reply_msg;
+};
+
struct radius_pd_t {
struct list_head entry;
struct ap_private pd;
struct ap_session *ses;
pthread_mutex_t lock;
+ int refs:8;
int authenticated:1;
+ int acct_started:1;
int ipv6_dp_assigned:1;
- struct rad_req_t *auth_req;
struct rad_req_t *acct_req;
struct triton_timer_t acct_interim_timer;
@@ -34,7 +48,6 @@ struct radius_pd_t {
struct ipv6db_item_t ipv6_addr;
struct ipv6db_prefix_t ipv6_dp;
int acct_interim_interval;
- time_t acct_timestamp;
uint8_t *attr_class;
int attr_class_len;
@@ -42,12 +55,13 @@ struct radius_pd_t {
int attr_state_len;
int termination_action;
+ struct radius_auth_ctx *auth_ctx;
+
struct list_head plugin_list;
};
struct rad_req_t {
struct list_head entry;
- struct triton_context_t ctx;
struct triton_md_handler_t hnd;
struct triton_timer_t timeout;
uint8_t RA[16];
@@ -56,11 +70,21 @@ struct rad_req_t {
struct radius_pd_t *rpd;
struct rad_server_t *serv;
- struct triton_context_t *wait_ctx;
in_addr_t server_addr;
- int server_port;
- int type;
+
+ int server_port:16;
+ int type:8;
+ int try:6;
+ int active:1;
+ int async:1;
+
+ time_t ts;
+
+ void (*recv)(struct rad_req_t *);
+ int (*before_send)(struct rad_req_t *);
+ int (*send)(struct rad_req_t *, int async);
+ void (*sent)(struct rad_req_t *, int res);
void (*log)(const char *fmt, ...);
};
@@ -149,13 +173,16 @@ void rad_dict_free(struct rad_dict_t *dict);
struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username);
struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port);
+struct rad_req_t *rad_req_alloc_empty();
int rad_req_acct_fill(struct rad_req_t *);
void rad_req_free(struct rad_req_t *);
-int rad_req_send(struct rad_req_t *req, void (*log)(const char *fmt, ...));
-int rad_req_wait(struct rad_req_t *, int);
+int rad_req_send(struct rad_req_t *req);
+int rad_req_read(struct triton_md_handler_t *h);
struct radius_pd_t *find_pd(struct ap_session *ses);
int rad_proc_attrs(struct rad_req_t *req);
+void hold_pd(struct radius_pd_t *rpd);
+void release_pd(struct radius_pd_t *rpd);
int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args);
int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args);
@@ -164,7 +191,8 @@ int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list ar
int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args);
int rad_acct_start(struct radius_pd_t *rpd);
-void rad_acct_stop(struct radius_pd_t *rpd);
+int rad_acct_stop(struct radius_pd_t *rpd);
+void rad_acct_stop_defer(struct radius_pd_t *rpd);
struct rad_packet_t *rad_packet_alloc(int code);
int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA);
@@ -180,6 +208,7 @@ struct rad_server_t *rad_server_get2(int, in_addr_t, int);
void rad_server_put(struct rad_server_t *, int);
int rad_server_req_enter(struct rad_req_t *);
void rad_server_req_exit(struct rad_req_t *);
+int rad_server_req_cancel(struct rad_req_t *);
int rad_server_realloc(struct rad_req_t *);
void rad_server_fail(struct rad_server_t *);
void rad_server_timeout(struct rad_server_t *);
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index 27a33f2..172fb1c 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -4,25 +4,26 @@
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
-#include <sched.h>
+#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.h"
#include "radius_p.h"
+#include "mempool.h"
#include "memdebug.h"
-static int rad_req_read(struct triton_md_handler_t *h);
-static void rad_req_timeout(struct triton_timer_t *t);
static int make_socket(struct rad_req_t *req);
+static mempool_t req_pool;
static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port)
{
struct rad_plugin_t *plugin;
struct ppp_t *ppp = NULL;
- struct rad_req_t *req = _malloc(sizeof(*req));
+ struct rad_req_t *req = mempool_alloc(req_pool);
+ struct timespec ts;
if (!req) {
log_emerg("radius: out of memory\n");
@@ -32,10 +33,13 @@ static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, cons
if (rpd->ses->ctrl->ppp)
ppp = container_of(rpd->ses, typeof(*ppp), ses);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
memset(req, 0, sizeof(*req));
req->rpd = rpd;
req->hnd.fd = -1;
- req->ctx.before_switch = log_switch;
+ req->hnd.read = rad_req_read;
+ req->ts = ts.tv_sec;
req->type = code == CODE_ACCESS_REQUEST ? RAD_SERV_AUTH : RAD_SERV_ACCT;
@@ -161,6 +165,21 @@ struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *
return req;
}
+struct rad_req_t *rad_req_alloc_empty()
+{
+ struct rad_req_t *req = mempool_alloc(req_pool);
+
+ if (!req) {
+ log_emerg("radius: out of memory\n");
+ return NULL;
+ }
+
+ memset(req, 0, sizeof(*req));
+ req->hnd.fd = -1;
+
+ return req;
+}
+
int rad_req_acct_fill(struct rad_req_t *req)
{
struct ipv6db_addr_t *a;
@@ -211,15 +230,26 @@ int rad_req_acct_fill(struct rad_req_t *req)
void rad_req_free(struct rad_req_t *req)
{
+ assert(!req->active);
+
if (req->serv)
rad_server_put(req->serv, req->type);
- if (req->hnd.fd >= 0 )
+
+ if (req->hnd.tpd)
+ triton_md_unregister_handler(&req->hnd, 1);
+ else if (req->hnd.fd != -1)
close(req->hnd.fd);
+
+ if (req->timeout.tpd)
+ triton_timer_del(&req->timeout);
+
if (req->pack)
rad_packet_free(req->pack);
+
if (req->reply)
rad_packet_free(req->reply);
- _free(req);
+
+ mempool_free(req);
}
static int make_socket(struct rad_req_t *req)
@@ -231,7 +261,7 @@ static int make_socket(struct rad_req_t *req)
log_ppp_error("radius:socket: %s\n", strerror(errno));
return -1;
}
-
+
fcntl(req->hnd.fd, F_SETFD, fcntl(req->hnd.fd, F_GETFD) | FD_CLOEXEC);
memset(&addr, 0, sizeof(addr));
@@ -270,95 +300,120 @@ out_err:
return -1;
}
-int rad_req_send(struct rad_req_t *req, void (*log)(const char *fmt, ...))
+static int __rad_req_send(struct rad_req_t *req, int async)
{
+ if (async == -1) {
+ req->try = conf_max_try - 1;
+ rad_req_send(req);
+ return 0;
+ }
+
if (req->hnd.fd == -1 && make_socket(req))
return -1;
+
+ if (req->before_send && req->before_send(req))
+ goto out_err;
if (!req->pack->buf && rad_packet_build(req->pack, req->RA))
goto out_err;
- if (log) {
- log("send ");
- rad_packet_print(req->pack, req->serv, log);
+ if (req->log) {
+ req->log("send ");
+ rad_packet_print(req->pack, req->serv, req->log);
}
+
+ if (req->sent)
+ req->sent(req, 0);
rad_packet_send(req->pack, req->hnd.fd, NULL);
return 0;
out_err:
- close(req->hnd.fd);
- req->hnd.fd = -1;
+ if (req->hnd.tpd)
+ triton_md_unregister_handler(&req->hnd, 1);
+ else {
+ close(req->hnd.fd);
+ req->hnd.fd = -1;
+ }
+
+ if (async && req->sent)
+ req->sent(req, -1);
+
return -1;
}
-static void req_wakeup(struct rad_req_t *req)
-{
- struct triton_context_t *ctx = req->wait_ctx;
- if (req->timeout.tpd)
- triton_timer_del(&req->timeout);
- triton_md_unregister_handler(&req->hnd, 0);
- triton_context_unregister(&req->ctx);
- triton_context_wakeup(ctx);
-}
-static int rad_req_read(struct triton_md_handler_t *h)
+int rad_req_send(struct rad_req_t *req)
{
- struct rad_req_t *req = container_of(h, typeof(*req), hnd);
- struct rad_packet_t *pack;
int r;
- while (1) {
- r = rad_packet_recv(h->fd, &pack, NULL);
-
- if (pack) {
- if (req->reply)
- rad_packet_free(req->reply);
- req->reply = pack;
+ req->send = __rad_req_send;
+
+ if (req->try++ == conf_max_try) {
+ rad_server_req_exit(req);
+ rad_server_fail(req->serv);
+
+ if (rad_server_realloc(req)) {
+ if (req->rpd)
+ log_ppp_warn("radius: no available servers\n");
+ return -1;
}
- if (r)
- break;
+ req->try = 1;
}
- req_wakeup(req);
-
- return 1;
-}
-static void rad_req_timeout(struct triton_timer_t *t)
-{
- struct rad_req_t *req = container_of(t, typeof(*req), timeout);
-
- req_wakeup(req);
+ if (!req->active) {
+ while (1) {
+ r = rad_server_req_enter(req);
+
+ if (r >= 0)
+ break;
+
+ if (rad_server_realloc(req)) {
+ if (req->rpd)
+ log_ppp_warn("radius: no available servers\n");
+ return -1;
+ }
+ }
+ } else
+ r = __rad_req_send(req, 0);
+
+ return r;
}
-int rad_req_wait(struct rad_req_t *req, int timeout)
+int rad_req_read(struct triton_md_handler_t *h)
{
- req->wait_ctx = triton_context_self();
- req->hnd.read = rad_req_read;
- req->timeout.expire = rad_req_timeout;
-
- triton_context_register(&req->ctx, req->rpd ? req->rpd->ses : NULL);
- triton_context_set_priority(&req->ctx, 1);
- triton_md_register_handler(&req->ctx, &req->hnd);
- triton_md_enable_handler(&req->hnd, MD_MODE_READ);
+ struct rad_req_t *req = container_of(h, typeof(*req), hnd);
+ struct rad_packet_t *pack;
- req->timeout.period = timeout * 1000;
- triton_timer_add(&req->ctx, &req->timeout, 0);
+ while (1) {
+ if (rad_packet_recv(h->fd, &pack, NULL))
+ return 0;
+
+ if (pack->id == req->pack->id)
+ break;
+
+ rad_packet_free(req->reply);
+ }
- triton_context_wakeup(&req->ctx);
+ req->reply = pack;
- triton_context_schedule();
+ rad_server_req_exit(req);
- if (req->log && req->reply) {
+ if (req->log) {
req->log("recv ");
rad_packet_print(req->reply, req->serv, req->log);
}
- return 0;
+
+ if (req->recv)
+ req->recv(req);
+
+ return 1;
}
static void req_init(void)
{
+ req_pool = mempool_create(sizeof(struct rad_req_t));
}
DEFINE_INIT(50, req_init);
diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c
index 0910314..6c01a88 100644
--- a/accel-pppd/radius/serv.c
+++ b/accel-pppd/radius/serv.c
@@ -100,6 +100,48 @@ void rad_server_put(struct rad_server_t *s, int type)
}
}
+static void req_wakeup(struct rad_req_t *req)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ pthread_mutex_lock(&req->serv->lock);
+
+ if (ts.tv_sec < req->serv->fail_time || req->serv->need_free) {
+ req->active = 0;
+ req->serv->req_cnt--;
+ pthread_mutex_unlock(&req->serv->lock);
+
+ req->send(req, -1);
+
+ return;
+ }
+ pthread_mutex_unlock(&req->serv->lock);
+
+ req->send(req, 1);
+}
+
+int rad_server_req_cancel(struct rad_req_t *req)
+{
+ int r = 0;
+
+ pthread_mutex_lock(&req->serv->lock);
+ if (req->entry.next) {
+ list_del(&req->entry);
+ req->serv->queue_cnt--;
+ r = 1;
+ }
+ pthread_mutex_unlock(&req->serv->lock);
+
+ rad_server_req_exit(req);
+
+ if (req->timeout.tpd)
+ triton_timer_del(&req->timeout);
+
+ return r;
+}
+
int rad_server_req_enter(struct rad_req_t *req)
{
struct timespec ts;
@@ -112,8 +154,13 @@ int rad_server_req_enter(struct rad_req_t *req)
if (ts.tv_sec < req->serv->fail_time)
return -1;
- if (!req->serv->req_limit)
+ if (!req->serv->req_limit) {
+ if (req->send)
+ return req->send(req, 0);
return 0;
+ }
+
+ assert(!req->active);
pthread_mutex_lock(&req->serv->lock);
@@ -123,46 +170,47 @@ int rad_server_req_enter(struct rad_req_t *req)
}
if (req->serv->req_cnt >= req->serv->req_limit) {
- list_add_tail(&req->entry, &req->serv->req_queue);
- req->serv->queue_cnt++;
-
- pthread_mutex_unlock(&req->serv->lock);
- triton_context_schedule();
- pthread_mutex_lock(&req->serv->lock);
-
- req->serv->queue_cnt--;
- if (ts.tv_sec < req->serv->fail_time || req->serv->need_free) {
+ if (req->send) {
+ list_add_tail(&req->entry, &req->serv->req_queue);
+ req->serv->queue_cnt++;
pthread_mutex_unlock(&req->serv->lock);
- return -1;
+ return 0;
}
+
+ pthread_mutex_unlock(&req->serv->lock);
+ return 1;
}
req->serv->req_cnt++;
log_ppp_debug("radius(%i): req_enter %i\n", req->serv->id, req->serv->req_cnt);
pthread_mutex_unlock(&req->serv->lock);
+
+ req->active = 1;
return 0;
}
void rad_server_req_exit(struct rad_req_t *req)
{
- struct rad_req_t *r = NULL;
-
if (!req->serv->req_limit)
return;
+ assert(req->active);
+
+ req->active = 0;
+
pthread_mutex_lock(&req->serv->lock);
req->serv->req_cnt--;
log_ppp_debug("radius(%i): req_exit %i\n", req->serv->id, req->serv->req_cnt);
assert(req->serv->req_cnt >= 0);
if (req->serv->req_cnt < req->serv->req_limit && !list_empty(&req->serv->req_queue)) {
- r = list_entry(req->serv->req_queue.next, typeof(*r), entry);
+ struct rad_req_t *r = list_entry(req->serv->req_queue.next, typeof(*r), entry);
list_del(&r->entry);
+ req->serv->queue_cnt--;
+ req->active = 1;
+ triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r);
}
pthread_mutex_unlock(&req->serv->lock);
-
- if (r)
- triton_context_wakeup(r->rpd->ses->ctrl->ctx);
}
int rad_server_realloc(struct rad_req_t *req)
@@ -214,7 +262,7 @@ void rad_server_fail(struct rad_server_t *s)
while (!list_empty(&s->req_queue)) {
r = list_entry(s->req_queue.next, typeof(*r), entry);
list_del(&r->entry);
- triton_context_wakeup(r->rpd->ses->ctrl->ctx);
+ triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r);
}
}
@@ -223,7 +271,7 @@ void rad_server_fail(struct rad_server_t *s)
void rad_server_timeout(struct rad_server_t *s)
{
- if (__sync_add_and_fetch(&s->timeout_cnt, 1) >= conf_max_try)
+ if (__sync_add_and_fetch(&s->timeout_cnt, 1) >= conf_max_try * 3)
rad_server_fail(s);
}
@@ -248,13 +296,49 @@ static int req_set_RA(struct rad_req_t *req, const char *secret)
return 0;
}
+static void acct_on_sent(struct rad_req_t *req, int res)
+{
+ if (!res && !req->hnd.tpd) {
+ triton_md_register_handler(&req->serv->ctx, &req->hnd);
+ triton_md_enable_handler(&req->hnd, MD_MODE_READ);
+ }
+}
+
+static void acct_on_recv(struct rad_req_t *req)
+{
+ struct rad_server_t *s = req->serv;
+
+ rad_req_free(req);
+
+ if (req->serv->starting) {
+ req->serv->starting = 0;
+ req->serv->acct_on = 1;
+ } else
+ __free_server(s);
+}
+
+static void acct_on_timeout(struct triton_timer_t *t)
+{
+ struct rad_req_t *req = container_of(t, typeof(*req), timeout);
+ struct rad_server_t *s = req->serv;
+
+ if (!s->starting && ++req->serv->req_cnt == conf_max_try) {
+ rad_req_free(req);
+ __free_server(s);
+ return;
+ }
+
+ req->try = 1;
+
+ rad_req_send(req);
+}
+
static void send_acct_on(struct rad_server_t *s)
{
struct rad_req_t *req = _malloc(sizeof(*req));
- int i;
if (!req)
- goto out_err;
+ return;
memset(req, 0, sizeof(*req));
req->hnd.fd = -1;
@@ -262,6 +346,12 @@ static void send_acct_on(struct rad_server_t *s)
req->server_addr = s->addr;
req->server_port = s->acct_port;
req->serv = s;
+ req->sent = acct_on_sent;
+ req->recv = acct_on_recv;
+ req->hnd.read = rad_req_read;
+ req->timeout.expire = acct_on_timeout;
+ req->timeout.period = conf_timeout * 1000;
+ req->try = 1;
__sync_add_and_fetch(&s->client_cnt[req->type], 1);
if (conf_verbose)
req->log = log_info1;
@@ -284,55 +374,14 @@ static void send_acct_on(struct rad_server_t *s)
if (req_set_RA(req, s->secret))
goto out_err;
- for (i = 0; i < conf_max_try; i++) {
- if (rad_req_send(req, conf_verbose ? log_info1 : NULL))
- goto out_err;
-
- rad_req_wait(req, conf_timeout);
-
- if (!s->starting)
- break;
+ rad_req_send(req);
- if (!req->reply)
- continue;
-
- if (req->reply->id == req->pack->id && req->reply->code == CODE_ACCOUNTING_RESPONSE) {
- s->starting = 0;
- s->acct_on = 1;
- break;
- }
-
- rad_packet_free(req->reply);
- req->reply = NULL;
- }
-
- if (!s->starting) {
- if (s->timer.tpd)
- triton_timer_del(&s->timer);
-
- if (!s->acct_on)
- triton_context_unregister(&s->ctx);
-
- rad_req_free(req);
+ triton_timer_add(&s->ctx, &req->timeout, 0);
- return;
- }
+ return;
out_err:
- if (req)
- rad_req_free(req);
-
- if (s->timer.tpd)
- triton_timer_mod(&s->timer, 0);
- else
- triton_timer_add(&s->ctx, &s->timer, 0);
-}
-
-static void restart_acct_on(struct triton_timer_t *t)
-{
- struct rad_server_t *s = container_of(t, typeof(*s), timer);
-
- send_acct_on(s);
+ rad_req_free(req);
}
static void serv_ctx_close(struct triton_context_t *ctx)
@@ -444,6 +493,14 @@ static void __add_server(struct rad_server_t *s)
s->stat_interim_lost_5m = stat_accm_create(5 * 60);
s->stat_interim_query_1m = stat_accm_create(60);
s->stat_interim_query_5m = stat_accm_create(5 * 60);
+
+ s->ctx.close = serv_ctx_close;
+
+ triton_context_register(&s->ctx, NULL);
+ triton_context_set_priority(&s->ctx, 1);
+ if (conf_acct_on)
+ triton_context_call(&s->ctx, (triton_event_func)send_acct_on, s);
+ triton_context_wakeup(&s->ctx);
}
static void __free_server(struct rad_server_t *s)
@@ -465,6 +522,8 @@ static void __free_server(struct rad_server_t *s)
stat_accm_free(s->stat_interim_query_1m);
stat_accm_free(s->stat_interim_query_5m);
+ triton_context_unregister(&s->ctx);
+
_free(s);
}
@@ -732,7 +791,7 @@ static void load_config(void)
while (!list_empty(&s->req_queue)) {
r = list_entry(s->req_queue.next, typeof(*r), entry);
list_del(&r->entry);
- triton_context_wakeup(r->rpd->ses->ctrl->ctx);
+ triton_context_call(r->rpd->ses->ctrl->ctx, (triton_event_func)req_wakeup, r);
}
if (!s->client_cnt[0] && !s->client_cnt[1]) {
@@ -756,18 +815,8 @@ static void load_config(void)
list_for_each_entry(s, &serv_list, entry) {
if (s->starting) {
- if (!conf_accounting || !s->acct_port)
+ if (!conf_accounting || !s->auth_port)
s->starting = 0;
- else {
- s->ctx.close = serv_ctx_close;
- s->timer.expire = restart_acct_on;
- s->timer.expire_tv.tv_sec = 10;
-
- triton_context_register(&s->ctx, NULL);
- triton_context_set_priority(&s->ctx, 1);
- triton_context_call(&s->ctx, (triton_event_func)send_acct_on, s);
- triton_context_wakeup(&s->ctx);
- }
}
}
}