Commit 36f41849 authored by Ray Bellis's avatar Ray Bellis

refactor state handling in client code

parent 082a58cd
......@@ -13,16 +13,39 @@
*/
const RadiusPacket = require('./packet');
const Code = require('./code');
const dgram = require('dgram');
const crypto = require('crypto');
async function _request(state, code, attrs)
async function _request(client_state, code, attrs)
{
const buffers = state.servers.map(server => {
const id = server.id++;
const authen = RadiusPacket.randomAuthenticator();
const req = new RadiusPacket(code, id, authen, attrs);
return req.toWire(server.secret, response = false);
});
// canonicalise the code value
code = Code.from(code);
// state to be remembered between attempts
const state = [];
let timer = undefined;
// retrieves (or creates) the state for a retry
function getState(n) {
if (state[n] === undefined) {
// round-robin server selection
const server = client_state.servers[n];
const address = server.server;
const port = (code === Code.ACCOUNTING_REQUEST) ? server.acct : server.auth;
// server-specific packet content
const identifier = (server.id++ & 0xff);
const authenticator = RadiusPacket.randomAuthenticator();
const req = new RadiusPacket(code, identifier, authenticator, attrs);
const buffer = req.toWire(server.secret, response = false);
state[n] = { code, identifier, authenticator, address, port, buffer };
}
return state[n];
}
return new Promise((resolve, reject) => {
......@@ -30,9 +53,11 @@ async function _request(state, code, attrs)
socket.on('message', function(msg, rinfo) {
const s = state[attempt];
// check it came from the original target
if (rinfo.address !== current.address ||
rinfo.port !== current.port)
if (rinfo.address !== s.address ||
rinfo.port !== s.port)
{
console.log(`ignoring packet from ${rinfo.address}:${rinfo.port}`);
return;
......@@ -42,7 +67,7 @@ async function _request(state, code, attrs)
const res = RadiusPacket.fromWire(msg);
// ignore packets whose identifier doesn't match
if (res.identifier !== current.identifier) {
if (res.identifier !== s.identifier) {
return;
}
......@@ -65,7 +90,7 @@ async function _request(state, code, attrs)
}
if (action) {
clearTimeout(current.timer);
clearTimeout(timer);
socket.close();
action(res);
}
......@@ -77,33 +102,30 @@ async function _request(state, code, attrs)
});
socket.on('close', () => {
// does nothing (yet)
});
let attempt = 0;
let retry = state.retry * state.servers.length;
let current = { };
const slen = client_state.servers.length;
const max = client_state.retry * slen;
const timeout = client_state.delay * 1000;
// start sending packets
(function send() {
const which = attempt % state.servers.length;
const server = state.servers[which];
const buffer = buffers[which];
const code = buffer[0];
const identifier = buffer[1];
const address = server.server;
const port = (code === 4) ? server.acct : server.auth;
const n = attempt % slen;
const s = getState(n);
let timer = setTimeout(() => {
timer = setTimeout(() => {
timer = undefined;
if (++attempt < retry) {
if (++attempt < max) {
send();
} else {
socket.close();
reject(new Error('timeout'));
}
}, Math.floor(state.delay * 1000));
}, timeout);
current = { address, port, code, timer, identifier };
socket.send(buffer, 0, buffer.length, port, address);
socket.send(s.buffer, 0, s.buffer.length, s.port, s.address);
})();
});
......@@ -190,6 +212,7 @@ class RadiusClient {
// generate initial ID for queries sent to this client
const id = Math.floor(Math.random() * 256);
// push the (required) first configured server
state.servers.push({ server, secret, auth, acct, id });
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment