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
+50 -14
+50 -14
View File
@@ -75,10 +75,15 @@ __xdata uint8_t postbody_endpoint;
__xdata uint16_t postbody_start; __xdata uint16_t postbody_start;
__xdata char passwd[21]; __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 uint8_t authenticated;
__xdata uint32_t now; __xdata uint32_t now;
__xdata uint32_t last_session_use;
#define TSTATE_NONE 0 #define TSTATE_NONE 0
#define TSTATE_TX 1 #define TSTATE_TX 1
@@ -109,6 +114,33 @@ void httpd_init(void) __banked
// handling one, and nothing has set it yet at init time. // handling one, and nothing has set it yet at init time.
for (uint8_t i = 0; i < UIP_CONNS; i++) for (uint8_t i = 0; i < UIP_CONNS; i++)
uip_conns[i].appstate.tstate = TSTATE_CLOSED; 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); read_reg_timer(&now);
if (session && session_id[0]) { if (session) {
if (now - last_session_use > session_timeout) { for (session_slot = 0; session_slot < SESSIONS; session_slot++) {
dbg_string("Session expired\n"); if (!session_id[session_slot][0])
} else { continue;
if (is_word_x(session, session_id)) { if (session_stale()) {
dbg_string("Session expired\n");
session_id[session_slot][0] = NUL;
} else if (is_word_x(session, session_id[session_slot])) {
authenticated = 1; authenticated = 1;
last_session_use = now; last_session_use[session_slot] = now;
} else { break;
dbg_string("Invalid session cookie!\n");
} }
} }
} }
@@ -675,13 +709,15 @@ static void run_login_body(__xdata uint8_t *body)
{ {
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) { if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
dbg_string("Password accepted!\n"); dbg_string("Password accepted!\n");
read_reg_timer(&last_session_use); read_reg_timer(&now);
gen_random_hex_chars(session_id, SESSION_ID_LENGTH); session_pick();
session_id[SESSION_ID_LENGTH] = NUL; 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" \ slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
"Set-Cookie: session="); "Set-Cookie: session=");
for (uint8_t i = 0; i < SESSION_ID_LENGTH; i++) 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"); slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
} else { } else {
dbg_string("Password invalid!\n"); dbg_string("Password invalid!\n");