jcs
/subtext
/amendments
/211
*: Properly handle running out of sessions
Limit sessions to the number of uthreads we can handle, and then
reserve 1 session for the console.
In telnet, allocate one extra node so we can print a message to the
client that we have no free nodes, and then disconnect. Add a view
for this to make it editable.
In console, handle getting a null session back from session_create.
jcs made amendment 211 over 2 years ago
--- console.c Fri Jun 24 09:47:08 2022
+++ console.c Sat Jul 16 23:05:59 2022
@@ -68,6 +68,15 @@ console_init(void)
short width, height;
console = xmalloczero(sizeof(struct console));
+
+ console->session = session_create("console", "console",
+ &console_node_funcs);
+ if (console->session == NULL) {
+ free(console);
+ warn("No free nodes for a console");
+ return NULL;
+ }
+
memset(console->chars, ' ', sizeof(console->chars));
console->ncolumns = DEFAULT_TERMINAL_COLUMNS;
console->nlines = DEFAULT_TERMINAL_LINES;
@@ -101,8 +110,6 @@ console_init(void)
console->focusable = focusable;
add_focusable(focusable);
- console->session = session_create("console", "console",
- &console_node_funcs);
console->session->cookie = (void *)console;
console->session->vt100 = 1;
console->session->cp437 = 1;
--- db.h Wed Jul 13 17:44:37 2022
+++ db.h Sat Jul 16 23:12:38 2022
@@ -41,6 +41,7 @@
#define DB_TEXT_ISSUE_ID 3
#define DB_TEXT_SIGNUP_ID 4
#define DB_TEXT_PAGE_SYSOP_ID 5
+#define DB_TEXT_NO_FREE_NODES_ID 6
#define DB_USERNAME_LENGTH 16
--- main.c Fri Jul 15 22:33:17 2022
+++ main.c Sat Jul 16 23:35:49 2022
@@ -328,6 +328,9 @@ handle_menu(long menu_id)
case VIEWS_SUBMENU_PAGE_SYSOP_ID:
view_editor_show(DB_TEXT_PAGE_SYSOP_ID, "Edit: Page Sysop view");
break;
+ case VIEWS_SUBMENU_NO_FREE_NODES_ID:
+ view_editor_show(DB_TEXT_NO_FREE_NODES_ID, "Edit: No Free Nodes view");
+ break;
}
ret = 1;
break;
--- session.c Sat Jul 16 14:32:15 2022
+++ session.c Sat Jul 16 22:59:31 2022
@@ -74,8 +74,15 @@ session_create(char *node, char *via, struct node_func
struct session *session;
size_t n;
- if (nsessions >= MAX_SESSIONS)
- return NULL;
+ /* reserve 1 session for the console */
+ if (nsessions >= MAX_SESSIONS - 1) {
+ if (strcmp(node, "console") != 0)
+ return NULL;
+
+ /* but only 1 */
+ if (nsessions == MAX_SESSIONS)
+ return NULL;
+ }
nsessions++;
--- session.h Sat Jul 16 14:32:32 2022
+++ session.h Sat Jul 16 21:42:56 2022
@@ -102,7 +102,7 @@ struct session {
struct uthread *uthread;
};
-#define MAX_SESSIONS 20
+#define MAX_SESSIONS NUM_UTHREADS
extern struct session *sessions[MAX_SESSIONS];
extern short nsessions;
--- subtext.h Tue Jun 21 15:42:02 2022
+++ subtext.h Sat Jul 16 23:35:31 2022
@@ -44,6 +44,7 @@
#define VIEWS_SUBMENU_SHORT_MENU_ID 3
#define VIEWS_SUBMENU_SIGNUP_ID 4
#define VIEWS_SUBMENU_PAGE_SYSOP_ID 5
+#define VIEWS_SUBMENU_NO_FREE_NODES_ID 6
#define STR_LAST_DB 128
--- telnet.c Thu Jul 14 09:41:45 2022
+++ telnet.c Sun Jul 17 00:00:16 2022
@@ -111,7 +111,9 @@ struct telnet_node {
wdsEntry tcp_wds[2];
};
-#define MAX_TELNET_NODES 10
+/* add one to be able to print busy messages */
+#define MAX_TELNET_NODES (MAX_SESSIONS + 1)
+
static struct telnet_node *telnet_nodes[MAX_TELNET_NODES] = { NULL };
static struct telnet_node *telnet_listener_node = NULL;
static TCPiopb telnet_exit_pb;
@@ -147,6 +149,7 @@ void telnet_listen_on_node(struct telnet_node *node);
void telnet_output_iac(struct session *session, const char *iacs,
size_t len);
bool telnet_ip_is_banned(ip_addr ip);
+void telnet_print_busy(struct telnet_node *node);
struct node_funcs telnet_node_funcs = {
telnet_setup,
@@ -324,6 +327,15 @@ telnet_idle(void)
node->session = session_create(node->name,
node->from_trusted_proxy ? "web" : "telnet",
&telnet_node_funcs);
+ if (node->session == NULL) {
+ logger_printf(logger, "[%s] No free nodes, "
+ "disconnecting", node->name);
+ telnet_print_busy(node);
+ _TCPRelease(&node->listen_pb, node->stream, nil,
+ nil, false);
+ node->state = TELNET_PB_STATE_UNUSED;
+ goto next_node;
+ }
node->session->cookie = (void *)node;
node->session->tspeed = 19200;
node->session->is_telnet = true;
@@ -901,4 +913,44 @@ telnet_ip_is_banned(ip_addr ip)
}
return ret;
+}
+
+void
+telnet_print_busy(struct telnet_node *node)
+{
+ size_t len, n, olen;
+ unsigned long now;
+ short error;
+ char *data = NULL;
+
+ if ((len = bile_read_alloc(db->bile, DB_TEXT_TYPE,
+ DB_TEXT_NO_FREE_NODES_ID, &data)) == 0) {
+ len = snprintf((char *)&node->obuf, sizeof(node->obuf),
+ "No free nodes, please call back later.\r\n");
+ } else {
+ for (n = 0, olen = 0; n < len && olen < sizeof(node->obuf) - 1;
+ n++) {
+ node->obuf[olen++] = data[n];
+ if (data[n] == '\r' && data[n + 1] != '\n')
+ node->obuf[olen++] = '\n';
+ }
+ free(data);
+ }
+
+ node->tcp_wds[0].ptr = (Ptr)&node->obuf;
+ node->tcp_wds[0].length = len;
+ node->tcp_wds[1].ptr = 0;
+ node->tcp_wds[1].length = 0;
+
+ now = Ticks;
+ error = _TCPSend(&node->send_pb, node->stream, node->tcp_wds, nil, nil,
+ true);
+ if (error)
+ return;
+
+ for (;;) {
+ /* spin for 500ms to let the send finish */
+ if (Ticks - now > 30 || node->send_pb.ioResult <= 0)
+ return;
+ }
}
--- uthread.c Sun Jul 10 21:35:22 2022
+++ uthread.c Sat Jul 16 21:42:21 2022
@@ -25,7 +25,6 @@
#define STACK_SIZE (1024 * 5)
#define CANARY 0xdeadf00d
-#define NUM_UTHREADS 5
jmp_buf uthread_coord_env;
static struct uthread uthreads[NUM_UTHREADS] = { 0 };
--- uthread.h Mon Dec 6 15:47:50 2021
+++ uthread.h Sat Jul 16 21:42:35 2022
@@ -19,6 +19,8 @@
#ifndef __UTHREAD_H__
#define __UTHREAD_H__
+#define NUM_UTHREADS 5
+
enum {
UTHREAD_STATE_DEAD,
UTHREAD_STATE_SETUP,