Newer
Older
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
case CURL_TS_DONT:
printoption(data, "RCVD", CURL_DONT, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
case CURL_TS_SB:
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
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)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
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;
Daniel Stenberg
committed
int 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;
HANDLE objs[2];
DWORD waitret;
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;
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
1159
1160
1161
1162
1163
1164
1165
1166
/*
** 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] = stdin_handle;
objs[1] = event_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 0;
}
/* Keep on listening and act on events */
while(keepon) {
waitret = WaitForMultipleObjects(2, objs, FALSE, INFINITE);
switch(waitret - WAIT_OBJECT_0) {
case 0:
unsigned char outbuf[2];
int out_count = 0;
ssize_t bytes_written;
char *buffer = buf;
if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
(LPDWORD)&nread, NULL)) {
keepon = FALSE;
break;
}
while(nread--) {
outbuf[0] = *buffer++;
out_count = 1;
if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC;
Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written);
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);
telrcv(conn, (unsigned char *)buf, nread);
fflush(stdout);
/* 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;
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;
while(nread--) {
outbuf[0] = *buffer++;
out_count = 1;
Daniel Stenberg
committed
if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC;
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;