jcs
/subtext
/amendments
/144
telnet: Use TCPNoCopyRcv instead of TCPRcv
Avoid copying input data to an intermediate node buffer, just to then
process it and copy it to the session buffer.
Doesn't seem to make things any faster, but might as well do it
jcs made amendment 144 over 2 years ago
--- telnet.c Sun Jun 12 08:41:43 2022
+++ telnet.c Wed Jun 15 13:48:57 2022
@@ -93,10 +93,9 @@ struct telnet_node {
TCPiopb rcv_pb, send_pb, listen_pb;
StreamPtr stream;
wdsEntry tcp_wds[2];
+ rdsEntry tcp_rds[2];
unsigned short obuflen;
unsigned char obuf[512];
- unsigned char ibuf[64];
- unsigned short ibuflen;
unsigned short sending_iac;
unsigned short escaped_obuflen;
short iac_state;
@@ -116,12 +115,11 @@ TCPStatusPB telnet_status_pb;
bool did_initial_log = false;
void telnet_setup(struct session *session);
-short telnet_process_input(struct session *session);
void telnet_output_iac(struct session *session, char *iacs, size_t len);
struct node_funcs telnet_node_funcs = {
telnet_setup,
- telnet_process_input, /* we'll receive input outside of session */
+ telnet_input,
telnet_output,
telnet_close
};
@@ -168,7 +166,7 @@ telnet_idle(void)
{
char ip_s[20];
struct telnet_node *node;
- short n, error;
+ short n, j, error;
ip_addr ip;
tcp_port port;
long mask;
@@ -237,6 +235,7 @@ telnet_idle(void)
node->session = session_create(tty, "telnet",
&telnet_node_funcs);
node->session->cookie = (void *)node;
+ node->session->tspeed = 19200;
node->session->log.ip_address = telnet_status_pb.remoteHost;
/* start up a new socket for listening */
@@ -244,12 +243,13 @@ telnet_idle(void)
}
break;
case TELNET_PB_STATE_CONNECTED:
- if (node->session) {
- telnet_output(node->session);
- if (node->session->ending)
- break;
- telnet_input(node->session);
+ if (!node->session) {
+ free(node);
+ telnet_nodes[n] = NULL;
+ break;
}
+
+ telnet_output(node->session);
break;
}
}
@@ -275,18 +275,10 @@ short
telnet_input(struct session *session)
{
struct telnet_node *node = (struct telnet_node *)session->cookie;
- unsigned short rlen;
short error, n;
unsigned char c;
char iac_out[8] = { IAC, 0 };
- if (session->ending || node->ibuflen >= sizeof(node->ibuf))
- return 0;
-
- if (node->rcv_pb.ioResult > 0)
- /* previous _TCPSend/_TCPRecv has not completed yet */
- return 0;
-
error = _TCPStatus(&node->rcv_pb, node->stream, &telnet_status_pb, nil,
nil, false);
if (error ||
@@ -297,46 +289,40 @@ telnet_input(struct session *session)
if (telnet_status_pb.amtUnreadData == 0)
return 0;
-
- rlen = telnet_status_pb.amtUnreadData;
- 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);
+ 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;
+
+ error = _TCPNoCopyRcv(&node->rcv_pb, node->stream,
+ (Ptr)&node->tcp_rds[0], 1, nil, nil, false);
if (error) {
- warn("TCPRecv[%d] failed: %d", node->id, error);
+ warn("TCPNoCopyRcv[%d] failed: %d", node->id, error);
session->ending = 1;
return 0;
}
- node->ibuflen += rlen;
-
- return rlen;
-}
-
-short
-telnet_process_input(struct session *session)
-{
- struct telnet_node *node = (struct telnet_node *)session->cookie;
- short error, n;
- unsigned char c;
- char iac_out[8] = { IAC, 0 };
-
- if (node->ibuflen == 0)
+ if (node->tcp_rds[0].length == 0)
return 0;
-
- if (session->ending)
- 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->ibuflen; n++) {
- if (session->ibuflen >= sizeof(session->ibuf) - 5)
+ 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!");
break;
-
- c = node->ibuf[n];
+ }
+ c = ((char *)(node->tcp_rds[0].ptr))[n];
+
switch (node->iac_state) {
case TELNET_IAC_STATE_IDLE:
if (c == IAC)
@@ -508,11 +494,13 @@ telnet_process_input(struct session *session)
}
if (n) {
- node->ibuflen -= n;
- if (node->ibuflen == 1)
- node->ibuf[0] = node->ibuf[n];
- else if (node->ibuflen != 0)
- memmove(node->ibuf, node->ibuf + n, node->ibuflen);
+ error = _TCPBfrReturn(&node->rcv_pb, node->stream,
+ (Ptr)&node->tcp_rds[0], nil, nil, false);
+ if (error) {
+ warn("TCPNoCopyRcv[%d] failed: %d", node->id, error);
+ session->ending = 1;
+ return 0;
+ }
}
return n;