1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, 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 ***************************************************************************/
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>
55 #define _MPRINTF_REPLACE /* use our functions only */
56 #include <curl/mprintf.h>
61 #include "arpa_telnet.h"
62 #include "curl_memory.h"
68 /* The last #include file should be: */
71 #define SUBBUFSIZE 512
73 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
74 #define CURL_SB_TERM(x) \
76 x->subend = x->subpointer; \
79 #define CURL_SB_ACCUM(x,c) \
81 if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
82 *x->subpointer++ = (c); \
85 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
86 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
87 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
88 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
90 #ifdef CURL_DISABLE_VERBOSE_STRINGS
91 #define printoption(a,b,c,d) Curl_nop_stmt
95 typedef FARPROC WSOCK2_FUNC;
96 static CURLcode check_wsock2 ( struct SessionHandle *data );
100 CURLcode telrcv(struct connectdata *,
101 const unsigned char *inbuf, /* Data received from socket */
102 ssize_t count); /* Number of bytes received */
104 #ifndef CURL_DISABLE_VERBOSE_STRINGS
105 static void printoption(struct SessionHandle *data,
106 const char *direction,
107 int cmd, int option);
110 static void negotiate(struct connectdata *);
111 static void send_negotiation(struct connectdata *, int cmd, int option);
112 static void set_local_option(struct connectdata *, int cmd, int option);
113 static void set_remote_option(struct connectdata *, int cmd, int option);
115 static void printsub(struct SessionHandle *data,
116 int direction, unsigned char *pointer,
118 static void suboption(struct connectdata *);
119 static void sendsuboption(struct connectdata *conn, int option);
121 static CURLcode telnet_do(struct connectdata *conn, bool *done);
122 static CURLcode telnet_done(struct connectdata *conn,
123 CURLcode, bool premature);
124 static CURLcode send_telnet_data(struct connectdata *conn,
125 char *buffer, ssize_t nread);
127 /* For negotiation compliant to RFC 1143 */
130 #define CURL_WANTYES 2
131 #define CURL_WANTNO 3
134 #define CURL_OPPOSITE 1
137 * Telnet receiver states for fsm
148 CURL_TS_SB, /* sub-option collection */
149 CURL_TS_SE /* looking for sub-option end */
153 int please_negotiate;
154 int already_negotiated;
157 int us_preferred[256];
160 int him_preferred[256];
161 int subnegotiation[256];
162 char subopt_ttype[32]; /* Set with suboption TTYPE */
163 char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
164 unsigned short subopt_wsx; /* Set with suboption NAWS */
165 unsigned short subopt_wsy; /* Set with suboption NAWS */
166 struct curl_slist *telnet_vars; /* Environment variables */
169 unsigned char subbuffer[SUBBUFSIZE];
170 unsigned char *subpointer, *subend; /* buffer for sub-options */
172 TelnetReceive telrcv_state;
177 * TELNET protocol handler.
180 const struct Curl_handler Curl_handler_telnet = {
181 "TELNET", /* scheme */
182 ZERO_NULL, /* setup_connection */
183 telnet_do, /* do_it */
184 telnet_done, /* done */
185 ZERO_NULL, /* do_more */
186 ZERO_NULL, /* connect_it */
187 ZERO_NULL, /* connecting */
188 ZERO_NULL, /* doing */
189 ZERO_NULL, /* proto_getsock */
190 ZERO_NULL, /* doing_getsock */
191 ZERO_NULL, /* domore_getsock */
192 ZERO_NULL, /* perform_getsock */
193 ZERO_NULL, /* disconnect */
194 ZERO_NULL, /* readwrite */
195 PORT_TELNET, /* defport */
196 CURLPROTO_TELNET, /* protocol */
197 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
203 check_wsock2 ( struct SessionHandle *data )
206 WORD wVersionRequested;
211 /* telnet requires at least WinSock 2.0 so ask for it. */
212 wVersionRequested = MAKEWORD(2, 0);
214 err = WSAStartup(wVersionRequested, &wsaData);
216 /* We must've called this once already, so this call */
217 /* should always succeed. But, just in case... */
219 failf(data,"WSAStartup failed (%d)",err);
220 return CURLE_FAILED_INIT;
223 /* We have to have a WSACleanup call for every successful */
224 /* WSAStartup call. */
227 /* Check that our version is supported */
228 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
229 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
230 /* Our version isn't supported */
231 failf(data,"insufficient winsock version to support "
233 return CURLE_FAILED_INIT;
236 /* Our version is supported */
242 CURLcode init_telnet(struct connectdata *conn)
246 tn = calloc(1, sizeof(struct TELNET));
248 return CURLE_OUT_OF_MEMORY;
250 conn->data->req.protop = tn; /* make us known */
252 tn->telrcv_state = CURL_TS_DATA;
254 /* Init suboptions */
257 /* Set the options we want by default */
258 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
259 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
261 /* To be compliant with previous releases of libcurl
262 we enable this option by default. This behaviour
263 can be changed thanks to the "BINARY" option in
264 CURLOPT_TELNETOPTIONS
266 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
267 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
269 /* We must allow the server to echo what we sent
270 but it is not necessary to request the server
271 to do so (it might forces the server to close
272 the connection). Hence, we ignore ECHO in the
275 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
277 /* Set the subnegotiation fields to send information
278 just after negotiation passed (do/will)
280 Default values are (0,0) initialized by calloc.
281 According to the RFC1013 it is valid:
282 A value equal to zero is acceptable for the width (or height),
283 and means that no character width (or height) is being sent.
284 In this case, the width (or height) that will be assumed by the
285 Telnet server is operating system specific (it will probably be
286 based upon the terminal type information that may have been sent
287 using the TERMINAL TYPE Telnet option). */
288 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
292 static void negotiate(struct connectdata *conn)
295 struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
297 for(i = 0;i < CURL_NTELOPTS;i++) {
298 if(i==CURL_TELOPT_ECHO)
301 if(tn->us_preferred[i] == CURL_YES)
302 set_local_option(conn, i, CURL_YES);
304 if(tn->him_preferred[i] == CURL_YES)
305 set_remote_option(conn, i, CURL_YES);
309 #ifndef CURL_DISABLE_VERBOSE_STRINGS
310 static void printoption(struct SessionHandle *data,
311 const char *direction, int cmd, int option)
316 if(data->set.verbose) {
317 if(cmd == CURL_IAC) {
318 if(CURL_TELCMD_OK(option))
319 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
321 infof(data, "%s IAC %d\n", direction, option);
324 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
325 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
327 if(CURL_TELOPT_OK(option))
328 opt = CURL_TELOPT(option);
329 else if(option == CURL_TELOPT_EXOPL)
335 infof(data, "%s %s %s\n", direction, fmt, opt);
337 infof(data, "%s %s %d\n", direction, fmt, option);
340 infof(data, "%s %d %d\n", direction, cmd, option);
346 static void send_negotiation(struct connectdata *conn, int cmd, int option)
348 unsigned char buf[3];
349 ssize_t bytes_written;
351 struct SessionHandle *data = conn->data;
354 buf[1] = (unsigned char)cmd;
355 buf[2] = (unsigned char)option;
357 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
358 if(bytes_written < 0) {
360 failf(data,"Sending data failed (%d)",err);
363 printoption(conn->data, "SENT", cmd, option);
367 void set_remote_option(struct connectdata *conn, int option, int newstate)
369 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
370 if(newstate == CURL_YES) {
371 switch(tn->him[option]) {
373 tn->him[option] = CURL_WANTYES;
374 send_negotiation(conn, CURL_DO, option);
378 /* Already enabled */
382 switch(tn->himq[option]) {
384 /* Already negotiating for CURL_YES, queue the request */
385 tn->himq[option] = CURL_OPPOSITE;
388 /* Error: already queued an enable request */
394 switch(tn->himq[option]) {
396 /* Error: already negotiating for enable */
399 tn->himq[option] = CURL_EMPTY;
406 switch(tn->him[option]) {
408 /* Already disabled */
412 tn->him[option] = CURL_WANTNO;
413 send_negotiation(conn, CURL_DONT, option);
417 switch(tn->himq[option]) {
419 /* Already negotiating for NO */
422 tn->himq[option] = CURL_EMPTY;
428 switch(tn->himq[option]) {
430 tn->himq[option] = CURL_OPPOSITE;
441 void rec_will(struct connectdata *conn, int option)
443 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
444 switch(tn->him[option]) {
446 if(tn->him_preferred[option] == CURL_YES) {
447 tn->him[option] = CURL_YES;
448 send_negotiation(conn, CURL_DO, option);
451 send_negotiation(conn, CURL_DONT, option);
456 /* Already enabled */
460 switch(tn->himq[option]) {
462 /* Error: DONT answered by WILL */
463 tn->him[option] = CURL_NO;
466 /* Error: DONT answered by WILL */
467 tn->him[option] = CURL_YES;
468 tn->himq[option] = CURL_EMPTY;
474 switch(tn->himq[option]) {
476 tn->him[option] = CURL_YES;
479 tn->him[option] = CURL_WANTNO;
480 tn->himq[option] = CURL_EMPTY;
481 send_negotiation(conn, CURL_DONT, option);
489 void rec_wont(struct connectdata *conn, int option)
491 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
492 switch(tn->him[option]) {
494 /* Already disabled */
498 tn->him[option] = CURL_NO;
499 send_negotiation(conn, CURL_DONT, option);
503 switch(tn->himq[option]) {
505 tn->him[option] = CURL_NO;
509 tn->him[option] = CURL_WANTYES;
510 tn->himq[option] = CURL_EMPTY;
511 send_negotiation(conn, CURL_DO, option);
517 switch(tn->himq[option]) {
519 tn->him[option] = CURL_NO;
522 tn->him[option] = CURL_NO;
523 tn->himq[option] = CURL_EMPTY;
531 set_local_option(struct connectdata *conn, int option, int newstate)
533 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
534 if(newstate == CURL_YES) {
535 switch(tn->us[option]) {
537 tn->us[option] = CURL_WANTYES;
538 send_negotiation(conn, CURL_WILL, option);
542 /* Already enabled */
546 switch(tn->usq[option]) {
548 /* Already negotiating for CURL_YES, queue the request */
549 tn->usq[option] = CURL_OPPOSITE;
552 /* Error: already queued an enable request */
558 switch(tn->usq[option]) {
560 /* Error: already negotiating for enable */
563 tn->usq[option] = CURL_EMPTY;
570 switch(tn->us[option]) {
572 /* Already disabled */
576 tn->us[option] = CURL_WANTNO;
577 send_negotiation(conn, CURL_WONT, option);
581 switch(tn->usq[option]) {
583 /* Already negotiating for NO */
586 tn->usq[option] = CURL_EMPTY;
592 switch(tn->usq[option]) {
594 tn->usq[option] = CURL_OPPOSITE;
605 void rec_do(struct connectdata *conn, int option)
607 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
608 switch(tn->us[option]) {
610 if(tn->us_preferred[option] == CURL_YES) {
611 tn->us[option] = CURL_YES;
612 send_negotiation(conn, CURL_WILL, option);
613 if(tn->subnegotiation[option] == CURL_YES)
614 /* transmission of data option */
615 sendsuboption(conn, option);
617 else if(tn->subnegotiation[option] == CURL_YES) {
618 /* send information to achieve this option*/
619 tn->us[option] = CURL_YES;
620 send_negotiation(conn, CURL_WILL, option);
621 sendsuboption(conn, option);
624 send_negotiation(conn, CURL_WONT, option);
628 /* Already enabled */
632 switch(tn->usq[option]) {
634 /* Error: DONT answered by WILL */
635 tn->us[option] = CURL_NO;
638 /* Error: DONT answered by WILL */
639 tn->us[option] = CURL_YES;
640 tn->usq[option] = CURL_EMPTY;
646 switch(tn->usq[option]) {
648 tn->us[option] = CURL_YES;
649 if(tn->subnegotiation[option] == CURL_YES) {
650 /* transmission of data option */
651 sendsuboption(conn, option);
655 tn->us[option] = CURL_WANTNO;
656 tn->himq[option] = CURL_EMPTY;
657 send_negotiation(conn, CURL_WONT, option);
665 void rec_dont(struct connectdata *conn, int option)
667 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
668 switch(tn->us[option]) {
670 /* Already disabled */
674 tn->us[option] = CURL_NO;
675 send_negotiation(conn, CURL_WONT, option);
679 switch(tn->usq[option]) {
681 tn->us[option] = CURL_NO;
685 tn->us[option] = CURL_WANTYES;
686 tn->usq[option] = CURL_EMPTY;
687 send_negotiation(conn, CURL_WILL, option);
693 switch(tn->usq[option]) {
695 tn->us[option] = CURL_NO;
698 tn->us[option] = CURL_NO;
699 tn->usq[option] = CURL_EMPTY;
707 static void printsub(struct SessionHandle *data,
708 int direction, /* '<' or '>' */
709 unsigned char *pointer, /* where suboption data is */
710 size_t length) /* length of suboption data */
714 if(data->set.verbose) {
716 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
720 i = pointer[length-2];
721 j = pointer[length-1];
723 if(i != CURL_IAC || j != CURL_SE) {
724 infof(data, "(terminated by ");
725 if(CURL_TELOPT_OK(i))
726 infof(data, "%s ", CURL_TELOPT(i));
727 else if(CURL_TELCMD_OK(i))
728 infof(data, "%s ", CURL_TELCMD(i));
730 infof(data, "%u ", i);
731 if(CURL_TELOPT_OK(j))
732 infof(data, "%s", CURL_TELOPT(j));
733 else if(CURL_TELCMD_OK(j))
734 infof(data, "%s", CURL_TELCMD(j));
736 infof(data, "%d", j);
737 infof(data, ", not IAC SE!) ");
743 infof(data, "(Empty suboption?)");
747 if(CURL_TELOPT_OK(pointer[0])) {
749 case CURL_TELOPT_TTYPE:
750 case CURL_TELOPT_XDISPLOC:
751 case CURL_TELOPT_NEW_ENVIRON:
752 case CURL_TELOPT_NAWS:
753 infof(data, "%s", CURL_TELOPT(pointer[0]));
756 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
761 infof(data, "%d (unknown)", pointer[i]);
764 case CURL_TELOPT_NAWS:
766 infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
767 (pointer[3]<<8) | pointer[4]);
771 case CURL_TELQUAL_IS:
774 case CURL_TELQUAL_SEND:
775 infof(data, " SEND");
777 case CURL_TELQUAL_INFO:
778 infof(data, " INFO/REPLY");
780 case CURL_TELQUAL_NAME:
781 infof(data, " NAME");
786 case CURL_TELOPT_TTYPE:
787 case CURL_TELOPT_XDISPLOC:
789 infof(data, " \"%s\"", &pointer[2]);
791 case CURL_TELOPT_NEW_ENVIRON:
792 if(pointer[1] == CURL_TELQUAL_IS) {
794 for(i = 3;i < length;i++) {
796 case CURL_NEW_ENV_VAR:
799 case CURL_NEW_ENV_VALUE:
803 infof(data, "%c", pointer[i]);
810 for(i = 2; i < length; i++)
811 infof(data, " %.2x", pointer[i]);
820 static CURLcode check_telnet_options(struct connectdata *conn)
822 struct curl_slist *head;
823 struct curl_slist *beg;
824 char option_keyword[128] = "";
825 char option_arg[256] = "";
826 struct SessionHandle *data = conn->data;
827 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
828 CURLcode result = CURLE_OK;
831 /* Add the user name as an environment variable if it
832 was given on the command line */
833 if(conn->bits.user_passwd) {
834 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
835 beg = curl_slist_append(tn->telnet_vars, option_arg);
837 curl_slist_free_all(tn->telnet_vars);
838 tn->telnet_vars = NULL;
839 return CURLE_OUT_OF_MEMORY;
841 tn->telnet_vars = beg;
842 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
845 for(head = data->set.telnet_options; head; head=head->next) {
846 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
847 option_keyword, option_arg) == 2) {
850 if(Curl_raw_equal(option_keyword, "TTYPE")) {
851 strncpy(tn->subopt_ttype, option_arg, 31);
852 tn->subopt_ttype[31] = 0; /* String termination */
853 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
857 /* Display variable */
858 if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
859 strncpy(tn->subopt_xdisploc, option_arg, 127);
860 tn->subopt_xdisploc[127] = 0; /* String termination */
861 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
865 /* Environment variable */
866 if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
867 beg = curl_slist_append(tn->telnet_vars, option_arg);
869 result = CURLE_OUT_OF_MEMORY;
872 tn->telnet_vars = beg;
873 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
878 if(Curl_raw_equal(option_keyword, "WS")) {
879 if(sscanf(option_arg, "%hu%*[xX]%hu",
880 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
881 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
883 failf(data, "Syntax error in telnet option: %s", head->data);
884 result = CURLE_TELNET_OPTION_SYNTAX;
890 /* To take care or not of the 8th bit in data exchange */
891 if(Curl_raw_equal(option_keyword, "BINARY")) {
892 binary_option=atoi(option_arg);
893 if(binary_option!=1) {
894 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
895 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
900 failf(data, "Unknown telnet option %s", head->data);
901 result = CURLE_UNKNOWN_TELNET_OPTION;
905 failf(data, "Syntax error in telnet option: %s", head->data);
906 result = CURLE_TELNET_OPTION_SYNTAX;
912 curl_slist_free_all(tn->telnet_vars);
913 tn->telnet_vars = NULL;
922 * Look at the sub-option buffer, and try to be helpful to the other
926 static void suboption(struct connectdata *conn)
928 struct curl_slist *v;
929 unsigned char temp[2048];
930 ssize_t bytes_written;
934 char varname[128] = "";
935 char varval[128] = "";
936 struct SessionHandle *data = conn->data;
937 struct TELNET *tn = (struct TELNET *)data->req.protop;
939 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
940 switch (CURL_SB_GET(tn)) {
941 case CURL_TELOPT_TTYPE:
942 len = strlen(tn->subopt_ttype) + 4 + 2;
943 snprintf((char *)temp, sizeof(temp),
944 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
945 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
946 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
947 if(bytes_written < 0) {
949 failf(data,"Sending data failed (%d)",err);
951 printsub(data, '>', &temp[2], len-2);
953 case CURL_TELOPT_XDISPLOC:
954 len = strlen(tn->subopt_xdisploc) + 4 + 2;
955 snprintf((char *)temp, sizeof(temp),
956 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
957 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
958 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
959 if(bytes_written < 0) {
961 failf(data,"Sending data failed (%d)",err);
963 printsub(data, '>', &temp[2], len-2);
965 case CURL_TELOPT_NEW_ENVIRON:
966 snprintf((char *)temp, sizeof(temp),
967 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
971 for(v = tn->telnet_vars;v;v = v->next) {
972 tmplen = (strlen(v->data) + 1);
973 /* Add the variable only if it fits */
974 if(len + tmplen < (int)sizeof(temp)-6) {
975 if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
976 snprintf((char *)&temp[len], sizeof(temp) - len,
977 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
978 CURL_NEW_ENV_VALUE, varval);
983 snprintf((char *)&temp[len], sizeof(temp) - len,
984 "%c%c", CURL_IAC, CURL_SE);
986 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
987 if(bytes_written < 0) {
989 failf(data,"Sending data failed (%d)",err);
991 printsub(data, '>', &temp[2], len-2);
1001 * Send suboption information to the server side.
1004 static void sendsuboption(struct connectdata *conn, int option)
1006 ssize_t bytes_written;
1008 unsigned short x, y;
1009 unsigned char*uc1, *uc2;
1011 struct SessionHandle *data = conn->data;
1012 struct TELNET *tn = (struct TELNET *)data->req.protop;
1015 case CURL_TELOPT_NAWS:
1016 /* We prepare data to be sent */
1018 CURL_SB_ACCUM(tn, CURL_IAC);
1019 CURL_SB_ACCUM(tn, CURL_SB);
1020 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1021 /* We must deal either with litte or big endien processors */
1022 /* Window size must be sent according to the 'network order' */
1023 x=htons(tn->subopt_wsx);
1024 y=htons(tn->subopt_wsy);
1025 uc1 = (unsigned char*)&x;
1026 uc2 = (unsigned char*)&y;
1027 CURL_SB_ACCUM(tn, uc1[0]);
1028 CURL_SB_ACCUM(tn, uc1[1]);
1029 CURL_SB_ACCUM(tn, uc2[0]);
1030 CURL_SB_ACCUM(tn, uc2[1]);
1032 CURL_SB_ACCUM(tn, CURL_IAC);
1033 CURL_SB_ACCUM(tn, CURL_SE);
1035 /* data suboption is now ready */
1037 printsub(data, '>', (unsigned char *)tn->subbuffer+2,
1040 /* we send the header of the suboption... */
1041 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1042 if(bytes_written < 0) {
1044 failf(data, "Sending data failed (%d)", err);
1046 /* ... then the window size with the send_telnet_data() function
1047 to deal with 0xFF cases ... */
1048 send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
1049 /* ... and the footer */
1050 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
1051 if(bytes_written < 0) {
1053 failf(data, "Sending data failed (%d)", err);
1061 CURLcode telrcv(struct connectdata *conn,
1062 const unsigned char *inbuf, /* Data received from socket */
1063 ssize_t count) /* Number of bytes received */
1069 struct SessionHandle *data = conn->data;
1070 struct TELNET *tn = (struct TELNET *)data->req.protop;
1072 #define startskipping() \
1073 if(startwrite >= 0) { \
1074 result = Curl_client_write(conn, \
1076 (char *)&inbuf[startwrite], \
1083 #define writebyte() \
1084 if(startwrite < 0) \
1087 #define bufferflush() startskipping()
1092 switch (tn->telrcv_state) {
1094 tn->telrcv_state = CURL_TS_DATA;
1097 break; /* Ignore \0 after CR */
1104 tn->telrcv_state = CURL_TS_IAC;
1109 tn->telrcv_state = CURL_TS_CR;
1115 DEBUGASSERT(startwrite < 0);
1118 tn->telrcv_state = CURL_TS_WILL;
1121 tn->telrcv_state = CURL_TS_WONT;
1124 tn->telrcv_state = CURL_TS_DO;
1127 tn->telrcv_state = CURL_TS_DONT;
1131 tn->telrcv_state = CURL_TS_SB;
1134 tn->telrcv_state = CURL_TS_DATA;
1141 tn->telrcv_state = CURL_TS_DATA;
1142 printoption(data, "RCVD", CURL_IAC, c);
1148 printoption(data, "RCVD", CURL_WILL, c);
1149 tn->please_negotiate = 1;
1151 tn->telrcv_state = CURL_TS_DATA;
1155 printoption(data, "RCVD", CURL_WONT, c);
1156 tn->please_negotiate = 1;
1158 tn->telrcv_state = CURL_TS_DATA;
1162 printoption(data, "RCVD", CURL_DO, c);
1163 tn->please_negotiate = 1;
1165 tn->telrcv_state = CURL_TS_DATA;
1169 printoption(data, "RCVD", CURL_DONT, c);
1170 tn->please_negotiate = 1;
1172 tn->telrcv_state = CURL_TS_DATA;
1177 tn->telrcv_state = CURL_TS_SE;
1179 CURL_SB_ACCUM(tn,c);
1186 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1187 * Several things may have happened. An IAC was not doubled, the
1188 * IAC SE was left off, or another option got inserted into the
1189 * suboption are all possibilities. If we assume that the IAC was
1190 * not doubled, and really the IAC SE was left off, we could get
1191 * into an infinate loop here. So, instead, we terminate the
1192 * suboption, and process the partial suboption if we can.
1194 CURL_SB_ACCUM(tn, CURL_IAC);
1195 CURL_SB_ACCUM(tn, c);
1196 tn->subpointer -= 2;
1199 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1200 suboption(conn); /* handle sub-option */
1201 tn->telrcv_state = CURL_TS_IAC;
1204 CURL_SB_ACCUM(tn,c);
1205 tn->telrcv_state = CURL_TS_SB;
1209 CURL_SB_ACCUM(tn, CURL_IAC);
1210 CURL_SB_ACCUM(tn, CURL_SE);
1211 tn->subpointer -= 2;
1213 suboption(conn); /* handle sub-option */
1214 tn->telrcv_state = CURL_TS_DATA;
1224 /* Escape and send a telnet data block */
1225 /* TODO: write large chunks of data instead of one byte at a time */
1226 static CURLcode send_telnet_data(struct connectdata *conn,
1227 char *buffer, ssize_t nread)
1229 unsigned char outbuf[2];
1230 ssize_t bytes_written, total_written;
1232 CURLcode result = CURLE_OK;
1234 while(!result && nread--) {
1235 outbuf[0] = *buffer++;
1237 if(outbuf[0] == CURL_IAC)
1238 outbuf[out_count++] = CURL_IAC;
1242 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1243 struct pollfd pfd[1];
1244 pfd[0].fd = conn->sock[FIRSTSOCKET];
1245 pfd[0].events = POLLOUT;
1246 switch (Curl_poll(pfd, 1, -1)) {
1247 case -1: /* error, abort writing */
1248 case 0: /* timeout (will never happen) */
1249 result = CURLE_SEND_ERROR;
1251 default: /* write! */
1253 result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1254 outbuf+total_written, out_count-total_written,
1256 total_written += bytes_written;
1259 /* handle partial write */
1260 } while(!result && total_written < out_count);
1265 static CURLcode telnet_done(struct connectdata *conn,
1266 CURLcode status, bool premature)
1268 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1269 (void)status; /* unused */
1270 (void)premature; /* not used */
1275 curl_slist_free_all(tn->telnet_vars);
1276 tn->telnet_vars = NULL;
1278 Curl_safefree(conn->data->req.protop);
1283 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1286 struct SessionHandle *data = conn->data;
1287 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1290 WSOCK2_FUNC close_event_func;
1291 WSOCK2_FUNC create_event_func;
1292 WSOCK2_FUNC event_select_func;
1293 WSOCK2_FUNC enum_netevents_func;
1294 WSAEVENT event_handle;
1295 WSANETWORKEVENTS events;
1296 HANDLE stdin_handle;
1301 DWORD readfile_read;
1305 struct pollfd pfd[2];
1307 curl_off_t total_dl = 0;
1308 curl_off_t total_ul = 0;
1313 char *buf = data->state.buffer;
1316 *done = TRUE; /* unconditionally */
1318 code = init_telnet(conn);
1322 tn = (struct TELNET *)data->req.protop;
1324 code = check_telnet_options(conn);
1330 ** This functionality only works with WinSock >= 2.0. So,
1331 ** make sure have it.
1333 code = check_wsock2(data);
1337 /* OK, so we have WinSock 2.0. We need to dynamically */
1338 /* load ws2_32.dll and get the function pointers we need. */
1339 wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
1340 if(wsock2 == NULL) {
1341 failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
1342 return CURLE_FAILED_INIT;
1345 /* Grab a pointer to WSACreateEvent */
1346 create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1347 if(create_event_func == NULL) {
1348 failf(data,"failed to find WSACreateEvent function (%d)",
1350 FreeLibrary(wsock2);
1351 return CURLE_FAILED_INIT;
1354 /* And WSACloseEvent */
1355 close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1356 if(close_event_func == NULL) {
1357 failf(data,"failed to find WSACloseEvent function (%d)",
1359 FreeLibrary(wsock2);
1360 return CURLE_FAILED_INIT;
1363 /* And WSAEventSelect */
1364 event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1365 if(event_select_func == NULL) {
1366 failf(data,"failed to find WSAEventSelect function (%d)",
1368 FreeLibrary(wsock2);
1369 return CURLE_FAILED_INIT;
1372 /* And WSAEnumNetworkEvents */
1373 enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1374 if(enum_netevents_func == NULL) {
1375 failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1377 FreeLibrary(wsock2);
1378 return CURLE_FAILED_INIT;
1381 /* We want to wait for both stdin and the socket. Since
1382 ** the select() function in winsock only works on sockets
1383 ** we have to use the WaitForMultipleObjects() call.
1386 /* First, create a sockets event object */
1387 event_handle = (WSAEVENT)create_event_func();
1388 if(event_handle == WSA_INVALID_EVENT) {
1389 failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
1390 FreeLibrary(wsock2);
1391 return CURLE_FAILED_INIT;
1394 /* Tell winsock what events we want to listen to */
1395 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1397 close_event_func(event_handle);
1398 FreeLibrary(wsock2);
1402 /* The get the Windows file handle for stdin */
1403 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1405 /* Create the list of objects to wait for */
1406 objs[0] = event_handle;
1407 objs[1] = stdin_handle;
1409 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1410 else use the old WaitForMultipleObjects() way */
1411 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1412 data->set.is_fread_set) {
1413 /* Don't wait for stdin_handle, just wait for event_handle */
1415 /* Check stdin_handle per 100 milliseconds */
1420 wait_timeout = 1000;
1423 /* Keep on listening and act on events */
1425 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1430 if(obj_count == 1) {
1431 /* read from user-supplied method */
1432 code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1433 if(code == CURL_READFUNC_ABORT) {
1435 code = CURLE_READ_ERROR;
1439 if(code == CURL_READFUNC_PAUSE)
1442 if(code == 0) /* no bytes */
1445 readfile_read = code; /* fall thru with number of bytes read */
1448 /* read from stdin */
1449 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1450 &readfile_read, NULL)) {
1452 code = CURLE_READ_ERROR;
1459 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1460 &readfile_read, NULL)) {
1462 code = CURLE_READ_ERROR;
1467 code = send_telnet_data(conn, buf, readfile_read);
1476 case WAIT_OBJECT_0 + 1:
1478 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1479 &readfile_read, NULL)) {
1481 code = CURLE_READ_ERROR;
1485 code = send_telnet_data(conn, buf, readfile_read);
1495 events.lNetworkEvents = 0;
1496 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1497 if((err = SOCKERRNO) != EINPROGRESS) {
1498 infof(data,"WSAEnumNetworkEvents failed (%d)", err);
1500 code = CURLE_READ_ERROR;
1504 if(events.lNetworkEvents & FD_READ) {
1505 /* read data from network */
1506 code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1507 /* read would've blocked. Loop again */
1508 if(code == CURLE_AGAIN)
1510 /* returned not-zero, this an error */
1515 /* returned zero but actually received 0 or less here,
1516 the server closed the connection and we bail out */
1517 else if(nread <= 0) {
1522 code = telrcv(conn, (unsigned char *)buf, nread);
1528 /* Negotiate if the peer has started negotiating,
1529 otherwise don't. We don't want to speak telnet with
1530 non-telnet servers, like POP or SMTP. */
1531 if(tn->please_negotiate && !tn->already_negotiated) {
1533 tn->already_negotiated = 1;
1536 if(events.lNetworkEvents & FD_CLOSE) {
1543 if(data->set.timeout) {
1545 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1546 failf(data, "Time-out");
1547 code = CURLE_OPERATION_TIMEDOUT;
1553 /* We called WSACreateEvent, so call WSACloseEvent */
1554 if(!close_event_func(event_handle)) {
1555 infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
1558 /* "Forget" pointers into the library we're about to free */
1559 create_event_func = NULL;
1560 close_event_func = NULL;
1561 event_select_func = NULL;
1562 enum_netevents_func = NULL;
1564 /* We called LoadLibrary, so call FreeLibrary */
1565 if(!FreeLibrary(wsock2))
1566 infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
1569 pfd[0].events = POLLIN;
1571 if(conn->fread_func != (curl_read_callback)fread) {
1573 interval_ms = 100; /* poll user-supplied read function */
1576 /* really using fread, so infile is a FILE* */
1577 pfd[1].fd = fileno((FILE *)conn->fread_in);
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 in file */
1631 nread = read(pfd[1].fd, 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);