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 ***************************************************************************/
25 #ifndef CURL_DISABLE_TELNET
27 #ifdef HAVE_SYS_SOCKET_H
28 #include <sys/socket.h>
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
39 #ifdef HAVE_ARPA_INET_H
40 #include <arpa/inet.h>
45 #ifdef HAVE_SYS_IOCTL_H
46 #include <sys/ioctl.h>
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h>
54 #include <curl/curl.h>
61 #define _MPRINTF_REPLACE /* use our functions only */
62 #include <curl/mprintf.h>
67 #include "arpa_telnet.h"
68 #include "curl_memory.h"
74 /* The last #include file should be: */
77 #define SUBBUFSIZE 512
79 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
80 #define CURL_SB_TERM(x) \
82 x->subend = x->subpointer; \
85 #define CURL_SB_ACCUM(x,c) \
87 if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
88 *x->subpointer++ = (c); \
91 #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
92 #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
93 #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
94 #define CURL_SB_LEN(x) (x->subend - x->subpointer)
96 #ifdef CURL_DISABLE_VERBOSE_STRINGS
97 #define printoption(a,b,c,d) Curl_nop_stmt
101 typedef FARPROC WSOCK2_FUNC;
102 static CURLcode check_wsock2 ( struct SessionHandle *data );
106 CURLcode telrcv(struct connectdata *,
107 const unsigned char *inbuf, /* Data received from socket */
108 ssize_t count); /* Number of bytes received */
110 #ifndef CURL_DISABLE_VERBOSE_STRINGS
111 static void printoption(struct SessionHandle *data,
112 const char *direction,
113 int cmd, int option);
116 static void negotiate(struct connectdata *);
117 static void send_negotiation(struct connectdata *, int cmd, int option);
118 static void set_local_option(struct connectdata *, int cmd, int option);
119 static void set_remote_option(struct connectdata *, int cmd, int option);
121 static void printsub(struct SessionHandle *data,
122 int direction, unsigned char *pointer,
124 static void suboption(struct connectdata *);
125 static void sendsuboption(struct connectdata *conn, int option);
127 static CURLcode telnet_do(struct connectdata *conn, bool *done);
128 static CURLcode telnet_done(struct connectdata *conn,
129 CURLcode, bool premature);
130 static CURLcode send_telnet_data(struct connectdata *conn,
131 char *buffer, ssize_t nread);
133 /* For negotiation compliant to RFC 1143 */
136 #define CURL_WANTYES 2
137 #define CURL_WANTNO 3
140 #define CURL_OPPOSITE 1
143 * Telnet receiver states for fsm
154 CURL_TS_SB, /* sub-option collection */
155 CURL_TS_SE /* looking for sub-option end */
159 int please_negotiate;
160 int already_negotiated;
163 int us_preferred[256];
166 int him_preferred[256];
167 int subnegotiation[256];
168 char subopt_ttype[32]; /* Set with suboption TTYPE */
169 char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
170 unsigned short subopt_wsx; /* Set with suboption NAWS */
171 unsigned short subopt_wsy; /* Set with suboption NAWS */
172 struct curl_slist *telnet_vars; /* Environment variables */
175 unsigned char subbuffer[SUBBUFSIZE];
176 unsigned char *subpointer, *subend; /* buffer for sub-options */
178 TelnetReceive telrcv_state;
183 * TELNET protocol handler.
186 const struct Curl_handler Curl_handler_telnet = {
187 "TELNET", /* scheme */
188 ZERO_NULL, /* setup_connection */
189 telnet_do, /* do_it */
190 telnet_done, /* done */
191 ZERO_NULL, /* do_more */
192 ZERO_NULL, /* connect_it */
193 ZERO_NULL, /* connecting */
194 ZERO_NULL, /* doing */
195 ZERO_NULL, /* proto_getsock */
196 ZERO_NULL, /* doing_getsock */
197 ZERO_NULL, /* domore_getsock */
198 ZERO_NULL, /* perform_getsock */
199 ZERO_NULL, /* disconnect */
200 ZERO_NULL, /* readwrite */
201 PORT_TELNET, /* defport */
202 CURLPROTO_TELNET, /* protocol */
203 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
209 check_wsock2 ( struct SessionHandle *data )
212 WORD wVersionRequested;
217 /* telnet requires at least WinSock 2.0 so ask for it. */
218 wVersionRequested = MAKEWORD(2, 0);
220 err = WSAStartup(wVersionRequested, &wsaData);
222 /* We must've called this once already, so this call */
223 /* should always succeed. But, just in case... */
225 failf(data,"WSAStartup failed (%d)",err);
226 return CURLE_FAILED_INIT;
229 /* We have to have a WSACleanup call for every successful */
230 /* WSAStartup call. */
233 /* Check that our version is supported */
234 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
235 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
236 /* Our version isn't supported */
237 failf(data,"insufficient winsock version to support "
239 return CURLE_FAILED_INIT;
242 /* Our version is supported */
248 CURLcode init_telnet(struct connectdata *conn)
252 tn = calloc(1, sizeof(struct TELNET));
254 return CURLE_OUT_OF_MEMORY;
256 conn->data->state.proto.telnet = (void *)tn; /* make us known */
258 tn->telrcv_state = CURL_TS_DATA;
260 /* Init suboptions */
263 /* Set the options we want by default */
264 tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
265 tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
267 /* To be compliant with previous releases of libcurl
268 we enable this option by default. This behaviour
269 can be changed thanks to the "BINARY" option in
270 CURLOPT_TELNETOPTIONS
272 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
273 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
275 /* We must allow the server to echo what we sent
276 but it is not necessary to request the server
277 to do so (it might forces the server to close
278 the connection). Hence, we ignore ECHO in the
281 tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
283 /* Set the subnegotiation fields to send information
284 just after negotiation passed (do/will)
286 Default values are (0,0) initialized by calloc.
287 According to the RFC1013 it is valid:
288 A value equal to zero is acceptable for the width (or height),
289 and means that no character width (or height) is being sent.
290 In this case, the width (or height) that will be assumed by the
291 Telnet server is operating system specific (it will probably be
292 based upon the terminal type information that may have been sent
293 using the TERMINAL TYPE Telnet option). */
294 tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
298 static void negotiate(struct connectdata *conn)
301 struct TELNET *tn = (struct TELNET *) conn->data->state.proto.telnet;
303 for(i = 0;i < CURL_NTELOPTS;i++) {
304 if(i==CURL_TELOPT_ECHO)
307 if(tn->us_preferred[i] == CURL_YES)
308 set_local_option(conn, i, CURL_YES);
310 if(tn->him_preferred[i] == CURL_YES)
311 set_remote_option(conn, i, CURL_YES);
315 #ifndef CURL_DISABLE_VERBOSE_STRINGS
316 static void printoption(struct SessionHandle *data,
317 const char *direction, int cmd, int option)
322 if(data->set.verbose) {
323 if(cmd == CURL_IAC) {
324 if(CURL_TELCMD_OK(option))
325 infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
327 infof(data, "%s IAC %d\n", direction, option);
330 fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
331 (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
333 if(CURL_TELOPT_OK(option))
334 opt = CURL_TELOPT(option);
335 else if(option == CURL_TELOPT_EXOPL)
341 infof(data, "%s %s %s\n", direction, fmt, opt);
343 infof(data, "%s %s %d\n", direction, fmt, option);
346 infof(data, "%s %d %d\n", direction, cmd, option);
352 static void send_negotiation(struct connectdata *conn, int cmd, int option)
354 unsigned char buf[3];
355 ssize_t bytes_written;
357 struct SessionHandle *data = conn->data;
360 buf[1] = (unsigned char)cmd;
361 buf[2] = (unsigned char)option;
363 bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
364 if(bytes_written < 0) {
366 failf(data,"Sending data failed (%d)",err);
369 printoption(conn->data, "SENT", cmd, option);
373 void set_remote_option(struct connectdata *conn, int option, int newstate)
375 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
376 if(newstate == CURL_YES) {
377 switch(tn->him[option]) {
379 tn->him[option] = CURL_WANTYES;
380 send_negotiation(conn, CURL_DO, option);
384 /* Already enabled */
388 switch(tn->himq[option]) {
390 /* Already negotiating for CURL_YES, queue the request */
391 tn->himq[option] = CURL_OPPOSITE;
394 /* Error: already queued an enable request */
400 switch(tn->himq[option]) {
402 /* Error: already negotiating for enable */
405 tn->himq[option] = CURL_EMPTY;
412 switch(tn->him[option]) {
414 /* Already disabled */
418 tn->him[option] = CURL_WANTNO;
419 send_negotiation(conn, CURL_DONT, option);
423 switch(tn->himq[option]) {
425 /* Already negotiating for NO */
428 tn->himq[option] = CURL_EMPTY;
434 switch(tn->himq[option]) {
436 tn->himq[option] = CURL_OPPOSITE;
447 void rec_will(struct connectdata *conn, int option)
449 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
450 switch(tn->him[option]) {
452 if(tn->him_preferred[option] == CURL_YES) {
453 tn->him[option] = CURL_YES;
454 send_negotiation(conn, CURL_DO, option);
457 send_negotiation(conn, CURL_DONT, option);
462 /* Already enabled */
466 switch(tn->himq[option]) {
468 /* Error: DONT answered by WILL */
469 tn->him[option] = CURL_NO;
472 /* Error: DONT answered by WILL */
473 tn->him[option] = CURL_YES;
474 tn->himq[option] = CURL_EMPTY;
480 switch(tn->himq[option]) {
482 tn->him[option] = CURL_YES;
485 tn->him[option] = CURL_WANTNO;
486 tn->himq[option] = CURL_EMPTY;
487 send_negotiation(conn, CURL_DONT, option);
495 void rec_wont(struct connectdata *conn, int option)
497 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
498 switch(tn->him[option]) {
500 /* Already disabled */
504 tn->him[option] = CURL_NO;
505 send_negotiation(conn, CURL_DONT, option);
509 switch(tn->himq[option]) {
511 tn->him[option] = CURL_NO;
515 tn->him[option] = CURL_WANTYES;
516 tn->himq[option] = CURL_EMPTY;
517 send_negotiation(conn, CURL_DO, option);
523 switch(tn->himq[option]) {
525 tn->him[option] = CURL_NO;
528 tn->him[option] = CURL_NO;
529 tn->himq[option] = CURL_EMPTY;
537 set_local_option(struct connectdata *conn, int option, int newstate)
539 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
540 if(newstate == CURL_YES) {
541 switch(tn->us[option]) {
543 tn->us[option] = CURL_WANTYES;
544 send_negotiation(conn, CURL_WILL, option);
548 /* Already enabled */
552 switch(tn->usq[option]) {
554 /* Already negotiating for CURL_YES, queue the request */
555 tn->usq[option] = CURL_OPPOSITE;
558 /* Error: already queued an enable request */
564 switch(tn->usq[option]) {
566 /* Error: already negotiating for enable */
569 tn->usq[option] = CURL_EMPTY;
576 switch(tn->us[option]) {
578 /* Already disabled */
582 tn->us[option] = CURL_WANTNO;
583 send_negotiation(conn, CURL_WONT, option);
587 switch(tn->usq[option]) {
589 /* Already negotiating for NO */
592 tn->usq[option] = CURL_EMPTY;
598 switch(tn->usq[option]) {
600 tn->usq[option] = CURL_OPPOSITE;
611 void rec_do(struct connectdata *conn, int option)
613 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
614 switch(tn->us[option]) {
616 if(tn->us_preferred[option] == CURL_YES) {
617 tn->us[option] = CURL_YES;
618 send_negotiation(conn, CURL_WILL, option);
619 if(tn->subnegotiation[option] == CURL_YES)
620 /* transmission of data option */
621 sendsuboption(conn, option);
623 else if(tn->subnegotiation[option] == CURL_YES) {
624 /* send information to achieve this option*/
625 tn->us[option] = CURL_YES;
626 send_negotiation(conn, CURL_WILL, option);
627 sendsuboption(conn, option);
630 send_negotiation(conn, CURL_WONT, option);
634 /* Already enabled */
638 switch(tn->usq[option]) {
640 /* Error: DONT answered by WILL */
641 tn->us[option] = CURL_NO;
644 /* Error: DONT answered by WILL */
645 tn->us[option] = CURL_YES;
646 tn->usq[option] = CURL_EMPTY;
652 switch(tn->usq[option]) {
654 tn->us[option] = CURL_YES;
655 if(tn->subnegotiation[option] == CURL_YES) {
656 /* transmission of data option */
657 sendsuboption(conn, option);
661 tn->us[option] = CURL_WANTNO;
662 tn->himq[option] = CURL_EMPTY;
663 send_negotiation(conn, CURL_WONT, option);
671 void rec_dont(struct connectdata *conn, int option)
673 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
674 switch(tn->us[option]) {
676 /* Already disabled */
680 tn->us[option] = CURL_NO;
681 send_negotiation(conn, CURL_WONT, option);
685 switch(tn->usq[option]) {
687 tn->us[option] = CURL_NO;
691 tn->us[option] = CURL_WANTYES;
692 tn->usq[option] = CURL_EMPTY;
693 send_negotiation(conn, CURL_WILL, option);
699 switch(tn->usq[option]) {
701 tn->us[option] = CURL_NO;
704 tn->us[option] = CURL_NO;
705 tn->usq[option] = CURL_EMPTY;
713 static void printsub(struct SessionHandle *data,
714 int direction, /* '<' or '>' */
715 unsigned char *pointer, /* where suboption data is */
716 size_t length) /* length of suboption data */
719 unsigned short *pval;
721 if(data->set.verbose) {
723 infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
727 i = pointer[length-2];
728 j = pointer[length-1];
730 if(i != CURL_IAC || j != CURL_SE) {
731 infof(data, "(terminated by ");
732 if(CURL_TELOPT_OK(i))
733 infof(data, "%s ", CURL_TELOPT(i));
734 else if(CURL_TELCMD_OK(i))
735 infof(data, "%s ", CURL_TELCMD(i));
737 infof(data, "%u ", i);
738 if(CURL_TELOPT_OK(j))
739 infof(data, "%s", CURL_TELOPT(j));
740 else if(CURL_TELCMD_OK(j))
741 infof(data, "%s", CURL_TELCMD(j));
743 infof(data, "%d", j);
744 infof(data, ", not IAC SE!) ");
750 infof(data, "(Empty suboption?)");
754 if(CURL_TELOPT_OK(pointer[0])) {
756 case CURL_TELOPT_TTYPE:
757 case CURL_TELOPT_XDISPLOC:
758 case CURL_TELOPT_NEW_ENVIRON:
759 case CURL_TELOPT_NAWS:
760 infof(data, "%s", CURL_TELOPT(pointer[0]));
763 infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
768 infof(data, "%d (unknown)", pointer[i]);
771 case CURL_TELOPT_NAWS:
772 pval = (unsigned short*)(pointer+1);
773 infof(data, "Width: %hu ; Height: %hu",
774 ntohs(pval[0]), ntohs(pval[1]));
778 case CURL_TELQUAL_IS:
781 case CURL_TELQUAL_SEND:
782 infof(data, " SEND");
784 case CURL_TELQUAL_INFO:
785 infof(data, " INFO/REPLY");
787 case CURL_TELQUAL_NAME:
788 infof(data, " NAME");
793 case CURL_TELOPT_TTYPE:
794 case CURL_TELOPT_XDISPLOC:
796 infof(data, " \"%s\"", &pointer[2]);
798 case CURL_TELOPT_NEW_ENVIRON:
799 if(pointer[1] == CURL_TELQUAL_IS) {
801 for(i = 3;i < length;i++) {
803 case CURL_NEW_ENV_VAR:
806 case CURL_NEW_ENV_VALUE:
810 infof(data, "%c", pointer[i]);
817 for(i = 2; i < length; i++)
818 infof(data, " %.2x", pointer[i]);
827 static CURLcode check_telnet_options(struct connectdata *conn)
829 struct curl_slist *head;
830 struct curl_slist *beg;
831 char option_keyword[128];
832 char option_arg[256];
833 struct SessionHandle *data = conn->data;
834 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
835 CURLcode result = CURLE_OK;
838 /* Add the user name as an environment variable if it
839 was given on the command line */
840 if(conn->bits.user_passwd) {
841 snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
842 beg = curl_slist_append(tn->telnet_vars, option_arg);
844 curl_slist_free_all(tn->telnet_vars);
845 tn->telnet_vars = NULL;
846 return CURLE_OUT_OF_MEMORY;
848 tn->telnet_vars = beg;
849 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
852 for(head = data->set.telnet_options; head; head=head->next) {
853 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
854 option_keyword, option_arg) == 2) {
857 if(Curl_raw_equal(option_keyword, "TTYPE")) {
858 strncpy(tn->subopt_ttype, option_arg, 31);
859 tn->subopt_ttype[31] = 0; /* String termination */
860 tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
864 /* Display variable */
865 if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
866 strncpy(tn->subopt_xdisploc, option_arg, 127);
867 tn->subopt_xdisploc[127] = 0; /* String termination */
868 tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
872 /* Environment variable */
873 if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
874 beg = curl_slist_append(tn->telnet_vars, option_arg);
876 result = CURLE_OUT_OF_MEMORY;
879 tn->telnet_vars = beg;
880 tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
885 if(Curl_raw_equal(option_keyword, "WS")) {
886 if(sscanf(option_arg, "%hu%*[xX]%hu",
887 &tn->subopt_wsx, &tn->subopt_wsy) == 2)
888 tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
890 failf(data, "Syntax error in telnet option: %s", head->data);
891 result = CURLE_TELNET_OPTION_SYNTAX;
897 /* To take care or not of the 8th bit in data exchange */
898 if(Curl_raw_equal(option_keyword, "BINARY")) {
899 binary_option=atoi(option_arg);
900 if(binary_option!=1) {
901 tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
902 tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
907 failf(data, "Unknown telnet option %s", head->data);
908 result = CURLE_UNKNOWN_TELNET_OPTION;
912 failf(data, "Syntax error in telnet option: %s", head->data);
913 result = CURLE_TELNET_OPTION_SYNTAX;
919 curl_slist_free_all(tn->telnet_vars);
920 tn->telnet_vars = NULL;
929 * Look at the sub-option buffer, and try to be helpful to the other
933 static void suboption(struct connectdata *conn)
935 struct curl_slist *v;
936 unsigned char temp[2048];
937 ssize_t bytes_written;
943 struct SessionHandle *data = conn->data;
944 struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
946 printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
947 switch (CURL_SB_GET(tn)) {
948 case CURL_TELOPT_TTYPE:
949 len = strlen(tn->subopt_ttype) + 4 + 2;
950 snprintf((char *)temp, sizeof(temp),
951 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
952 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
953 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
954 if(bytes_written < 0) {
956 failf(data,"Sending data failed (%d)",err);
958 printsub(data, '>', &temp[2], len-2);
960 case CURL_TELOPT_XDISPLOC:
961 len = strlen(tn->subopt_xdisploc) + 4 + 2;
962 snprintf((char *)temp, sizeof(temp),
963 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
964 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
965 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
966 if(bytes_written < 0) {
968 failf(data,"Sending data failed (%d)",err);
970 printsub(data, '>', &temp[2], len-2);
972 case CURL_TELOPT_NEW_ENVIRON:
973 snprintf((char *)temp, sizeof(temp),
974 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
978 for(v = tn->telnet_vars;v;v = v->next) {
979 tmplen = (strlen(v->data) + 1);
980 /* Add the variable only if it fits */
981 if(len + tmplen < (int)sizeof(temp)-6) {
982 sscanf(v->data, "%127[^,],%127s", varname, varval);
983 snprintf((char *)&temp[len], sizeof(temp) - len,
984 "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
985 CURL_NEW_ENV_VALUE, varval);
989 snprintf((char *)&temp[len], sizeof(temp) - len,
990 "%c%c", CURL_IAC, CURL_SE);
992 bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
993 if(bytes_written < 0) {
995 failf(data,"Sending data failed (%d)",err);
997 printsub(data, '>', &temp[2], len-2);
1007 * Send suboption information to the server side.
1010 static void sendsuboption(struct connectdata *conn, int option)
1012 ssize_t bytes_written;
1014 unsigned short x, y;
1015 unsigned char*uc1, *uc2;
1017 struct SessionHandle *data = conn->data;
1018 struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
1021 case CURL_TELOPT_NAWS:
1022 /* We prepare data to be sent */
1024 CURL_SB_ACCUM(tn, CURL_IAC);
1025 CURL_SB_ACCUM(tn, CURL_SB);
1026 CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1027 /* We must deal either with litte or big endien processors */
1028 /* Window size must be sent according to the 'network order' */
1029 x=htons(tn->subopt_wsx);
1030 y=htons(tn->subopt_wsy);
1031 uc1 = (unsigned char*)&x;
1032 uc2 = (unsigned char*)&y;
1033 CURL_SB_ACCUM(tn, uc1[0]);
1034 CURL_SB_ACCUM(tn, uc1[1]);
1035 CURL_SB_ACCUM(tn, uc2[0]);
1036 CURL_SB_ACCUM(tn, uc2[1]);
1038 CURL_SB_ACCUM(tn, CURL_IAC);
1039 CURL_SB_ACCUM(tn, CURL_SE);
1041 /* data suboption is now ready */
1043 printsub(data, '>', (unsigned char *)tn->subbuffer+2,
1046 /* we send the header of the suboption... */
1047 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1048 if(bytes_written < 0) {
1050 failf(data, "Sending data failed (%d)", err);
1052 /* ... then the window size with the send_telnet_data() function
1053 to deal with 0xFF cases ... */
1054 send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
1055 /* ... and the footer */
1056 bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
1057 if(bytes_written < 0) {
1059 failf(data, "Sending data failed (%d)", err);
1067 CURLcode telrcv(struct connectdata *conn,
1068 const unsigned char *inbuf, /* Data received from socket */
1069 ssize_t count) /* Number of bytes received */
1075 struct SessionHandle *data = conn->data;
1076 struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
1078 #define startskipping() \
1079 if(startwrite >= 0) { \
1080 result = Curl_client_write(conn, \
1082 (char *)&inbuf[startwrite], \
1084 if(result != CURLE_OK) \
1089 #define writebyte() \
1090 if(startwrite < 0) \
1093 #define bufferflush() startskipping()
1098 switch (tn->telrcv_state) {
1100 tn->telrcv_state = CURL_TS_DATA;
1103 break; /* Ignore \0 after CR */
1110 tn->telrcv_state = CURL_TS_IAC;
1115 tn->telrcv_state = CURL_TS_CR;
1121 DEBUGASSERT(startwrite < 0);
1124 tn->telrcv_state = CURL_TS_WILL;
1127 tn->telrcv_state = CURL_TS_WONT;
1130 tn->telrcv_state = CURL_TS_DO;
1133 tn->telrcv_state = CURL_TS_DONT;
1137 tn->telrcv_state = CURL_TS_SB;
1140 tn->telrcv_state = CURL_TS_DATA;
1147 tn->telrcv_state = CURL_TS_DATA;
1148 printoption(data, "RCVD", CURL_IAC, c);
1154 printoption(data, "RCVD", CURL_WILL, c);
1155 tn->please_negotiate = 1;
1157 tn->telrcv_state = CURL_TS_DATA;
1161 printoption(data, "RCVD", CURL_WONT, c);
1162 tn->please_negotiate = 1;
1164 tn->telrcv_state = CURL_TS_DATA;
1168 printoption(data, "RCVD", CURL_DO, c);
1169 tn->please_negotiate = 1;
1171 tn->telrcv_state = CURL_TS_DATA;
1175 printoption(data, "RCVD", CURL_DONT, c);
1176 tn->please_negotiate = 1;
1178 tn->telrcv_state = CURL_TS_DATA;
1183 tn->telrcv_state = CURL_TS_SE;
1185 CURL_SB_ACCUM(tn,c);
1192 * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1193 * Several things may have happened. An IAC was not doubled, the
1194 * IAC SE was left off, or another option got inserted into the
1195 * suboption are all possibilities. If we assume that the IAC was
1196 * not doubled, and really the IAC SE was left off, we could get
1197 * into an infinate loop here. So, instead, we terminate the
1198 * suboption, and process the partial suboption if we can.
1200 CURL_SB_ACCUM(tn, CURL_IAC);
1201 CURL_SB_ACCUM(tn, c);
1202 tn->subpointer -= 2;
1205 printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1206 suboption(conn); /* handle sub-option */
1207 tn->telrcv_state = CURL_TS_IAC;
1210 CURL_SB_ACCUM(tn,c);
1211 tn->telrcv_state = CURL_TS_SB;
1215 CURL_SB_ACCUM(tn, CURL_IAC);
1216 CURL_SB_ACCUM(tn, CURL_SE);
1217 tn->subpointer -= 2;
1219 suboption(conn); /* handle sub-option */
1220 tn->telrcv_state = CURL_TS_DATA;
1230 /* Escape and send a telnet data block */
1231 /* TODO: write large chunks of data instead of one byte at a time */
1232 static CURLcode send_telnet_data(struct connectdata *conn,
1233 char *buffer, ssize_t nread)
1235 unsigned char outbuf[2];
1236 ssize_t bytes_written, total_written;
1238 CURLcode rc = CURLE_OK;
1240 while(rc == CURLE_OK && nread--) {
1241 outbuf[0] = *buffer++;
1243 if(outbuf[0] == CURL_IAC)
1244 outbuf[out_count++] = CURL_IAC;
1248 /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1249 struct pollfd pfd[1];
1250 pfd[0].fd = conn->sock[FIRSTSOCKET];
1251 pfd[0].events = POLLOUT;
1252 switch (Curl_poll(pfd, 1, -1)) {
1253 case -1: /* error, abort writing */
1254 case 0: /* timeout (will never happen) */
1255 rc = CURLE_SEND_ERROR;
1257 default: /* write! */
1259 rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
1260 out_count-total_written, &bytes_written);
1261 total_written += bytes_written;
1264 /* handle partial write */
1265 } while(rc == CURLE_OK && total_written < out_count);
1270 static CURLcode telnet_done(struct connectdata *conn,
1271 CURLcode status, bool premature)
1273 struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
1274 (void)status; /* unused */
1275 (void)premature; /* not used */
1280 curl_slist_free_all(tn->telnet_vars);
1281 tn->telnet_vars = NULL;
1283 Curl_safefree(conn->data->state.proto.telnet);
1288 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1291 struct SessionHandle *data = conn->data;
1292 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1295 WSOCK2_FUNC close_event_func;
1296 WSOCK2_FUNC create_event_func;
1297 WSOCK2_FUNC event_select_func;
1298 WSOCK2_FUNC enum_netevents_func;
1299 WSAEVENT event_handle;
1300 WSANETWORKEVENTS events;
1301 HANDLE stdin_handle;
1306 DWORD readfile_read;
1310 struct pollfd pfd[2];
1312 curl_off_t total_dl = 0;
1313 curl_off_t total_ul = 0;
1318 char *buf = data->state.buffer;
1321 *done = TRUE; /* unconditionally */
1323 code = init_telnet(conn);
1327 tn = (struct TELNET *)data->state.proto.telnet;
1329 code = check_telnet_options(conn);
1335 ** This functionality only works with WinSock >= 2.0. So,
1336 ** make sure have it.
1338 code = check_wsock2(data);
1342 /* OK, so we have WinSock 2.0. We need to dynamically */
1343 /* load ws2_32.dll and get the function pointers we need. */
1344 wsock2 = LoadLibrary("WS2_32.DLL");
1345 if(wsock2 == NULL) {
1346 failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
1347 return CURLE_FAILED_INIT;
1350 /* Grab a pointer to WSACreateEvent */
1351 create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1352 if(create_event_func == NULL) {
1353 failf(data,"failed to find WSACreateEvent function (%d)",
1355 FreeLibrary(wsock2);
1356 return CURLE_FAILED_INIT;
1359 /* And WSACloseEvent */
1360 close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1361 if(close_event_func == NULL) {
1362 failf(data,"failed to find WSACloseEvent function (%d)",
1364 FreeLibrary(wsock2);
1365 return CURLE_FAILED_INIT;
1368 /* And WSAEventSelect */
1369 event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1370 if(event_select_func == NULL) {
1371 failf(data,"failed to find WSAEventSelect function (%d)",
1373 FreeLibrary(wsock2);
1374 return CURLE_FAILED_INIT;
1377 /* And WSAEnumNetworkEvents */
1378 enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1379 if(enum_netevents_func == NULL) {
1380 failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1382 FreeLibrary(wsock2);
1383 return CURLE_FAILED_INIT;
1386 /* We want to wait for both stdin and the socket. Since
1387 ** the select() function in winsock only works on sockets
1388 ** we have to use the WaitForMultipleObjects() call.
1391 /* First, create a sockets event object */
1392 event_handle = (WSAEVENT)create_event_func();
1393 if(event_handle == WSA_INVALID_EVENT) {
1394 failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
1395 FreeLibrary(wsock2);
1396 return CURLE_FAILED_INIT;
1399 /* Tell winsock what events we want to listen to */
1400 if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1402 close_event_func(event_handle);
1403 FreeLibrary(wsock2);
1407 /* The get the Windows file handle for stdin */
1408 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1410 /* Create the list of objects to wait for */
1411 objs[0] = event_handle;
1412 objs[1] = stdin_handle;
1414 /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1415 else use the old WaitForMultipleObjects() way */
1416 if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1417 data->set.is_fread_set) {
1418 /* Don't wait for stdin_handle, just wait for event_handle */
1420 /* Check stdin_handle per 100 milliseconds */
1425 wait_timeout = 1000;
1428 /* Keep on listening and act on events */
1430 waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1435 if(obj_count == 1) {
1436 /* read from user-supplied method */
1437 code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1438 if(code == CURL_READFUNC_ABORT) {
1440 code = CURLE_READ_ERROR;
1444 if(code == CURL_READFUNC_PAUSE)
1447 if(code == 0) /* no bytes */
1450 readfile_read = code; /* fall thru with number of bytes read */
1453 /* read from stdin */
1454 if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1455 &readfile_read, NULL)) {
1457 code = CURLE_READ_ERROR;
1464 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1465 &readfile_read, NULL)) {
1467 code = CURLE_READ_ERROR;
1472 code = send_telnet_data(conn, buf, readfile_read);
1481 case WAIT_OBJECT_0 + 1:
1483 if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1484 &readfile_read, NULL)) {
1486 code = CURLE_READ_ERROR;
1490 code = send_telnet_data(conn, buf, readfile_read);
1500 if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1501 if((err = SOCKERRNO) != EINPROGRESS) {
1502 infof(data,"WSAEnumNetworkEvents failed (%d)", err);
1504 code = CURLE_READ_ERROR;
1508 if(events.lNetworkEvents & FD_READ) {
1509 /* read data from network */
1510 code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1511 /* read would've blocked. Loop again */
1512 if(code == CURLE_AGAIN)
1514 /* returned not-zero, this an error */
1519 /* returned zero but actually received 0 or less here,
1520 the server closed the connection and we bail out */
1521 else if(nread <= 0) {
1526 code = telrcv(conn, (unsigned char *)buf, nread);
1532 /* Negotiate if the peer has started negotiating,
1533 otherwise don't. We don't want to speak telnet with
1534 non-telnet servers, like POP or SMTP. */
1535 if(tn->please_negotiate && !tn->already_negotiated) {
1537 tn->already_negotiated = 1;
1540 if(events.lNetworkEvents & FD_CLOSE) {
1547 if(data->set.timeout) {
1549 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1550 failf(data, "Time-out");
1551 code = CURLE_OPERATION_TIMEDOUT;
1557 /* We called WSACreateEvent, so call WSACloseEvent */
1558 if(!close_event_func(event_handle)) {
1559 infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
1562 /* "Forget" pointers into the library we're about to free */
1563 create_event_func = NULL;
1564 close_event_func = NULL;
1565 event_select_func = NULL;
1566 enum_netevents_func = NULL;
1568 /* We called LoadLibrary, so call FreeLibrary */
1569 if(!FreeLibrary(wsock2))
1570 infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
1573 pfd[0].events = POLLIN;
1575 if(conn->fread_func != (curl_read_callback)fread) {
1577 interval_ms = 100; /* poll user-supplied read function */
1580 /* really using fread, so infile is a FILE* */
1581 pfd[1].fd = fileno((FILE *)conn->fread_in);
1582 pfd[1].events = POLLIN;
1584 interval_ms = 1 * 1000;
1588 switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1589 case -1: /* error, stop reading */
1592 case 0: /* timeout */
1596 default: /* read! */
1597 if(pfd[0].revents & POLLIN) {
1598 /* read data from network */
1599 code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1600 /* read would've blocked. Loop again */
1601 if(code == CURLE_AGAIN)
1603 /* returned not-zero, this an error */
1608 /* returned zero but actually received 0 or less here,
1609 the server closed the connection and we bail out */
1610 else if(nread <= 0) {
1616 Curl_pgrsSetDownloadCounter(data, total_dl);
1617 code = telrcv(conn, (unsigned char *)buf, nread);
1623 /* Negotiate if the peer has started negotiating,
1624 otherwise don't. We don't want to speak telnet with
1625 non-telnet servers, like POP or SMTP. */
1626 if(tn->please_negotiate && !tn->already_negotiated) {
1628 tn->already_negotiated = 1;
1634 if(pfd[1].revents & POLLIN) { /* read from in file */
1635 nread = read(pfd[1].fd, buf, BUFSIZE - 1);
1639 /* read from user-supplied method */
1640 nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1641 if(nread == CURL_READFUNC_ABORT) {
1645 if(nread == CURL_READFUNC_PAUSE)
1650 code = send_telnet_data(conn, buf, nread);
1656 Curl_pgrsSetUploadCounter(data, total_ul);
1662 } /* poll switch statement */
1664 if(data->set.timeout) {
1666 if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1667 failf(data, "Time-out");
1668 code = CURLE_OPERATION_TIMEDOUT;
1673 if(Curl_pgrsUpdate(conn)) {
1674 code = CURLE_ABORTED_BY_CALLBACK;
1679 /* mark this as "no further transfer wanted" */
1680 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);