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.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_TELNET
27 /* -- WIN32 approved -- */
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #ifdef HAVE_SYS_TIME_H
49 #ifdef HAVE_ARPA_INET_H
50 #include <arpa/inet.h>
55 #include <sys/ioctl.h>
58 #ifdef HAVE_SYS_PARAM_H
59 #include <sys/param.h>
65 #include <curl/curl.h>
71 #define _MPRINTF_REPLACE /* use our functions only */
72 #include <curl/mprintf.h>
77 #include "arpa_telnet.h"
81 /* The last #include file should be: */
84 #define SUBBUFSIZE 512
86 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer;
87 #define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
88 #define CURL_SB_ACCUM(x,c) \
89 if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
90 *x->subpointer++ = (c); \
93 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
94 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
95 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
96 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
98 #ifdef CURL_DISABLE_VERBOSE_STRINGS
99 #define printoption(a,b,c,d) do { } while(0)
103 typedef FARPROC WSOCK2_FUNC
;
104 static CURLcode
check_wsock2 ( struct SessionHandle
*data
);
108 void telrcv(struct connectdata
*,
109 const unsigned char *inbuf
, /* Data received from socket */
110 ssize_t count
); /* Number of bytes received */
112 #ifndef CURL_DISABLE_VERBOSE_STRINGS
113 static void printoption(struct SessionHandle
*data
,
114 const char *direction
,
115 int cmd
, int option
);
118 static void negotiate(struct connectdata
*);
119 static void send_negotiation(struct connectdata
*, int cmd
, int option
);
120 static void set_local_option(struct connectdata
*, int cmd
, int option
);
121 static void set_remote_option(struct connectdata
*, int cmd
, int option
);
123 static void printsub(struct SessionHandle
*data
,
124 int direction
, unsigned char *pointer
,
126 static void suboption(struct connectdata
*);
128 static CURLcode
telnet_do(struct connectdata
*conn
, bool *done
);
129 static CURLcode
telnet_done(struct connectdata
*conn
,
130 CURLcode
, bool premature
);
132 /* For negotiation compliant to RFC 1143 */
135 #define CURL_WANTYES 2
136 #define CURL_WANTNO 3
139 #define CURL_OPPOSITE 1
142 * Telnet receiver states for fsm
153 CURL_TS_SB
, /* sub-option collection */
154 CURL_TS_SE
/* looking for sub-option end */
158 int please_negotiate
;
159 int already_negotiated
;
162 int us_preferred
[256];
165 int him_preferred
[256];
166 char subopt_ttype
[32]; /* Set with suboption TTYPE */
167 char subopt_xdisploc
[128]; /* Set with suboption XDISPLOC */
168 struct curl_slist
*telnet_vars
; /* Environment variables */
171 unsigned char subbuffer
[SUBBUFSIZE
];
172 unsigned char *subpointer
, *subend
; /* buffer for sub-options */
174 TelnetReceive telrcv_state
;
179 * TELNET protocol handler.
182 const struct Curl_handler Curl_handler_telnet
= {
183 "TELNET", /* scheme */
184 ZERO_NULL
, /* setup_connection */
185 telnet_do
, /* do_it */
186 telnet_done
, /* done */
187 ZERO_NULL
, /* do_more */
188 ZERO_NULL
, /* connect_it */
189 ZERO_NULL
, /* connecting */
190 ZERO_NULL
, /* doing */
191 ZERO_NULL
, /* proto_getsock */
192 ZERO_NULL
, /* doing_getsock */
193 ZERO_NULL
, /* disconnect */
194 PORT_TELNET
, /* defport */
195 PROT_TELNET
/* protocol */
201 check_wsock2 ( struct SessionHandle
*data
)
204 WORD wVersionRequested
;
209 /* telnet requires at least WinSock 2.0 so ask for it. */
210 wVersionRequested
= MAKEWORD(2, 0);
212 err
= WSAStartup(wVersionRequested
, &wsaData
);
214 /* We must've called this once already, so this call */
215 /* should always succeed. But, just in case... */
217 failf(data
,"WSAStartup failed (%d)",err
);
218 return CURLE_FAILED_INIT
;
221 /* We have to have a WSACleanup call for every successful */
222 /* WSAStartup call. */
225 /* Check that our version is supported */
226 if(LOBYTE(wsaData
.wVersion
) != LOBYTE(wVersionRequested
) ||
227 HIBYTE(wsaData
.wVersion
) != HIBYTE(wVersionRequested
)) {
228 /* Our version isn't supported */
229 failf(data
,"insufficient winsock version to support "
231 return CURLE_FAILED_INIT
;
234 /* Our version is supported */
240 CURLcode
init_telnet(struct connectdata
*conn
)
244 tn
= (struct TELNET
*)calloc(1, sizeof(struct TELNET
));
246 return CURLE_OUT_OF_MEMORY
;
248 conn
->data
->state
.proto
.telnet
= (void *)tn
; /* make us known */
250 tn
->telrcv_state
= CURL_TS_DATA
;
252 /* Init suboptions */
255 /* Set the options we want by default */
256 tn
->us_preferred
[CURL_TELOPT_BINARY
] = CURL_YES
;
257 tn
->us_preferred
[CURL_TELOPT_SGA
] = CURL_YES
;
258 tn
->him_preferred
[CURL_TELOPT_BINARY
] = CURL_YES
;
259 tn
->him_preferred
[CURL_TELOPT_SGA
] = CURL_YES
;
264 static void negotiate(struct connectdata
*conn
)
267 struct TELNET
*tn
= (struct TELNET
*) conn
->data
->state
.proto
.telnet
;
269 for(i
= 0;i
< CURL_NTELOPTS
;i
++)
271 if(tn
->us_preferred
[i
] == CURL_YES
)
272 set_local_option(conn
, i
, CURL_YES
);
274 if(tn
->him_preferred
[i
] == CURL_YES
)
275 set_remote_option(conn
, i
, CURL_YES
);
279 #ifndef CURL_DISABLE_VERBOSE_STRINGS
280 static void printoption(struct SessionHandle
*data
,
281 const char *direction
, int cmd
, int option
)
286 if(data
->set
.verbose
)
290 if(CURL_TELCMD_OK(option
))
291 infof(data
, "%s IAC %s\n", direction
, CURL_TELCMD(option
));
293 infof(data
, "%s IAC %d\n", direction
, option
);
297 fmt
= (cmd
== CURL_WILL
) ? "WILL" : (cmd
== CURL_WONT
) ? "WONT" :
298 (cmd
== CURL_DO
) ? "DO" : (cmd
== CURL_DONT
) ? "DONT" : 0;
301 if(CURL_TELOPT_OK(option
))
302 opt
= CURL_TELOPT(option
);
303 else if(option
== CURL_TELOPT_EXOPL
)
309 infof(data
, "%s %s %s\n", direction
, fmt
, opt
);
311 infof(data
, "%s %s %d\n", direction
, fmt
, option
);
314 infof(data
, "%s %d %d\n", direction
, cmd
, option
);
320 static void send_negotiation(struct connectdata
*conn
, int cmd
, int option
)
322 unsigned char buf
[3];
323 ssize_t bytes_written
;
325 struct SessionHandle
*data
= conn
->data
;
328 buf
[1] = (unsigned char)cmd
;
329 buf
[2] = (unsigned char)option
;
331 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], buf
, 3);
332 if(bytes_written
< 0) {
334 failf(data
,"Sending data failed (%d)",err
);
337 printoption(conn
->data
, "SENT", cmd
, option
);
341 void set_remote_option(struct connectdata
*conn
, int option
, int newstate
)
343 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
344 if(newstate
== CURL_YES
)
346 switch(tn
->him
[option
])
349 tn
->him
[option
] = CURL_WANTYES
;
350 send_negotiation(conn
, CURL_DO
, option
);
354 /* Already enabled */
358 switch(tn
->himq
[option
])
361 /* Already negotiating for CURL_YES, queue the request */
362 tn
->himq
[option
] = CURL_OPPOSITE
;
365 /* Error: already queued an enable request */
371 switch(tn
->himq
[option
])
374 /* Error: already negotiating for enable */
377 tn
->himq
[option
] = CURL_EMPTY
;
385 switch(tn
->him
[option
])
388 /* Already disabled */
392 tn
->him
[option
] = CURL_WANTNO
;
393 send_negotiation(conn
, CURL_DONT
, option
);
397 switch(tn
->himq
[option
])
400 /* Already negotiating for NO */
403 tn
->himq
[option
] = CURL_EMPTY
;
409 switch(tn
->himq
[option
])
412 tn
->himq
[option
] = CURL_OPPOSITE
;
423 void rec_will(struct connectdata
*conn
, int option
)
425 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
426 switch(tn
->him
[option
])
429 if(tn
->him_preferred
[option
] == CURL_YES
)
431 tn
->him
[option
] = CURL_YES
;
432 send_negotiation(conn
, CURL_DO
, option
);
436 send_negotiation(conn
, CURL_DONT
, option
);
441 /* Already enabled */
445 switch(tn
->himq
[option
])
448 /* Error: DONT answered by WILL */
449 tn
->him
[option
] = CURL_NO
;
452 /* Error: DONT answered by WILL */
453 tn
->him
[option
] = CURL_YES
;
454 tn
->himq
[option
] = CURL_EMPTY
;
460 switch(tn
->himq
[option
])
463 tn
->him
[option
] = CURL_YES
;
466 tn
->him
[option
] = CURL_WANTNO
;
467 tn
->himq
[option
] = CURL_EMPTY
;
468 send_negotiation(conn
, CURL_DONT
, option
);
476 void rec_wont(struct connectdata
*conn
, int option
)
478 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
479 switch(tn
->him
[option
])
482 /* Already disabled */
486 tn
->him
[option
] = CURL_NO
;
487 send_negotiation(conn
, CURL_DONT
, option
);
491 switch(tn
->himq
[option
])
494 tn
->him
[option
] = CURL_NO
;
498 tn
->him
[option
] = CURL_WANTYES
;
499 tn
->himq
[option
] = CURL_EMPTY
;
500 send_negotiation(conn
, CURL_DO
, option
);
506 switch(tn
->himq
[option
])
509 tn
->him
[option
] = CURL_NO
;
512 tn
->him
[option
] = CURL_NO
;
513 tn
->himq
[option
] = CURL_EMPTY
;
521 set_local_option(struct connectdata
*conn
, int option
, int newstate
)
523 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
524 if(newstate
== CURL_YES
)
526 switch(tn
->us
[option
])
529 tn
->us
[option
] = CURL_WANTYES
;
530 send_negotiation(conn
, CURL_WILL
, option
);
534 /* Already enabled */
538 switch(tn
->usq
[option
])
541 /* Already negotiating for CURL_YES, queue the request */
542 tn
->usq
[option
] = CURL_OPPOSITE
;
545 /* Error: already queued an enable request */
551 switch(tn
->usq
[option
])
554 /* Error: already negotiating for enable */
557 tn
->usq
[option
] = CURL_EMPTY
;
565 switch(tn
->us
[option
])
568 /* Already disabled */
572 tn
->us
[option
] = CURL_WANTNO
;
573 send_negotiation(conn
, CURL_WONT
, option
);
577 switch(tn
->usq
[option
])
580 /* Already negotiating for NO */
583 tn
->usq
[option
] = CURL_EMPTY
;
589 switch(tn
->usq
[option
])
592 tn
->usq
[option
] = CURL_OPPOSITE
;
603 void rec_do(struct connectdata
*conn
, int option
)
605 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
606 switch(tn
->us
[option
])
609 if(tn
->us_preferred
[option
] == CURL_YES
)
611 tn
->us
[option
] = CURL_YES
;
612 send_negotiation(conn
, CURL_WILL
, option
);
616 send_negotiation(conn
, CURL_WONT
, option
);
621 /* Already enabled */
625 switch(tn
->usq
[option
])
628 /* Error: DONT answered by WILL */
629 tn
->us
[option
] = CURL_NO
;
632 /* Error: DONT answered by WILL */
633 tn
->us
[option
] = CURL_YES
;
634 tn
->usq
[option
] = CURL_EMPTY
;
640 switch(tn
->usq
[option
])
643 tn
->us
[option
] = CURL_YES
;
646 tn
->us
[option
] = CURL_WANTNO
;
647 tn
->himq
[option
] = CURL_EMPTY
;
648 send_negotiation(conn
, CURL_WONT
, option
);
656 void rec_dont(struct connectdata
*conn
, int option
)
658 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
659 switch(tn
->us
[option
])
662 /* Already disabled */
666 tn
->us
[option
] = CURL_NO
;
667 send_negotiation(conn
, CURL_WONT
, option
);
671 switch(tn
->usq
[option
])
674 tn
->us
[option
] = CURL_NO
;
678 tn
->us
[option
] = CURL_WANTYES
;
679 tn
->usq
[option
] = CURL_EMPTY
;
680 send_negotiation(conn
, CURL_WILL
, option
);
686 switch(tn
->usq
[option
])
689 tn
->us
[option
] = CURL_NO
;
692 tn
->us
[option
] = CURL_NO
;
693 tn
->usq
[option
] = CURL_EMPTY
;
701 static void printsub(struct SessionHandle
*data
,
702 int direction
, /* '<' or '>' */
703 unsigned char *pointer
, /* where suboption data is */
704 size_t length
) /* length of suboption data */
708 if(data
->set
.verbose
)
712 infof(data
, "%s IAC SB ", (direction
== '<')? "RCVD":"SENT");
717 i
= pointer
[length
-2];
718 j
= pointer
[length
-1];
720 if(i
!= CURL_IAC
|| j
!= CURL_SE
)
722 infof(data
, "(terminated by ");
723 if(CURL_TELOPT_OK(i
))
724 infof(data
, "%s ", CURL_TELOPT(i
));
725 else if(CURL_TELCMD_OK(i
))
726 infof(data
, "%s ", CURL_TELCMD(i
));
728 infof(data
, "%d ", i
);
729 if(CURL_TELOPT_OK(j
))
730 infof(data
, "%s", CURL_TELOPT(j
));
731 else if(CURL_TELCMD_OK(j
))
732 infof(data
, "%s", CURL_TELCMD(j
));
734 infof(data
, "%d", j
);
735 infof(data
, ", not IAC SE!) ");
742 infof(data
, "(Empty suboption?)");
746 if(CURL_TELOPT_OK(pointer
[0])) {
748 case CURL_TELOPT_TTYPE
:
749 case CURL_TELOPT_XDISPLOC
:
750 case CURL_TELOPT_NEW_ENVIRON
:
751 infof(data
, "%s", CURL_TELOPT(pointer
[0]));
754 infof(data
, "%s (unsupported)", CURL_TELOPT(pointer
[0]));
759 infof(data
, "%d (unknown)", pointer
[i
]);
762 case CURL_TELQUAL_IS
:
765 case CURL_TELQUAL_SEND
:
766 infof(data
, " SEND");
768 case CURL_TELQUAL_INFO
:
769 infof(data
, " INFO/REPLY");
771 case CURL_TELQUAL_NAME
:
772 infof(data
, " NAME");
777 case CURL_TELOPT_TTYPE
:
778 case CURL_TELOPT_XDISPLOC
:
780 infof(data
, " \"%s\"", &pointer
[2]);
782 case CURL_TELOPT_NEW_ENVIRON
:
783 if(pointer
[1] == CURL_TELQUAL_IS
) {
785 for(i
= 3;i
< length
;i
++) {
787 case CURL_NEW_ENV_VAR
:
790 case CURL_NEW_ENV_VALUE
:
794 infof(data
, "%c", pointer
[i
]);
801 for (i
= 2; i
< length
; i
++)
802 infof(data
, " %.2x", pointer
[i
]);
813 static CURLcode
check_telnet_options(struct connectdata
*conn
)
815 struct curl_slist
*head
;
816 char option_keyword
[128];
817 char option_arg
[256];
819 struct SessionHandle
*data
= conn
->data
;
820 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
822 /* Add the user name as an environment variable if it
823 was given on the command line */
824 if(conn
->bits
.user_passwd
)
826 snprintf(option_arg
, sizeof(option_arg
), "USER,%s", conn
->user
);
827 tn
->telnet_vars
= curl_slist_append(tn
->telnet_vars
, option_arg
);
829 tn
->us_preferred
[CURL_TELOPT_NEW_ENVIRON
] = CURL_YES
;
832 for(head
= data
->set
.telnet_options
; head
; head
=head
->next
) {
833 if(sscanf(head
->data
, "%127[^= ]%*[ =]%255s",
834 option_keyword
, option_arg
) == 2) {
837 if(curl_strequal(option_keyword
, "TTYPE")) {
838 strncpy(tn
->subopt_ttype
, option_arg
, 31);
839 tn
->subopt_ttype
[31] = 0; /* String termination */
840 tn
->us_preferred
[CURL_TELOPT_TTYPE
] = CURL_YES
;
844 /* Display variable */
845 if(curl_strequal(option_keyword
, "XDISPLOC")) {
846 strncpy(tn
->subopt_xdisploc
, option_arg
, 127);
847 tn
->subopt_xdisploc
[127] = 0; /* String termination */
848 tn
->us_preferred
[CURL_TELOPT_XDISPLOC
] = CURL_YES
;
852 /* Environment variable */
853 if(curl_strequal(option_keyword
, "NEW_ENV")) {
854 buf
= strdup(option_arg
);
856 return CURLE_OUT_OF_MEMORY
;
857 tn
->telnet_vars
= curl_slist_append(tn
->telnet_vars
, buf
);
858 tn
->us_preferred
[CURL_TELOPT_NEW_ENVIRON
] = CURL_YES
;
862 failf(data
, "Unknown telnet option %s", head
->data
);
863 return CURLE_UNKNOWN_TELNET_OPTION
;
865 failf(data
, "Syntax error in telnet option: %s", head
->data
);
866 return CURLE_TELNET_OPTION_SYNTAX
;
876 * Look at the sub-option buffer, and try to be helpful to the other
880 static void suboption(struct connectdata
*conn
)
882 struct curl_slist
*v
;
883 unsigned char temp
[2048];
884 ssize_t bytes_written
;
890 struct SessionHandle
*data
= conn
->data
;
891 struct TELNET
*tn
= (struct TELNET
*)data
->state
.proto
.telnet
;
893 printsub(data
, '<', (unsigned char *)tn
->subbuffer
, CURL_SB_LEN(tn
)+2);
894 switch (CURL_SB_GET(tn
)) {
895 case CURL_TELOPT_TTYPE
:
896 len
= strlen(tn
->subopt_ttype
) + 4 + 2;
897 snprintf((char *)temp
, sizeof(temp
),
898 "%c%c%c%c%s%c%c", CURL_IAC
, CURL_SB
, CURL_TELOPT_TTYPE
,
899 CURL_TELQUAL_IS
, tn
->subopt_ttype
, CURL_IAC
, CURL_SE
);
900 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], temp
, len
);
901 if(bytes_written
< 0) {
903 failf(data
,"Sending data failed (%d)",err
);
905 printsub(data
, '>', &temp
[2], len
-2);
907 case CURL_TELOPT_XDISPLOC
:
908 len
= strlen(tn
->subopt_xdisploc
) + 4 + 2;
909 snprintf((char *)temp
, sizeof(temp
),
910 "%c%c%c%c%s%c%c", CURL_IAC
, CURL_SB
, CURL_TELOPT_XDISPLOC
,
911 CURL_TELQUAL_IS
, tn
->subopt_xdisploc
, CURL_IAC
, CURL_SE
);
912 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], temp
, len
);
913 if(bytes_written
< 0) {
915 failf(data
,"Sending data failed (%d)",err
);
917 printsub(data
, '>', &temp
[2], len
-2);
919 case CURL_TELOPT_NEW_ENVIRON
:
920 snprintf((char *)temp
, sizeof(temp
),
921 "%c%c%c%c", CURL_IAC
, CURL_SB
, CURL_TELOPT_NEW_ENVIRON
,
925 for(v
= tn
->telnet_vars
;v
;v
= v
->next
) {
926 tmplen
= (strlen(v
->data
) + 1);
927 /* Add the variable only if it fits */
928 if(len
+ tmplen
< (int)sizeof(temp
)-6) {
929 sscanf(v
->data
, "%127[^,],%127s", varname
, varval
);
930 snprintf((char *)&temp
[len
], sizeof(temp
) - len
,
931 "%c%s%c%s", CURL_NEW_ENV_VAR
, varname
,
932 CURL_NEW_ENV_VALUE
, varval
);
936 snprintf((char *)&temp
[len
], sizeof(temp
) - len
,
937 "%c%c", CURL_IAC
, CURL_SE
);
939 bytes_written
= swrite(conn
->sock
[FIRSTSOCKET
], temp
, len
);
940 if(bytes_written
< 0) {
942 failf(data
,"Sending data failed (%d)",err
);
944 printsub(data
, '>', &temp
[2], len
-2);
951 void telrcv(struct connectdata
*conn
,
952 const unsigned char *inbuf
, /* Data received from socket */
953 ssize_t count
) /* Number of bytes received */
958 struct SessionHandle
*data
= conn
->data
;
959 struct TELNET
*tn
= (struct TELNET
*)data
->state
.proto
.telnet
;
961 #define startskipping() \
962 if(startwrite >= 0) \
963 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&inbuf[startwrite], in-startwrite); \
966 #define writebyte() \
970 #define bufferflush() startskipping()
976 /*infof(data,"In rcv state %d char %d\n", tn->telrcv_state, c);*/
977 switch (tn
->telrcv_state
)
980 tn
->telrcv_state
= CURL_TS_DATA
;
984 break; /* Ignore \0 after CR */
992 tn
->telrcv_state
= CURL_TS_IAC
;
998 tn
->telrcv_state
= CURL_TS_CR
;
1005 DEBUGASSERT(startwrite
< 0);
1009 tn
->telrcv_state
= CURL_TS_WILL
;
1012 tn
->telrcv_state
= CURL_TS_WONT
;
1015 tn
->telrcv_state
= CURL_TS_DO
;
1018 tn
->telrcv_state
= CURL_TS_DONT
;
1022 tn
->telrcv_state
= CURL_TS_SB
;
1025 tn
->telrcv_state
= CURL_TS_DATA
;
1032 tn
->telrcv_state
= CURL_TS_DATA
;
1033 printoption(data
, "RCVD", CURL_IAC
, c
);
1039 printoption(data
, "RCVD", CURL_WILL
, c
);
1040 tn
->please_negotiate
= 1;
1042 tn
->telrcv_state
= CURL_TS_DATA
;
1046 printoption(data
, "RCVD", CURL_WONT
, c
);
1047 tn
->please_negotiate
= 1;
1049 tn
->telrcv_state
= CURL_TS_DATA
;
1053 printoption(data
, "RCVD", CURL_DO
, c
);
1054 tn
->please_negotiate
= 1;
1056 tn
->telrcv_state
= CURL_TS_DATA
;
1060 printoption(data
, "RCVD", CURL_DONT
, c
);
1061 tn
->please_negotiate
= 1;
1063 tn
->telrcv_state
= CURL_TS_DATA
;
1069 tn
->telrcv_state
= CURL_TS_SE
;
1073 CURL_SB_ACCUM(tn
,c
);
1083 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1084 * Several things may have happend. An IAC was not doubled, the
1085 * IAC SE was left off, or another option got inserted into the
1086 * suboption are all possibilities. If we assume that the IAC was
1087 * not doubled, and really the IAC SE was left off, we could get
1088 * into an infinate loop here. So, instead, we terminate the
1089 * suboption, and process the partial suboption if we can.
1091 CURL_SB_ACCUM(tn
, CURL_IAC
);
1092 CURL_SB_ACCUM(tn
, c
);
1093 tn
->subpointer
-= 2;
1096 printoption(data
, "In SUBOPTION processing, RCVD", CURL_IAC
, c
);
1097 suboption(conn
); /* handle sub-option */
1098 tn
->telrcv_state
= CURL_TS_IAC
;
1101 CURL_SB_ACCUM(tn
,c
);
1102 tn
->telrcv_state
= CURL_TS_SB
;
1106 CURL_SB_ACCUM(tn
, CURL_IAC
);
1107 CURL_SB_ACCUM(tn
, CURL_SE
);
1108 tn
->subpointer
-= 2;
1110 suboption(conn
); /* handle sub-option */
1111 tn
->telrcv_state
= CURL_TS_DATA
;
1120 /* Escape and send a telnet data block */
1121 /* TODO: write large chunks of data instead of one byte at a time */
1122 static CURLcode
send_telnet_data(struct connectdata
*conn
,
1123 char *buffer
, ssize_t nread
)
1125 unsigned char outbuf
[2];
1126 ssize_t bytes_written
, total_written
;
1128 CURLcode rc
= CURLE_OK
;
1130 while(rc
== CURLE_OK
&& nread
--) {
1131 outbuf
[0] = *buffer
++;
1133 if(outbuf
[0] == CURL_IAC
)
1134 outbuf
[out_count
++] = CURL_IAC
;
1138 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1139 struct pollfd pfd
[1];
1140 pfd
[0].fd
= conn
->sock
[FIRSTSOCKET
];
1141 pfd
[0].events
= POLLOUT
;
1142 switch (Curl_poll(pfd
, 1, -1)) {
1143 case -1: /* error, abort writing */
1144 case 0: /* timeout (will never happen) */
1145 rc
= CURLE_SEND_ERROR
;
1147 default: /* write! */
1149 rc
= Curl_write(conn
, conn
->sock
[FIRSTSOCKET
], outbuf
+total_written
,
1150 out_count
-total_written
, &bytes_written
);
1151 total_written
+= bytes_written
;
1154 /* handle partial write */
1155 } while (rc
== CURLE_OK
&& total_written
< out_count
);
1160 static CURLcode
telnet_done(struct connectdata
*conn
,
1161 CURLcode status
, bool premature
)
1163 struct TELNET
*tn
= (struct TELNET
*)conn
->data
->state
.proto
.telnet
;
1164 (void)status
; /* unused */
1165 (void)premature
; /* not used */
1167 curl_slist_free_all(tn
->telnet_vars
);
1169 free(conn
->data
->state
.proto
.telnet
);
1170 conn
->data
->state
.proto
.telnet
= NULL
;
1175 static CURLcode
telnet_do(struct connectdata
*conn
, bool *done
)
1178 struct SessionHandle
*data
= conn
->data
;
1179 curl_socket_t sockfd
= conn
->sock
[FIRSTSOCKET
];
1182 WSOCK2_FUNC close_event_func
;
1183 WSOCK2_FUNC create_event_func
;
1184 WSOCK2_FUNC event_select_func
;
1185 WSOCK2_FUNC enum_netevents_func
;
1186 WSAEVENT event_handle
;
1187 WSANETWORKEVENTS events
;
1188 HANDLE stdin_handle
;
1193 DWORD readfile_read
;
1196 struct pollfd pfd
[2];
1200 char *buf
= data
->state
.buffer
;
1203 *done
= TRUE
; /* unconditionally */
1205 code
= init_telnet(conn
);
1209 tn
= (struct TELNET
*)data
->state
.proto
.telnet
;
1211 code
= check_telnet_options(conn
);
1217 ** This functionality only works with WinSock >= 2.0. So,
1218 ** make sure have it.
1220 code
= check_wsock2(data
);
1224 /* OK, so we have WinSock 2.0. We need to dynamically */
1225 /* load ws2_32.dll and get the function pointers we need. */
1226 wsock2
= LoadLibrary("WS2_32.DLL");
1227 if(wsock2
== NULL
) {
1228 failf(data
,"failed to load WS2_32.DLL (%d)", ERRNO
);
1229 return CURLE_FAILED_INIT
;
1232 /* Grab a pointer to WSACreateEvent */
1233 create_event_func
= GetProcAddress(wsock2
,"WSACreateEvent");
1234 if(create_event_func
== NULL
) {
1235 failf(data
,"failed to find WSACreateEvent function (%d)",
1237 FreeLibrary(wsock2
);
1238 return CURLE_FAILED_INIT
;
1241 /* And WSACloseEvent */
1242 close_event_func
= GetProcAddress(wsock2
,"WSACloseEvent");
1243 if(close_event_func
== NULL
) {
1244 failf(data
,"failed to find WSACloseEvent function (%d)",
1246 FreeLibrary(wsock2
);
1247 return CURLE_FAILED_INIT
;
1250 /* And WSAEventSelect */
1251 event_select_func
= GetProcAddress(wsock2
,"WSAEventSelect");
1252 if(event_select_func
== NULL
) {
1253 failf(data
,"failed to find WSAEventSelect function (%d)",
1255 FreeLibrary(wsock2
);
1256 return CURLE_FAILED_INIT
;
1259 /* And WSAEnumNetworkEvents */
1260 enum_netevents_func
= GetProcAddress(wsock2
,"WSAEnumNetworkEvents");
1261 if(enum_netevents_func
== NULL
) {
1262 failf(data
,"failed to find WSAEnumNetworkEvents function (%d)",
1264 FreeLibrary(wsock2
);
1265 return CURLE_FAILED_INIT
;
1268 /* We want to wait for both stdin and the socket. Since
1269 ** the select() function in winsock only works on sockets
1270 ** we have to use the WaitForMultipleObjects() call.
1273 /* First, create a sockets event object */
1274 event_handle
= (WSAEVENT
)create_event_func();
1275 if(event_handle
== WSA_INVALID_EVENT
) {
1276 failf(data
,"WSACreateEvent failed (%d)", SOCKERRNO
);
1277 FreeLibrary(wsock2
);
1278 return CURLE_FAILED_INIT
;
1281 /* The get the Windows file handle for stdin */
1282 stdin_handle
= GetStdHandle(STD_INPUT_HANDLE
);
1284 /* Create the list of objects to wait for */
1285 objs
[0] = event_handle
;
1286 objs
[1] = stdin_handle
;
1288 /* Tell winsock what events we want to listen to */
1289 if(event_select_func(sockfd
, event_handle
, FD_READ
|FD_CLOSE
) == SOCKET_ERROR
) {
1290 close_event_func(event_handle
);
1291 FreeLibrary(wsock2
);
1295 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1296 else use the old WaitForMultipleObjects() way */
1297 if(GetFileType(stdin_handle
) == FILE_TYPE_PIPE
) {
1298 /* Don't wait for stdin_handle, just wait for event_handle */
1300 /* Check stdin_handle per 100 milliseconds */
1304 wait_timeout
= INFINITE
;
1307 /* Keep on listening and act on events */
1309 waitret
= WaitForMultipleObjects(obj_count
, objs
, FALSE
, wait_timeout
);
1314 if(!PeekNamedPipe(stdin_handle
, NULL
, 0, NULL
, &readfile_read
, NULL
)) {
1316 code
= CURLE_READ_ERROR
;
1323 if(!ReadFile(stdin_handle
, buf
, sizeof(data
->state
.buffer
),
1324 &readfile_read
, NULL
)) {
1326 code
= CURLE_READ_ERROR
;
1330 code
= send_telnet_data(conn
, buf
, readfile_read
);
1339 case WAIT_OBJECT_0
+ 1:
1341 if(!ReadFile(stdin_handle
, buf
, sizeof(data
->state
.buffer
),
1342 &readfile_read
, NULL
)) {
1344 code
= CURLE_READ_ERROR
;
1348 code
= send_telnet_data(conn
, buf
, readfile_read
);
1357 if(enum_netevents_func(sockfd
, event_handle
, &events
)
1359 if(events
.lNetworkEvents
& FD_READ
) {
1360 /* This reallu OUGHT to check its return code. */
1361 (void)Curl_read(conn
, sockfd
, buf
, BUFSIZE
- 1, &nread
);
1363 telrcv(conn
, (unsigned char *)buf
, nread
);
1367 /* Negotiate if the peer has started negotiating,
1368 otherwise don't. We don't want to speak telnet with
1369 non-telnet servers, like POP or SMTP. */
1370 if(tn
->please_negotiate
&& !tn
->already_negotiated
) {
1372 tn
->already_negotiated
= 1;
1376 if(events
.lNetworkEvents
& FD_CLOSE
) {
1384 /* We called WSACreateEvent, so call WSACloseEvent */
1385 if(close_event_func(event_handle
) == FALSE
) {
1386 infof(data
,"WSACloseEvent failed (%d)", SOCKERRNO
);
1389 /* "Forget" pointers into the library we're about to free */
1390 create_event_func
= NULL
;
1391 close_event_func
= NULL
;
1392 event_select_func
= NULL
;
1393 enum_netevents_func
= NULL
;
1395 /* We called LoadLibrary, so call FreeLibrary */
1396 if(!FreeLibrary(wsock2
))
1397 infof(data
,"FreeLibrary(wsock2) failed (%d)", ERRNO
);
1400 pfd
[0].events
= POLLIN
;
1402 pfd
[1].events
= POLLIN
;
1403 interval_ms
= 1 * 1000;
1406 switch (Curl_poll(pfd
, 2, interval_ms
)) {
1407 case -1: /* error, stop reading */
1410 case 0: /* timeout */
1412 default: /* read! */
1413 if(pfd
[1].revents
& POLLIN
) { /* read from stdin */
1414 nread
= read(0, buf
, 255);
1415 code
= send_telnet_data(conn
, buf
, nread
);
1422 if(pfd
[0].revents
& POLLIN
) {
1423 /* This OUGHT to check the return code... */
1424 (void)Curl_read(conn
, sockfd
, buf
, BUFSIZE
- 1, &nread
);
1426 /* if we receive 0 or less here, the server closed the connection and
1427 we bail out from this! */
1433 telrcv(conn
, (unsigned char *)buf
, nread
);
1435 /* Negotiate if the peer has started negotiating,
1436 otherwise don't. We don't want to speak telnet with
1437 non-telnet servers, like POP or SMTP. */
1438 if(tn
->please_negotiate
&& !tn
->already_negotiated
) {
1440 tn
->already_negotiated
= 1;
1444 if(data
->set
.timeout
) {
1445 struct timeval now
; /* current time */
1447 if(Curl_tvdiff(now
, conn
->created
) >= data
->set
.timeout
) {
1448 failf(data
, "Time-out");
1449 code
= CURLE_OPERATION_TIMEDOUT
;
1455 /* mark this as "no further transfer wanted" */
1456 Curl_setup_transfer(conn
, -1, -1, FALSE
, NULL
, -1, NULL
);