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 */
713 unsigned short *pval;
715 if(data->set.verbose) {
717 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
721 i = pointer[length-2];
722 j = pointer[length-1];
724 if(i != CURL_IAC || j != CURL_SE) {
725 infof(data, "(terminated by ");
726 if(CURL_TELOPT_OK(i))
727 infof(data, "%s ", CURL_TELOPT(i));
728 else if(CURL_TELCMD_OK(i))
729 infof(data, "%s ", CURL_TELCMD(i));
731 infof(data, "%u ", i);
732 if(CURL_TELOPT_OK(j))
733 infof(data, "%s", CURL_TELOPT(j));
734 else if(CURL_TELCMD_OK(j))
735 infof(data, "%s", CURL_TELCMD(j));
737 infof(data, "%d", j);
738 infof(data, ", not IAC SE!) ");
744 infof(data, "(Empty suboption?)");
748 if(CURL_TELOPT_OK(pointer[0])) {
750 case CURL_TELOPT_TTYPE:
751 case CURL_TELOPT_XDISPLOC:
752 case CURL_TELOPT_NEW_ENVIRON:
753 case CURL_TELOPT_NAWS:
754 infof(data, "%s", CURL_TELOPT(pointer[0]));
757 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
762 infof(data, "%d (unknown)", pointer[i]);
765 case CURL_TELOPT_NAWS:
766 pval = (unsigned short*)(pointer+1);
767 infof(data, "Width: %hu ; Height: %hu",
768 ntohs(pval[0]), ntohs(pval[1]));
772 case CURL_TELQUAL_IS:
775 case CURL_TELQUAL_SEND:
776 infof(data, " SEND");
778 case CURL_TELQUAL_INFO:
779 infof(data, " INFO/REPLY");
781 case CURL_TELQUAL_NAME:
782 infof(data, " NAME");
787 case CURL_TELOPT_TTYPE:
788 case CURL_TELOPT_XDISPLOC:
790 infof(data, " \"%s\"", &pointer[2]);
792 case CURL_TELOPT_NEW_ENVIRON:
793 if(pointer[1] == CURL_TELQUAL_IS) {
795 for(i = 3;i < length;i++) {
797 case CURL_NEW_ENV_VAR:
800 case CURL_NEW_ENV_VALUE:
804 infof(data, "%c", pointer[i]);
811 for(i = 2; i < length; i++)
812 infof(data, " %.2x", pointer[i]);
821 static CURLcode check_telnet_options(struct connectdata *conn)
823 struct curl_slist *head;
824 struct curl_slist *beg;
825 char option_keyword[128] = "";
826 char option_arg[256] = "";
827 struct SessionHandle *data = conn->data;
828 struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
829 CURLcode result = CURLE_OK;
832 /* Add the user name as an environment variable if it
833 was given on the command line */
834 if(conn->bits.user_passwd) {
835 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
836 beg = curl_slist_append(tn->telnet_vars, option_arg);
838 curl_slist_free_all(tn->telnet_vars);
839 tn->telnet_vars = NULL;
840 return CURLE_OUT_OF_MEMORY;
842 tn->telnet_vars = beg;
843 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
846 for(head = data->set.telnet_options; head; head=head->next) {
847 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
848 option_keyword, option_arg) == 2) {
851 if(Curl_raw_equal(option_keyword, "TTYPE")) {
852 strncpy(tn->subopt_ttype, option_arg, 31);
853 tn->subopt_ttype[31] = 0; /* String termination */
854 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
858 /* Display variable */
859 if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
860 strncpy(tn->subopt_xdisploc, option_arg, 127);
861 tn->subopt_xdisploc[127] = 0; /* String termination */
862 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
866 /* Environment variable */
867 if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
868 beg = curl_slist_append(tn->telnet_vars, option_arg);
870 result = CURLE_OUT_OF_MEMORY;
873 tn->telnet_vars = beg;
874 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
879 if(Curl_raw_equal(option_keyword, "WS")) {
880 if(sscanf(option_arg, "%hu%*[xX]%hu",
881 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
882 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
884 failf(data, "Syntax error in telnet option: %s", head->data);
885 result = CURLE_TELNET_OPTION_SYNTAX;
891 /* To take care or not of the 8th bit in data exchange */
892 if(Curl_raw_equal(option_keyword, "BINARY")) {
893 binary_option=atoi(option_arg);
894 if(binary_option!=1) {
895 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
896 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
901 failf(data, "Unknown telnet option %s", head->data);
902 result = CURLE_UNKNOWN_TELNET_OPTION;
906 failf(data, "Syntax error in telnet option: %s", head->data);
907 result = CURLE_TELNET_OPTION_SYNTAX;
913 curl_slist_free_all(tn->telnet_vars);
914 tn->telnet_vars = NULL;
923 * Look at the sub-option buffer, and try to be helpful to the other
927 static void suboption(struct connectdata *conn)
929 struct curl_slist *v;
930 unsigned char temp[2048];
931 ssize_t bytes_written;
935 char varname[128] = "";
936 char varval[128] = "";
937 struct SessionHandle *data = conn->data;
938 struct TELNET *tn = (struct TELNET *)data->req.protop;
940 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
941 switch (CURL_SB_GET(tn)) {
942 case CURL_TELOPT_TTYPE:
943 len = strlen(tn->subopt_ttype) + 4 + 2;
944 snprintf((char *)temp, sizeof(temp),
945 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
946 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
947 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
948 if(bytes_written < 0) {
950 failf(data,"Sending data failed (%d)",err);
952 printsub(data, '>', &temp[2], len-2);
954 case CURL_TELOPT_XDISPLOC:
955 len = strlen(tn->subopt_xdisploc) + 4 + 2;
956 snprintf((char *)temp, sizeof(temp),
957 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
958 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
959 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
960 if(bytes_written < 0) {
962 failf(data,"Sending data failed (%d)",err);
964 printsub(data, '>', &temp[2], len-2);
966 case CURL_TELOPT_NEW_ENVIRON:
967 snprintf((char *)temp, sizeof(temp),
968 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
972 for(v = tn->telnet_vars;v;v = v->next) {
973 tmplen = (strlen(v->data) + 1);
974 /* Add the variable only if it fits */
975 if(len + tmplen < (int)sizeof(temp)-6) {
976 if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
977 snprintf((char *)&temp[len], sizeof(temp) - len,
978 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
979 CURL_NEW_ENV_VALUE, varval);
984 snprintf((char *)&temp[len], sizeof(temp) - len,
985 "%c%c", CURL_IAC, CURL_SE);
987 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
988 if(bytes_written < 0) {
990 failf(data,"Sending data failed (%d)",err);
992 printsub(data, '>', &temp[2], len-2);
1002 * Send suboption information to the server side.
1005 static void sendsuboption(struct connectdata *conn, int option)
1007 ssize_t bytes_written;
1009 unsigned short x, y;
1010 unsigned char*uc1, *uc2;
1012 struct SessionHandle *data = conn->data;
1013 struct TELNET *tn = (struct TELNET *)data->req.protop;
1016 case CURL_TELOPT_NAWS:
1017 /* We prepare data to be sent */
1019 CURL_SB_ACCUM(tn, CURL_IAC);
1020 CURL_SB_ACCUM(tn, CURL_SB);
1021 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1022 /* We must deal either with litte or big endien processors */
1023 /* Window size must be sent according to the 'network order' */
1024 x=htons(tn->subopt_wsx);
1025 y=htons(tn->subopt_wsy);
1026 uc1 = (unsigned char*)&x;
1027 uc2 = (unsigned char*)&y;
1028 CURL_SB_ACCUM(tn, uc1[0]);
1029 CURL_SB_ACCUM(tn, uc1[1]);
1030 CURL_SB_ACCUM(tn, uc2[0]);
1031 CURL_SB_ACCUM(tn, uc2[1]);
1033 CURL_SB_ACCUM(tn, CURL_IAC);
1034 CURL_SB_ACCUM(tn, CURL_SE);
1036 /* data suboption is now ready */
1038 printsub(data, '>', (unsigned char *)tn->subbuffer+2,
1041 /* we send the header of the suboption... */
1042 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1043 if(bytes_written < 0) {
1045 failf(data, "Sending data failed (%d)", err);
1047 /* ... then the window size with the send_telnet_data() function
1048 to deal with 0xFF cases ... */
1049 send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
1050 /* ... and the footer */
1051 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
1052 if(bytes_written < 0) {
1054 failf(data, "Sending data failed (%d)", err);
1062 CURLcode telrcv(struct connectdata *conn,
1063 const unsigned char *inbuf, /* Data received from socket */
1064 ssize_t count) /* Number of bytes received */
1070 struct SessionHandle *data = conn->data;
1071 struct TELNET *tn = (struct TELNET *)data->req.protop;
1073 #define startskipping() \
1074 if(startwrite >= 0) { \
1075 result = Curl_client_write(conn, \
1077 (char *)&inbuf[startwrite], \
1079 if(result != CURLE_OK) \
1084 #define writebyte() \
1085 if(startwrite < 0) \
1088 #define bufferflush() startskipping()
1093 switch (tn->telrcv_state) {
1095 tn->telrcv_state = CURL_TS_DATA;
1098 break; /* Ignore \0 after CR */
1105 tn->telrcv_state = CURL_TS_IAC;
1110 tn->telrcv_state = CURL_TS_CR;
1116 DEBUGASSERT(startwrite < 0);
1119 tn->telrcv_state = CURL_TS_WILL;
1122 tn->telrcv_state = CURL_TS_WONT;
1125 tn->telrcv_state = CURL_TS_DO;
1128 tn->telrcv_state = CURL_TS_DONT;
1132 tn->telrcv_state = CURL_TS_SB;
1135 tn->telrcv_state = CURL_TS_DATA;
1142 tn->telrcv_state = CURL_TS_DATA;
1143 printoption(data, "RCVD", CURL_IAC, c);
1149 printoption(data, "RCVD", CURL_WILL, c);
1150 tn->please_negotiate = 1;
1152 tn->telrcv_state = CURL_TS_DATA;
1156 printoption(data, "RCVD", CURL_WONT, c);
1157 tn->please_negotiate = 1;
1159 tn->telrcv_state = CURL_TS_DATA;
1163 printoption(data, "RCVD", CURL_DO, c);
1164 tn->please_negotiate = 1;
1166 tn->telrcv_state = CURL_TS_DATA;
1170 printoption(data, "RCVD", CURL_DONT, c);
1171 tn->please_negotiate = 1;
1173 tn->telrcv_state = CURL_TS_DATA;
1178 tn->telrcv_state = CURL_TS_SE;
1180 CURL_SB_ACCUM(tn,c);
1187 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1188 * Several things may have happened. An IAC was not doubled, the
1189 * IAC SE was left off, or another option got inserted into the
1190 * suboption are all possibilities. If we assume that the IAC was
1191 * not doubled, and really the IAC SE was left off, we could get
1192 * into an infinate loop here. So, instead, we terminate the
1193 * suboption, and process the partial suboption if we can.
1195 CURL_SB_ACCUM(tn, CURL_IAC);
1196 CURL_SB_ACCUM(tn, c);
1197 tn->subpointer -= 2;
1200 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1201 suboption(conn); /* handle sub-option */
1202 tn->telrcv_state = CURL_TS_IAC;
1205 CURL_SB_ACCUM(tn,c);
1206 tn->telrcv_state = CURL_TS_SB;
1210 CURL_SB_ACCUM(tn, CURL_IAC);
1211 CURL_SB_ACCUM(tn, CURL_SE);
1212 tn->subpointer -= 2;
1214 suboption(conn); /* handle sub-option */
1215 tn->telrcv_state = CURL_TS_DATA;
1225 /* Escape and send a telnet data block */
1226 /* TODO: write large chunks of data instead of one byte at a time */
1227 static CURLcode send_telnet_data(struct connectdata *conn,
1228 char *buffer, ssize_t nread)
1230 unsigned char outbuf[2];
1231 ssize_t bytes_written, total_written;
1233 CURLcode rc = CURLE_OK;
1235 while(rc == CURLE_OK && nread--) {
1236 outbuf[0] = *buffer++;
1238 if(outbuf[0] == CURL_IAC)
1239 outbuf[out_count++] = CURL_IAC;
1243 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1244 struct pollfd pfd[1];
1245 pfd[0].fd = conn->sock[FIRSTSOCKET];
1246 pfd[0].events = POLLOUT;
1247 switch (Curl_poll(pfd, 1, -1)) {
1248 case -1: /* error, abort writing */
1249 case 0: /* timeout (will never happen) */
1250 rc = CURLE_SEND_ERROR;
1252 default: /* write! */
1254 rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
1255 out_count-total_written, &bytes_written);
1256 total_written += bytes_written;
1259 /* handle partial write */
1260 } while(rc == CURLE_OK && 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);