AmendHub

Download:

jcs

/

subtext

/

amendments

/

188

telnet: When doing file transfers, fast-path to TCP buffer

We're doing IAC escaping in the zmodem code, so just move data
directly into node buffer. Also, avoid memmoving on each read since
the buffer will often have more than one byte in it, just use an
offset into ibuf and only memmove when it's over half full.

jcs made amendment 188 about 1 year ago
--- telnet.c Thu Jun 23 14:21:30 2022 +++ telnet.c Mon Jul 11 10:57:13 2022 @@ -95,6 +95,9 @@ struct telnet_node { struct session *session; unsigned short obuflen; unsigned char obuf[512]; + unsigned char ibuf[64]; + unsigned short ibuflen; + unsigned short ibufoff; unsigned short sending_iac; unsigned short escaped_obuflen; short iac_state; @@ -106,7 +109,6 @@ struct telnet_node { TCPiopb rcv_pb, send_pb, listen_pb; StreamPtr stream; wdsEntry tcp_wds[2]; - rdsEntry tcp_rds[2]; }; #define MAX_TELNET_NODES 10 @@ -305,6 +307,7 @@ telnet_idle(void) &telnet_node_funcs); node->session->cookie = (void *)node; node->session->tspeed = 19200; + node->session->need_IAC_escaped = true; node->session->log.ip_address = telnet_status_pb.remoteHost; break; default: @@ -369,7 +372,8 @@ short telnet_input(struct session *session) { struct telnet_node *node = (struct telnet_node *)session->cookie; - short error, n, j; + unsigned short rlen; + short error, n, j, used; unsigned char c; char iac_out[8] = { IAC, 0 }; @@ -384,13 +388,44 @@ telnet_input(struct session *session) if (telnet_status_pb.amtUnreadData == 0) return 0; - node->tcp_rds[0].length = MIN(telnet_status_pb.amtUnreadData, - sizeof(session->ibuf) - 5 - session->ibuflen); - node->tcp_rds[0].ptr = 0; - node->tcp_rds[1].length = 0; + rlen = telnet_status_pb.amtUnreadData; - error = _TCPNoCopyRcv(&node->rcv_pb, node->stream, - (Ptr)&node->tcp_rds[0], 1, nil, nil, false); + if (session->transferring_file) { + if (session->ibuflen + session->ibufoff + rlen > + sizeof(session->ibuf)) { + /* if we're already halfway through the buffer, reset */ + if (session->ibufoff >= (sizeof(session->ibuf) / 2)) { + memmove(session->ibuf, session->ibuf + session->ibufoff, + session->ibuflen); + session->ibufoff = 0; + } + rlen = sizeof(session->ibuf) - session->ibuflen - + session->ibufoff; + if (rlen == 0) + return 0; + } + + error = _TCPRcv(&node->rcv_pb, node->stream, + (Ptr)(session->ibuf + session->ibufoff + session->ibuflen), &rlen, + nil, nil, false); + if (error) { + session_log(session, "TCP read failed (%d), closing connection", + error); + session->ending = 1; + return 0; + } + if (rlen == 0) + return 0; + session->last_input_at = Time; + session->ibuflen += rlen; + return rlen; + } + + if (node->ibuflen + rlen > sizeof(node->ibuf)) + rlen = sizeof(node->ibuf) - node->ibuflen; + + error = _TCPRcv(&node->rcv_pb, node->stream, + (Ptr)(node->ibuf + node->ibuflen), &rlen, nil, nil, false); if (error) { session_log(session, "TCP read failed (%d), closing connection", error); @@ -398,26 +433,20 @@ telnet_input(struct session *session) return 0; } - if (node->tcp_rds[0].length == 0) + if (rlen == 0) return 0; - if (node->tcp_rds[0].ptr == NULL) - panic("TCPNoCopyRcv returned rds of length %d but NULL ptr!", - node->tcp_rds[0].length); session->last_input_at = Time; - - for (n = 0; n < node->tcp_rds[0].length; n++) { - if (session->ibuflen >= sizeof(session->ibuf) - 5) { - /* - * We will lose remaining data because we already told - * TCPNoCopyRcv we're taking so many bytes - */ - session_log(session, "TCP read into session ibuf overflow!"); + node->ibuflen += rlen; + + used = 0; + for (n = 0; n < node->ibuflen; n++) { + if (session->ibuflen >= sizeof(session->ibuf)) break; - } + + c = node->ibuf[n]; + used++; - c = ((char *)(node->tcp_rds[0].ptr))[n]; - switch (node->iac_state) { case TELNET_IAC_STATE_IDLE: if (c == IAC) @@ -664,18 +693,14 @@ telnet_input(struct session *session) } } - if (n) { - error = _TCPBfrReturn(&node->rcv_pb, node->stream, - (Ptr)&node->tcp_rds[0], nil, nil, false); - if (error) { - session_log(session, "TCP read return failed (%d), closing " - "connection", error); - session->ending = 1; - return 0; - } + if (used == node->ibuflen) + node->ibuflen = 0; + else { + memmove(node->ibuf, node->ibuf + used, node->ibuflen - used); + node->ibuflen -= used; } - return n; + return rlen; } short @@ -712,6 +737,9 @@ process_result: if (session->obuflen == 1 && session->obuf[0] != IAC) { node->obuf[0] = session->obuf[0]; node->escaped_obuflen = node->obuflen = 1; + } else if (session->transferring_file) { + memcpy(node->obuf, session->obuf, session->obuflen); + node->escaped_obuflen = node->obuflen = session->obuflen; } else { /* copy obuf to node buffer, escaping IACs */ for (node->escaped_obuflen = 0, node->obuflen = 0;