telnet: use dynbuf instad of malloc for escape buffer

Previously, send_telnet_data() would malloc + free a buffer every time
for escaping IAC codes. Now, it reuses a dynbuf for this purpose.

Closes #12652
This commit is contained in:
Daniel Stenberg 2024-01-07 16:28:15 +01:00
parent d18811b52b
commit 2959f45b7d
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -160,6 +160,7 @@ struct TELNET {
unsigned short subopt_wsy; /* Set with suboption NAWS */ unsigned short subopt_wsy; /* Set with suboption NAWS */
TelnetReceive telrcv_state; TelnetReceive telrcv_state;
struct curl_slist *telnet_vars; /* Environment variables */ struct curl_slist *telnet_vars; /* Environment variables */
struct dynbuf out; /* output buffer */
/* suboptions */ /* suboptions */
unsigned char subbuffer[SUBBUFSIZE]; unsigned char subbuffer[SUBBUFSIZE];
@ -204,6 +205,7 @@ CURLcode init_telnet(struct Curl_easy *data)
if(!tn) if(!tn)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
Curl_dyn_init(&tn->out, 0xffff);
data->req.p.telnet = tn; /* make us known */ data->req.p.telnet = tn; /* make us known */
tn->telrcv_state = CURL_TS_DATA; tn->telrcv_state = CURL_TS_DATA;
@ -1229,37 +1231,33 @@ process_iac:
static CURLcode send_telnet_data(struct Curl_easy *data, static CURLcode send_telnet_data(struct Curl_easy *data,
char *buffer, ssize_t nread) char *buffer, ssize_t nread)
{ {
ssize_t escapes, i, outlen; ssize_t i, outlen;
unsigned char *outbuf = NULL; unsigned char *outbuf;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
ssize_t bytes_written, total_written; ssize_t bytes_written, total_written = 0;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
struct TELNET *tn = data->req.p.telnet;
/* Determine size of new buffer after escaping */ DEBUGASSERT(tn);
escapes = 0;
for(i = 0; i < nread; i++)
if((unsigned char)buffer[i] == CURL_IAC)
escapes++;
outlen = nread + escapes;
if(outlen == nread) if(memchr(buffer, CURL_IAC, nread)) {
outbuf = (unsigned char *)buffer; /* only use the escape buffer when necessary */
else { Curl_dyn_reset(&tn->out);
ssize_t j;
outbuf = malloc(nread + escapes + 1);
if(!outbuf)
return CURLE_OUT_OF_MEMORY;
j = 0; for(i = 0; i < nread && !result; i++) {
for(i = 0; i < nread; i++) { result = Curl_dyn_addn(&tn->out, &buffer[i], 1);
outbuf[j++] = (unsigned char)buffer[i]; if(!result && ((unsigned char)buffer[i] == CURL_IAC))
if((unsigned char)buffer[i] == CURL_IAC) /* IAC is FF in hex */
outbuf[j++] = CURL_IAC; result = Curl_dyn_addn(&tn->out, "\xff", 1);
} }
outbuf[j] = '\0';
}
total_written = 0; outlen = Curl_dyn_len(&tn->out);
outbuf = Curl_dyn_uptr(&tn->out);
}
else {
outlen = nread;
outbuf = (unsigned char *)buffer;
}
while(!result && total_written < outlen) { while(!result && total_written < outlen) {
/* Make sure socket is writable to avoid EWOULDBLOCK condition */ /* Make sure socket is writable to avoid EWOULDBLOCK condition */
struct pollfd pfd[1]; struct pollfd pfd[1];
@ -1272,19 +1270,13 @@ static CURLcode send_telnet_data(struct Curl_easy *data,
break; break;
default: /* write! */ default: /* write! */
bytes_written = 0; bytes_written = 0;
result = Curl_nwrite(data, FIRSTSOCKET, result = Curl_nwrite(data, FIRSTSOCKET, outbuf + total_written,
outbuf + total_written, outlen - total_written, &bytes_written);
outlen - total_written,
&bytes_written);
total_written += bytes_written; total_written += bytes_written;
break; break;
} }
} }
/* Free malloc copy if escaped */
if(outbuf != (unsigned char *)buffer)
free(outbuf);
return result; return result;
} }
@ -1300,6 +1292,7 @@ static CURLcode telnet_done(struct Curl_easy *data,
curl_slist_free_all(tn->telnet_vars); curl_slist_free_all(tn->telnet_vars);
tn->telnet_vars = NULL; tn->telnet_vars = NULL;
Curl_dyn_free(&tn->out);
return CURLE_OK; return CURLE_OK;
} }