1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2015, 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 "curl_printf.h"
59 #include "arpa_telnet.h"
65 /* The last #include files should be: */
66 #include "curl_memory.h"
69 #define SUBBUFSIZE 512
71 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
72 #define CURL_SB_TERM(x) \
74 x->subend = x->subpointer; \
77 #define CURL_SB_ACCUM(x,c) \
79 if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
80 *x->subpointer++ = (c); \
83 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
84 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
85 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
86 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
88 #ifdef CURL_DISABLE_VERBOSE_STRINGS
89 #define printoption(a,b,c,d) Curl_nop_stmt
93 typedef FARPROC WSOCK2_FUNC;
94 static CURLcode check_wsock2 ( struct SessionHandle *data );
98 CURLcode telrcv(struct connectdata *,
99 const unsigned char *inbuf, /* Data received from socket */
100 ssize_t count); /* Number of bytes received */
102 #ifndef CURL_DISABLE_VERBOSE_STRINGS
103 static void printoption(struct SessionHandle *data,
104 const char *direction,
105 int cmd, int option);
108 static void negotiate(struct connectdata *);
109 static void send_negotiation(struct connectdata *, int cmd, int option);
110 static void set_local_option(struct connectdata *, int cmd, int option);
111 static void set_remote_option(struct connectdata *, int cmd, int option);
113 static void printsub(struct SessionHandle *data,
114 int direction, unsigned char *pointer,
116 static void suboption(struct connectdata *);
117 static void sendsuboption(struct connectdata *conn, int option);
119 static CURLcode telnet_do(struct connectdata *conn, bool *done);
120 static CURLcode telnet_done(struct connectdata *conn,
121 CURLcode, bool premature);
122 static CURLcode send_telnet_data(struct connectdata *conn,
123 char *buffer, ssize_t nread);
125 /* For negotiation compliant to RFC 1143 */
128 #define CURL_WANTYES 2
129 #define CURL_WANTNO 3
132 #define CURL_OPPOSITE 1
135 * Telnet receiver states for fsm
146 CURL_TS_SB, /* sub-option collection */
147 CURL_TS_SE /* looking for sub-option end */
151 int please_negotiate;
152 int already_negotiated;
155 int us_preferred[256];
158 int him_preferred[256];
159 int subnegotiation[256];
160 char subopt_ttype[32]; /* Set with suboption TTYPE */
161 char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
162 unsigned short subopt_wsx; /* Set with suboption NAWS */
163 unsigned short subopt_wsy; /* Set with suboption NAWS */
164 struct curl_slist *telnet_vars; /* Environment variables */
167 unsigned char subbuffer[SUBBUFSIZE];
168 unsigned char *subpointer, *subend; /* buffer for sub-options */
170 TelnetReceive telrcv_state;
175 * TELNET protocol handler.
178 const struct Curl_handler Curl_handler_telnet = {
179 "TELNET", /* scheme */
180 ZERO_NULL, /* setup_connection */
181 telnet_do, /* do_it */
182 telnet_done, /* done */
183 ZERO_NULL, /* do_more */
184 ZERO_NULL, /* connect_it */
185 ZERO_NULL, /* connecting */
186 ZERO_NULL, /* doing */
187 ZERO_NULL, /* proto_getsock */
188 ZERO_NULL, /* doing_getsock */
189 ZERO_NULL, /* domore_getsock */
190 ZERO_NULL, /* perform_getsock */
191 ZERO_NULL, /* disconnect */
192 ZERO_NULL, /* readwrite */
193 PORT_TELNET, /* defport */
194 CURLPROTO_TELNET, /* protocol */
195 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
201 check_wsock2 ( struct SessionHandle *data )
204 WORD wVersionRequested;
209 /* telnet requires at least WinSock 2.0 so ask for it. */
210 wVersionRequested = MAKEWORD(2, 0);
212 err = WSAStartup(wVersionRequested, &wsaData);
214 /* We must've called this once already, so this call */
215 /* should always succeed. But, just in case... */
217 failf(data,"WSAStartup failed (%d)",err);
218 return CURLE_FAILED_INIT;
221 /* We have to have a WSACleanup call for every successful */
222 /* WSAStartup call. */
225 /* Check that our version is supported */
226 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
227 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
228 /* Our version isn't supported */
229 failf(data, "insufficient winsock version to support "
231 return CURLE_FAILED_INIT;
234 /* Our version is supported */
240 CURLcode init_telnet(struct connectdata *conn)
244 tn = calloc(1, sizeof(struct TELNET));
246 return CURLE_OUT_OF_MEMORY;
248 conn->data->req.protop = tn; /* make us known */
250 tn->telrcv_state = CURL_TS_DATA;
252 /* Init suboptions */
255 /* Set the options we want by default */
256 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
257 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
259 /* To be compliant with previous releases of libcurl
260 we enable this option by default. This behaviour
261 can be changed thanks to the "BINARY" option in
262 CURLOPT_TELNETOPTIONS
264 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
265 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
267 /* We must allow the server to echo what we sent
268 but it is not necessary to request the server
269 to do so (it might forces the server to close
270 the connection). Hence, we ignore ECHO in the
273 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
275 /* Set the subnegotiation fields to send information
276 just after negotiation passed (do/will)
278 Default values are (0,0) initialized by calloc.
279 According to the RFC1013 it is valid:
280 A value equal to zero is acceptable for the width (or height),
281 and means that no character width (or height) is being sent.
282 In this case, the width (or height) that will be assumed by the
283 Telnet server is operating system specific (it will probably be
284 based upon the terminal type information that may have been sent
285 using the TERMINAL TYPE Telnet option). */
286 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
290 static void negotiate(struct connectdata *conn)
293 struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
295 for(i = 0;i < CURL_NTELOPTS;i++) {
296 if(i==CURL_TELOPT_ECHO)
299 if(tn->us_preferred[i] == CURL_YES)
300 set_local_option(conn, i, CURL_YES);
302 if(tn->him_preferred[i] == CURL_YES)
303 set_remote_option(conn, i, CURL_YES);
307 #ifndef CURL_DISABLE_VERBOSE_STRINGS
308 static void printoption(struct SessionHandle *data,
309 const char *direction, int cmd, int option)
314 if(data->set.verbose) {
315 if(cmd == CURL_IAC) {
316 if(CURL_TELCMD_OK(option))
317 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
319 infof(data, "%s IAC %d\n", direction, option);
322 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
323 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
325 if(CURL_TELOPT_OK(option))
326 opt = CURL_TELOPT(option);
327 else if(option == CURL_TELOPT_EXOPL)
333 infof(data, "%s %s %s\n", direction, fmt, opt);
335 infof(data, "%s %s %d\n", direction, fmt, option);
338 infof(data, "%s %d %d\n", direction, cmd, option);
344 static void send_negotiation(struct connectdata *conn, int cmd, int option)
346 unsigned char buf[3];
347 ssize_t bytes_written;
349 struct SessionHandle *data = conn->data;
352 buf[1] = (unsigned char)cmd;
353 buf[2] = (unsigned char)option;
355 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
356 if(bytes_written < 0) {
358 failf(data,"Sending data failed (%d)",err);
361 printoption(conn->data, "SENT", cmd, option);
365 void set_remote_option(struct connectdata *conn, int option, int newstate)
367 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
368 if(newstate == CURL_YES) {
369 switch(tn->him[option]) {
371 tn->him[option] = CURL_WANTYES;
372 send_negotiation(conn, CURL_DO, option);
376 /* Already enabled */
380 switch(tn->himq[option]) {
382 /* Already negotiating for CURL_YES, queue the request */
383 tn->himq[option] = CURL_OPPOSITE;
386 /* Error: already queued an enable request */
392 switch(tn->himq[option]) {
394 /* Error: already negotiating for enable */
397 tn->himq[option] = CURL_EMPTY;
404 switch(tn->him[option]) {
406 /* Already disabled */
410 tn->him[option] = CURL_WANTNO;
411 send_negotiation(conn, CURL_DONT, option);
415 switch(tn->himq[option]) {
417 /* Already negotiating for NO */
420 tn->himq[option] = CURL_EMPTY;
426 switch(tn->himq[option]) {
428 tn->himq[option] = CURL_OPPOSITE;
439 void rec_will(struct connectdata *conn, int option)
441 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
442 switch(tn->him[option]) {
444 if(tn->him_preferred[option] == CURL_YES) {
445 tn->him[option] = CURL_YES;
446 send_negotiation(conn, CURL_DO, option);
449 send_negotiation(conn, CURL_DONT, option);
454 /* Already enabled */
458 switch(tn->himq[option]) {
460 /* Error: DONT answered by WILL */
461 tn->him[option] = CURL_NO;
464 /* Error: DONT answered by WILL */
465 tn->him[option] = CURL_YES;
466 tn->himq[option] = CURL_EMPTY;
472 switch(tn->himq[option]) {
474 tn->him[option] = CURL_YES;
477 tn->him[option] = CURL_WANTNO;
478 tn->himq[option] = CURL_EMPTY;
479 send_negotiation(conn, CURL_DONT, option);
487 void rec_wont(struct connectdata *conn, int option)
489 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
490 switch(tn->him[option]) {
492 /* Already disabled */
496 tn->him[option] = CURL_NO;
497 send_negotiation(conn, CURL_DONT, option);
501 switch(tn->himq[option]) {
503 tn->him[option] = CURL_NO;
507 tn->him[option] = CURL_WANTYES;
508 tn->himq[option] = CURL_EMPTY;
509 send_negotiation(conn, CURL_DO, option);
515 switch(tn->himq[option]) {
517 tn->him[option] = CURL_NO;
520 tn->him[option] = CURL_NO;
521 tn->himq[option] = CURL_EMPTY;
529 set_local_option(struct connectdata *conn, int option, int newstate)
531 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
532 if(newstate == CURL_YES) {
533 switch(tn->us[option]) {
535 tn->us[option] = CURL_WANTYES;
536 send_negotiation(conn, CURL_WILL, option);
540 /* Already enabled */
544 switch(tn->usq[option]) {
546 /* Already negotiating for CURL_YES, queue the request */
547 tn->usq[option] = CURL_OPPOSITE;
550 /* Error: already queued an enable request */
556 switch(tn->usq[option]) {
558 /* Error: already negotiating for enable */
561 tn->usq[option] = CURL_EMPTY;
568 switch(tn->us[option]) {
570 /* Already disabled */
574 tn->us[option] = CURL_WANTNO;
575 send_negotiation(conn, CURL_WONT, option);
579 switch(tn->usq[option]) {
581 /* Already negotiating for NO */
584 tn->usq[option] = CURL_EMPTY;
590 switch(tn->usq[option]) {
592 tn->usq[option] = CURL_OPPOSITE;
603 void rec_do(struct connectdata *conn, int option)
605 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
606 switch(tn->us[option]) {
608 if(tn->us_preferred[option] == CURL_YES) {
609 tn->us[option] = CURL_YES;
610 send_negotiation(conn, CURL_WILL, option);
611 if(tn->subnegotiation[option] == CURL_YES)
612 /* transmission of data option */
613 sendsuboption(conn, option);
615 else if(tn->subnegotiation[option] == CURL_YES) {
616 /* send information to achieve this option*/
617 tn->us[option] = CURL_YES;
618 send_negotiation(conn, CURL_WILL, option);
619 sendsuboption(conn, option);
622 send_negotiation(conn, CURL_WONT, option);
626 /* Already enabled */
630 switch(tn->usq[option]) {
632 /* Error: DONT answered by WILL */
633 tn->us[option] = CURL_NO;
636 /* Error: DONT answered by WILL */
637 tn->us[option] = CURL_YES;
638 tn->usq[option] = CURL_EMPTY;
644 switch(tn->usq[option]) {
646 tn->us[option] = CURL_YES;
647 if(tn->subnegotiation[option] == CURL_YES) {
648 /* transmission of data option */
649 sendsuboption(conn, option);
653 tn->us[option] = CURL_WANTNO;
654 tn->himq[option] = CURL_EMPTY;
655 send_negotiation(conn, CURL_WONT, option);
663 void rec_dont(struct connectdata *conn, int option)
665 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
666 switch(tn->us[option]) {
668 /* Already disabled */
672 tn->us[option] = CURL_NO;
673 send_negotiation(conn, CURL_WONT, option);
677 switch(tn->usq[option]) {
679 tn->us[option] = CURL_NO;
683 tn->us[option] = CURL_WANTYES;
684 tn->usq[option] = CURL_EMPTY;
685 send_negotiation(conn, CURL_WILL, option);
691 switch(tn->usq[option]) {
693 tn->us[option] = CURL_NO;
696 tn->us[option] = CURL_NO;
697 tn->usq[option] = CURL_EMPTY;
705 static void printsub(struct SessionHandle *data,
706 int direction, /* '<' or '>' */
707 unsigned char *pointer, /* where suboption data is */
708 size_t length) /* length of suboption data */
712 if(data->set.verbose) {
714 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
718 i = pointer[length-2];
719 j = pointer[length-1];
721 if(i != CURL_IAC || j != CURL_SE) {
722 infof(data, "(terminated by ");
723 if(CURL_TELOPT_OK(i))
724 infof(data, "%s ", CURL_TELOPT(i));
725 else if(CURL_TELCMD_OK(i))
726 infof(data, "%s ", CURL_TELCMD(i));
728 infof(data, "%u ", i);
729 if(CURL_TELOPT_OK(j))
730 infof(data, "%s", CURL_TELOPT(j));
731 else if(CURL_TELCMD_OK(j))
732 infof(data, "%s", CURL_TELCMD(j));
734 infof(data, "%d", j);
735 infof(data, ", not IAC SE!) ");
741 infof(data, "(Empty suboption?)");
745 if(CURL_TELOPT_OK(pointer[0])) {
747 case CURL_TELOPT_TTYPE:
748 case CURL_TELOPT_XDISPLOC:
749 case CURL_TELOPT_NEW_ENVIRON:
750 case CURL_TELOPT_NAWS:
751 infof(data, "%s", CURL_TELOPT(pointer[0]));
754 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
759 infof(data, "%d (unknown)", pointer[i]);
762 case CURL_TELOPT_NAWS:
764 infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
765 (pointer[3]<<8) | pointer[4]);
769 case CURL_TELQUAL_IS:
772 case CURL_TELQUAL_SEND:
773 infof(data, " SEND");
775 case CURL_TELQUAL_INFO:
776 infof(data, " INFO/REPLY");
778 case CURL_TELQUAL_NAME:
779 infof(data, " NAME");
784 case CURL_TELOPT_TTYPE:
785 case CURL_TELOPT_XDISPLOC:
787 infof(data, " \"%s\"", &pointer[2]);
789 case CURL_TELOPT_NEW_ENVIRON:
790 if(pointer[1] == CURL_TELQUAL_IS) {
792 for(i = 3;i < length;i++) {
794 case CURL_NEW_ENV_VAR:
797 case CURL_NEW_ENV_VALUE:
801 infof(data, "%c", pointer[i]);
808 for(i = 2; i < length; i++)
809 infof(data, " %.2x", pointer[i]);
818 static CURLcode check_telnet_options(struct connectdata *conn)
820 struct curl_slist *head;
821 struct curl_slist *beg;
822 char option_keyword[128] = "";
823 char option_arg[256] = "";
824 struct SessionHandle *data = conn->data;
825 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
826 CURLcode result = CURLE_OK;
829 /* Add the user name as an environment variable if it
830 was given on the command line */
831 if(conn->bits.user_passwd) {
832 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
833 beg = curl_slist_append(tn->telnet_vars, option_arg);
835 curl_slist_free_all(tn->telnet_vars);
836 tn->telnet_vars = NULL;
837 return CURLE_OUT_OF_MEMORY;
839 tn->telnet_vars = beg;
840 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
843 for(head = data->set.telnet_options; head; head=head->next) {
844 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
845 option_keyword, option_arg) == 2) {
848 if(Curl_raw_equal(option_keyword, "TTYPE")) {
849 strncpy(tn->subopt_ttype, option_arg, 31);
850 tn->subopt_ttype[31] = 0; /* String termination */
851 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
855 /* Display variable */
856 if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
857 strncpy(tn->subopt_xdisploc, option_arg, 127);
858 tn->subopt_xdisploc[127] = 0; /* String termination */
859 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
863 /* Environment variable */
864 if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
865 beg = curl_slist_append(tn->telnet_vars, option_arg);
867 result = CURLE_OUT_OF_MEMORY;
870 tn->telnet_vars = beg;
871 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
876 if(Curl_raw_equal(option_keyword, "WS")) {
877 if(sscanf(option_arg, "%hu%*[xX]%hu",
878 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
879 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
881 failf(data, "Syntax error in telnet option: %s", head->data);
882 result = CURLE_TELNET_OPTION_SYNTAX;
888 /* To take care or not of the 8th bit in data exchange */
889 if(Curl_raw_equal(option_keyword, "BINARY")) {
890 binary_option=atoi(option_arg);
891 if(binary_option!=1) {
892 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
893 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
898 failf(data, "Unknown telnet option %s", head->data);
899 result = CURLE_UNKNOWN_TELNET_OPTION;
903 failf(data, "Syntax error in telnet option: %s", head->data);
904 result = CURLE_TELNET_OPTION_SYNTAX;
910 curl_slist_free_all(tn->telnet_vars);
911 tn->telnet_vars = NULL;
920 * Look at the sub-option buffer, and try to be helpful to the other
924 static void suboption(struct connectdata *conn)
926 struct curl_slist *v;
927 unsigned char temp[2048];
928 ssize_t bytes_written;
932 char varname[128] = "";
933 char varval[128] = "";
934 struct SessionHandle *data = conn->data;
935 struct TELNET *tn = (struct TELNET *)data->req.protop;
937 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
938 switch (CURL_SB_GET(tn)) {
939 case CURL_TELOPT_TTYPE:
940 len = strlen(tn->subopt_ttype) + 4 + 2;
941 snprintf((char *)temp, sizeof(temp),
942 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
943 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
944 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
945 if(bytes_written < 0) {
947 failf(data,"Sending data failed (%d)",err);
949 printsub(data, '>', &temp[2], len-2);
951 case CURL_TELOPT_XDISPLOC:
952 len = strlen(tn->subopt_xdisploc) + 4 + 2;
953 snprintf((char *)temp, sizeof(temp),
954 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
955 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
956 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
957 if(bytes_written < 0) {
959 failf(data,"Sending data failed (%d)",err);
961 printsub(data, '>', &temp[2], len-2);
963 case CURL_TELOPT_NEW_ENVIRON:
964 snprintf((char *)temp, sizeof(temp),
965 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
969 for(v = tn->telnet_vars;v;v = v->next) {
970 tmplen = (strlen(v->data) + 1);
971 /* Add the variable only if it fits */
972 if(len + tmplen < (int)sizeof(temp)-6) {
973 if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
974 snprintf((char *)&temp[len], sizeof(temp) - len,
975 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
976 CURL_NEW_ENV_VALUE, varval);
981 snprintf((char *)&temp[len], sizeof(temp) - len,
982 "%c%c", CURL_IAC, CURL_SE);
984 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
985 if(bytes_written < 0) {
987 failf(data,"Sending data failed (%d)",err);
989 printsub(data, '>', &temp[2], len-2);
999 * Send suboption information to the server side.
1002 static void sendsuboption(struct connectdata *conn, int option)
1004 ssize_t bytes_written;
1006 unsigned short x, y;
1007 unsigned char*uc1, *uc2;
1009 struct SessionHandle *data = conn->data;
1010 struct TELNET *tn = (struct TELNET *)data->req.protop;
1013 case CURL_TELOPT_NAWS:
1014 /* We prepare data to be sent */
1016 CURL_SB_ACCUM(tn, CURL_IAC);
1017 CURL_SB_ACCUM(tn, CURL_SB);
1018 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1019 /* We must deal either with litte or big endien processors */
1020 /* Window size must be sent according to the 'network order' */
1021 x=htons(tn->subopt_wsx);
1022 y=htons(tn->subopt_wsy);
1023 uc1 = (unsigned char*)&x;
1024 uc2 = (unsigned char*)&y;
1025 CURL_SB_ACCUM(tn, uc1[0]);
1026 CURL_SB_ACCUM(tn, uc1[1]);
1027 CURL_SB_ACCUM(tn, uc2[0]);
1028 CURL_SB_ACCUM(tn, uc2[1]);
1030 CURL_SB_ACCUM(tn, CURL_IAC);
1031 CURL_SB_ACCUM(tn, CURL_SE);
1033 /* data suboption is now ready */
1035 printsub(data, '>', (unsigned char *)tn->subbuffer+2,
1038 /* we send the header of the suboption... */
1039 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1040 if(bytes_written < 0) {
1042 failf(data, "Sending data failed (%d)", err);
1044 /* ... then the window size with the send_telnet_data() function
1045 to deal with 0xFF cases ... */
1046 send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
1047 /* ... and the footer */
1048 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
1049 if(bytes_written < 0) {
1051 failf(data, "Sending data failed (%d)", err);
1059 CURLcode telrcv(struct connectdata *conn,
1060 const unsigned char *inbuf, /* Data received from socket */
1061 ssize_t count) /* Number of bytes received */
1067 struct SessionHandle *data = conn->data;
1068 struct TELNET *tn = (struct TELNET *)data->req.protop;
1070 #define startskipping() \
1071 if(startwrite >= 0) { \
1072 result = Curl_client_write(conn, \
1074 (char *)&inbuf[startwrite], \
1081 #define writebyte() \
1082 if(startwrite < 0) \
1085 #define bufferflush() startskipping()
1090 switch (tn->telrcv_state) {
1092 tn->telrcv_state = CURL_TS_DATA;
1095 break; /* Ignore \0 after CR */
1102 tn->telrcv_state = CURL_TS_IAC;
1107 tn->telrcv_state = CURL_TS_CR;
1113 DEBUGASSERT(startwrite < 0);
1116 tn->telrcv_state = CURL_TS_WILL;
1119 tn->telrcv_state = CURL_TS_WONT;
1122 tn->telrcv_state = CURL_TS_DO;
1125 tn->telrcv_state = CURL_TS_DONT;
1129 tn->telrcv_state = CURL_TS_SB;
1132 tn->telrcv_state = CURL_TS_DATA;
1139 tn->telrcv_state = CURL_TS_DATA;
1140 printoption(data, "RCVD", CURL_IAC, c);
1146 printoption(data, "RCVD", CURL_WILL, c);
1147 tn->please_negotiate = 1;
1149 tn->telrcv_state = CURL_TS_DATA;
1153 printoption(data, "RCVD", CURL_WONT, c);
1154 tn->please_negotiate = 1;
1156 tn->telrcv_state = CURL_TS_DATA;
1160 printoption(data, "RCVD", CURL_DO, c);
1161 tn->please_negotiate = 1;
1163 tn->telrcv_state = CURL_TS_DATA;
1167 printoption(data, "RCVD", CURL_DONT, c);
1168 tn->please_negotiate = 1;
1170 tn->telrcv_state = CURL_TS_DATA;
1175 tn->telrcv_state = CURL_TS_SE;
1177 CURL_SB_ACCUM(tn, c);
1184 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1185 * Several things may have happened. An IAC was not doubled, the
1186 * IAC SE was left off, or another option got inserted into the
1187 * suboption are all possibilities. If we assume that the IAC was
1188 * not doubled, and really the IAC SE was left off, we could get
1189 * into an infinate loop here. So, instead, we terminate the
1190 * suboption, and process the partial suboption if we can.
1192 CURL_SB_ACCUM(tn, CURL_IAC);
1193 CURL_SB_ACCUM(tn, c);
1194 tn->subpointer -= 2;
1197 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1198 suboption(conn); /* handle sub-option */
1199 tn->telrcv_state = CURL_TS_IAC;
1202 CURL_SB_ACCUM(tn, c);
1203 tn->telrcv_state = CURL_TS_SB;
1207 CURL_SB_ACCUM(tn, CURL_IAC);
1208 CURL_SB_ACCUM(tn, CURL_SE);
1209 tn->subpointer -= 2;
1211 suboption(conn); /* handle sub-option */
1212 tn->telrcv_state = CURL_TS_DATA;
1222 /* Escape and send a telnet data block */
1223 /* TODO: write large chunks of data instead of one byte at a time */
1224 static CURLcode send_telnet_data(struct connectdata *conn,
1225 char *buffer, ssize_t nread)
1227 unsigned char outbuf[2];
1228 ssize_t bytes_written, total_written;
1230 CURLcode result = CURLE_OK;
1232 while(!result && nread--) {
1233 outbuf[0] = *buffer++;
1235 if(outbuf[0] == CURL_IAC)
1236 outbuf[out_count++] = CURL_IAC;
1240 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1241 struct pollfd pfd[1];
1242 pfd[0].fd = conn->sock[FIRSTSOCKET];
1243 pfd[0].events = POLLOUT;
1244 switch (Curl_poll(pfd, 1, -1)) {
1245 case -1: /* error, abort writing */
1246 case 0: /* timeout (will never happen) */
1247 result = CURLE_SEND_ERROR;
1249 default: /* write! */
1251 result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1252 outbuf+total_written, out_count-total_written,
1254 total_written += bytes_written;
1257 /* handle partial write */
1258 } while(!result && total_written < out_count);
1263 static CURLcode telnet_done(struct connectdata *conn,
1264 CURLcode status, bool premature)
1266 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1267 (void)status; /* unused */
1268 (void)premature; /* not used */
1273 curl_slist_free_all(tn->telnet_vars);
1274 tn->telnet_vars = NULL;
1276 Curl_safefree(conn->data->req.protop);
1281 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1284 struct SessionHandle *data = conn->data;
1285 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1288 WSOCK2_FUNC close_event_func;
1289 WSOCK2_FUNC create_event_func;
1290 WSOCK2_FUNC event_select_func;
1291 WSOCK2_FUNC enum_netevents_func;
1292 WSAEVENT event_handle;
1293 WSANETWORKEVENTS events;
1294 HANDLE stdin_handle;
1299 DWORD readfile_read;
1303 struct pollfd pfd[2];
1305 curl_off_t total_dl = 0;
1306 curl_off_t total_ul = 0;
1311 char *buf = data->state.buffer;
1314 *done = TRUE; /* unconditionally */
1316 result = init_telnet(conn);
1320 tn = (struct TELNET *)data->req.protop;
1322 result = check_telnet_options(conn);
1328 ** This functionality only works with WinSock >= 2.0. So,
1329 ** make sure have it.
1331 result = check_wsock2(data);
1335 /* OK, so we have WinSock 2.0. We need to dynamically */
1336 /* load ws2_32.dll and get the function pointers we need. */
1337 wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
1338 if(wsock2 == NULL) {
1339 failf(data, "failed to load WS2_32.DLL (%d)", ERRNO);
1340 return CURLE_FAILED_INIT;
1343 /* Grab a pointer to WSACreateEvent */
1344 create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
1345 if(create_event_func == NULL) {
1346 failf(data, "failed to find WSACreateEvent function (%d)", ERRNO);
1347 FreeLibrary(wsock2);
1348 return CURLE_FAILED_INIT;
1351 /* And WSACloseEvent */
1352 close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
1353 if(close_event_func == NULL) {
1354 failf(data, "failed to find WSACloseEvent function (%d)", ERRNO);
1355 FreeLibrary(wsock2);
1356 return CURLE_FAILED_INIT;
1359 /* And WSAEventSelect */
1360 event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
1361 if(event_select_func == NULL) {
1362 failf(data, "failed to find WSAEventSelect function (%d)", ERRNO);
1363 FreeLibrary(wsock2);
1364 return CURLE_FAILED_INIT;
1367 /* And WSAEnumNetworkEvents */
1368 enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
1369 if(enum_netevents_func == NULL) {
1370 failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO);
1371 FreeLibrary(wsock2);
1372 return CURLE_FAILED_INIT;
1375 /* We want to wait for both stdin and the socket. Since
1376 ** the select() function in winsock only works on sockets
1377 ** we have to use the WaitForMultipleObjects() call.
1380 /* First, create a sockets event object */
1381 event_handle = (WSAEVENT)create_event_func();
1382 if(event_handle == WSA_INVALID_EVENT) {
1383 failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1384 FreeLibrary(wsock2);
1385 return CURLE_FAILED_INIT;
1388 /* Tell winsock what events we want to listen to */
1389 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1391 close_event_func(event_handle);
1392 FreeLibrary(wsock2);
1396 /* The get the Windows file handle for stdin */
1397 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1399 /* Create the list of objects to wait for */
1400 objs[0] = event_handle;
1401 objs[1] = stdin_handle;
1403 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1404 else use the old WaitForMultipleObjects() way */
1405 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1406 data->set.is_fread_set) {
1407 /* Don't wait for stdin_handle, just wait for event_handle */
1409 /* Check stdin_handle per 100 milliseconds */
1414 wait_timeout = 1000;
1417 /* Keep on listening and act on events */
1419 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1424 if(data->set.is_fread_set) {
1425 /* read from user-supplied method */
1426 result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
1428 if(result == CURL_READFUNC_ABORT) {
1430 result = CURLE_READ_ERROR;
1434 if(result == CURL_READFUNC_PAUSE)
1437 if(result == 0) /* no bytes */
1440 readfile_read = result; /* fall thru with number of bytes read */
1443 /* read from stdin */
1444 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1445 &readfile_read, NULL)) {
1447 result = CURLE_READ_ERROR;
1454 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1455 &readfile_read, NULL)) {
1457 result = CURLE_READ_ERROR;
1462 result = send_telnet_data(conn, buf, readfile_read);
1471 case WAIT_OBJECT_0 + 1:
1473 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1474 &readfile_read, NULL)) {
1476 result = CURLE_READ_ERROR;
1480 result = send_telnet_data(conn, buf, readfile_read);
1490 events.lNetworkEvents = 0;
1491 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1492 if((err = SOCKERRNO) != EINPROGRESS) {
1493 infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1495 result = CURLE_READ_ERROR;
1499 if(events.lNetworkEvents & FD_READ) {
1500 /* read data from network */
1501 result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1502 /* read would've blocked. Loop again */
1503 if(result == CURLE_AGAIN)
1505 /* returned not-zero, this an error */
1510 /* returned zero but actually received 0 or less here,
1511 the server closed the connection and we bail out */
1512 else if(nread <= 0) {
1517 result = telrcv(conn, (unsigned char *) buf, nread);
1523 /* Negotiate if the peer has started negotiating,
1524 otherwise don't. We don't want to speak telnet with
1525 non-telnet servers, like POP or SMTP. */
1526 if(tn->please_negotiate && !tn->already_negotiated) {
1528 tn->already_negotiated = 1;
1531 if(events.lNetworkEvents & FD_CLOSE) {
1538 if(data->set.timeout) {
1540 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1541 failf(data, "Time-out");
1542 result = CURLE_OPERATION_TIMEDOUT;
1548 /* We called WSACreateEvent, so call WSACloseEvent */
1549 if(!close_event_func(event_handle)) {
1550 infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1553 /* "Forget" pointers into the library we're about to free */
1554 create_event_func = NULL;
1555 close_event_func = NULL;
1556 event_select_func = NULL;
1557 enum_netevents_func = NULL;
1559 /* We called LoadLibrary, so call FreeLibrary */
1560 if(!FreeLibrary(wsock2))
1561 infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO);
1564 pfd[0].events = POLLIN;
1566 if(data->set.is_fread_set) {
1568 interval_ms = 100; /* poll user-supplied read function */
1571 /* really using fread, so infile is a FILE* */
1572 pfd[1].fd = fileno((FILE *)data->state.in);
1573 pfd[1].events = POLLIN;
1575 interval_ms = 1 * 1000;
1579 switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1580 case -1: /* error, stop reading */
1583 case 0: /* timeout */
1587 default: /* read! */
1588 if(pfd[0].revents & POLLIN) {
1589 /* read data from network */
1590 result = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1591 /* read would've blocked. Loop again */
1592 if(result == CURLE_AGAIN)
1594 /* returned not-zero, this an error */
1599 /* returned zero but actually received 0 or less here,
1600 the server closed the connection and we bail out */
1601 else if(nread <= 0) {
1607 Curl_pgrsSetDownloadCounter(data, total_dl);
1608 result = telrcv(conn, (unsigned char *)buf, nread);
1614 /* Negotiate if the peer has started negotiating,
1615 otherwise don't. We don't want to speak telnet with
1616 non-telnet servers, like POP or SMTP. */
1617 if(tn->please_negotiate && !tn->already_negotiated) {
1619 tn->already_negotiated = 1;
1625 if(pfd[1].revents & POLLIN) { /* read from in file */
1626 nread = read(pfd[1].fd, buf, BUFSIZE - 1);
1630 /* read from user-supplied method */
1631 nread = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
1633 if(nread == CURL_READFUNC_ABORT) {
1637 if(nread == CURL_READFUNC_PAUSE)
1642 result = send_telnet_data(conn, buf, nread);
1648 Curl_pgrsSetUploadCounter(data, total_ul);
1654 } /* poll switch statement */
1656 if(data->set.timeout) {
1658 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1659 failf(data, "Time-out");
1660 result = CURLE_OPERATION_TIMEDOUT;
1665 if(Curl_pgrsUpdate(conn)) {
1666 result = CURLE_ABORTED_BY_CALLBACK;
1671 /* mark this as "no further transfer wanted" */
1672 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);