1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2011, 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 http://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 ***************************************************************************/
25 #ifndef CURL_DISABLE_TELNET
27 #ifdef HAVE_SYS_SOCKET_H
28 #include <sys/socket.h>
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
39 #ifdef HAVE_ARPA_INET_H
40 #include <arpa/inet.h>
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h>
54 #include <curl/curl.h>
61 #define _MPRINTF_REPLACE /* use our functions only */
62 #include <curl/mprintf.h>
67 #include "arpa_telnet.h"
68 #include "curl_memory.h"
73 /* The last #include file should be: */
76 #define SUBBUFSIZE 512
78 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
79 #define CURL_SB_TERM(x) \
81 x->subend = x->subpointer; \
84 #define CURL_SB_ACCUM(x,c) \
86 if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
87 *x->subpointer++ = (c); \
90 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
91 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
92 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
93 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
95 #ifdef CURL_DISABLE_VERBOSE_STRINGS
96 #define printoption(a,b,c,d) Curl_nop_stmt
100 typedef FARPROC WSOCK2_FUNC;
101 static CURLcode check_wsock2 ( struct SessionHandle *data );
105 CURLcode telrcv(struct connectdata *,
106 const unsigned char *inbuf, /* Data received from socket */
107 ssize_t count); /* Number of bytes received */
109 #ifndef CURL_DISABLE_VERBOSE_STRINGS
110 static void printoption(struct SessionHandle *data,
111 const char *direction,
112 int cmd, int option);
115 static void negotiate(struct connectdata *);
116 static void send_negotiation(struct connectdata *, int cmd, int option);
117 static void set_local_option(struct connectdata *, int cmd, int option);
118 static void set_remote_option(struct connectdata *, int cmd, int option);
120 static void printsub(struct SessionHandle *data,
121 int direction, unsigned char *pointer,
123 static void suboption(struct connectdata *);
124 static void sendsuboption(struct connectdata *conn, int option);
126 static CURLcode telnet_do(struct connectdata *conn, bool *done);
127 static CURLcode telnet_done(struct connectdata *conn,
128 CURLcode, bool premature);
129 static CURLcode send_telnet_data(struct connectdata *conn,
130 char *buffer, ssize_t nread);
132 /* For negotiation compliant to RFC 1143 */
135 #define CURL_WANTYES 2
136 #define CURL_WANTNO 3
139 #define CURL_OPPOSITE 1
142 * Telnet receiver states for fsm
153 CURL_TS_SB, /* sub-option collection */
154 CURL_TS_SE /* looking for sub-option end */
158 int please_negotiate;
159 int already_negotiated;
162 int us_preferred[256];
165 int him_preferred[256];
166 int subnegotiation[256];
167 char subopt_ttype[32]; /* Set with suboption TTYPE */
168 char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
169 unsigned short subopt_wsx; /* Set with suboption NAWS */
170 unsigned short subopt_wsy; /* Set with suboption NAWS */
171 struct curl_slist *telnet_vars; /* Environment variables */
174 unsigned char subbuffer[SUBBUFSIZE];
175 unsigned char *subpointer, *subend; /* buffer for sub-options */
177 TelnetReceive telrcv_state;
182 * TELNET protocol handler.
185 const struct Curl_handler Curl_handler_telnet = {
186 "TELNET", /* scheme */
187 ZERO_NULL, /* setup_connection */
188 telnet_do, /* do_it */
189 telnet_done, /* done */
190 ZERO_NULL, /* do_more */
191 ZERO_NULL, /* connect_it */
192 ZERO_NULL, /* connecting */
193 ZERO_NULL, /* doing */
194 ZERO_NULL, /* proto_getsock */
195 ZERO_NULL, /* doing_getsock */
196 ZERO_NULL, /* domore_getsock */
197 ZERO_NULL, /* perform_getsock */
198 ZERO_NULL, /* disconnect */
199 ZERO_NULL, /* readwrite */
200 PORT_TELNET, /* defport */
201 CURLPROTO_TELNET, /* protocol */
202 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
208 check_wsock2 ( struct SessionHandle *data )
211 WORD wVersionRequested;
216 /* telnet requires at least WinSock 2.0 so ask for it. */
217 wVersionRequested = MAKEWORD(2, 0);
219 err = WSAStartup(wVersionRequested, &wsaData);
221 /* We must've called this once already, so this call */
222 /* should always succeed. But, just in case... */
224 failf(data,"WSAStartup failed (%d)",err);
225 return CURLE_FAILED_INIT;
228 /* We have to have a WSACleanup call for every successful */
229 /* WSAStartup call. */
232 /* Check that our version is supported */
233 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
234 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
235 /* Our version isn't supported */
236 failf(data,"insufficient winsock version to support "
238 return CURLE_FAILED_INIT;
241 /* Our version is supported */
247 CURLcode init_telnet(struct connectdata *conn)
251 tn = calloc(1, sizeof(struct TELNET));
253 return CURLE_OUT_OF_MEMORY;
255 conn->data->state.proto.telnet = (void *)tn; /* make us known */
257 tn->telrcv_state = CURL_TS_DATA;
259 /* Init suboptions */
262 /* Set the options we want by default */
263 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
264 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
266 /* To be compliant with previous releases of libcurl
267 we enable this option by default. This behaviour
268 can be changed thanks to the "BINARY" option in
269 CURLOPT_TELNETOPTIONS
271 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
272 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
274 /* We must allow the server to echo what we sent
275 but it is not necessary to request the server
276 to do so (it might forces the server to close
277 the connection). Hence, we ignore ECHO in the
280 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
282 /* Set the subnegotiation fields to send information
283 just after negotiation passed (do/will)
285 Default values are (0,0) initialized by calloc.
286 According to the RFC1013 it is valid:
287 A value equal to zero is acceptable for the width (or height),
288 and means that no character width (or height) is being sent.
289 In this case, the width (or height) that will be assumed by the
290 Telnet server is operating system specific (it will probably be
291 based upon the terminal type information that may have been sent
292 using the TERMINAL TYPE Telnet option). */
293 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
297 static void negotiate(struct connectdata *conn)
300 struct TELNET *tn = (struct TELNET *) conn->data->state.proto.telnet;
302 for(i = 0;i < CURL_NTELOPTS;i++) {
303 if(i==CURL_TELOPT_ECHO)
306 if(tn->us_preferred[i] == CURL_YES)
307 set_local_option(conn, i, CURL_YES);
309 if(tn->him_preferred[i] == CURL_YES)
310 set_remote_option(conn, i, CURL_YES);
314 #ifndef CURL_DISABLE_VERBOSE_STRINGS
315 static void printoption(struct SessionHandle *data,
316 const char *direction, int cmd, int option)
321 if(data->set.verbose) {
322 if(cmd == CURL_IAC) {
323 if(CURL_TELCMD_OK(option))
324 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
326 infof(data, "%s IAC %d\n", direction, option);
329 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
330 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
332 if(CURL_TELOPT_OK(option))
333 opt = CURL_TELOPT(option);
334 else if(option == CURL_TELOPT_EXOPL)
340 infof(data, "%s %s %s\n", direction, fmt, opt);
342 infof(data, "%s %s %d\n", direction, fmt, option);
345 infof(data, "%s %d %d\n", direction, cmd, option);
351 static void send_negotiation(struct connectdata *conn, int cmd, int option)
353 unsigned char buf[3];
354 ssize_t bytes_written;
356 struct SessionHandle *data = conn->data;
359 buf[1] = (unsigned char)cmd;
360 buf[2] = (unsigned char)option;
362 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
363 if(bytes_written < 0) {
365 failf(data,"Sending data failed (%d)",err);
368 printoption(conn->data, "SENT", cmd, option);
372 void set_remote_option(struct connectdata *conn, int option, int newstate)
374 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
375 if(newstate == CURL_YES) {
376 switch(tn->him[option]) {
378 tn->him[option] = CURL_WANTYES;
379 send_negotiation(conn, CURL_DO, option);
383 /* Already enabled */
387 switch(tn->himq[option]) {
389 /* Already negotiating for CURL_YES, queue the request */
390 tn->himq[option] = CURL_OPPOSITE;
393 /* Error: already queued an enable request */
399 switch(tn->himq[option]) {
401 /* Error: already negotiating for enable */
404 tn->himq[option] = CURL_EMPTY;
411 switch(tn->him[option]) {
413 /* Already disabled */
417 tn->him[option] = CURL_WANTNO;
418 send_negotiation(conn, CURL_DONT, option);
422 switch(tn->himq[option]) {
424 /* Already negotiating for NO */
427 tn->himq[option] = CURL_EMPTY;
433 switch(tn->himq[option]) {
435 tn->himq[option] = CURL_OPPOSITE;
446 void rec_will(struct connectdata *conn, int option)
448 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
449 switch(tn->him[option]) {
451 if(tn->him_preferred[option] == CURL_YES) {
452 tn->him[option] = CURL_YES;
453 send_negotiation(conn, CURL_DO, option);
456 send_negotiation(conn, CURL_DONT, option);
461 /* Already enabled */
465 switch(tn->himq[option]) {
467 /* Error: DONT answered by WILL */
468 tn->him[option] = CURL_NO;
471 /* Error: DONT answered by WILL */
472 tn->him[option] = CURL_YES;
473 tn->himq[option] = CURL_EMPTY;
479 switch(tn->himq[option]) {
481 tn->him[option] = CURL_YES;
484 tn->him[option] = CURL_WANTNO;
485 tn->himq[option] = CURL_EMPTY;
486 send_negotiation(conn, CURL_DONT, option);
494 void rec_wont(struct connectdata *conn, int option)
496 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
497 switch(tn->him[option]) {
499 /* Already disabled */
503 tn->him[option] = CURL_NO;
504 send_negotiation(conn, CURL_DONT, option);
508 switch(tn->himq[option]) {
510 tn->him[option] = CURL_NO;
514 tn->him[option] = CURL_WANTYES;
515 tn->himq[option] = CURL_EMPTY;
516 send_negotiation(conn, CURL_DO, option);
522 switch(tn->himq[option]) {
524 tn->him[option] = CURL_NO;
527 tn->him[option] = CURL_NO;
528 tn->himq[option] = CURL_EMPTY;
536 set_local_option(struct connectdata *conn, int option, int newstate)
538 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
539 if(newstate == CURL_YES) {
540 switch(tn->us[option]) {
542 tn->us[option] = CURL_WANTYES;
543 send_negotiation(conn, CURL_WILL, option);
547 /* Already enabled */
551 switch(tn->usq[option]) {
553 /* Already negotiating for CURL_YES, queue the request */
554 tn->usq[option] = CURL_OPPOSITE;
557 /* Error: already queued an enable request */
563 switch(tn->usq[option]) {
565 /* Error: already negotiating for enable */
568 tn->usq[option] = CURL_EMPTY;
575 switch(tn->us[option]) {
577 /* Already disabled */
581 tn->us[option] = CURL_WANTNO;
582 send_negotiation(conn, CURL_WONT, option);
586 switch(tn->usq[option]) {
588 /* Already negotiating for NO */
591 tn->usq[option] = CURL_EMPTY;
597 switch(tn->usq[option]) {
599 tn->usq[option] = CURL_OPPOSITE;
610 void rec_do(struct connectdata *conn, int option)
612 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
613 switch(tn->us[option]) {
615 if(tn->us_preferred[option] == CURL_YES) {
616 tn->us[option] = CURL_YES;
617 send_negotiation(conn, CURL_WILL, option);
618 if(tn->subnegotiation[option] == CURL_YES)
619 /* transmission of data option */
620 sendsuboption(conn, option);
622 else if(tn->subnegotiation[option] == CURL_YES) {
623 /* send information to achieve this option*/
624 tn->us[option] = CURL_YES;
625 send_negotiation(conn, CURL_WILL, option);
626 sendsuboption(conn, option);
629 send_negotiation(conn, CURL_WONT, option);
633 /* Already enabled */
637 switch(tn->usq[option]) {
639 /* Error: DONT answered by WILL */
640 tn->us[option] = CURL_NO;
643 /* Error: DONT answered by WILL */
644 tn->us[option] = CURL_YES;
645 tn->usq[option] = CURL_EMPTY;
651 switch(tn->usq[option]) {
653 tn->us[option] = CURL_YES;
654 if(tn->subnegotiation[option] == CURL_YES) {
655 /* transmission of data option */
656 sendsuboption(conn, option);
660 tn->us[option] = CURL_WANTNO;
661 tn->himq[option] = CURL_EMPTY;
662 send_negotiation(conn, CURL_WONT, option);
670 void rec_dont(struct connectdata *conn, int option)
672 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
673 switch(tn->us[option]) {
675 /* Already disabled */
679 tn->us[option] = CURL_NO;
680 send_negotiation(conn, CURL_WONT, option);
684 switch(tn->usq[option]) {
686 tn->us[option] = CURL_NO;
690 tn->us[option] = CURL_WANTYES;
691 tn->usq[option] = CURL_EMPTY;
692 send_negotiation(conn, CURL_WILL, option);
698 switch(tn->usq[option]) {
700 tn->us[option] = CURL_NO;
703 tn->us[option] = CURL_NO;
704 tn->usq[option] = CURL_EMPTY;
712 static void printsub(struct SessionHandle *data,
713 int direction, /* '<' or '>' */
714 unsigned char *pointer, /* where suboption data is */
715 size_t length) /* length of suboption data */
718 unsigned short *pval;
720 if(data->set.verbose) {
722 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
726 i = pointer[length-2];
727 j = pointer[length-1];
729 if(i != CURL_IAC || j != CURL_SE) {
730 infof(data, "(terminated by ");
731 if(CURL_TELOPT_OK(i))
732 infof(data, "%s ", CURL_TELOPT(i));
733 else if(CURL_TELCMD_OK(i))
734 infof(data, "%s ", CURL_TELCMD(i));
736 infof(data, "%u ", i);
737 if(CURL_TELOPT_OK(j))
738 infof(data, "%s", CURL_TELOPT(j));
739 else if(CURL_TELCMD_OK(j))
740 infof(data, "%s", CURL_TELCMD(j));
742 infof(data, "%d", j);
743 infof(data, ", not IAC SE!) ");
749 infof(data, "(Empty suboption?)");
753 if(CURL_TELOPT_OK(pointer[0])) {
755 case CURL_TELOPT_TTYPE:
756 case CURL_TELOPT_XDISPLOC:
757 case CURL_TELOPT_NEW_ENVIRON:
758 case CURL_TELOPT_NAWS:
759 infof(data, "%s", CURL_TELOPT(pointer[0]));
762 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
767 infof(data, "%d (unknown)", pointer[i]);
770 case CURL_TELOPT_NAWS:
771 pval = (unsigned short*)(pointer+1);
772 infof(data, "Width: %hu ; Height: %hu",
773 ntohs(pval[0]), ntohs(pval[1]));
777 case CURL_TELQUAL_IS:
780 case CURL_TELQUAL_SEND:
781 infof(data, " SEND");
783 case CURL_TELQUAL_INFO:
784 infof(data, " INFO/REPLY");
786 case CURL_TELQUAL_NAME:
787 infof(data, " NAME");
792 case CURL_TELOPT_TTYPE:
793 case CURL_TELOPT_XDISPLOC:
795 infof(data, " \"%s\"", &pointer[2]);
797 case CURL_TELOPT_NEW_ENVIRON:
798 if(pointer[1] == CURL_TELQUAL_IS) {
800 for(i = 3;i < length;i++) {
802 case CURL_NEW_ENV_VAR:
805 case CURL_NEW_ENV_VALUE:
809 infof(data, "%c", pointer[i]);
816 for(i = 2; i < length; i++)
817 infof(data, " %.2x", pointer[i]);
826 static CURLcode check_telnet_options(struct connectdata *conn)
828 struct curl_slist *head;
829 struct curl_slist *beg;
830 char option_keyword[128];
831 char option_arg[256];
832 struct SessionHandle *data = conn->data;
833 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
834 CURLcode result = CURLE_OK;
837 /* Add the user name as an environment variable if it
838 was given on the command line */
839 if(conn->bits.user_passwd) {
840 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
841 beg = curl_slist_append(tn->telnet_vars, option_arg);
843 curl_slist_free_all(tn->telnet_vars);
844 tn->telnet_vars = NULL;
845 return CURLE_OUT_OF_MEMORY;
847 tn->telnet_vars = beg;
848 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
851 for(head = data->set.telnet_options; head; head=head->next) {
852 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
853 option_keyword, option_arg) == 2) {
856 if(Curl_raw_equal(option_keyword, "TTYPE")) {
857 strncpy(tn->subopt_ttype, option_arg, 31);
858 tn->subopt_ttype[31] = 0; /* String termination */
859 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
863 /* Display variable */
864 if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
865 strncpy(tn->subopt_xdisploc, option_arg, 127);
866 tn->subopt_xdisploc[127] = 0; /* String termination */
867 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
871 /* Environment variable */
872 if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
873 beg = curl_slist_append(tn->telnet_vars, option_arg);
875 result = CURLE_OUT_OF_MEMORY;
878 tn->telnet_vars = beg;
879 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
884 if(Curl_raw_equal(option_keyword, "WS")) {
885 if(sscanf(option_arg, "%hu%*[xX]%hu",
886 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
887 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
889 failf(data, "Syntax error in telnet option: %s", head->data);
890 result = CURLE_TELNET_OPTION_SYNTAX;
896 /* To take care or not of the 8th bit in data exchange */
897 if(Curl_raw_equal(option_keyword, "BINARY")) {
898 binary_option=atoi(option_arg);
899 if(binary_option!=1) {
900 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
901 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
906 failf(data, "Unknown telnet option %s", head->data);
907 result = CURLE_UNKNOWN_TELNET_OPTION;
911 failf(data, "Syntax error in telnet option: %s", head->data);
912 result = CURLE_TELNET_OPTION_SYNTAX;
918 curl_slist_free_all(tn->telnet_vars);
919 tn->telnet_vars = NULL;
928 * Look at the sub-option buffer, and try to be helpful to the other
932 static void suboption(struct connectdata *conn)
934 struct curl_slist *v;
935 unsigned char temp[2048];
936 ssize_t bytes_written;
942 struct SessionHandle *data = conn->data;
943 struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
945 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
946 switch (CURL_SB_GET(tn)) {
947 case CURL_TELOPT_TTYPE:
948 len = strlen(tn->subopt_ttype) + 4 + 2;
949 snprintf((char *)temp, sizeof(temp),
950 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
951 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
952 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
953 if(bytes_written < 0) {
955 failf(data,"Sending data failed (%d)",err);
957 printsub(data, '>', &temp[2], len-2);
959 case CURL_TELOPT_XDISPLOC:
960 len = strlen(tn->subopt_xdisploc) + 4 + 2;
961 snprintf((char *)temp, sizeof(temp),
962 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
963 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
964 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
965 if(bytes_written < 0) {
967 failf(data,"Sending data failed (%d)",err);
969 printsub(data, '>', &temp[2], len-2);
971 case CURL_TELOPT_NEW_ENVIRON:
972 snprintf((char *)temp, sizeof(temp),
973 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
977 for(v = tn->telnet_vars;v;v = v->next) {
978 tmplen = (strlen(v->data) + 1);
979 /* Add the variable only if it fits */
980 if(len + tmplen < (int)sizeof(temp)-6) {
981 sscanf(v->data, "%127[^,],%127s", varname, varval);
982 snprintf((char *)&temp[len], sizeof(temp) - len,
983 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
984 CURL_NEW_ENV_VALUE, varval);
988 snprintf((char *)&temp[len], sizeof(temp) - len,
989 "%c%c", CURL_IAC, CURL_SE);
991 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
992 if(bytes_written < 0) {
994 failf(data,"Sending data failed (%d)",err);
996 printsub(data, '>', &temp[2], len-2);
1006 * Send suboption information to the server side.
1009 static void sendsuboption(struct connectdata *conn, int option)
1011 ssize_t bytes_written;
1013 unsigned short x, y;
1014 unsigned char*uc1, *uc2;
1016 struct SessionHandle *data = conn->data;
1017 struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
1020 case CURL_TELOPT_NAWS:
1021 /* We prepare data to be sent */
1023 CURL_SB_ACCUM(tn, CURL_IAC);
1024 CURL_SB_ACCUM(tn, CURL_SB);
1025 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1026 /* We must deal either with litte or big endien processors */
1027 /* Window size must be sent according to the 'network order' */
1028 x=htons(tn->subopt_wsx);
1029 y=htons(tn->subopt_wsy);
1030 uc1 = (unsigned char*)&x;
1031 uc2 = (unsigned char*)&y;
1032 CURL_SB_ACCUM(tn, uc1[0]);
1033 CURL_SB_ACCUM(tn, uc1[1]);
1034 CURL_SB_ACCUM(tn, uc2[0]);
1035 CURL_SB_ACCUM(tn, uc2[1]);
1037 CURL_SB_ACCUM(tn, CURL_IAC);
1038 CURL_SB_ACCUM(tn, CURL_SE);
1040 /* data suboption is now ready */
1042 printsub(data, '>', (unsigned char *)tn->subbuffer+2,
1045 /* we send the header of the suboption... */
1046 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1047 if(bytes_written < 0) {
1049 failf(data, "Sending data failed (%d)", err);
1051 /* ... then the window size with the send_telnet_data() function
1052 to deal with 0xFF cases ... */
1053 send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
1054 /* ... and the footer */
1055 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
1056 if(bytes_written < 0) {
1058 failf(data, "Sending data failed (%d)", err);
1066 CURLcode telrcv(struct connectdata *conn,
1067 const unsigned char *inbuf, /* Data received from socket */
1068 ssize_t count) /* Number of bytes received */
1074 struct SessionHandle *data = conn->data;
1075 struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
1077 #define startskipping() \
1078 if(startwrite >= 0) { \
1079 result = Curl_client_write(conn, \
1081 (char *)&inbuf[startwrite], \
1083 if(result != CURLE_OK) \
1088 #define writebyte() \
1089 if(startwrite < 0) \
1092 #define bufferflush() startskipping()
1097 switch (tn->telrcv_state) {
1099 tn->telrcv_state = CURL_TS_DATA;
1102 break; /* Ignore \0 after CR */
1109 tn->telrcv_state = CURL_TS_IAC;
1114 tn->telrcv_state = CURL_TS_CR;
1120 DEBUGASSERT(startwrite < 0);
1123 tn->telrcv_state = CURL_TS_WILL;
1126 tn->telrcv_state = CURL_TS_WONT;
1129 tn->telrcv_state = CURL_TS_DO;
1132 tn->telrcv_state = CURL_TS_DONT;
1136 tn->telrcv_state = CURL_TS_SB;
1139 tn->telrcv_state = CURL_TS_DATA;
1146 tn->telrcv_state = CURL_TS_DATA;
1147 printoption(data, "RCVD", CURL_IAC, c);
1153 printoption(data, "RCVD", CURL_WILL, c);
1154 tn->please_negotiate = 1;
1156 tn->telrcv_state = CURL_TS_DATA;
1160 printoption(data, "RCVD", CURL_WONT, c);
1161 tn->please_negotiate = 1;
1163 tn->telrcv_state = CURL_TS_DATA;
1167 printoption(data, "RCVD", CURL_DO, c);
1168 tn->please_negotiate = 1;
1170 tn->telrcv_state = CURL_TS_DATA;
1174 printoption(data, "RCVD", CURL_DONT, c);
1175 tn->please_negotiate = 1;
1177 tn->telrcv_state = CURL_TS_DATA;
1182 tn->telrcv_state = CURL_TS_SE;
1184 CURL_SB_ACCUM(tn,c);
1191 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1192 * Several things may have happened. An IAC was not doubled, the
1193 * IAC SE was left off, or another option got inserted into the
1194 * suboption are all possibilities. If we assume that the IAC was
1195 * not doubled, and really the IAC SE was left off, we could get
1196 * into an infinate loop here. So, instead, we terminate the
1197 * suboption, and process the partial suboption if we can.
1199 CURL_SB_ACCUM(tn, CURL_IAC);
1200 CURL_SB_ACCUM(tn, c);
1201 tn->subpointer -= 2;
1204 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1205 suboption(conn); /* handle sub-option */
1206 tn->telrcv_state = CURL_TS_IAC;
1209 CURL_SB_ACCUM(tn,c);
1210 tn->telrcv_state = CURL_TS_SB;
1214 CURL_SB_ACCUM(tn, CURL_IAC);
1215 CURL_SB_ACCUM(tn, CURL_SE);
1216 tn->subpointer -= 2;
1218 suboption(conn); /* handle sub-option */
1219 tn->telrcv_state = CURL_TS_DATA;
1229 /* Escape and send a telnet data block */
1230 /* TODO: write large chunks of data instead of one byte at a time */
1231 static CURLcode send_telnet_data(struct connectdata *conn,
1232 char *buffer, ssize_t nread)
1234 unsigned char outbuf[2];
1235 ssize_t bytes_written, total_written;
1237 CURLcode rc = CURLE_OK;
1239 while(rc == CURLE_OK && nread--) {
1240 outbuf[0] = *buffer++;
1242 if(outbuf[0] == CURL_IAC)
1243 outbuf[out_count++] = CURL_IAC;
1247 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1248 struct pollfd pfd[1];
1249 pfd[0].fd = conn->sock[FIRSTSOCKET];
1250 pfd[0].events = POLLOUT;
1251 switch (Curl_poll(pfd, 1, -1)) {
1252 case -1: /* error, abort writing */
1253 case 0: /* timeout (will never happen) */
1254 rc = CURLE_SEND_ERROR;
1256 default: /* write! */
1258 rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
1259 out_count-total_written, &bytes_written);
1260 total_written += bytes_written;
1263 /* handle partial write */
1264 } while(rc == CURLE_OK && total_written < out_count);
1269 static CURLcode telnet_done(struct connectdata *conn,
1270 CURLcode status, bool premature)
1272 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
1273 (void)status; /* unused */
1274 (void)premature; /* not used */
1276 curl_slist_free_all(tn->telnet_vars);
1277 tn->telnet_vars = NULL;
1279 free(conn->data->state.proto.telnet);
1280 conn->data->state.proto.telnet = NULL;
1285 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1288 struct SessionHandle *data = conn->data;
1289 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1292 WSOCK2_FUNC close_event_func;
1293 WSOCK2_FUNC create_event_func;
1294 WSOCK2_FUNC event_select_func;
1295 WSOCK2_FUNC enum_netevents_func;
1296 WSAEVENT event_handle;
1297 WSANETWORKEVENTS events;
1298 HANDLE stdin_handle;
1303 DWORD readfile_read;
1307 struct pollfd pfd[2];
1309 curl_off_t total_dl = 0;
1310 curl_off_t total_ul = 0;
1315 char *buf = data->state.buffer;
1318 *done = TRUE; /* unconditionally */
1320 code = init_telnet(conn);
1324 tn = (struct TELNET *)data->state.proto.telnet;
1326 code = check_telnet_options(conn);
1332 ** This functionality only works with WinSock >= 2.0. So,
1333 ** make sure have it.
1335 code = check_wsock2(data);
1339 /* OK, so we have WinSock 2.0. We need to dynamically */
1340 /* load ws2_32.dll and get the function pointers we need. */
1341 wsock2 = LoadLibrary("WS2_32.DLL");
1342 if(wsock2 == NULL) {
1343 failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
1344 return CURLE_FAILED_INIT;
1347 /* Grab a pointer to WSACreateEvent */
1348 create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1349 if(create_event_func == NULL) {
1350 failf(data,"failed to find WSACreateEvent function (%d)",
1352 FreeLibrary(wsock2);
1353 return CURLE_FAILED_INIT;
1356 /* And WSACloseEvent */
1357 close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1358 if(close_event_func == NULL) {
1359 failf(data,"failed to find WSACloseEvent function (%d)",
1361 FreeLibrary(wsock2);
1362 return CURLE_FAILED_INIT;
1365 /* And WSAEventSelect */
1366 event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1367 if(event_select_func == NULL) {
1368 failf(data,"failed to find WSAEventSelect function (%d)",
1370 FreeLibrary(wsock2);
1371 return CURLE_FAILED_INIT;
1374 /* And WSAEnumNetworkEvents */
1375 enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1376 if(enum_netevents_func == NULL) {
1377 failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1379 FreeLibrary(wsock2);
1380 return CURLE_FAILED_INIT;
1383 /* We want to wait for both stdin and the socket. Since
1384 ** the select() function in winsock only works on sockets
1385 ** we have to use the WaitForMultipleObjects() call.
1388 /* First, create a sockets event object */
1389 event_handle = (WSAEVENT)create_event_func();
1390 if(event_handle == WSA_INVALID_EVENT) {
1391 failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
1392 FreeLibrary(wsock2);
1393 return CURLE_FAILED_INIT;
1396 /* Tell winsock what events we want to listen to */
1397 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1399 close_event_func(event_handle);
1400 FreeLibrary(wsock2);
1404 /* The get the Windows file handle for stdin */
1405 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1407 /* Create the list of objects to wait for */
1408 objs[0] = event_handle;
1409 objs[1] = stdin_handle;
1411 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1412 else use the old WaitForMultipleObjects() way */
1413 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1414 data->set.is_fread_set) {
1415 /* Don't wait for stdin_handle, just wait for event_handle */
1417 /* Check stdin_handle per 100 milliseconds */
1422 wait_timeout = 1000;
1425 /* Keep on listening and act on events */
1427 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1432 if(obj_count == 1) {
1433 /* read from user-supplied method */
1434 code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1435 if(code == CURL_READFUNC_ABORT) {
1437 code = CURLE_READ_ERROR;
1441 if(code == CURL_READFUNC_PAUSE)
1444 if(code == 0) /* no bytes */
1447 readfile_read = code; /* fall thru with number of bytes read */
1450 /* read from stdin */
1451 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1452 &readfile_read, NULL)) {
1454 code = CURLE_READ_ERROR;
1461 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1462 &readfile_read, NULL)) {
1464 code = CURLE_READ_ERROR;
1469 code = send_telnet_data(conn, buf, readfile_read);
1478 case WAIT_OBJECT_0 + 1:
1480 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1481 &readfile_read, NULL)) {
1483 code = CURLE_READ_ERROR;
1487 code = send_telnet_data(conn, buf, readfile_read);
1497 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1498 if((err = SOCKERRNO) != EINPROGRESS) {
1499 infof(data,"WSAEnumNetworkEvents failed (%d)", err);
1501 code = CURLE_READ_ERROR;
1505 if(events.lNetworkEvents & FD_READ) {
1506 /* read data from network */
1507 code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1508 /* read would've blocked. Loop again */
1509 if(code == CURLE_AGAIN)
1511 /* returned not-zero, this an error */
1516 /* returned zero but actually received 0 or less here,
1517 the server closed the connection and we bail out */
1518 else if(nread <= 0) {
1523 code = telrcv(conn, (unsigned char *)buf, nread);
1529 /* Negotiate if the peer has started negotiating,
1530 otherwise don't. We don't want to speak telnet with
1531 non-telnet servers, like POP or SMTP. */
1532 if(tn->please_negotiate && !tn->already_negotiated) {
1534 tn->already_negotiated = 1;
1537 if(events.lNetworkEvents & FD_CLOSE) {
1544 if(data->set.timeout) {
1546 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1547 failf(data, "Time-out");
1548 code = CURLE_OPERATION_TIMEDOUT;
1554 /* We called WSACreateEvent, so call WSACloseEvent */
1555 if(!close_event_func(event_handle)) {
1556 infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
1559 /* "Forget" pointers into the library we're about to free */
1560 create_event_func = NULL;
1561 close_event_func = NULL;
1562 event_select_func = NULL;
1563 enum_netevents_func = NULL;
1565 /* We called LoadLibrary, so call FreeLibrary */
1566 if(!FreeLibrary(wsock2))
1567 infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
1570 pfd[0].events = POLLIN;
1572 if(data->set.is_fread_set) {
1574 interval_ms = 100; /* poll user-supplied read function */
1578 pfd[1].events = POLLIN;
1580 interval_ms = 1 * 1000;
1584 switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1585 case -1: /* error, stop reading */
1588 case 0: /* timeout */
1592 default: /* read! */
1593 if(pfd[0].revents & POLLIN) {
1594 /* read data from network */
1595 code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1596 /* read would've blocked. Loop again */
1597 if(code == CURLE_AGAIN)
1599 /* returned not-zero, this an error */
1604 /* returned zero but actually received 0 or less here,
1605 the server closed the connection and we bail out */
1606 else if(nread <= 0) {
1612 Curl_pgrsSetDownloadCounter(data, total_dl);
1613 code = telrcv(conn, (unsigned char *)buf, nread);
1619 /* Negotiate if the peer has started negotiating,
1620 otherwise don't. We don't want to speak telnet with
1621 non-telnet servers, like POP or SMTP. */
1622 if(tn->please_negotiate && !tn->already_negotiated) {
1624 tn->already_negotiated = 1;
1630 if(pfd[1].revents & POLLIN) { /* read from stdin */
1631 nread = read(0, buf, BUFSIZE - 1);
1635 /* read from user-supplied method */
1636 nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1637 if(nread == CURL_READFUNC_ABORT) {
1641 if(nread == CURL_READFUNC_PAUSE)
1646 code = send_telnet_data(conn, buf, nread);
1652 Curl_pgrsSetUploadCounter(data, total_ul);
1658 } /* poll switch statement */
1660 if(data->set.timeout) {
1662 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1663 failf(data, "Time-out");
1664 code = CURLE_OPERATION_TIMEDOUT;
1669 if(Curl_pgrsUpdate(conn)) {
1670 code = CURLE_ABORTED_BY_CALLBACK;
1675 /* mark this as "no further transfer wanted" */
1676 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);