Improved telnet support by drastically reducing the number of write

callbacks needed to pass a buffer to the user.  Instead one per byte it
is now as little as one per segment.
This commit is contained in:
Dan Fandrich 2007-11-07 05:52:03 +00:00
parent 70f10f1ac9
commit 33f7ac06c3
2 changed files with 45 additions and 23 deletions

View File

@ -6,6 +6,11 @@
Changelog Changelog
Dan F (6 Nov 2007)
- Improved telnet support by drastically reducing the number of write
callbacks needed to pass a buffer to the user. Instead one per byte it
is now as little as one per segment.
Yang Tse (6 Nov 2007) Yang Tse (6 Nov 2007)
- Bug report #1824894 (http://curl.haxx.se/bug/view.cgi?id=1824894) pointed - Bug report #1824894 (http://curl.haxx.se/bug/view.cgi?id=1824894) pointed
out a problem in curl.h when building C++ apps with MSVC. To fix it, the out a problem in curl.h when building C++ apps with MSVC. To fix it, the

View File

@ -106,7 +106,7 @@ static CURLcode check_wsock2 ( struct SessionHandle *data );
static static
void telrcv(struct connectdata *, void telrcv(struct connectdata *,
unsigned char *inbuf, /* Data received from socket */ const unsigned char *inbuf, /* Data received from socket */
ssize_t count); /* Number of bytes received */ ssize_t count); /* Number of bytes received */
#ifndef CURL_DISABLE_VERBOSE_STRINGS #ifndef CURL_DISABLE_VERBOSE_STRINGS
@ -949,104 +949,119 @@ static void suboption(struct connectdata *conn)
static static
void telrcv(struct connectdata *conn, void telrcv(struct connectdata *conn,
unsigned char *inbuf, /* Data received from socket */ const unsigned char *inbuf, /* Data received from socket */
ssize_t count) /* Number of bytes received */ ssize_t count) /* Number of bytes received */
{ {
unsigned char c; unsigned char c;
int in = 0; int in = 0;
int startwrite=-1;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet; struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet;
#define startskipping() \
if (startwrite >= 0) \
Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&inbuf[startwrite], in-startwrite); \
startwrite = -1
#define writebyte() \
if (startwrite < 0) \
startwrite = in
#define bufferflush() startskipping()
while(count--) while(count--)
{ {
c = inbuf[in++]; c = inbuf[in];
/*infof(data,"In rcv state %d char %d\n", tn->telrcv_state, c);*/
switch (tn->telrcv_state) switch (tn->telrcv_state)
{ {
case CURL_TS_CR: case CURL_TS_CR:
tn->telrcv_state = CURL_TS_DATA; tn->telrcv_state = CURL_TS_DATA;
if(c == '\0') if(c == '\0')
{ {
startskipping();
break; /* Ignore \0 after CR */ break; /* Ignore \0 after CR */
} }
writebyte();
Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); break;
continue;
case CURL_TS_DATA: case CURL_TS_DATA:
if(c == CURL_IAC) if(c == CURL_IAC)
{ {
tn->telrcv_state = CURL_TS_IAC; tn->telrcv_state = CURL_TS_IAC;
startskipping();
break; break;
} }
else if(c == '\r') else if(c == '\r')
{ {
tn->telrcv_state = CURL_TS_CR; tn->telrcv_state = CURL_TS_CR;
} }
writebyte();
Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); break;
continue;
case CURL_TS_IAC: case CURL_TS_IAC:
process_iac: process_iac:
DEBUGASSERT(startwrite < 0);
switch (c) switch (c)
{ {
case CURL_WILL: case CURL_WILL:
tn->telrcv_state = CURL_TS_WILL; tn->telrcv_state = CURL_TS_WILL;
continue; break;
case CURL_WONT: case CURL_WONT:
tn->telrcv_state = CURL_TS_WONT; tn->telrcv_state = CURL_TS_WONT;
continue; break;
case CURL_DO: case CURL_DO:
tn->telrcv_state = CURL_TS_DO; tn->telrcv_state = CURL_TS_DO;
continue; break;
case CURL_DONT: case CURL_DONT:
tn->telrcv_state = CURL_TS_DONT; tn->telrcv_state = CURL_TS_DONT;
continue; break;
case CURL_SB: case CURL_SB:
CURL_SB_CLEAR(tn); CURL_SB_CLEAR(tn);
tn->telrcv_state = CURL_TS_SB; tn->telrcv_state = CURL_TS_SB;
continue; break;
case CURL_IAC: case CURL_IAC:
Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); tn->telrcv_state = CURL_TS_DATA;
writebyte();
break; break;
case CURL_DM: case CURL_DM:
case CURL_NOP: case CURL_NOP:
case CURL_GA: case CURL_GA:
default: default:
tn->telrcv_state = CURL_TS_DATA;
printoption(data, "RCVD", CURL_IAC, c); printoption(data, "RCVD", CURL_IAC, c);
break; break;
} }
tn->telrcv_state = CURL_TS_DATA; break;
continue;
case CURL_TS_WILL: case CURL_TS_WILL:
printoption(data, "RCVD", CURL_WILL, c); printoption(data, "RCVD", CURL_WILL, c);
tn->please_negotiate = 1; tn->please_negotiate = 1;
rec_will(conn, c); rec_will(conn, c);
tn->telrcv_state = CURL_TS_DATA; tn->telrcv_state = CURL_TS_DATA;
continue; break;
case CURL_TS_WONT: case CURL_TS_WONT:
printoption(data, "RCVD", CURL_WONT, c); printoption(data, "RCVD", CURL_WONT, c);
tn->please_negotiate = 1; tn->please_negotiate = 1;
rec_wont(conn, c); rec_wont(conn, c);
tn->telrcv_state = CURL_TS_DATA; tn->telrcv_state = CURL_TS_DATA;
continue; break;
case CURL_TS_DO: case CURL_TS_DO:
printoption(data, "RCVD", CURL_DO, c); printoption(data, "RCVD", CURL_DO, c);
tn->please_negotiate = 1; tn->please_negotiate = 1;
rec_do(conn, c); rec_do(conn, c);
tn->telrcv_state = CURL_TS_DATA; tn->telrcv_state = CURL_TS_DATA;
continue; break;
case CURL_TS_DONT: case CURL_TS_DONT:
printoption(data, "RCVD", CURL_DONT, c); printoption(data, "RCVD", CURL_DONT, c);
tn->please_negotiate = 1; tn->please_negotiate = 1;
rec_dont(conn, c); rec_dont(conn, c);
tn->telrcv_state = CURL_TS_DATA; tn->telrcv_state = CURL_TS_DATA;
continue; break;
case CURL_TS_SB: case CURL_TS_SB:
if(c == CURL_IAC) if(c == CURL_IAC)
@ -1057,7 +1072,7 @@ void telrcv(struct connectdata *conn,
{ {
CURL_SB_ACCUM(tn,c); CURL_SB_ACCUM(tn,c);
} }
continue; break;
case CURL_TS_SE: case CURL_TS_SE:
if(c != CURL_SE) if(c != CURL_SE)
@ -1097,7 +1112,9 @@ void telrcv(struct connectdata *conn,
} }
break; break;
} }
++in;
} }
bufferflush();
} }
static CURLcode Curl_telnet_done(struct connectdata *conn, static CURLcode Curl_telnet_done(struct connectdata *conn,
@ -1143,7 +1160,7 @@ static CURLcode Curl_telnet(struct connectdata *conn, bool *done)
char *buf = data->state.buffer; char *buf = data->state.buffer;
struct TELNET *tn; struct TELNET *tn;
*done = TRUE; /* uncontionally */ *done = TRUE; /* unconditionally */
code = init_telnet(conn); code = init_telnet(conn);
if(code) if(code)