httpd: four login sessions instead of one

Logging in from a second browser ended the first one's session at its next
request: two browsers open on the switch logged each other out every few
seconds. Up to four sessions now, each with its own cookie and expiry; a
fifth login replaces the least recently used. The expiry check is a leaf
function so its 32-bit scratch stays out of internal RAM (stack still
159 bytes with HEALTH).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tx2W7xVecMoKbBCkD2i8PG
(cherry picked from commit 03330f4077ef8872d861d951c8e44ece3c573935)
This commit is contained in:
Claude authored and Brunoz78 committed 2026-10-25 10:51:05 +01:00
1 parent a18c334139
commit 70f59b64f5
1 file changed
+49 -13
+49 -13
View File
@@ -75,10 +75,15 @@ __xdata uint8_t postbody_endpoint;
__xdata uint16_t postbody_start;
__xdata char passwd[21];
__xdata char session_id[SESSION_ID_LENGTH + 1];
/* Up to SESSIONS logins at once, each with its own cookie and its own
* expiry. With a single one, logging in from a second browser (or a phone)
* ended the first browser's session at its next request. */
#define SESSIONS 4
__xdata char session_id[SESSIONS][SESSION_ID_LENGTH + 1];
__xdata uint32_t last_session_use[SESSIONS];
__xdata uint8_t session_slot;
__xdata uint8_t authenticated;
__xdata uint32_t now;
__xdata uint32_t last_session_use;
#define TSTATE_NONE 0
#define TSTATE_TX 1
@@ -109,6 +114,33 @@ void httpd_init(void) __banked
// handling one, and nothing has set it yet at init time.
for (uint8_t i = 0; i < UIP_CONNS; i++)
uip_conns[i].appstate.tstate = TSTATE_CLOSED;
for (session_slot = 0; session_slot < SESSIONS; session_slot++)
session_id[session_slot][0] = NUL;
}
/* Leaf functions, so the compiler keeps their 32-bit scratch in the overlay
* rather than in internal RAM. */
static uint8_t session_stale(void)
{
if (now - last_session_use[session_slot] > session_timeout)
return 1;
return 0;
}
/* For a new login: a free or expired slot, else the least recently used. */
static void session_pick(void)
{
__xdata uint8_t i;
__xdata uint8_t oldest = 0;
for (i = 0; i < SESSIONS; i++) {
session_slot = i;
if (!session_id[i][0] || session_stale())
return;
if (last_session_use[i] < last_session_use[oldest])
oldest = i;
}
session_slot = oldest;
}
@@ -343,15 +375,17 @@ __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
read_reg_timer(&now);
if (session && session_id[0]) {
if (now - last_session_use > session_timeout) {
if (session) {
for (session_slot = 0; session_slot < SESSIONS; session_slot++) {
if (!session_id[session_slot][0])
continue;
if (session_stale()) {
dbg_string("Session expired\n");
} else {
if (is_word_x(session, session_id)) {
session_id[session_slot][0] = NUL;
} else if (is_word_x(session, session_id[session_slot])) {
authenticated = 1;
last_session_use = now;
} else {
dbg_string("Invalid session cookie!\n");
last_session_use[session_slot] = now;
break;
}
}
}
@@ -675,13 +709,15 @@ static void run_login_body(__xdata uint8_t *body)
{
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
dbg_string("Password accepted!\n");
read_reg_timer(&last_session_use);
gen_random_hex_chars(session_id, SESSION_ID_LENGTH);
session_id[SESSION_ID_LENGTH] = NUL;
read_reg_timer(&now);
session_pick();
last_session_use[session_slot] = now;
gen_random_hex_chars(session_id[session_slot], SESSION_ID_LENGTH);
session_id[session_slot][SESSION_ID_LENGTH] = NUL;
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
"Set-Cookie: session=");
for (uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
outbuf[slen++] = session_id[i];
outbuf[slen++] = session_id[session_slot][i];
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
} else {
dbg_string("Password invalid!\n");