Newer
Older
Daniel Stenberg
committed
if (c == CURL_IAC)
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_SE;
Daniel Stenberg
committed
CURL_SB_ACCUM(tn,c);
Daniel Stenberg
committed
case CURL_TS_SE:
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.
*/
Daniel Stenberg
committed
CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
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;
Daniel Stenberg
committed
CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
CURL_SB_ACCUM(tn, (unsigned char)CURL_SE);
Daniel Stenberg
committed
CURL_SB_TERM(tn);
suboption(conn); /* handle sub-option */
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
}
break;
}
}
CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
(void)status; /* unused */
curl_slist_free_all(tn->telnet_vars);
free(conn->proto.telnet);
conn->proto.telnet = NULL;
CURLcode Curl_telnet(struct connectdata *conn)
Daniel Stenberg
committed
struct SessionHandle *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
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;
Daniel Stenberg
committed
ssize_t nread;
Daniel Stenberg
committed
char *buf = data->state.buffer;
struct TELNET *tn;
code = init_telnet(conn);
if(code)
return code;
tn = (struct TELNET *)conn->proto.telnet;
code = check_telnet_options(conn);
if(code)
return code;
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
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
/*
** This functionality only works with WinSock >= 2.0. So,
** make sure have it.
*/
code = check_wsock2(data);
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");
if (wsock2 == NULL) {
failf(data,"failed to load WS2_32.DLL (%d)",GetLastError());
return CURLE_FAILED_INIT;
}
/* Grab a pointer to WSACreateEvent */
create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
if (create_event_func == NULL) {
failf(data,"failed to find WSACreateEvent function (%d)",
GetLastError());
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* And WSACloseEvent */
close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
if (create_event_func == NULL) {
failf(data,"failed to find WSACloseEvent function (%d)",
GetLastError());
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* And WSAEventSelect */
event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
if (event_select_func == NULL) {
failf(data,"failed to find WSAEventSelect function (%d)",
GetLastError());
FreeLibrary(wsock2);
return CURLE_FAILED_INIT;
}
/* And WSAEnumNetworkEvents */
enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
if (enum_netevents_func == NULL) {
failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
GetLastError());
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();
if (event_handle == WSA_INVALID_EVENT) {
failf(data,"WSACreateEvent failed (%d)",WSAGetLastError());
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);
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:
{
unsigned char outbuf[2];
int out_count = 0;
ssize_t bytes_written;
char *buffer = buf;
for(;;) {
if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
keepon = FALSE;
break;
}
Daniel Stenberg
committed
if(!nread)
break;
Daniel Stenberg
committed
if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
&readfile_read, NULL)) {
keepon = FALSE;
break;
}
nread = readfile_read;
Daniel Stenberg
committed
while(nread--) {
outbuf[0] = *buffer++;
out_count = 1;
if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC;
Daniel Stenberg
committed
Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written);
}
}
Daniel Stenberg
committed
}
Daniel Stenberg
committed
case WAIT_OBJECT_0 + 1:
unsigned char outbuf[2];
int out_count = 0;
ssize_t bytes_written;
char *buffer = buf;
Daniel Stenberg
committed
if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
Daniel Stenberg
committed
&readfile_read, NULL)) {
keepon = FALSE;
break;
}
Daniel Stenberg
committed
nread = readfile_read;
Daniel Stenberg
committed
while(nread--) {
outbuf[0] = *buffer++;
out_count = 1;
if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC;
Daniel Stenberg
committed
Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written);
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 */
if (close_event_func(event_handle) == FALSE) {
infof(data,"WSACloseEvent failed (%d)",WSAGetLastError());
}
/* "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 */
if (!FreeLibrary(wsock2))
infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
FD_ZERO (&readfd); /* clear it */
FD_SET (sockfd, &readfd);
struct timeval interval;
readfd = keepfd; /* set this every lap in the loop */
interval.tv_sec = 1;
interval.tv_usec = 0;
switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) {
case -1: /* error, stop reading */
keepon = FALSE;
continue;
case 0: /* timeout */
break;
default: /* read! */
if(FD_ISSET(0, &readfd)) { /* read from stdin */
unsigned char outbuf[2];
int out_count = 0;
ssize_t bytes_written;
Daniel Stenberg
committed
while(nread--) {
outbuf[0] = *buffer++;
out_count = 1;
Daniel Stenberg
committed
if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC;
Daniel Stenberg
committed
Daniel Stenberg
committed
Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written);
}
}
if(FD_ISSET(sockfd, &readfd)) {
/* 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! */
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();
if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
failf(data, "Time-out");
code = CURLE_OPERATION_TIMEOUTED;
keepon = FALSE;
}
}
/* mark this as "no further transfer wanted" */
Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
return code;