1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2012, 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->state.proto.telnet = (void *)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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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;
937 struct SessionHandle *data = conn->data;
938 struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
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 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);
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->state.proto.telnet;
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->state.proto.telnet;
1072 #define startskipping() \
1073 if(startwrite >= 0) { \
1074 result = Curl_client_write(conn, \
1076 (char *)&inbuf[startwrite], \
1078 if(result != CURLE_OK) \
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 rc = CURLE_OK;
1234 while(rc == CURLE_OK && 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 rc = CURLE_SEND_ERROR;
1251 default: /* write! */
1253 rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
1254 out_count-total_written, &bytes_written);
1255 total_written += bytes_written;
1258 /* handle partial write */
1259 } while(rc == CURLE_OK && total_written < out_count);
1264 static CURLcode telnet_done(struct connectdata *conn,
1265 CURLcode status, bool premature)
1267 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
1268 (void)status; /* unused */
1269 (void)premature; /* not used */
1274 curl_slist_free_all(tn->telnet_vars);
1275 tn->telnet_vars = NULL;
1277 Curl_safefree(conn->data->state.proto.telnet);
1282 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1285 struct SessionHandle *data = conn->data;
1286 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1289 WSOCK2_FUNC close_event_func;
1290 WSOCK2_FUNC create_event_func;
1291 WSOCK2_FUNC event_select_func;
1292 WSOCK2_FUNC enum_netevents_func;
1293 WSAEVENT event_handle;
1294 WSANETWORKEVENTS events;
1295 HANDLE stdin_handle;
1300 DWORD readfile_read;
1304 struct pollfd pfd[2];
1306 curl_off_t total_dl = 0;
1307 curl_off_t total_ul = 0;
1312 char *buf = data->state.buffer;
1315 *done = TRUE; /* unconditionally */
1317 code = init_telnet(conn);
1321 tn = (struct TELNET *)data->state.proto.telnet;
1323 code = check_telnet_options(conn);
1329 ** This functionality only works with WinSock >= 2.0. So,
1330 ** make sure have it.
1332 code = check_wsock2(data);
1336 /* OK, so we have WinSock 2.0. We need to dynamically */
1337 /* load ws2_32.dll and get the function pointers we need. */
1338 wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
1339 if(wsock2 == NULL) {
1340 failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
1341 return CURLE_FAILED_INIT;
1344 /* Grab a pointer to WSACreateEvent */
1345 create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1346 if(create_event_func == NULL) {
1347 failf(data,"failed to find WSACreateEvent function (%d)",
1349 FreeLibrary(wsock2);
1350 return CURLE_FAILED_INIT;
1353 /* And WSACloseEvent */
1354 close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1355 if(close_event_func == NULL) {
1356 failf(data,"failed to find WSACloseEvent function (%d)",
1358 FreeLibrary(wsock2);
1359 return CURLE_FAILED_INIT;
1362 /* And WSAEventSelect */
1363 event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1364 if(event_select_func == NULL) {
1365 failf(data,"failed to find WSAEventSelect function (%d)",
1367 FreeLibrary(wsock2);
1368 return CURLE_FAILED_INIT;
1371 /* And WSAEnumNetworkEvents */
1372 enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1373 if(enum_netevents_func == NULL) {
1374 failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1376 FreeLibrary(wsock2);
1377 return CURLE_FAILED_INIT;
1380 /* We want to wait for both stdin and the socket. Since
1381 ** the select() function in winsock only works on sockets
1382 ** we have to use the WaitForMultipleObjects() call.
1385 /* First, create a sockets event object */
1386 event_handle = (WSAEVENT)create_event_func();
1387 if(event_handle == WSA_INVALID_EVENT) {
1388 failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
1389 FreeLibrary(wsock2);
1390 return CURLE_FAILED_INIT;
1393 /* Tell winsock what events we want to listen to */
1394 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1396 close_event_func(event_handle);
1397 FreeLibrary(wsock2);
1401 /* The get the Windows file handle for stdin */
1402 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1404 /* Create the list of objects to wait for */
1405 objs[0] = event_handle;
1406 objs[1] = stdin_handle;
1408 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1409 else use the old WaitForMultipleObjects() way */
1410 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1411 data->set.is_fread_set) {
1412 /* Don't wait for stdin_handle, just wait for event_handle */
1414 /* Check stdin_handle per 100 milliseconds */
1419 wait_timeout = 1000;
1422 /* Keep on listening and act on events */
1424 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1429 if(obj_count == 1) {
1430 /* read from user-supplied method */
1431 code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1432 if(code == CURL_READFUNC_ABORT) {
1434 code = CURLE_READ_ERROR;
1438 if(code == CURL_READFUNC_PAUSE)
1441 if(code == 0) /* no bytes */
1444 readfile_read = code; /* fall thru with number of bytes read */
1447 /* read from stdin */
1448 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1449 &readfile_read, NULL)) {
1451 code = CURLE_READ_ERROR;
1458 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1459 &readfile_read, NULL)) {
1461 code = CURLE_READ_ERROR;
1466 code = send_telnet_data(conn, buf, readfile_read);
1475 case WAIT_OBJECT_0 + 1:
1477 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1478 &readfile_read, NULL)) {
1480 code = CURLE_READ_ERROR;
1484 code = send_telnet_data(conn, buf, readfile_read);
1494 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1495 if((err = SOCKERRNO) != EINPROGRESS) {
1496 infof(data,"WSAEnumNetworkEvents failed (%d)", err);
1498 code = CURLE_READ_ERROR;
1502 if(events.lNetworkEvents & FD_READ) {
1503 /* read data from network */
1504 code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1505 /* read would've blocked. Loop again */
1506 if(code == CURLE_AGAIN)
1508 /* returned not-zero, this an error */
1513 /* returned zero but actually received 0 or less here,
1514 the server closed the connection and we bail out */
1515 else if(nread <= 0) {
1520 code = telrcv(conn, (unsigned char *)buf, nread);
1526 /* Negotiate if the peer has started negotiating,
1527 otherwise don't. We don't want to speak telnet with
1528 non-telnet servers, like POP or SMTP. */
1529 if(tn->please_negotiate && !tn->already_negotiated) {
1531 tn->already_negotiated = 1;
1534 if(events.lNetworkEvents & FD_CLOSE) {
1541 if(data->set.timeout) {
1543 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1544 failf(data, "Time-out");
1545 code = CURLE_OPERATION_TIMEDOUT;
1551 /* We called WSACreateEvent, so call WSACloseEvent */
1552 if(!close_event_func(event_handle)) {
1553 infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
1556 /* "Forget" pointers into the library we're about to free */
1557 create_event_func = NULL;
1558 close_event_func = NULL;
1559 event_select_func = NULL;
1560 enum_netevents_func = NULL;
1562 /* We called LoadLibrary, so call FreeLibrary */
1563 if(!FreeLibrary(wsock2))
1564 infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
1567 pfd[0].events = POLLIN;
1569 if(conn->fread_func != (curl_read_callback)fread) {
1571 interval_ms = 100; /* poll user-supplied read function */
1574 /* really using fread, so infile is a FILE* */
1575 pfd[1].fd = fileno((FILE *)conn->fread_in);
1576 pfd[1].events = POLLIN;
1578 interval_ms = 1 * 1000;
1582 switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1583 case -1: /* error, stop reading */
1586 case 0: /* timeout */
1590 default: /* read! */
1591 if(pfd[0].revents & POLLIN) {
1592 /* read data from network */
1593 code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1594 /* read would've blocked. Loop again */
1595 if(code == CURLE_AGAIN)
1597 /* returned not-zero, this an error */
1602 /* returned zero but actually received 0 or less here,
1603 the server closed the connection and we bail out */
1604 else if(nread <= 0) {
1610 Curl_pgrsSetDownloadCounter(data, total_dl);
1611 code = telrcv(conn, (unsigned char *)buf, nread);
1617 /* Negotiate if the peer has started negotiating,
1618 otherwise don't. We don't want to speak telnet with
1619 non-telnet servers, like POP or SMTP. */
1620 if(tn->please_negotiate && !tn->already_negotiated) {
1622 tn->already_negotiated = 1;
1628 if(pfd[1].revents & POLLIN) { /* read from in file */
1629 nread = read(pfd[1].fd, buf, BUFSIZE - 1);
1633 /* read from user-supplied method */
1634 nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1635 if(nread == CURL_READFUNC_ABORT) {
1639 if(nread == CURL_READFUNC_PAUSE)
1644 code = send_telnet_data(conn, buf, nread);
1650 Curl_pgrsSetUploadCounter(data, total_ul);
1656 } /* poll switch statement */
1658 if(data->set.timeout) {
1660 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1661 failf(data, "Time-out");
1662 code = CURLE_OPERATION_TIMEDOUT;
1667 if(Curl_pgrsUpdate(conn)) {
1668 code = CURLE_ABORTED_BY_CALLBACK;
1673 /* mark this as "no further transfer wanted" */
1674 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);