1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifndef CURL_DISABLE_TELNET
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
43 #ifdef HAVE_SYS_PARAM_H
44 #include <sys/param.h>
48 #include <curl/curl.h>
54 #include "system_win32.h"
59 #include "arpa_telnet.h"
65 /* The last 3 #include files should be in this order */
66 #include "curl_printf.h"
67 #include "curl_memory.h"
70 #define SUBBUFSIZE 512
72 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
73 #define CURL_SB_TERM(x) \
75 x->subend = x->subpointer; \
78 #define CURL_SB_ACCUM(x,c) \
80 if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
81 *x->subpointer++ = (c); \
84 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
85 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
86 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
87 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
89 #ifdef CURL_DISABLE_VERBOSE_STRINGS
90 #define printoption(a,b,c,d) Curl_nop_stmt
94 typedef FARPROC WSOCK2_FUNC;
95 static CURLcode check_wsock2 (struct Curl_easy *data);
99 CURLcode telrcv(struct connectdata *,
100 const unsigned char *inbuf, /* Data received from socket */
101 ssize_t count); /* Number of bytes received */
103 #ifndef CURL_DISABLE_VERBOSE_STRINGS
104 static void printoption(struct Curl_easy *data,
105 const char *direction,
106 int cmd, int option);
109 static void negotiate(struct connectdata *);
110 static void send_negotiation(struct connectdata *, int cmd, int option);
111 static void set_local_option(struct connectdata *, int cmd, int option);
112 static void set_remote_option(struct connectdata *, int cmd, int option);
114 static void printsub(struct Curl_easy *data,
115 int direction, unsigned char *pointer,
117 static void suboption(struct connectdata *);
118 static void sendsuboption(struct connectdata *conn, int option);
120 static CURLcode telnet_do(struct connectdata *conn, bool *done);
121 static CURLcode telnet_done(struct connectdata *conn,
122 CURLcode, bool premature);
123 static CURLcode send_telnet_data(struct connectdata *conn,
124 char *buffer, ssize_t nread);
126 /* For negotiation compliant to RFC 1143 */
129 #define CURL_WANTYES 2
130 #define CURL_WANTNO 3
133 #define CURL_OPPOSITE 1
136 * Telnet receiver states for fsm
147 CURL_TS_SB, /* sub-option collection */
148 CURL_TS_SE /* looking for sub-option end */
152 int please_negotiate;
153 int already_negotiated;
156 int us_preferred[256];
159 int him_preferred[256];
160 int subnegotiation[256];
161 char subopt_ttype[32]; /* Set with suboption TTYPE */
162 char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
163 unsigned short subopt_wsx; /* Set with suboption NAWS */
164 unsigned short subopt_wsy; /* Set with suboption NAWS */
165 struct curl_slist *telnet_vars; /* Environment variables */
168 unsigned char subbuffer[SUBBUFSIZE];
169 unsigned char *subpointer, *subend; /* buffer for sub-options */
171 TelnetReceive telrcv_state;
176 * TELNET protocol handler.
179 const struct Curl_handler Curl_handler_telnet = {
180 "TELNET", /* scheme */
181 ZERO_NULL, /* setup_connection */
182 telnet_do, /* do_it */
183 telnet_done, /* done */
184 ZERO_NULL, /* do_more */
185 ZERO_NULL, /* connect_it */
186 ZERO_NULL, /* connecting */
187 ZERO_NULL, /* doing */
188 ZERO_NULL, /* proto_getsock */
189 ZERO_NULL, /* doing_getsock */
190 ZERO_NULL, /* domore_getsock */
191 ZERO_NULL, /* perform_getsock */
192 ZERO_NULL, /* disconnect */
193 ZERO_NULL, /* readwrite */
194 PORT_TELNET, /* defport */
195 CURLPROTO_TELNET, /* protocol */
196 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
202 check_wsock2(struct Curl_easy *data)
205 WORD wVersionRequested;
210 /* telnet requires at least WinSock 2.0 so ask for it. */
211 wVersionRequested = MAKEWORD(2, 0);
213 err = WSAStartup(wVersionRequested, &wsaData);
215 /* We must've called this once already, so this call */
216 /* should always succeed. But, just in case... */
218 failf(data,"WSAStartup failed (%d)",err);
219 return CURLE_FAILED_INIT;
222 /* We have to have a WSACleanup call for every successful */
223 /* WSAStartup call. */
226 /* Check that our version is supported */
227 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
228 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
229 /* Our version isn't supported */
230 failf(data, "insufficient winsock version to support "
232 return CURLE_FAILED_INIT;
235 /* Our version is supported */
241 CURLcode init_telnet(struct connectdata *conn)
245 tn = calloc(1, sizeof(struct TELNET));
247 return CURLE_OUT_OF_MEMORY;
249 conn->data->req.protop = tn; /* make us known */
251 tn->telrcv_state = CURL_TS_DATA;
253 /* Init suboptions */
256 /* Set the options we want by default */
257 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
258 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
260 /* To be compliant with previous releases of libcurl
261 we enable this option by default. This behaviour
262 can be changed thanks to the "BINARY" option in
263 CURLOPT_TELNETOPTIONS
265 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
266 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
268 /* We must allow the server to echo what we sent
269 but it is not necessary to request the server
270 to do so (it might forces the server to close
271 the connection). Hence, we ignore ECHO in the
274 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
276 /* Set the subnegotiation fields to send information
277 just after negotiation passed (do/will)
279 Default values are (0,0) initialized by calloc.
280 According to the RFC1013 it is valid:
281 A value equal to zero is acceptable for the width (or height),
282 and means that no character width (or height) is being sent.
283 In this case, the width (or height) that will be assumed by the
284 Telnet server is operating system specific (it will probably be
285 based upon the terminal type information that may have been sent
286 using the TERMINAL TYPE Telnet option). */
287 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
291 static void negotiate(struct connectdata *conn)
294 struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
296 for(i = 0;i < CURL_NTELOPTS;i++) {
297 if(i==CURL_TELOPT_ECHO)
300 if(tn->us_preferred[i] == CURL_YES)
301 set_local_option(conn, i, CURL_YES);
303 if(tn->him_preferred[i] == CURL_YES)
304 set_remote_option(conn, i, CURL_YES);
308 #ifndef CURL_DISABLE_VERBOSE_STRINGS
309 static void printoption(struct Curl_easy *data,
310 const char *direction, int cmd, int option)
315 if(data->set.verbose) {
316 if(cmd == CURL_IAC) {
317 if(CURL_TELCMD_OK(option))
318 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
320 infof(data, "%s IAC %d\n", direction, option);
323 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
324 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
326 if(CURL_TELOPT_OK(option))
327 opt = CURL_TELOPT(option);
328 else if(option == CURL_TELOPT_EXOPL)
334 infof(data, "%s %s %s\n", direction, fmt, opt);
336 infof(data, "%s %s %d\n", direction, fmt, option);
339 infof(data, "%s %d %d\n", direction, cmd, option);
345 static void send_negotiation(struct connectdata *conn, int cmd, int option)
347 unsigned char buf[3];
348 ssize_t bytes_written;
350 struct Curl_easy *data = conn->data;
353 buf[1] = (unsigned char)cmd;
354 buf[2] = (unsigned char)option;
356 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
357 if(bytes_written < 0) {
359 failf(data,"Sending data failed (%d)",err);
362 printoption(conn->data, "SENT", cmd, option);
366 void set_remote_option(struct connectdata *conn, int option, int newstate)
368 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
369 if(newstate == CURL_YES) {
370 switch(tn->him[option]) {
372 tn->him[option] = CURL_WANTYES;
373 send_negotiation(conn, CURL_DO, option);
377 /* Already enabled */
381 switch(tn->himq[option]) {
383 /* Already negotiating for CURL_YES, queue the request */
384 tn->himq[option] = CURL_OPPOSITE;
387 /* Error: already queued an enable request */
393 switch(tn->himq[option]) {
395 /* Error: already negotiating for enable */
398 tn->himq[option] = CURL_EMPTY;
405 switch(tn->him[option]) {
407 /* Already disabled */
411 tn->him[option] = CURL_WANTNO;
412 send_negotiation(conn, CURL_DONT, option);
416 switch(tn->himq[option]) {
418 /* Already negotiating for NO */
421 tn->himq[option] = CURL_EMPTY;
427 switch(tn->himq[option]) {
429 tn->himq[option] = CURL_OPPOSITE;
440 void rec_will(struct connectdata *conn, int option)
442 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
443 switch(tn->him[option]) {
445 if(tn->him_preferred[option] == CURL_YES) {
446 tn->him[option] = CURL_YES;
447 send_negotiation(conn, CURL_DO, option);
450 send_negotiation(conn, CURL_DONT, option);
455 /* Already enabled */
459 switch(tn->himq[option]) {
461 /* Error: DONT answered by WILL */
462 tn->him[option] = CURL_NO;
465 /* Error: DONT answered by WILL */
466 tn->him[option] = CURL_YES;
467 tn->himq[option] = CURL_EMPTY;
473 switch(tn->himq[option]) {
475 tn->him[option] = CURL_YES;
478 tn->him[option] = CURL_WANTNO;
479 tn->himq[option] = CURL_EMPTY;
480 send_negotiation(conn, CURL_DONT, option);
488 void rec_wont(struct connectdata *conn, int option)
490 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
491 switch(tn->him[option]) {
493 /* Already disabled */
497 tn->him[option] = CURL_NO;
498 send_negotiation(conn, CURL_DONT, option);
502 switch(tn->himq[option]) {
504 tn->him[option] = CURL_NO;
508 tn->him[option] = CURL_WANTYES;
509 tn->himq[option] = CURL_EMPTY;
510 send_negotiation(conn, CURL_DO, option);
516 switch(tn->himq[option]) {
518 tn->him[option] = CURL_NO;
521 tn->him[option] = CURL_NO;
522 tn->himq[option] = CURL_EMPTY;
530 set_local_option(struct connectdata *conn, int option, int newstate)
532 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
533 if(newstate == CURL_YES) {
534 switch(tn->us[option]) {
536 tn->us[option] = CURL_WANTYES;
537 send_negotiation(conn, CURL_WILL, option);
541 /* Already enabled */
545 switch(tn->usq[option]) {
547 /* Already negotiating for CURL_YES, queue the request */
548 tn->usq[option] = CURL_OPPOSITE;
551 /* Error: already queued an enable request */
557 switch(tn->usq[option]) {
559 /* Error: already negotiating for enable */
562 tn->usq[option] = CURL_EMPTY;
569 switch(tn->us[option]) {
571 /* Already disabled */
575 tn->us[option] = CURL_WANTNO;
576 send_negotiation(conn, CURL_WONT, option);
580 switch(tn->usq[option]) {
582 /* Already negotiating for NO */
585 tn->usq[option] = CURL_EMPTY;
591 switch(tn->usq[option]) {
593 tn->usq[option] = CURL_OPPOSITE;
604 void rec_do(struct connectdata *conn, int option)
606 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
607 switch(tn->us[option]) {
609 if(tn->us_preferred[option] == CURL_YES) {
610 tn->us[option] = CURL_YES;
611 send_negotiation(conn, CURL_WILL, option);
612 if(tn->subnegotiation[option] == CURL_YES)
613 /* transmission of data option */
614 sendsuboption(conn, option);
616 else if(tn->subnegotiation[option] == CURL_YES) {
617 /* send information to achieve this option*/
618 tn->us[option] = CURL_YES;
619 send_negotiation(conn, CURL_WILL, option);
620 sendsuboption(conn, option);
623 send_negotiation(conn, CURL_WONT, option);
627 /* Already enabled */
631 switch(tn->usq[option]) {
633 /* Error: DONT answered by WILL */
634 tn->us[option] = CURL_NO;
637 /* Error: DONT answered by WILL */
638 tn->us[option] = CURL_YES;
639 tn->usq[option] = CURL_EMPTY;
645 switch(tn->usq[option]) {
647 tn->us[option] = CURL_YES;
648 if(tn->subnegotiation[option] == CURL_YES) {
649 /* transmission of data option */
650 sendsuboption(conn, option);
654 tn->us[option] = CURL_WANTNO;
655 tn->himq[option] = CURL_EMPTY;
656 send_negotiation(conn, CURL_WONT, option);
664 void rec_dont(struct connectdata *conn, int option)
666 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
667 switch(tn->us[option]) {
669 /* Already disabled */
673 tn->us[option] = CURL_NO;
674 send_negotiation(conn, CURL_WONT, option);
678 switch(tn->usq[option]) {
680 tn->us[option] = CURL_NO;
684 tn->us[option] = CURL_WANTYES;
685 tn->usq[option] = CURL_EMPTY;
686 send_negotiation(conn, CURL_WILL, option);
692 switch(tn->usq[option]) {
694 tn->us[option] = CURL_NO;
697 tn->us[option] = CURL_NO;
698 tn->usq[option] = CURL_EMPTY;
706 static void printsub(struct Curl_easy *data,
707 int direction, /* '<' or '>' */
708 unsigned char *pointer, /* where suboption data is */
709 size_t length) /* length of suboption data */
713 if(data->set.verbose) {
715 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
719 i = pointer[length-2];
720 j = pointer[length-1];
722 if(i != CURL_IAC || j != CURL_SE) {
723 infof(data, "(terminated by ");
724 if(CURL_TELOPT_OK(i))
725 infof(data, "%s ", CURL_TELOPT(i));
726 else if(CURL_TELCMD_OK(i))
727 infof(data, "%s ", CURL_TELCMD(i));
729 infof(data, "%u ", i);
730 if(CURL_TELOPT_OK(j))
731 infof(data, "%s", CURL_TELOPT(j));
732 else if(CURL_TELCMD_OK(j))
733 infof(data, "%s", CURL_TELCMD(j));
735 infof(data, "%d", j);
736 infof(data, ", not IAC SE!) ");
742 infof(data, "(Empty suboption?)");
746 if(CURL_TELOPT_OK(pointer[0])) {
748 case CURL_TELOPT_TTYPE:
749 case CURL_TELOPT_XDISPLOC:
750 case CURL_TELOPT_NEW_ENVIRON:
751 case CURL_TELOPT_NAWS:
752 infof(data, "%s", CURL_TELOPT(pointer[0]));
755 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
760 infof(data, "%d (unknown)", pointer[i]);
763 case CURL_TELOPT_NAWS:
765 infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
766 (pointer[3]<<8) | pointer[4]);
770 case CURL_TELQUAL_IS:
773 case CURL_TELQUAL_SEND:
774 infof(data, " SEND");
776 case CURL_TELQUAL_INFO:
777 infof(data, " INFO/REPLY");
779 case CURL_TELQUAL_NAME:
780 infof(data, " NAME");
785 case CURL_TELOPT_TTYPE:
786 case CURL_TELOPT_XDISPLOC:
788 infof(data, " \"%s\"", &pointer[2]);
790 case CURL_TELOPT_NEW_ENVIRON:
791 if(pointer[1] == CURL_TELQUAL_IS) {
793 for(i = 3;i < length;i++) {
795 case CURL_NEW_ENV_VAR:
798 case CURL_NEW_ENV_VALUE:
802 infof(data, "%c", pointer[i]);
809 for(i = 2; i < length; i++)
810 infof(data, " %.2x", pointer[i]);
819 static CURLcode check_telnet_options(struct connectdata *conn)
821 struct curl_slist *head;
822 struct curl_slist *beg;
823 char option_keyword[128] = "";
824 char option_arg[256] = "";
825 struct Curl_easy *data = conn->data;
826 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
827 CURLcode result = CURLE_OK;
830 /* Add the user name as an environment variable if it
831 was given on the command line */
832 if(conn->bits.user_passwd) {
833 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
834 beg = curl_slist_append(tn->telnet_vars, option_arg);
836 curl_slist_free_all(tn->telnet_vars);
837 tn->telnet_vars = NULL;
838 return CURLE_OUT_OF_MEMORY;
840 tn->telnet_vars = beg;
841 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
844 for(head = data->set.telnet_options; head; head=head->next) {
845 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
846 option_keyword, option_arg) == 2) {
849 if(Curl_raw_equal(option_keyword, "TTYPE")) {
850 strncpy(tn->subopt_ttype, option_arg, 31);
851 tn->subopt_ttype[31] = 0; /* String termination */
852 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
856 /* Display variable */
857 if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
858 strncpy(tn->subopt_xdisploc, option_arg, 127);
859 tn->subopt_xdisploc[127] = 0; /* String termination */
860 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
864 /* Environment variable */
865 if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
866 beg = curl_slist_append(tn->telnet_vars, option_arg);
868 result = CURLE_OUT_OF_MEMORY;
871 tn->telnet_vars = beg;
872 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
877 if(Curl_raw_equal(option_keyword, "WS")) {
878 if(sscanf(option_arg, "%hu%*[xX]%hu",
879 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
880 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
882 failf(data, "Syntax error in telnet option: %s", head->data);
883 result = CURLE_TELNET_OPTION_SYNTAX;
889 /* To take care or not of the 8th bit in data exchange */
890 if(Curl_raw_equal(option_keyword, "BINARY")) {
891 binary_option=atoi(option_arg);
892 if(binary_option!=1) {
893 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
894 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
899 failf(data, "Unknown telnet option %s", head->data);
900 result = CURLE_UNKNOWN_TELNET_OPTION;
904 failf(data, "Syntax error in telnet option: %s", head->data);
905 result = CURLE_TELNET_OPTION_SYNTAX;
911 curl_slist_free_all(tn->telnet_vars);
912 tn->telnet_vars = NULL;
921 * Look at the sub-option buffer, and try to be helpful to the other
925 static void suboption(struct connectdata *conn)
927 struct curl_slist *v;
928 unsigned char temp[2048];
929 ssize_t bytes_written;
933 char varname[128] = "";
934 char varval[128] = "";
935 struct Curl_easy *data = conn->data;
936 struct TELNET *tn = (struct TELNET *)data->req.protop;
938 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
939 switch (CURL_SB_GET(tn)) {
940 case CURL_TELOPT_TTYPE:
941 len = strlen(tn->subopt_ttype) + 4 + 2;
942 snprintf((char *)temp, sizeof(temp),
943 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
944 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
945 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
946 if(bytes_written < 0) {
948 failf(data,"Sending data failed (%d)",err);
950 printsub(data, '>', &temp[2], len-2);
952 case CURL_TELOPT_XDISPLOC:
953 len = strlen(tn->subopt_xdisploc) + 4 + 2;
954 snprintf((char *)temp, sizeof(temp),
955 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
956 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
957 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
958 if(bytes_written < 0) {
960 failf(data,"Sending data failed (%d)",err);
962 printsub(data, '>', &temp[2], len-2);
964 case CURL_TELOPT_NEW_ENVIRON:
965 snprintf((char *)temp, sizeof(temp),
966 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
970 for(v = tn->telnet_vars;v;v = v->next) {
971 tmplen = (strlen(v->data) + 1);
972 /* Add the variable only if it fits */
973 if(len + tmplen < (int)sizeof(temp)-6) {
974 if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
975 snprintf((char *)&temp[len], sizeof(temp) - len,
976 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
977 CURL_NEW_ENV_VALUE, varval);
982 snprintf((char *)&temp[len], sizeof(temp) - len,
983 "%c%c", CURL_IAC, CURL_SE);
985 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
986 if(bytes_written < 0) {
988 failf(data,"Sending data failed (%d)",err);
990 printsub(data, '>', &temp[2], len-2);
1000 * Send suboption information to the server side.
1003 static void sendsuboption(struct connectdata *conn, int option)
1005 ssize_t bytes_written;
1007 unsigned short x, y;
1008 unsigned char*uc1, *uc2;
1010 struct Curl_easy *data = conn->data;
1011 struct TELNET *tn = (struct TELNET *)data->req.protop;
1014 case CURL_TELOPT_NAWS:
1015 /* We prepare data to be sent */
1017 CURL_SB_ACCUM(tn, CURL_IAC);
1018 CURL_SB_ACCUM(tn, CURL_SB);
1019 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1020 /* We must deal either with litte or big endien processors */
1021 /* Window size must be sent according to the 'network order' */
1022 x=htons(tn->subopt_wsx);
1023 y=htons(tn->subopt_wsy);
1024 uc1 = (unsigned char*)&x;
1025 uc2 = (unsigned char*)&y;
1026 CURL_SB_ACCUM(tn, uc1[0]);
1027 CURL_SB_ACCUM(tn, uc1[1]);
1028 CURL_SB_ACCUM(tn, uc2[0]);
1029 CURL_SB_ACCUM(tn, uc2[1]);
1031 CURL_SB_ACCUM(tn, CURL_IAC);
1032 CURL_SB_ACCUM(tn, CURL_SE);
1034 /* data suboption is now ready */
1036 printsub(data, '>', (unsigned char *)tn->subbuffer+2,
1039 /* we send the header of the suboption... */
1040 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1041 if(bytes_written < 0) {
1043 failf(data, "Sending data failed (%d)", err);
1045 /* ... then the window size with the send_telnet_data() function
1046 to deal with 0xFF cases ... */
1047 send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
1048 /* ... and the footer */
1049 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
1050 if(bytes_written < 0) {
1052 failf(data, "Sending data failed (%d)", err);
1060 CURLcode telrcv(struct connectdata *conn,
1061 const unsigned char *inbuf, /* Data received from socket */
1062 ssize_t count) /* Number of bytes received */
1068 struct Curl_easy *data = conn->data;
1069 struct TELNET *tn = (struct TELNET *)data->req.protop;
1071 #define startskipping() \
1072 if(startwrite >= 0) { \
1073 result = Curl_client_write(conn, \
1075 (char *)&inbuf[startwrite], \
1082 #define writebyte() \
1083 if(startwrite < 0) \
1086 #define bufferflush() startskipping()
1091 switch (tn->telrcv_state) {
1093 tn->telrcv_state = CURL_TS_DATA;
1096 break; /* Ignore \0 after CR */
1103 tn->telrcv_state = CURL_TS_IAC;
1108 tn->telrcv_state = CURL_TS_CR;
1114 DEBUGASSERT(startwrite < 0);
1117 tn->telrcv_state = CURL_TS_WILL;
1120 tn->telrcv_state = CURL_TS_WONT;
1123 tn->telrcv_state = CURL_TS_DO;
1126 tn->telrcv_state = CURL_TS_DONT;
1130 tn->telrcv_state = CURL_TS_SB;
1133 tn->telrcv_state = CURL_TS_DATA;
1140 tn->telrcv_state = CURL_TS_DATA;
1141 printoption(data, "RCVD", CURL_IAC, c);
1147 printoption(data, "RCVD", CURL_WILL, c);
1148 tn->please_negotiate = 1;
1150 tn->telrcv_state = CURL_TS_DATA;
1154 printoption(data, "RCVD", CURL_WONT, c);
1155 tn->please_negotiate = 1;
1157 tn->telrcv_state = CURL_TS_DATA;
1161 printoption(data, "RCVD", CURL_DO, c);
1162 tn->please_negotiate = 1;
1164 tn->telrcv_state = CURL_TS_DATA;
1168 printoption(data, "RCVD", CURL_DONT, c);
1169 tn->please_negotiate = 1;
1171 tn->telrcv_state = CURL_TS_DATA;
1176 tn->telrcv_state = CURL_TS_SE;
1178 CURL_SB_ACCUM(tn, c);
1185 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1186 * Several things may have happened. An IAC was not doubled, the
1187 * IAC SE was left off, or another option got inserted into the
1188 * suboption are all possibilities. If we assume that the IAC was
1189 * not doubled, and really the IAC SE was left off, we could get
1190 * into an infinate loop here. So, instead, we terminate the
1191 * suboption, and process the partial suboption if we can.
1193 CURL_SB_ACCUM(tn, CURL_IAC);
1194 CURL_SB_ACCUM(tn, c);
1195 tn->subpointer -= 2;
1198 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1199 suboption(conn); /* handle sub-option */
1200 tn->telrcv_state = CURL_TS_IAC;
1203 CURL_SB_ACCUM(tn, c);
1204 tn->telrcv_state = CURL_TS_SB;
1208 CURL_SB_ACCUM(tn, CURL_IAC);
1209 CURL_SB_ACCUM(tn, CURL_SE);
1210 tn->subpointer -= 2;
1212 suboption(conn); /* handle sub-option */
1213 tn->telrcv_state = CURL_TS_DATA;
1223 /* Escape and send a telnet data block */
1224 /* TODO: write large chunks of data instead of one byte at a time */
1225 static CURLcode send_telnet_data(struct connectdata *conn,
1226 char *buffer, ssize_t nread)
1228 unsigned char outbuf[2];
1229 ssize_t bytes_written, total_written;
1231 CURLcode result = CURLE_OK;
1233 while(!result && nread--) {
1234 outbuf[0] = *buffer++;
1236 if(outbuf[0] == CURL_IAC)
1237 outbuf[out_count++] = CURL_IAC;
1241 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1242 struct pollfd pfd[1];
1243 pfd[0].fd = conn->sock[FIRSTSOCKET];
1244 pfd[0].events = POLLOUT;
1245 switch (Curl_poll(pfd, 1, -1)) {
1246 case -1: /* error, abort writing */
1247 case 0: /* timeout (will never happen) */
1248 result = CURLE_SEND_ERROR;
1250 default: /* write! */
1252 result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1253 outbuf+total_written, out_count-total_written,
1255 total_written += bytes_written;
1258 /* handle partial write */
1259 } while(!result && total_written < out_count);
1264 static CURLcode telnet_done(struct connectdata *conn,
1265 CURLcode status, bool premature)
1267 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1268 (void)status; /* unused */
1269 (void)premature; /* not used */
1274 curl_slist_free_all(tn->telnet_vars);
1275 tn->telnet_vars = NULL;
1277 Curl_safefree(conn->data->req.protop);
1282 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1285 struct Curl_easy *data = conn->data;
1286 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1289 WSOCK2_FUNC close_event_func;
1290 WSOCK2_FUNC create_event_func;
1291 WSOCK2_FUNC event_select_func;
1292 WSOCK2_FUNC enum_netevents_func;
1293 WSAEVENT event_handle;
1294 WSANETWORKEVENTS events;
1295 HANDLE stdin_handle;
1300 DWORD readfile_read;
1304 struct pollfd pfd[2];
1306 curl_off_t total_dl = 0;
1307 curl_off_t total_ul = 0;
1312 char *buf = data->state.buffer;
1315 *done = TRUE; /* unconditionally */
1317 result = init_telnet(conn);
1321 tn = (struct TELNET *)data->req.protop;
1323 result = check_telnet_options(conn);
1329 ** This functionality only works with WinSock >= 2.0. So,
1330 ** make sure have it.
1332 result = check_wsock2(data);
1336 /* OK, so we have WinSock 2.0. We need to dynamically */
1337 /* load ws2_32.dll and get the function pointers we need. */
1338 wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
1339 if(wsock2 == NULL) {
1340 failf(data, "failed to load WS2_32.DLL (%d)", ERRNO);
1341 return CURLE_FAILED_INIT;
1344 /* Grab a pointer to WSACreateEvent */
1345 create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
1346 if(create_event_func == NULL) {
1347 failf(data, "failed to find WSACreateEvent function (%d)", ERRNO);
1348 FreeLibrary(wsock2);
1349 return CURLE_FAILED_INIT;
1352 /* And WSACloseEvent */
1353 close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
1354 if(close_event_func == NULL) {
1355 failf(data, "failed to find WSACloseEvent function (%d)", ERRNO);
1356 FreeLibrary(wsock2);
1357 return CURLE_FAILED_INIT;
1360 /* And WSAEventSelect */
1361 event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
1362 if(event_select_func == NULL) {
1363 failf(data, "failed to find WSAEventSelect function (%d)", ERRNO);
1364 FreeLibrary(wsock2);
1365 return CURLE_FAILED_INIT;
1368 /* And WSAEnumNetworkEvents */
1369 enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
1370 if(enum_netevents_func == NULL) {
1371 failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO);
1372 FreeLibrary(wsock2);
1373 return CURLE_FAILED_INIT;
1376 /* We want to wait for both stdin and the socket. Since
1377 ** the select() function in winsock only works on sockets
1378 ** we have to use the WaitForMultipleObjects() call.
1381 /* First, create a sockets event object */
1382 event_handle = (WSAEVENT)create_event_func();
1383 if(event_handle == WSA_INVALID_EVENT) {
1384 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1385 FreeLibrary(wsock2);
1386 return CURLE_FAILED_INIT;
1389 /* Tell winsock what events we want to listen to */
1390 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1392 close_event_func(event_handle);
1393 FreeLibrary(wsock2);
1397 /* The get the Windows file handle for stdin */
1398 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1400 /* Create the list of objects to wait for */
1401 objs[0] = event_handle;
1402 objs[1] = stdin_handle;
1404 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1405 else use the old WaitForMultipleObjects() way */
1406 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1407 data->set.is_fread_set) {
1408 /* Don't wait for stdin_handle, just wait for event_handle */
1410 /* Check stdin_handle per 100 milliseconds */
1415 wait_timeout = 1000;
1418 /* Keep on listening and act on events */
1420 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1425 if(data->set.is_fread_set) {
1426 /* read from user-supplied method */
1427 result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
1429 if(result == CURL_READFUNC_ABORT) {
1431 result = CURLE_READ_ERROR;
1435 if(result == CURL_READFUNC_PAUSE)
1438 if(result == 0) /* no bytes */
1441 readfile_read = result; /* fall thru with number of bytes read */
1444 /* read from stdin */
1445 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1446 &readfile_read, NULL)) {
1448 result = CURLE_READ_ERROR;
1455 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1456 &readfile_read, NULL)) {
1458 result = CURLE_READ_ERROR;
1463 result = send_telnet_data(conn, buf, readfile_read);
1472 case WAIT_OBJECT_0 + 1:
1474 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1475 &readfile_read, NULL)) {
1477 result = CURLE_READ_ERROR;
1481 result = send_telnet_data(conn, buf, readfile_read);
1491 events.lNetworkEvents = 0;
1492 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1493 if((err = SOCKERRNO) != EINPROGRESS) {
1494 infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1496 result = CURLE_READ_ERROR;
1500 if(events.lNetworkEvents & FD_READ) {
1501 /* read data from network */
1502 result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1503 /* read would've blocked. Loop again */
1504 if(result == CURLE_AGAIN)
1506 /* returned not-zero, this an error */
1511 /* returned zero but actually received 0 or less here,
1512 the server closed the connection and we bail out */
1513 else if(nread <= 0) {
1518 result = telrcv(conn, (unsigned char *) buf, nread);
1524 /* Negotiate if the peer has started negotiating,
1525 otherwise don't. We don't want to speak telnet with
1526 non-telnet servers, like POP or SMTP. */
1527 if(tn->please_negotiate && !tn->already_negotiated) {
1529 tn->already_negotiated = 1;
1532 if(events.lNetworkEvents & FD_CLOSE) {
1539 if(data->set.timeout) {
1541 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1542 failf(data, "Time-out");
1543 result = CURLE_OPERATION_TIMEDOUT;
1549 /* We called WSACreateEvent, so call WSACloseEvent */
1550 if(!close_event_func(event_handle)) {
1551 infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1554 /* "Forget" pointers into the library we're about to free */
1555 create_event_func = NULL;
1556 close_event_func = NULL;
1557 event_select_func = NULL;
1558 enum_netevents_func = NULL;
1560 /* We called LoadLibrary, so call FreeLibrary */
1561 if(!FreeLibrary(wsock2))
1562 infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO);
1565 pfd[0].events = POLLIN;
1567 if(data->set.is_fread_set) {
1569 interval_ms = 100; /* poll user-supplied read function */
1572 /* really using fread, so infile is a FILE* */
1573 pfd[1].fd = fileno((FILE *)data->state.in);
1574 pfd[1].events = POLLIN;
1576 interval_ms = 1 * 1000;
1580 switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1581 case -1: /* error, stop reading */
1584 case 0: /* timeout */
1588 default: /* read! */
1589 if(pfd[0].revents & POLLIN) {
1590 /* read data from network */
1591 result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1592 /* read would've blocked. Loop again */
1593 if(result == CURLE_AGAIN)
1595 /* returned not-zero, this an error */
1600 /* returned zero but actually received 0 or less here,
1601 the server closed the connection and we bail out */
1602 else if(nread <= 0) {
1608 Curl_pgrsSetDownloadCounter(data, total_dl);
1609 result = telrcv(conn, (unsigned char *)buf, nread);
1615 /* Negotiate if the peer has started negotiating,
1616 otherwise don't. We don't want to speak telnet with
1617 non-telnet servers, like POP or SMTP. */
1618 if(tn->please_negotiate && !tn->already_negotiated) {
1620 tn->already_negotiated = 1;
1626 if(pfd[1].revents & POLLIN) { /* read from in file */
1627 nread = read(pfd[1].fd, buf, BUFSIZE - 1);
1631 /* read from user-supplied method */
1632 nread = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
1634 if(nread == CURL_READFUNC_ABORT) {
1638 if(nread == CURL_READFUNC_PAUSE)
1643 result = send_telnet_data(conn, buf, nread);
1649 Curl_pgrsSetUploadCounter(data, total_ul);
1655 } /* poll switch statement */
1657 if(data->set.timeout) {
1659 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1660 failf(data, "Time-out");
1661 result = CURLE_OPERATION_TIMEDOUT;
1666 if(Curl_pgrsUpdate(conn)) {
1667 result = CURLE_ABORTED_BY_CALLBACK;
1672 /* mark this as "no further transfer wanted" */
1673 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);