Newer
Older
Daniel Stenberg
committed
case CURL_TS_IAC:
DEBUGASSERT(startwrite < 0);
Daniel Stenberg
committed
case CURL_WILL:
tn->telrcv_state = CURL_TS_WILL;
break;
Daniel Stenberg
committed
case CURL_WONT:
tn->telrcv_state = CURL_TS_WONT;
break;
Daniel Stenberg
committed
case CURL_DO:
tn->telrcv_state = CURL_TS_DO;
break;
Daniel Stenberg
committed
case CURL_DONT:
tn->telrcv_state = CURL_TS_DONT;
break;
Daniel Stenberg
committed
case CURL_SB:
CURL_SB_CLEAR(tn);
tn->telrcv_state = CURL_TS_SB;
break;
Daniel Stenberg
committed
case CURL_IAC:
tn->telrcv_state = CURL_TS_DATA;
writebyte();
Daniel Stenberg
committed
case CURL_DM:
case CURL_NOP:
case CURL_GA:
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
printoption(data, "RCVD", CURL_IAC, c);
break;
Daniel Stenberg
committed
case CURL_TS_WILL:
printoption(data, "RCVD", CURL_WILL, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_TS_WONT:
printoption(data, "RCVD", CURL_WONT, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_TS_DO:
printoption(data, "RCVD", CURL_DO, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_TS_DONT:
printoption(data, "RCVD", CURL_DONT, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
break;
Daniel Stenberg
committed
case CURL_TS_SB:
Daniel Stenberg
committed
if(c == CURL_IAC)
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_SE;
Daniel Stenberg
committed
CURL_SB_ACCUM(tn,c);
break;
Daniel Stenberg
committed
case CURL_TS_SE:
Daniel Stenberg
committed
if(c != CURL_SE)
Daniel Stenberg
committed
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);
Daniel Stenberg
committed
CURL_SB_ACCUM(tn, c);
Daniel Stenberg
committed
CURL_SB_TERM(tn);
Daniel Stenberg
committed
Daniel Stenberg
committed
printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
suboption(conn); /* handle sub-option */
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_IAC;
Daniel Stenberg
committed
CURL_SB_ACCUM(tn,c);
tn->telrcv_state = CURL_TS_SB;
CURL_SB_ACCUM(tn, CURL_IAC);
CURL_SB_ACCUM(tn, CURL_SE);
Daniel Stenberg
committed
CURL_SB_TERM(tn);
suboption(conn); /* handle sub-option */
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
++in;
bufferflush();
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
/* Escape and send a telnet data block */
/* TODO: write large chunks of data instead of one byte at a time */
static CURLcode send_telnet_data(struct connectdata *conn,
char *buffer, ssize_t nread)
{
unsigned char outbuf[2];
ssize_t bytes_written, total_written;
int out_count;
CURLcode rc = CURLE_OK;
while(rc == CURLE_OK && nread--) {
outbuf[0] = *buffer++;
out_count = 1;
if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC;
total_written = 0;
do {
/* Make sure socket is writable to avoid EWOULDBLOCK condition */
struct pollfd pfd[1];
pfd[0].fd = conn->sock[FIRSTSOCKET];
pfd[0].events = POLLOUT;
switch (Curl_poll(pfd, 1, -1)) {
case -1: /* error, abort writing */
case 0: /* timeout (will never happen) */
rc = CURLE_SEND_ERROR;
break;
default: /* write! */
bytes_written = 0;
rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
out_count-total_written, &bytes_written);
total_written += bytes_written;
break;
}
/* handle partial write */
} while (rc == CURLE_OK && total_written < out_count);
}
return rc;
}
static CURLcode telnet_done(struct connectdata *conn,
Patrick Monnerat
committed
CURLcode status, bool premature)
Daniel Stenberg
committed
struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
(void)status; /* unused */
Daniel Stenberg
committed
(void)premature; /* not used */
curl_slist_free_all(tn->telnet_vars);
Daniel Stenberg
committed
free(conn->data->state.proto.telnet);
conn->data->state.proto.telnet = NULL;
static CURLcode telnet_do(struct connectdata *conn, bool *done)
Daniel Stenberg
committed
struct SessionHandle *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
#ifdef USE_WINSOCK
HMODULE wsock2;
WSOCK2_FUNC close_event_func;
WSOCK2_FUNC create_event_func;
WSOCK2_FUNC event_select_func;
WSOCK2_FUNC enum_netevents_func;
WSAEVENT event_handle;
WSANETWORKEVENTS events;
HANDLE stdin_handle;
Daniel Stenberg
committed
HANDLE objs[2];
DWORD obj_count;
DWORD wait_timeout;
Daniel Stenberg
committed
DWORD readfile_read;
int interval_ms;
struct pollfd pfd[2];
Daniel Stenberg
committed
ssize_t nread;
Daniel Stenberg
committed
char *buf = data->state.buffer;
*done = TRUE; /* unconditionally */
code = init_telnet(conn);
if(code)
return code;
Daniel Stenberg
committed
tn = (struct TELNET *)data->state.proto.telnet;
code = check_telnet_options(conn);
if(code)
return code;
#ifdef USE_WINSOCK
/*
** This functionality only works with WinSock >= 2.0. So,
** make sure have it.
*/
code = check_wsock2(data);
Daniel Stenberg
committed
if(code)
return code;
/* OK, so we have WinSock 2.0. We need to dynamically */
/* load ws2_32.dll and get the function pointers we need. */
wsock2 = LoadLibrary("WS2_32.DLL");
Daniel Stenberg
committed
if(wsock2 == NULL) {
failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
return CURLE_FAILED_INIT;
}
/* Grab a pointer to WSACreateEvent */
create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
Daniel Stenberg
committed
if(create_event_func == NULL) {
failf(data,"failed to find WSACreateEvent function (%d)",
ERRNO);
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* And WSACloseEvent */
close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
Daniel Stenberg
committed
if(close_event_func == NULL) {
failf(data,"failed to find WSACloseEvent function (%d)",
ERRNO);
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* And WSAEventSelect */
event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
Daniel Stenberg
committed
if(event_select_func == NULL) {
failf(data,"failed to find WSAEventSelect function (%d)",
ERRNO);
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* And WSAEnumNetworkEvents */
enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
Daniel Stenberg
committed
if(enum_netevents_func == NULL) {
failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
ERRNO);
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* We want to wait for both stdin and the socket. Since
** the select() function in winsock only works on sockets
** we have to use the WaitForMultipleObjects() call.
*/
/* First, create a sockets event object */
event_handle = (WSAEVENT)create_event_func();
Daniel Stenberg
committed
if(event_handle == WSA_INVALID_EVENT) {
failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* The get the Windows file handle for stdin */
stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
/* Create the list of objects to wait for */
objs[0] = event_handle;
objs[1] = stdin_handle;
/* Tell winsock what events we want to listen to */
if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
close_event_func(event_handle);
FreeLibrary(wsock2);
return CURLE_OK;
Daniel Stenberg
committed
/* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
else use the old WaitForMultipleObjects() way */
if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
/* Don't wait for stdin_handle, just wait for event_handle */
Daniel Stenberg
committed
obj_count = 1;
/* Check stdin_handle per 100 milliseconds */
Daniel Stenberg
committed
wait_timeout = 100;
} else {
obj_count = 2;
wait_timeout = INFINITE;
}
Daniel Stenberg
committed
/* Keep on listening and act on events */
while(keepon) {
waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
switch(waitret) {
case WAIT_TIMEOUT:
{
while(1) {
if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
keepon = FALSE;
code = CURLE_READ_ERROR;
break;
}
Daniel Stenberg
committed
if(!readfile_read)
Daniel Stenberg
committed
if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
&readfile_read, NULL)) {
keepon = FALSE;
code = CURLE_READ_ERROR;
break;
}
Daniel Stenberg
committed
code = send_telnet_data(conn, buf, readfile_read);
if(code) {
keepon = FALSE;
break;
}
Daniel Stenberg
committed
}
Daniel Stenberg
committed
case WAIT_OBJECT_0 + 1:
if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
Daniel Stenberg
committed
&readfile_read, NULL)) {
code = CURLE_READ_ERROR;
Daniel Stenberg
committed
code = send_telnet_data(conn, buf, readfile_read);
if(code) {
keepon = FALSE;
break;
Daniel Stenberg
committed
case WAIT_OBJECT_0:
if(enum_netevents_func(sockfd, event_handle, &events)
!= SOCKET_ERROR) {
if(events.lNetworkEvents & FD_READ) {
/* This reallu OUGHT to check its return code. */
(void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
Daniel Stenberg
committed
telrcv(conn, (unsigned char *)buf, nread);
Daniel Stenberg
committed
Daniel Stenberg
committed
/* Negotiate if the peer has started negotiating,
otherwise don't. We don't want to speak telnet with
non-telnet servers, like POP or SMTP. */
if(tn->please_negotiate && !tn->already_negotiated) {
negotiate(conn);
tn->already_negotiated = 1;
Daniel Stenberg
committed
if(events.lNetworkEvents & FD_CLOSE) {
keepon = FALSE;
/* We called WSACreateEvent, so call WSACloseEvent */
Daniel Stenberg
committed
if(close_event_func(event_handle) == FALSE) {
infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
}
/* "Forget" pointers into the library we're about to free */
create_event_func = NULL;
close_event_func = NULL;
event_select_func = NULL;
enum_netevents_func = NULL;
/* We called LoadLibrary, so call FreeLibrary */
Daniel Stenberg
committed
if(!FreeLibrary(wsock2))
infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
pfd[0].fd = sockfd;
pfd[0].events = POLLIN;
pfd[1].fd = 0;
pfd[1].events = POLLIN;
interval_ms = 1 * 1000;
Daniel Stenberg
committed
while(keepon) {
switch (Curl_poll(pfd, 2, interval_ms)) {
case -1: /* error, stop reading */
case 0: /* timeout */
default: /* read! */
if(pfd[1].revents & POLLIN) { /* read from stdin */
code = send_telnet_data(conn, buf, nread);
if(code) {
keepon = FALSE;
break;
}
/* This OUGHT to check the return code... */
(void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
/* if we receive 0 or less here, the server closed the connection and
we bail out from this! */
Daniel Stenberg
committed
if(nread <= 0) {
keepon = FALSE;
break;
}
telrcv(conn, (unsigned char *)buf, nread);
/* Negotiate if the peer has started negotiating,
otherwise don't. We don't want to speak telnet with
non-telnet servers, like POP or SMTP. */
if(tn->please_negotiate && !tn->already_negotiated) {
if(data->set.timeout) {
struct timeval now; /* current time */
now = Curl_tvnow();
Daniel Stenberg
committed
if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
failf(data, "Time-out");
code = CURLE_OPERATION_TIMEDOUT;
keepon = FALSE;
}
}
/* mark this as "no further transfer wanted" */
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);