jcs
/subtext
/amendments
/237
serial: Rewrite to allocate session on RING, then manually answer
If we can't allocate a session, just don't answer.
jcs made amendment 237 over 2 years ago
--- serial.c Wed Jul 20 09:02:33 2022
+++ serial.c Mon Jul 18 17:28:20 2022
@@ -60,13 +60,20 @@ static char serial_input_internal_buf[1024];
static char serial_input_buf[128];
static size_t serial_input_buf_len = 0;
+enum {
+ SERIAL_STATE_IDLE = 0,
+ SERIAL_STATE_ANSWERED,
+ SERIAL_STATE_CONNECTED,
+ SERIAL_STATE_HANGUP
+};
+
struct serial_node {
- bool connected;
+ short state;
unsigned short obuflen;
unsigned char obuf[512];
unsigned char ibuf[64];
unsigned short ibuflen;
- unsigned long last_ring;
+ unsigned long answered_at;
struct session *session;
} the_serial_node;
@@ -74,12 +81,13 @@ void serial_reset(void);
void serial_flush(void);
void serial_printf(const char *format, ...);
char * serial_get_line(bool wait);
+void serial_wait_for_connect(struct session *session);
short serial_input(struct session *session);
short serial_output(struct session *session);
void serial_close(struct session *session);
struct node_funcs serial_node_funcs = {
- NULL,
+ serial_wait_for_connect,
serial_input,
serial_output,
serial_close
@@ -204,10 +212,10 @@ serial_reset(void)
Delay(TICKS_PER_SEC, &m);
serial_flush();
- the_serial_node.connected = false;
+ the_serial_node.state = SERIAL_STATE_IDLE;
the_serial_node.obuflen = 0;
the_serial_node.ibuflen = 0;
- the_serial_node.last_ring = 0;
+ the_serial_node.answered_at = 0;
serial_input_buf_len = 0;
}
@@ -345,6 +353,23 @@ serial_atexit(void)
}
void
+serial_wait_for_connect(struct session *session)
+{
+ /*
+ * We get here as session setup shortly after we answered the call.
+ * Spin until serial_idle moves us to a connected state and we're
+ * ready for the actual session to proceed, or just end the session
+ * early if the negotiation failed.
+ */
+ while (the_serial_node.state == SERIAL_STATE_ANSWERED)
+ uthread_yield();
+
+ if (the_serial_node.state != SERIAL_STATE_CONNECTED &&
+ session != NULL)
+ session->ending = true;
+}
+
+void
serial_idle(void)
{
SerStaRec status;
@@ -362,43 +387,58 @@ serial_idle(void)
status.cumErrs);
#endif
- if (the_serial_node.connected)
- return;
+ switch (the_serial_node.state) {
+ case SERIAL_STATE_IDLE: {
+ char tty[7];
+
+ if ((line = serial_get_line(false)) == NULL)
+ return;
- if (the_serial_node.last_ring != 0 &&
- (Time - the_serial_node.last_ring > SERIAL_CONNECT_TIMEOUT)) {
- logger_printf(logger, "[modem] Timed out establishing a "
- "connection, resetting");
- serial_reset();
- return;
+ if (strstr(line, "RING") != NULL) {
+ sprintf(tty, "ttym%d", (db->config.modem_port == 2 ? 1 : 0));
+ the_serial_node.session = session_create(tty, "modem",
+ &serial_node_funcs);
+ if (the_serial_node.session == NULL) {
+ logger_printf(logger, "[modem] No free nodes, can't "
+ "answer call");
+ break;
+ }
+
+ the_serial_node.session->cookie = (void *)&the_serial_node;
+ the_serial_node.session->vt100 = 1;
+ the_serial_node.state = SERIAL_STATE_ANSWERED;
+ the_serial_node.answered_at = Time;
+
+ logger_printf(logger, "[modem] Answering call");
+ serial_printf("ATA\r");
+ }
+ break;
}
+ case SERIAL_STATE_ANSWERED: {
+ long baud; /* optimistic :) */
+ short count;
+
+ if (Time - the_serial_node.answered_at > SERIAL_CONNECT_TIMEOUT) {
+ logger_printf(logger, "[modem] Timed out establishing a "
+ "connection, aborting");
+ the_serial_node.session->ending = true;
+ the_serial_node.state = SERIAL_STATE_HANGUP;
+ break;
+ }
- if ((line = serial_get_line(false)) == NULL)
- return;
+ if ((line = serial_get_line(false)) == NULL)
+ break;
- if (strstr(line, "CONNECT ") != NULL) {
- char tty[7];
- long baud; /* optimistic :) */
- short count, ret;
-
- sprintf(tty, "ttym%d", (db->config.modem_port == 2 ? 1 : 0));
- the_serial_node.session = session_create(tty, "modem",
- &serial_node_funcs);
- if (the_serial_node.session == NULL) {
- logger_printf(logger, "[modem] No free nodes, hanging up");
- serial_reset();
- return;
+ if (strstr(line, "CONNECT ") != NULL) {
+ the_serial_node.state = SERIAL_STATE_CONNECTED;
+
+ if (sscanf(line, "CONNECT %ld/%n", &baud, &count) == 1 &&
+ count > 0)
+ the_serial_node.session->tspeed = baud;
}
- the_serial_node.connected = true;
- the_serial_node.session->cookie = (void *)&the_serial_node;
- the_serial_node.session->vt100 = 1;
- /* TODO: pass caller id */
- if (sscanf(line, "CONNECT %ld/%n", &baud, &count) == 1 &&
- count > 0)
- the_serial_node.session->tspeed = baud;
- } else if (strstr(line, "RING") != NULL) {
- the_serial_node.last_ring = Time;
+ break;
+ }
}
}