AmendHub

Download:

jcs

/

subtext

/

amendments

/

4

telnet: Add support for telnet nodes


jcs made amendment 4 over 2 years ago
--- console.c Sun Nov 28 21:12:14 2021 +++ console.c Tue Nov 30 15:07:20 2021 @@ -26,18 +26,17 @@ #define FONT_HEIGHT 10 struct node_funcs console_node_funcs = { - console_output, console_input, + console_output, }; void console_redraw(struct console *console); -void console_cursor(struct console *console, short line, short column); void console_parse_csi(struct console *console); struct console * console_init(void) { - char title[256] = { 0 }; + char title[64] = { 0 }; struct console *console; Rect bounds = { 0 }; Rect data_bounds = { 0, 0, 0, 1 }; /* tlbr */ @@ -256,20 +255,6 @@ console_redraw(struct console *console) InvertRect(&cursor); } } - -#if 0 -void -console_cursor(struct console *console, short line, short column) -{ - Rect cursor; - - cursor.left = 6 + ((console->win->portRect.left + column) * 6); - cursor.top = 6 + ((console->win->portRect.top + line) * 10) + 2; - cursor.right = cursor.left + 6; - cursor.bottom = cursor.top + 10; - InvertRect(&cursor); -} -#endif void console_parse_csi(struct console *console) --- MacTCP.h Thu Sep 17 17:48:48 2020 +++ MacTCP.h Tue Nov 30 09:11:17 2021 @@ -533,6 +533,20 @@ enum { NumOfHistoBuckets = 7 }; +enum { + ConnectionStateClosed = 0, + ConnectionStateListening = 2, + ConnectionStateSYNReceived = 4, + ConnectionStateSYNSent = 6, + ConnectionStateEstablished = 8, + ConnectionStateFINWait1 = 10, + ConnectionStateFINWait2 = 12, + ConnectionStateCloseWait = 14, + ConnectionStateClosing = 16, + ConnectionStateLastAck = 18, + ConnectionStateTimeWait = 20 +}; + struct TCPConnectionStats { unsigned long dataPktsRcvd; unsigned long dataPktsSent; --- main.c Sun Nov 28 21:17:44 2021 +++ main.c Tue Nov 30 14:45:17 2021 @@ -20,6 +20,7 @@ #include "subtext.h" #include "console.h" #include "session.h" +#include "telnet.h" #include "uthread.h" #include "util.h" @@ -41,7 +42,7 @@ main(void) GrafPtr old_port; short event_in, n; char key; - + uthread_init(); InitGraf(&thePort); @@ -55,7 +56,7 @@ main(void) MaxApplZone(); err_init(); - + mbar = GetNewMBar(MBAR_ID); SetMenuBar(mbar); apple_menu = GetMHandle(APPLE_MENU_ID); @@ -69,9 +70,11 @@ main(void) strcpy(config.name, "Kludge BBS"); strcpy(config.hostname, "klud.ge"); + telnet_init(); cur_console = console_init(); while (!quitting) { + telnet_idle(); uthread_coordinate(); WaitNextEvent(everyEvent, &event, 1L, 0L); --- session.h Fri Nov 26 13:41:08 2021 +++ session.h Tue Nov 30 13:23:40 2021 @@ -31,10 +31,9 @@ enum session_input_state { SESSION_INPUT_CHAR }; -/* TODO: move these to node struct to be session->node->output(..) */ struct node_funcs { - short (*output)(struct session *session); short (*input)(struct session *session); + short (*output)(struct session *session); }; struct session { --- tcp.c Tue Nov 16 12:53:10 2021 +++ tcp.c Tue Nov 30 09:22:58 2021 @@ -27,9 +27,8 @@ _TCPInit(void) pb.ioParam.ioPermssn = fsCurPerm; osErr = PBOpen(&pb, false); - if (noErr == osErr) { + if (noErr == osErr) gIPPDriverRefNum = pb.ioParam.ioRefNum; - } return osErr; } @@ -39,12 +38,12 @@ _TCPGetOurIP(ip_addr *ip, long *netMask) { OSErr osErr; GetAddrParamBlock pb; - int i; memset(&pb, 0, sizeof(pb)); pb.csCode = ipctlGetAddr; pb.ioCRefNum = gIPPDriverRefNum; + pb.ioResult = 1; osErr = PBControl((ParmBlkPtr)&pb, true); while (pb.ioResult > 0) @@ -70,9 +69,10 @@ _TCPCreate(TCPiopb *pb, StreamPtr *stream, Ptr rcvBufP memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPCreate; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPCreate; + pb->ioResult = 1; pb->csParam.create.rcvBuff = rcvBufPtr; pb->csParam.create.rcvBuffLen = rcvBufLen; @@ -98,17 +98,18 @@ _TCPPassiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPPassiveOpen; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPPassiveOpen; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.open.ulpTimeoutValue = 0; pb->csParam.open.ulpTimeoutAction = 1; pb->csParam.open.validityFlags = 0xC0; pb->csParam.open.commandTimeoutValue = 30; - pb->csParam.open.remoteHost = *remoteIP; - pb->csParam.open.remotePort = *remotePort; + pb->csParam.open.remoteHost = 0; + pb->csParam.open.remotePort = 0; pb->csParam.open.localHost = 0; pb->csParam.open.localPort = *localPort; pb->csParam.open.tosFlags = 0; @@ -123,9 +124,12 @@ _TCPPassiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr osErr = PBControl((ParmBlkPtr) pb, async); if (!async && (noErr == osErr)) { - *remoteIP = pb->csParam.open.remoteHost; - *remotePort = pb->csParam.open.remotePort; - *localIP = pb->csParam.open.localHost; + if (remoteIP) + *remoteIP = pb->csParam.open.remoteHost; + if (remotePort) + *remotePort = pb->csParam.open.remotePort; + if (localIP) + *localIP = pb->csParam.open.localHost; *localPort = pb->csParam.open.localPort; } @@ -143,10 +147,11 @@ _TCPActiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPActiveOpen; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPActiveOpen; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.open.ulpTimeoutValue = 30; pb->csParam.open.ulpTimeoutAction = 1; @@ -184,10 +189,11 @@ _TCPSend(TCPiopb *pb, StreamPtr stream, wdsEntry *wdsP { memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPSend; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPSend; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.send.ulpTimeoutValue = 30; pb->csParam.send.ulpTimeoutAction = 1; @@ -211,10 +217,11 @@ _TCPNoCopyRcv(TCPiopb *pb, StreamPtr stream, Ptr rdsPt memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPNoCopyRcv; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPNoCopyRcv; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.receive.commandTimeoutValue = 30; pb->csParam.receive.urgentFlag = 0; @@ -235,10 +242,11 @@ _TCPRcv(TCPiopb *pb, StreamPtr stream, Ptr rcvBufPtr, memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPRcv; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPRcv; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.receive.commandTimeoutValue = 30; pb->csParam.receive.urgentFlag = 0; @@ -260,10 +268,11 @@ _TCPBfrReturn(TCPiopb *pb, StreamPtr stream, Ptr rdsPt { memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPRcvBfrReturn; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPRcvBfrReturn; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.receive.rdsPtr = rdsPtr; pb->csParam.receive.userDataPtr = userData; @@ -277,10 +286,11 @@ _TCPClose(TCPiopb *pb, StreamPtr stream, Ptr userData, { memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPClose; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPClose; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.close.ulpTimeoutValue = 30; pb->csParam.close.ulpTimeoutAction = 1; @@ -296,10 +306,11 @@ _TCPAbort(TCPiopb *pb, StreamPtr stream, Ptr userData, { memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPAbort; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPAbort; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.abort.userDataPtr = userData; @@ -314,11 +325,12 @@ _TCPStatus(TCPiopb *pb, StreamPtr stream, struct TCPSt memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPStatus; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPStatus; pb->tcpStream = stream; pb->csParam.status.userDataPtr = userData; + pb->ioResult = 1; osErr = PBControl((ParmBlkPtr)pb, async); if (!async && (noErr == osErr)) { @@ -336,10 +348,11 @@ _TCPRelease(TCPiopb *pb, StreamPtr stream, Ptr userDat memset(pb, 0, sizeof(*pb)); + pb->csCode = TCPRelease; pb->ioCompletion = ioCompletion; pb->ioCRefNum = gIPPDriverRefNum; - pb->csCode = TCPRelease; pb->tcpStream = stream; + pb->ioResult = 1; pb->csParam.status.userDataPtr = userData; --- telnet.c Tue Nov 30 15:01:24 2021 +++ telnet.c Tue Nov 30 15:01:24 2021 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2021 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "session.h" +#include "telnet.h" +#include "tcp.h" +#include "util.h" + +enum { + TELNET_PB_STATE_UNUSED = 0, + TELNET_PB_STATE_LISTENING, + TELNET_PB_STATE_CONNECTED +}; + +struct telnet_node { + short id; + short state; + TCPiopb pb, listen_pb; + StreamPtr stream; + unsigned char *tcp_buf; + long tcp_buf_len; + wdsEntry tcp_wds[2]; + struct session *session; +}; + +#define TELNET_SLOTS 5 +struct telnet_node telnet_nodes[TELNET_SLOTS]; +short telnet_local_port; +TCPiopb telnet_exit_pb; +TCPStatusPB telnet_status_pb; + +void telnet_atexit(void); +short telnet_output(struct session *session); +short telnet_input(struct session *session); + +struct node_funcs telnet_node_funcs = { + telnet_input, + telnet_output, +}; + +void +telnet_init(void) +{ + struct telnet_node *node; + short error, i; + + if (_TCPInit() != 0) + err(1, "Failed initializing MacTCP"); + + _atexit(telnet_atexit); + + /* TODO: get from resource */ + telnet_local_port = 23; + + for (i = 0; i < TELNET_SLOTS; i++) { + node = &telnet_nodes[i]; + node->id = i; + memset(node, 0, sizeof(struct telnet_node)); + + if (i > 1) + continue; + + /* docs say buf should be 4*MTU+1024 */ + /* TODO: actually lookup MTU */ + node->tcp_buf_len = (4 * 1500) + 1024; + node->tcp_buf = xmalloc(node->tcp_buf_len); + + error = _TCPCreate(&node->pb, &node->stream, (Ptr)node->tcp_buf, + node->tcp_buf_len, nil, nil, nil, false); + if (error) + err(1, "TCPCreate[%d] failed: %d", i, error); + + error = _TCPPassiveOpen(&node->listen_pb, node->stream, nil, nil, + nil, (ip_port *)&telnet_local_port, nil, nil, true); + if (error) + err(1, "TCPPassiveOpen[%d] failed: %d", i, error); + node->state = TELNET_PB_STATE_LISTENING; + } +} + +void +telnet_atexit(void) +{ + struct telnet_node *node; + short i, error; + + for (i = 0; i < TELNET_SLOTS; i++) { + node = &telnet_nodes[i]; + + if (node->state > TELNET_PB_STATE_UNUSED) { + error = _TCPClose(&telnet_exit_pb, node->stream, nil, nil, + false); + if (error == noErr) + error = _TCPAbort(&telnet_exit_pb, node->stream, nil, nil, + false); + if (error == noErr) + error = _TCPRelease(&telnet_exit_pb, node->stream, nil, + nil, false); + } + + if (node->tcp_buf) + free(node->tcp_buf); + } +} + +void +telnet_idle(void) +{ + struct telnet_node *node; + short i, error; + + for (i = 0; i < TELNET_SLOTS; i++) { + node = &telnet_nodes[i]; + if (node->state == TELNET_PB_STATE_UNUSED) + continue; + + switch (node->state) { + case TELNET_PB_STATE_LISTENING: + if (node->listen_pb.ioResult > 0) + continue; + + error = _TCPStatus(&node->pb, node->stream, &telnet_status_pb, + nil, nil, false); + if (error == connectionDoesntExist) + continue; + if (error != noErr) + err(1, "TCPStatus[%d] %d", i, error); + if (telnet_status_pb.connectionState == + ConnectionStateEstablished) { + char tty[7]; + sprintf(tty, "ttyt%d", i); + node->state = TELNET_PB_STATE_CONNECTED; + node->session = session_create(tty, &telnet_node_funcs); + node->session->cookie = (void *)node; + } + break; + case TELNET_PB_STATE_CONNECTED: + break; + } + } +} + +short +telnet_output(struct session *session) +{ + struct telnet_node *node = (struct telnet_node *)session->cookie; + short error; + + if (session->obuflen == 0) + return 0; + + if (node->pb.ioResult > 0) + /* previous _TCPSend has not completed yet */ + return 0; + + if (node->tcp_wds[0].length) { + /* previous _TCPSend completed, shift out those bytes */ + BlockMove(session->obuf + node->tcp_wds[0].length, + session->obuf, session->obuflen - node->tcp_wds[0].length); + session->obuflen -= node->tcp_wds[0].length; + + if (session->obuflen == 0) + return 0; + } + + /* + * _TCPSend only knows how many wds pointers were passed in when it + * reads the next one and its pointer is zero (or size is zero?), so + * even though we're only sending one wds, memory after wds[0] + * has to be zeroed out. + */ + memset(&node->tcp_wds, 0, sizeof(node->tcp_wds)); + node->tcp_wds[0].ptr = session->obuf; + node->tcp_wds[0].length = session->obuflen; + + error = _TCPSend(&node->pb, node->stream, node->tcp_wds, nil, nil, + true); + if (error) + err(1, "TCPSend[%d] failed: %d", node->id, error); + /* XXX: make this not fatal */ + + return session->obuflen; +} + +short +telnet_input(struct session *session) +{ + uthread_yield(); + return 0; +} + --- telnet.h Mon Nov 29 15:26:06 2021 +++ telnet.h Mon Nov 29 15:26:06 2021 @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +void telnet_init(void); +void telnet_idle(void);