static void sendsuboption(struct connectdata *conn, int option) { ssize_t bytes_written; int err; unsigned short x, y; unsigned char*uc1, *uc2; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; switch (option) { case CURL_TELOPT_NAWS: /* We prepare data to be sent */ CURL_SB_CLEAR(tn); CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SB); CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); /* We must deal either with litte or big endien processors */ /* Window size must be sent according to the 'network order' */ x=htons(tn->subopt_wsx); y=htons(tn->subopt_wsy); uc1 = (unsigned char*)&x; uc2 = (unsigned char*)&y; CURL_SB_ACCUM(tn, uc1[0]); CURL_SB_ACCUM(tn, uc1[1]); CURL_SB_ACCUM(tn, uc2[0]); CURL_SB_ACCUM(tn, uc2[1]); CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SE); CURL_SB_TERM(tn); /* data suboption is now ready */ printsub(data, '>', (unsigned char *)tn->subbuffer+2, CURL_SB_LEN(tn)-2); /* we send the header of the suboption... */ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3); if(bytes_written < 0) { err = SOCKERRNO; failf(data, "Sending data failed (%d)", err); } /* ... then the window size with the send_telnet_data() function to deal with 0xFF cases ... */ send_telnet_data(conn, (char *)tn->subbuffer+3, 4); /* ... and the footer */ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2); if(bytes_written < 0) { err = SOCKERRNO; failf(data, "Sending data failed (%d)", err); } break; } }
static void telrcv(struct connectdata *conn, unsigned char *inbuf, /* Data received from socket */ ssize_t count) /* Number of bytes received */ { unsigned char c; int in = 0; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet; while(count--) { c = inbuf[in++]; switch (tn->telrcv_state) { case CURL_TS_CR: tn->telrcv_state = CURL_TS_DATA; if (c == '\0') { break; /* Ignore \0 after CR */ } Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); continue; case CURL_TS_DATA: if (c == CURL_IAC) { tn->telrcv_state = CURL_TS_IAC; break; } else if(c == '\r') { tn->telrcv_state = CURL_TS_CR; } Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); continue; case CURL_TS_IAC: process_iac: switch (c) { case CURL_WILL: tn->telrcv_state = CURL_TS_WILL; continue; case CURL_WONT: tn->telrcv_state = CURL_TS_WONT; continue; case CURL_DO: tn->telrcv_state = CURL_TS_DO; continue; case CURL_DONT: tn->telrcv_state = CURL_TS_DONT; continue; case CURL_SB: CURL_SB_CLEAR(tn); tn->telrcv_state = CURL_TS_SB; continue; case CURL_IAC: Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); break; case CURL_DM: case CURL_NOP: case CURL_GA: default: printoption(data, "RCVD", CURL_IAC, c); break; } tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_WILL: printoption(data, "RCVD", CURL_WILL, c); tn->please_negotiate = 1; rec_will(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_WONT: printoption(data, "RCVD", CURL_WONT, c); tn->please_negotiate = 1; rec_wont(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_DO: printoption(data, "RCVD", CURL_DO, c); tn->please_negotiate = 1; rec_do(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_DONT: printoption(data, "RCVD", CURL_DONT, c); tn->please_negotiate = 1; rec_dont(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_SB: if (c == CURL_IAC) { tn->telrcv_state = CURL_TS_SE; } else { CURL_SB_ACCUM(tn,c); } continue; case CURL_TS_SE: if (c != CURL_SE) { if (c != CURL_IAC) { /* * This is an error. We only expect to get "IAC IAC" or "IAC SE". * Several things may have happend. An IAC was not doubled, the * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get * into an infinate loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, c); tn->subpointer -= 2; CURL_SB_TERM(tn); printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_IAC; goto process_iac; } CURL_SB_ACCUM(tn,c); tn->telrcv_state = CURL_TS_SB; } else { CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SE); tn->subpointer -= 2; CURL_SB_TERM(tn); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_DATA; } break; } } }
static CURLcode telrcv(struct connectdata *conn, const unsigned char *inbuf, /* Data received from socket */ ssize_t count) /* Number of bytes received */ { unsigned char c; CURLcode result; int in = 0; int startwrite=-1; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; #define startskipping() \ if(startwrite >= 0) { \ result = Curl_client_write(conn, \ CLIENTWRITE_BODY, \ (char *)&inbuf[startwrite], \ in-startwrite); \ if(result) \ return result; \ } \ startwrite = -1 #define writebyte() \ if(startwrite < 0) \ startwrite = in #define bufferflush() startskipping() while(count--) { c = inbuf[in]; switch (tn->telrcv_state) { case CURL_TS_CR: tn->telrcv_state = CURL_TS_DATA; if(c == '\0') { startskipping(); break; /* Ignore \0 after CR */ } writebyte(); break; case CURL_TS_DATA: if(c == CURL_IAC) { tn->telrcv_state = CURL_TS_IAC; startskipping(); break; } else if(c == '\r') tn->telrcv_state = CURL_TS_CR; writebyte(); break; case CURL_TS_IAC: process_iac: DEBUGASSERT(startwrite < 0); switch (c) { case CURL_WILL: tn->telrcv_state = CURL_TS_WILL; break; case CURL_WONT: tn->telrcv_state = CURL_TS_WONT; break; case CURL_DO: tn->telrcv_state = CURL_TS_DO; break; case CURL_DONT: tn->telrcv_state = CURL_TS_DONT; break; case CURL_SB: CURL_SB_CLEAR(tn); tn->telrcv_state = CURL_TS_SB; break; case CURL_IAC: tn->telrcv_state = CURL_TS_DATA; writebyte(); break; case CURL_DM: case CURL_NOP: case CURL_GA: default: tn->telrcv_state = CURL_TS_DATA; printoption(data, "RCVD", CURL_IAC, c); break; } break; case CURL_TS_WILL: printoption(data, "RCVD", CURL_WILL, c); tn->please_negotiate = 1; rec_will(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_WONT: printoption(data, "RCVD", CURL_WONT, c); tn->please_negotiate = 1; rec_wont(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_DO: printoption(data, "RCVD", CURL_DO, c); tn->please_negotiate = 1; rec_do(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_DONT: printoption(data, "RCVD", CURL_DONT, c); tn->please_negotiate = 1; rec_dont(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_SB: if(c == CURL_IAC) tn->telrcv_state = CURL_TS_SE; else CURL_SB_ACCUM(tn, c); break; case CURL_TS_SE: if(c != CURL_SE) { if(c != CURL_IAC) { /* * This is an error. We only expect to get "IAC IAC" or "IAC SE". * Several things may have happened. An IAC was not doubled, the * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get * into an infinate loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, c); tn->subpointer -= 2; CURL_SB_TERM(tn); printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_IAC; goto process_iac; } CURL_SB_ACCUM(tn, c); tn->telrcv_state = CURL_TS_SB; } else { CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SE); tn->subpointer -= 2; CURL_SB_TERM(tn); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_DATA; } break; } ++in; } bufferflush(); return CURLE_OK; }