AmendHub

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 2 months 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; + } } }