1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, 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 * $Id: telnet.c,v 1.2 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_TELNET
27 /* -- WIN32 approved -- */
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
36 #ifdef HAVE_SYS_STAT_H
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #ifdef HAVE_SYS_TIME_H
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
61 #include <sys/ioctl.h>
64 #ifdef HAVE_SYS_PARAM_H
65 #include <sys/param.h>
72 #include <curl/curl.h>
78 #define _MPRINTF_REPLACE /* use our functions only */
79 #include <curl/mprintf.h>
84 #include "arpa_telnet.h"
88 /* The last #include file should be: */
91 #define SUBBUFSIZE 512
93 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer;
94 #define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
95 #define CURL_SB_ACCUM(x,c) \
96 if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
97 *x->subpointer++ = (c); \
100 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
101 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
102 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
103 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
106 typedef FARPROC WSOCK2_FUNC
;
107 static CURLcode
check_wsock2 ( struct SessionHandle
*data
);
111 void telrcv(struct connectdata
*,
112 unsigned char *inbuf
, /* Data received from socket */
113 ssize_t count
); /* Number of bytes received */
115 static void printoption(struct SessionHandle
*data
,
116 const char *direction
,
117 int cmd
, int option
);
119 static void negotiate(struct connectdata
*);
120 static void send_negotiation(struct connectdata
*, int cmd
, int option
);
121 static void set_local_option(struct connectdata
*, int cmd
, int option
);
122 static void set_remote_option(struct connectdata
*, int cmd
, int option
);
124 static void printsub(struct SessionHandle
*data
,
125 int direction
, unsigned char *pointer
,
127 static void suboption(struct connectdata
*);
129 /* For negotiation compliant to RFC 1143 */
132 #define CURL_WANTYES 2
133 #define CURL_WANTNO 3
136 #define CURL_OPPOSITE 1
139 * Telnet receiver states for fsm
150 CURL_TS_SB
, /* sub-option collection */
151 CURL_TS_SE
/* looking for sub-option end */
155 int please_negotiate
;
156 int already_negotiated
;
159 int us_preferred
[256];
162 int him_preferred
[256];
163 char subopt_ttype
[32]; /* Set with suboption TTYPE */
164 char subopt_xdisploc
[128]; /* Set with suboption XDISPLOC */
165 struct curl_slist
*telnet_vars
; /* Environment variables */
168 unsigned char subbuffer
[SUBBUFSIZE
];
169 unsigned char *subpointer
, *subend
; /* buffer for sub-options */
171 TelnetReceive telrcv_state
;
176 check_wsock2 ( struct SessionHandle
*data
)
179 WORD wVersionRequested
;
184 /* telnet requires at least WinSock 2.0 so ask for it. */
185 wVersionRequested
= MAKEWORD(2, 0);
187 err
= WSAStartup(wVersionRequested
, &wsaData
);
189 /* We must've called this once already, so this call */
190 /* should always succeed. But, just in case... */
192 failf(data
,"WSAStartup failed (%d)",err
);
193 return CURLE_FAILED_INIT
;
196 /* We have to have a WSACleanup call for every successful */
197 /* WSAStartup call. */
200 /* Check that our version is supported */
201 if (LOBYTE(wsaData
.wVersion
) != LOBYTE(wVersionRequested
) ||
202 HIBYTE(wsaData
.wVersion
) != HIBYTE(wVersionRequested
)) {
203 /* Our version isn't supported */
204 failf(data
,"insufficient winsock version to support "
206 return CURLE_FAILED_INIT
;
209 /* Our version is supported */
215 CURLcode
init_telnet(struct connectdata
*conn
)
219 tn
= (struct TELNET
*)calloc(1, sizeof(struct TELNET
));
221 return CURLE_OUT_OF_MEMORY
;
223 conn
->data
->reqdata
.proto
.telnet
= (void *)tn
; /* make us known */
225 tn
->telrcv_state
= CURL_TS_DATA
;
227 /* Init suboptions */
230 /* Set the options we want by default */
231 tn
->us_preferred
[CURL_TELOPT_BINARY
] = CURL_YES
;
232 tn
->us_preferred
[CURL_TELOPT_SGA
] = CURL_YES
;
233 tn
->him_preferred
[CURL_TELOPT_BINARY
] = CURL_YES
;
234 tn
->him_preferred
[CURL_TELOPT_SGA
] = CURL_YES
;
239 static void negotiate(struct connectdata
*conn
)
242 struct TELNET
*tn
= (struct TELNET
*) conn
->data
->reqdata
.proto
.telnet
;
244 for(i
= 0;i
< CURL_NTELOPTS
;i
++)
246 if(tn
->us_preferred
[i
] == CURL_YES
)
247 set_local_option(conn
, i
, CURL_YES
);
249 if(tn
->him_preferred
[i
] == CURL_YES
)
250 set_remote_option(conn
, i
, CURL_YES
);
254 static void printoption(struct SessionHandle
*data
,
255 const char *direction
, int cmd
, int option
)
260 if (data
->set
.verbose
)
264 if (CURL_TELCMD_OK(option
))
265 infof(data
, "%s IAC %s\n", direction
, CURL_TELCMD(option
));
267 infof(data
, "%s IAC %d\n", direction
, option
);
271 fmt
= (cmd
== CURL_WILL
) ? "WILL" : (cmd
== CURL_WONT
) ? "WONT" :
272 (cmd
== CURL_DO
) ? "DO" : (cmd
== CURL_DONT
) ? "DONT" : 0;
275 if (CURL_TELOPT_OK(option
))
276 opt
= CURL_TELOPT(option
);
277 else if (option
== CURL_TELOPT_EXOPL
)
283 infof(data
, "%s %s %s\n", direction
, fmt
, opt
);
285 infof(data
, "%s %s %d\n", direction
, fmt
, option
);
288 infof(data
, "%s %d %d\n", direction
, cmd
, option
);
293 static void send_negotiation(struct connectdata
*conn
, int cmd
, int option
)
295 unsigned char buf
[3];
296 ssize_t bytes_written
;
298 struct SessionHandle
*data
= conn
->data
;
301 buf
[1] = (unsigned char)cmd
;
302 buf
[2] = (unsigned char)option
;
304 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], buf
, 3);
305 if(bytes_written
< 0) {
306 err
= Curl_sockerrno();
307 failf(data
,"Sending data failed (%d)",err
);
310 printoption(conn
->data
, "SENT", cmd
, option
);
314 void set_remote_option(struct connectdata
*conn
, int option
, int newstate
)
316 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
317 if(newstate
== CURL_YES
)
319 switch(tn
->him
[option
])
322 tn
->him
[option
] = CURL_WANTYES
;
323 send_negotiation(conn
, CURL_DO
, option
);
327 /* Already enabled */
331 switch(tn
->himq
[option
])
334 /* Already negotiating for CURL_YES, queue the request */
335 tn
->himq
[option
] = CURL_OPPOSITE
;
338 /* Error: already queued an enable request */
344 switch(tn
->himq
[option
])
347 /* Error: already negotiating for enable */
350 tn
->himq
[option
] = CURL_EMPTY
;
358 switch(tn
->him
[option
])
361 /* Already disabled */
365 tn
->him
[option
] = CURL_WANTNO
;
366 send_negotiation(conn
, CURL_DONT
, option
);
370 switch(tn
->himq
[option
])
373 /* Already negotiating for NO */
376 tn
->himq
[option
] = CURL_EMPTY
;
382 switch(tn
->himq
[option
])
385 tn
->himq
[option
] = CURL_OPPOSITE
;
396 void rec_will(struct connectdata
*conn
, int option
)
398 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
399 switch(tn
->him
[option
])
402 if(tn
->him_preferred
[option
] == CURL_YES
)
404 tn
->him
[option
] = CURL_YES
;
405 send_negotiation(conn
, CURL_DO
, option
);
409 send_negotiation(conn
, CURL_DONT
, option
);
414 /* Already enabled */
418 switch(tn
->himq
[option
])
421 /* Error: DONT answered by WILL */
422 tn
->him
[option
] = CURL_NO
;
425 /* Error: DONT answered by WILL */
426 tn
->him
[option
] = CURL_YES
;
427 tn
->himq
[option
] = CURL_EMPTY
;
433 switch(tn
->himq
[option
])
436 tn
->him
[option
] = CURL_YES
;
439 tn
->him
[option
] = CURL_WANTNO
;
440 tn
->himq
[option
] = CURL_EMPTY
;
441 send_negotiation(conn
, CURL_DONT
, option
);
449 void rec_wont(struct connectdata
*conn
, int option
)
451 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
452 switch(tn
->him
[option
])
455 /* Already disabled */
459 tn
->him
[option
] = CURL_NO
;
460 send_negotiation(conn
, CURL_DONT
, option
);
464 switch(tn
->himq
[option
])
467 tn
->him
[option
] = CURL_NO
;
471 tn
->him
[option
] = CURL_WANTYES
;
472 tn
->himq
[option
] = CURL_EMPTY
;
473 send_negotiation(conn
, CURL_DO
, option
);
479 switch(tn
->himq
[option
])
482 tn
->him
[option
] = CURL_NO
;
485 tn
->him
[option
] = CURL_NO
;
486 tn
->himq
[option
] = CURL_EMPTY
;
494 set_local_option(struct connectdata
*conn
, int option
, int newstate
)
496 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
497 if(newstate
== CURL_YES
)
499 switch(tn
->us
[option
])
502 tn
->us
[option
] = CURL_WANTYES
;
503 send_negotiation(conn
, CURL_WILL
, option
);
507 /* Already enabled */
511 switch(tn
->usq
[option
])
514 /* Already negotiating for CURL_YES, queue the request */
515 tn
->usq
[option
] = CURL_OPPOSITE
;
518 /* Error: already queued an enable request */
524 switch(tn
->usq
[option
])
527 /* Error: already negotiating for enable */
530 tn
->usq
[option
] = CURL_EMPTY
;
538 switch(tn
->us
[option
])
541 /* Already disabled */
545 tn
->us
[option
] = CURL_WANTNO
;
546 send_negotiation(conn
, CURL_WONT
, option
);
550 switch(tn
->usq
[option
])
553 /* Already negotiating for NO */
556 tn
->usq
[option
] = CURL_EMPTY
;
562 switch(tn
->usq
[option
])
565 tn
->usq
[option
] = CURL_OPPOSITE
;
576 void rec_do(struct connectdata
*conn
, int option
)
578 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
579 switch(tn
->us
[option
])
582 if(tn
->us_preferred
[option
] == CURL_YES
)
584 tn
->us
[option
] = CURL_YES
;
585 send_negotiation(conn
, CURL_WILL
, option
);
589 send_negotiation(conn
, CURL_WONT
, option
);
594 /* Already enabled */
598 switch(tn
->usq
[option
])
601 /* Error: DONT answered by WILL */
602 tn
->us
[option
] = CURL_NO
;
605 /* Error: DONT answered by WILL */
606 tn
->us
[option
] = CURL_YES
;
607 tn
->usq
[option
] = CURL_EMPTY
;
613 switch(tn
->usq
[option
])
616 tn
->us
[option
] = CURL_YES
;
619 tn
->us
[option
] = CURL_WANTNO
;
620 tn
->himq
[option
] = CURL_EMPTY
;
621 send_negotiation(conn
, CURL_WONT
, option
);
629 void rec_dont(struct connectdata
*conn
, int option
)
631 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
632 switch(tn
->us
[option
])
635 /* Already disabled */
639 tn
->us
[option
] = CURL_NO
;
640 send_negotiation(conn
, CURL_WONT
, option
);
644 switch(tn
->usq
[option
])
647 tn
->us
[option
] = CURL_NO
;
651 tn
->us
[option
] = CURL_WANTYES
;
652 tn
->usq
[option
] = CURL_EMPTY
;
653 send_negotiation(conn
, CURL_WILL
, option
);
659 switch(tn
->usq
[option
])
662 tn
->us
[option
] = CURL_NO
;
665 tn
->us
[option
] = CURL_NO
;
666 tn
->usq
[option
] = CURL_EMPTY
;
674 static void printsub(struct SessionHandle
*data
,
675 int direction
, /* '<' or '>' */
676 unsigned char *pointer
, /* where suboption data is */
677 size_t length
) /* length of suboption data */
681 if (data
->set
.verbose
)
685 infof(data
, "%s IAC SB ", (direction
== '<')? "RCVD":"SENT");
690 i
= pointer
[length
-2];
691 j
= pointer
[length
-1];
693 if (i
!= CURL_IAC
|| j
!= CURL_SE
)
695 infof(data
, "(terminated by ");
696 if (CURL_TELOPT_OK(i
))
697 infof(data
, "%s ", CURL_TELOPT(i
));
698 else if (CURL_TELCMD_OK(i
))
699 infof(data
, "%s ", CURL_TELCMD(i
));
701 infof(data
, "%d ", i
);
702 if (CURL_TELOPT_OK(j
))
703 infof(data
, "%s", CURL_TELOPT(j
));
704 else if (CURL_TELCMD_OK(j
))
705 infof(data
, "%s", CURL_TELCMD(j
));
707 infof(data
, "%d", j
);
708 infof(data
, ", not IAC SE!) ");
715 infof(data
, "(Empty suboption?)");
719 if (CURL_TELOPT_OK(pointer
[0])) {
721 case CURL_TELOPT_TTYPE
:
722 case CURL_TELOPT_XDISPLOC
:
723 case CURL_TELOPT_NEW_ENVIRON
:
724 infof(data
, "%s", CURL_TELOPT(pointer
[0]));
727 infof(data
, "%s (unsupported)", CURL_TELOPT(pointer
[0]));
732 infof(data
, "%d (unknown)", pointer
[i
]);
735 case CURL_TELQUAL_IS
:
738 case CURL_TELQUAL_SEND
:
739 infof(data
, " SEND");
741 case CURL_TELQUAL_INFO
:
742 infof(data
, " INFO/REPLY");
744 case CURL_TELQUAL_NAME
:
745 infof(data
, " NAME");
750 case CURL_TELOPT_TTYPE
:
751 case CURL_TELOPT_XDISPLOC
:
753 infof(data
, " \"%s\"", &pointer
[2]);
755 case CURL_TELOPT_NEW_ENVIRON
:
756 if(pointer
[1] == CURL_TELQUAL_IS
) {
758 for(i
= 3;i
< length
;i
++) {
760 case CURL_NEW_ENV_VAR
:
763 case CURL_NEW_ENV_VALUE
:
767 infof(data
, "%c", pointer
[i
]);
774 for (i
= 2; i
< length
; i
++)
775 infof(data
, " %.2x", pointer
[i
]);
786 static CURLcode
check_telnet_options(struct connectdata
*conn
)
788 struct curl_slist
*head
;
789 char option_keyword
[128];
790 char option_arg
[256];
792 struct SessionHandle
*data
= conn
->data
;
793 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
795 /* Add the user name as an environment variable if it
796 was given on the command line */
797 if(conn
->bits
.user_passwd
)
799 snprintf(option_arg
, sizeof(option_arg
), "USER,%s", conn
->user
);
800 tn
->telnet_vars
= curl_slist_append(tn
->telnet_vars
, option_arg
);
802 tn
->us_preferred
[CURL_TELOPT_NEW_ENVIRON
] = CURL_YES
;
805 for(head
= data
->set
.telnet_options
; head
; head
=head
->next
) {
806 if(sscanf(head
->data
, "%127[^= ]%*[ =]%255s",
807 option_keyword
, option_arg
) == 2) {
810 if(curl_strequal(option_keyword
, "TTYPE")) {
811 strncpy(tn
->subopt_ttype
, option_arg
, 31);
812 tn
->subopt_ttype
[31] = 0; /* String termination */
813 tn
->us_preferred
[CURL_TELOPT_TTYPE
] = CURL_YES
;
817 /* Display variable */
818 if(curl_strequal(option_keyword
, "XDISPLOC")) {
819 strncpy(tn
->subopt_xdisploc
, option_arg
, 127);
820 tn
->subopt_xdisploc
[127] = 0; /* String termination */
821 tn
->us_preferred
[CURL_TELOPT_XDISPLOC
] = CURL_YES
;
825 /* Environment variable */
826 if(curl_strequal(option_keyword
, "NEW_ENV")) {
827 buf
= strdup(option_arg
);
829 return CURLE_OUT_OF_MEMORY
;
830 tn
->telnet_vars
= curl_slist_append(tn
->telnet_vars
, buf
);
831 tn
->us_preferred
[CURL_TELOPT_NEW_ENVIRON
] = CURL_YES
;
835 failf(data
, "Unknown telnet option %s", head
->data
);
836 return CURLE_UNKNOWN_TELNET_OPTION
;
838 failf(data
, "Syntax error in telnet option: %s", head
->data
);
839 return CURLE_TELNET_OPTION_SYNTAX
;
849 * Look at the sub-option buffer, and try to be helpful to the other
853 static void suboption(struct connectdata
*conn
)
855 struct curl_slist
*v
;
856 unsigned char temp
[2048];
857 ssize_t bytes_written
;
863 struct SessionHandle
*data
= conn
->data
;
864 struct TELNET
*tn
= (struct TELNET
*)data
->reqdata
.proto
.telnet
;
866 printsub(data
, '<', (unsigned char *)tn
->subbuffer
, CURL_SB_LEN(tn
)+2);
867 switch (CURL_SB_GET(tn
)) {
868 case CURL_TELOPT_TTYPE
:
869 len
= strlen(tn
->subopt_ttype
) + 4 + 2;
870 snprintf((char *)temp
, sizeof(temp
),
871 "%c%c%c%c%s%c%c", CURL_IAC
, CURL_SB
, CURL_TELOPT_TTYPE
,
872 CURL_TELQUAL_IS
, tn
->subopt_ttype
, CURL_IAC
, CURL_SE
);
873 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], temp
, len
);
874 if(bytes_written
< 0) {
875 err
= Curl_sockerrno();
876 failf(data
,"Sending data failed (%d)",err
);
878 printsub(data
, '>', &temp
[2], len
-2);
880 case CURL_TELOPT_XDISPLOC
:
881 len
= strlen(tn
->subopt_xdisploc
) + 4 + 2;
882 snprintf((char *)temp
, sizeof(temp
),
883 "%c%c%c%c%s%c%c", CURL_IAC
, CURL_SB
, CURL_TELOPT_XDISPLOC
,
884 CURL_TELQUAL_IS
, tn
->subopt_xdisploc
, CURL_IAC
, CURL_SE
);
885 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], temp
, len
);
886 if(bytes_written
< 0) {
887 err
= Curl_sockerrno();
888 failf(data
,"Sending data failed (%d)",err
);
890 printsub(data
, '>', &temp
[2], len
-2);
892 case CURL_TELOPT_NEW_ENVIRON
:
893 snprintf((char *)temp
, sizeof(temp
),
894 "%c%c%c%c", CURL_IAC
, CURL_SB
, CURL_TELOPT_NEW_ENVIRON
,
898 for(v
= tn
->telnet_vars
;v
;v
= v
->next
) {
899 tmplen
= (strlen(v
->data
) + 1);
900 /* Add the variable only if it fits */
901 if(len
+ tmplen
< (int)sizeof(temp
)-6) {
902 sscanf(v
->data
, "%127[^,],%127s", varname
, varval
);
903 snprintf((char *)&temp
[len
], sizeof(temp
) - len
,
904 "%c%s%c%s", CURL_NEW_ENV_VAR
, varname
,
905 CURL_NEW_ENV_VALUE
, varval
);
909 snprintf((char *)&temp
[len
], sizeof(temp
) - len
,
910 "%c%c", CURL_IAC
, CURL_SE
);
912 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], temp
, len
);
913 if(bytes_written
< 0) {
914 err
= Curl_sockerrno();
915 failf(data
,"Sending data failed (%d)",err
);
917 printsub(data
, '>', &temp
[2], len
-2);
924 void telrcv(struct connectdata
*conn
,
925 unsigned char *inbuf
, /* Data received from socket */
926 ssize_t count
) /* Number of bytes received */
930 struct SessionHandle
*data
= conn
->data
;
931 struct TELNET
*tn
= (struct TELNET
*)data
->reqdata
.proto
.telnet
;
937 switch (tn
->telrcv_state
)
940 tn
->telrcv_state
= CURL_TS_DATA
;
943 break; /* Ignore \0 after CR */
946 Curl_client_write(conn
, CLIENTWRITE_BODY
, (char *)&c
, 1);
952 tn
->telrcv_state
= CURL_TS_IAC
;
957 tn
->telrcv_state
= CURL_TS_CR
;
960 Curl_client_write(conn
, CLIENTWRITE_BODY
, (char *)&c
, 1);
968 tn
->telrcv_state
= CURL_TS_WILL
;
971 tn
->telrcv_state
= CURL_TS_WONT
;
974 tn
->telrcv_state
= CURL_TS_DO
;
977 tn
->telrcv_state
= CURL_TS_DONT
;
981 tn
->telrcv_state
= CURL_TS_SB
;
984 Curl_client_write(conn
, CLIENTWRITE_BODY
, (char *)&c
, 1);
990 printoption(data
, "RCVD", CURL_IAC
, c
);
993 tn
->telrcv_state
= CURL_TS_DATA
;
997 printoption(data
, "RCVD", CURL_WILL
, c
);
998 tn
->please_negotiate
= 1;
1000 tn
->telrcv_state
= CURL_TS_DATA
;
1004 printoption(data
, "RCVD", CURL_WONT
, c
);
1005 tn
->please_negotiate
= 1;
1007 tn
->telrcv_state
= CURL_TS_DATA
;
1011 printoption(data
, "RCVD", CURL_DO
, c
);
1012 tn
->please_negotiate
= 1;
1014 tn
->telrcv_state
= CURL_TS_DATA
;
1018 printoption(data
, "RCVD", CURL_DONT
, c
);
1019 tn
->please_negotiate
= 1;
1021 tn
->telrcv_state
= CURL_TS_DATA
;
1027 tn
->telrcv_state
= CURL_TS_SE
;
1031 CURL_SB_ACCUM(tn
,c
);
1041 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1042 * Several things may have happend. An IAC was not doubled, the
1043 * IAC SE was left off, or another option got inserted into the
1044 * suboption are all possibilities. If we assume that the IAC was
1045 * not doubled, and really the IAC SE was left off, we could get
1046 * into an infinate loop here. So, instead, we terminate the
1047 * suboption, and process the partial suboption if we can.
1049 CURL_SB_ACCUM(tn
, CURL_IAC
);
1050 CURL_SB_ACCUM(tn
, c
);
1051 tn
->subpointer
-= 2;
1054 printoption(data
, "In SUBOPTION processing, RCVD", CURL_IAC
, c
);
1055 suboption(conn
); /* handle sub-option */
1056 tn
->telrcv_state
= CURL_TS_IAC
;
1059 CURL_SB_ACCUM(tn
,c
);
1060 tn
->telrcv_state
= CURL_TS_SB
;
1064 CURL_SB_ACCUM(tn
, CURL_IAC
);
1065 CURL_SB_ACCUM(tn
, CURL_SE
);
1066 tn
->subpointer
-= 2;
1068 suboption(conn
); /* handle sub-option */
1069 tn
->telrcv_state
= CURL_TS_DATA
;
1076 CURLcode
Curl_telnet_done(struct connectdata
*conn
, CURLcode status
, bool premature
)
1078 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->reqdata
.proto
.telnet
;
1079 (void)status
; /* unused */
1080 (void)premature
; /* not used */
1082 curl_slist_free_all(tn
->telnet_vars
);
1084 free(conn
->data
->reqdata
.proto
.telnet
);
1085 conn
->data
->reqdata
.proto
.telnet
= NULL
;
1090 CURLcode
Curl_telnet(struct connectdata
*conn
, bool *done
)
1093 struct SessionHandle
*data
= conn
->data
;
1094 curl_socket_t sockfd
= conn
->sock
[FIRSTSOCKET
];
1097 WSOCK2_FUNC close_event_func
;
1098 WSOCK2_FUNC create_event_func
;
1099 WSOCK2_FUNC event_select_func
;
1100 WSOCK2_FUNC enum_netevents_func
;
1101 WSAEVENT event_handle
;
1102 WSANETWORKEVENTS events
;
1103 HANDLE stdin_handle
;
1108 DWORD readfile_read
;
1111 struct pollfd pfd
[2];
1115 char *buf
= data
->state
.buffer
;
1118 *done
= TRUE
; /* uncontionally */
1120 code
= init_telnet(conn
);
1124 tn
= (struct TELNET
*)data
->reqdata
.proto
.telnet
;
1126 code
= check_telnet_options(conn
);
1132 ** This functionality only works with WinSock >= 2.0. So,
1133 ** make sure have it.
1135 code
= check_wsock2(data
);
1139 /* OK, so we have WinSock 2.0. We need to dynamically */
1140 /* load ws2_32.dll and get the function pointers we need. */
1141 wsock2
= LoadLibrary("WS2_32.DLL");
1142 if (wsock2
== NULL
) {
1143 failf(data
,"failed to load WS2_32.DLL (%d)",GetLastError());
1144 return CURLE_FAILED_INIT
;
1147 /* Grab a pointer to WSACreateEvent */
1148 create_event_func
= GetProcAddress(wsock2
,"WSACreateEvent");
1149 if (create_event_func
== NULL
) {
1150 failf(data
,"failed to find WSACreateEvent function (%d)",
1152 FreeLibrary(wsock2
);
1153 return CURLE_FAILED_INIT
;
1156 /* And WSACloseEvent */
1157 close_event_func
= GetProcAddress(wsock2
,"WSACloseEvent");
1158 if (close_event_func
== NULL
) {
1159 failf(data
,"failed to find WSACloseEvent function (%d)",
1161 FreeLibrary(wsock2
);
1162 return CURLE_FAILED_INIT
;
1165 /* And WSAEventSelect */
1166 event_select_func
= GetProcAddress(wsock2
,"WSAEventSelect");
1167 if (event_select_func
== NULL
) {
1168 failf(data
,"failed to find WSAEventSelect function (%d)",
1170 FreeLibrary(wsock2
);
1171 return CURLE_FAILED_INIT
;
1174 /* And WSAEnumNetworkEvents */
1175 enum_netevents_func
= GetProcAddress(wsock2
,"WSAEnumNetworkEvents");
1176 if (enum_netevents_func
== NULL
) {
1177 failf(data
,"failed to find WSAEnumNetworkEvents function (%d)",
1179 FreeLibrary(wsock2
);
1180 return CURLE_FAILED_INIT
;
1183 /* We want to wait for both stdin and the socket. Since
1184 ** the select() function in winsock only works on sockets
1185 ** we have to use the WaitForMultipleObjects() call.
1188 /* First, create a sockets event object */
1189 event_handle
= (WSAEVENT
)create_event_func();
1190 if (event_handle
== WSA_INVALID_EVENT
) {
1191 failf(data
,"WSACreateEvent failed (%d)",WSAGetLastError());
1192 FreeLibrary(wsock2
);
1193 return CURLE_FAILED_INIT
;
1196 /* The get the Windows file handle for stdin */
1197 stdin_handle
= GetStdHandle(STD_INPUT_HANDLE
);
1199 /* Create the list of objects to wait for */
1200 objs
[0] = event_handle
;
1201 objs
[1] = stdin_handle
;
1203 /* Tell winsock what events we want to listen to */
1204 if(event_select_func(sockfd
, event_handle
, FD_READ
|FD_CLOSE
) == SOCKET_ERROR
) {
1205 close_event_func(event_handle
);
1206 FreeLibrary(wsock2
);
1210 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1211 else use the old WaitForMultipleObjects() way */
1212 if(GetFileType(stdin_handle
) == FILE_TYPE_PIPE
) {
1213 /* Don't wait for stdin_handle, just wait for event_handle */
1215 /* Check stdin_handle per 100 milliseconds */
1219 wait_timeout
= INFINITE
;
1222 /* Keep on listening and act on events */
1224 waitret
= WaitForMultipleObjects(obj_count
, objs
, FALSE
, wait_timeout
);
1228 unsigned char outbuf
[2];
1230 ssize_t bytes_written
;
1234 if(!PeekNamedPipe(stdin_handle
, NULL
, 0, NULL
, &readfile_read
, NULL
)) {
1238 nread
= readfile_read
;
1243 if(!ReadFile(stdin_handle
, buf
, sizeof(data
->state
.buffer
),
1244 &readfile_read
, NULL
)) {
1248 nread
= readfile_read
;
1251 outbuf
[0] = *buffer
++;
1253 if(outbuf
[0] == CURL_IAC
)
1254 outbuf
[out_count
++] = CURL_IAC
;
1256 Curl_write(conn
, conn
->sock
[FIRSTSOCKET
], outbuf
,
1257 out_count
, &bytes_written
);
1263 case WAIT_OBJECT_0
+ 1:
1265 unsigned char outbuf
[2];
1267 ssize_t bytes_written
;
1270 if(!ReadFile(stdin_handle
, buf
, sizeof(data
->state
.buffer
),
1271 &readfile_read
, NULL
)) {
1275 nread
= readfile_read
;
1278 outbuf
[0] = *buffer
++;
1280 if(outbuf
[0] == CURL_IAC
)
1281 outbuf
[out_count
++] = CURL_IAC
;
1283 Curl_write(conn
, conn
->sock
[FIRSTSOCKET
], outbuf
,
1284 out_count
, &bytes_written
);
1290 if(enum_netevents_func(sockfd
, event_handle
, &events
)
1292 if(events
.lNetworkEvents
& FD_READ
) {
1293 /* This reallu OUGHT to check its return code. */
1294 (void)Curl_read(conn
, sockfd
, buf
, BUFSIZE
- 1, &nread
);
1296 telrcv(conn
, (unsigned char *)buf
, nread
);
1300 /* Negotiate if the peer has started negotiating,
1301 otherwise don't. We don't want to speak telnet with
1302 non-telnet servers, like POP or SMTP. */
1303 if(tn
->please_negotiate
&& !tn
->already_negotiated
) {
1305 tn
->already_negotiated
= 1;
1309 if(events
.lNetworkEvents
& FD_CLOSE
) {
1317 /* We called WSACreateEvent, so call WSACloseEvent */
1318 if (close_event_func(event_handle
) == FALSE
) {
1319 infof(data
,"WSACloseEvent failed (%d)",WSAGetLastError());
1322 /* "Forget" pointers into the library we're about to free */
1323 create_event_func
= NULL
;
1324 close_event_func
= NULL
;
1325 event_select_func
= NULL
;
1326 enum_netevents_func
= NULL
;
1328 /* We called LoadLibrary, so call FreeLibrary */
1329 if (!FreeLibrary(wsock2
))
1330 infof(data
,"FreeLibrary(wsock2) failed (%d)",GetLastError());
1333 pfd
[0].events
= POLLIN
;
1335 pfd
[1].events
= POLLIN
;
1336 interval_ms
= 1 * 1000;
1339 switch (Curl_poll(pfd
, 2, interval_ms
)) {
1340 case -1: /* error, stop reading */
1343 case 0: /* timeout */
1345 default: /* read! */
1346 if(pfd
[1].revents
& POLLIN
) { /* read from stdin */
1347 unsigned char outbuf
[2];
1349 ssize_t bytes_written
;
1352 nread
= read(0, buf
, 255);
1355 outbuf
[0] = *buffer
++;
1357 if(outbuf
[0] == CURL_IAC
)
1358 outbuf
[out_count
++] = CURL_IAC
;
1360 Curl_write(conn
, conn
->sock
[FIRSTSOCKET
], outbuf
,
1361 out_count
, &bytes_written
);
1365 if(pfd
[0].revents
& POLLIN
) {
1366 /* This OUGHT to check the return code... */
1367 (void)Curl_read(conn
, sockfd
, buf
, BUFSIZE
- 1, &nread
);
1369 /* if we receive 0 or less here, the server closed the connection and
1370 we bail out from this! */
1376 telrcv(conn
, (unsigned char *)buf
, nread
);
1378 /* Negotiate if the peer has started negotiating,
1379 otherwise don't. We don't want to speak telnet with
1380 non-telnet servers, like POP or SMTP. */
1381 if(tn
->please_negotiate
&& !tn
->already_negotiated
) {
1383 tn
->already_negotiated
= 1;
1387 if(data
->set
.timeout
) {
1388 struct timeval now
; /* current time */
1390 if(Curl_tvdiff(now
, conn
->created
)/1000 >= data
->set
.timeout
) {
1391 failf(data
, "Time-out");
1392 code
= CURLE_OPERATION_TIMEOUTED
;
1398 /* mark this as "no further transfer wanted" */
1399 Curl_setup_transfer(conn
, -1, -1, FALSE
, NULL
, -1, NULL
);